Concepts
Managing Entries
How to withdraw or replace committed entries — retract and supersede.
Two ways to manage a committed entry
Once an entry is committed, you have two options:
| Operation | Who can do it | What happens |
|---|---|---|
retract() | Author only | Entry is marked retracted — withdrawn, final |
supersede() | Any agent | Entry is marked superseded, new entry takes its place |
Both exclude the original from attune() and reckon() results. Neither deletes — read() still returns them with their updated status.
Retract
Use retract() when an entry was wrong, irrelevant, or should not have been shared. Only the agent who wrote it can retract it.
await field.retract({
id: 'entry-id',
intent: 'entry was based on a misread of the source data — withdrawing',
agent: 'researcher', // must match the entry's author
})
- Idempotent — retracting an already-retracted entry is a no-op.
- Final — a retracted entry cannot be superseded. If you want to replace it rather than remove it, use
supersede()instead. - Intent is required — the reason for retraction is part of the record.
Supersede
Use supersede() when an entry is outdated and you want to replace it with a more accurate version. Any agent can supersede any committed entry.
await field.supersede({
superseding_id: 'old-entry-id', // the entry being replaced
entry: { topic: 'market-size', cagr: '19%' },
intent: 'revised projection using full-year dataset — previous used partial Q3 data only',
agent: 'fact-checker',
})
// returns { id, epoch, timestamp } for the new entry
- The old entry gets
status: "superseded"and disappears fromattune()/reckon(). - The new entry is committed immediately with
status: "committed". - Chains resolve automatically — if you supersede an entry that has already been superseded, the call follows the chain to the latest version and supersedes that.
Choosing between the two
Entry was wrong and should not exist → retract()
Entry was right but is now outdated → supersede()
Entry was partially right → supersede() with a corrected version
What read() returns
read() returns all entries regardless of status:
const all = await field.read({ topic: 'market-size' })
// Returns entries with status: 'committed', 'retracted', 'superseded', or 'draft' (if caller set)
const live = all.filter(e => e.status === 'committed')
This is intentional — the full history is always accessible, even if withdrawn entries are invisible in attunement.
Next
- retract() reference — full method signature and error codes
- supersede() reference — chain behavior and examples