TransitionRecord
Interface: TransitionRecord
Defined in: src/atom/types.ts:1218
One occurrence: a row in the interaction log. SETTLED (and stimulus/sync)
transitions join 1:1 to a CommitBundle by id; pending and
rejected/rolled-back rows exist only here — that asymmetry is deliberate
(a rejected effect never touched state, so it has no commit).
Properties
arrival?
optionalarrival?:"observed"|"claimed"
Defined in: src/atom/types.ts:1291
WHERE THE CLAIM AND THE OBSERVATION MEET — present only on a fire whose edge
declared effect.navigatesTo, whichever gesture carries it, and absent
everywhere else.
Exactly two values, ever:
'claimed'— stamped when the navigation claim is written, besidetoNodeClaimed. It means the app SAID this action navigates and nothing has observed the app arrive. A fire under SessionOptions.allowUnmaterializedFires that nothing executed says this and can never say more: there is no action for an observation to corroborate, and the record'smaterialized: falseis the other half.'observed'— a later Session.sync landed on the page this fire claimed. It means A MATCHING OBSERVATION LANDED. It is corroboration, not causal proof: the sync row that produced it still carriesunverifiedEdge: true, because the cursor moved without passing a guard and nothing here can see the app's router.
WHAT IT NEVER SAYS. There is no third value for "did not arrive": a sync
somewhere else, or no sync at all, leaves 'claimed' standing forever. A
later legitimate hop and a failed navigation are indistinguishable from
here, a session with no sync channel observes nothing by construction, and a
clock is not evidence — so silence is the honest answer and the field simply
stops moving. toNodeClaimed is never retroactively flipped, and the
settlement receipt taken at rest is never rewritten (the upgrade lands on the
live record and rides ALONGSIDE the receipt — see docs/design/answer-grammar.md).
askId?
optionalaskId?:string
Defined in: src/atom/types.ts:1323
Set when this fire was authorized by a high-effect confirm ask — the
ConfirmRecord askId it closes. Makes the ask → decision → fire
chain auditable from the transition log alone (a committed high-effect
action can be traced back to the receipts a human approved). Absent on a
fire that never went through a confirm gate (e.g. a low-effect action, or
a human clicking the button directly with no ask outstanding).
attribution
attribution:
Attribution
Defined in: src/atom/types.ts:1232
WHICH RUNG FILED THIS ROW, AND WHAT THAT IS WORTH — on every transition, of every kind, always. See Attribution.
Not part of cause, deliberately: cause says WHAT this row is (a fire, a
stimulus) and carries bytes consumers have read since 0.1. This says how the
library came to believe it, which is a different question with a different
answer — and on a stimulus nobody attributed the two honestly disagree
(cause.principal: 'system', attribution.principal: 'unknown').
captured?
optionalcaptured?:ActionCapture
Defined in: src/atom/types.ts:1360
D21 — THE CAPTURE ENVELOPE, present only on a fire of a contextful()
action: what was true the moment before it ran, how it came to rest, what
went wrong, and what its anchor saw while it was in flight.
DATA CHANNEL, ALWAYS. Nothing in here is ever composed into agent-facing
prose — not a brief, not a tool description, not a result sentence — which
is what makes it safe for it to describe a page the library does not
control. And nothing in here carries a value the app did not allowlist: key
NAMES and event TYPES are the default, and include is the only door out of
it (see ContextfulOptions).
before and after/failure are stamped by the fire itself, so a
settlement receipt carries them; sensed lands one turn later on the LIVE
record, exactly as an arrival: 'observed' upgrade does, because a receipt
taken at rest is never rewritten.
cause
cause:
Cause
Defined in: src/atom/types.ts:1221
cursorVersion
cursorVersion:
number
Defined in: src/atom/types.ts:1314
Cursor version when the transition was created.
effectVerified?
optionaleffectVerified?:boolean|"unobservable"
Defined in: src/atom/types.ts:1254
Whether every DECLARED write key was present in the settled delta. 'unobservable' when the affordance declared no writes. This checks key presence only — not values, extra writes, or navigation claims.
evidence?
optionalevidence?:FilterCondition[]
Defined in: src/atom/types.ts:1256
Guard evidence captured at fire time (why this edge was passable).
fromNode
fromNode:
string
Defined in: src/atom/types.ts:1257
guardUnevaluated?
optionalguardUnevaluated?:string[]
Defined in: src/atom/types.ts:1303
Guard keys that could NOT be evaluated at fire time because the session's state view never contained them (L0/L1 — no state tap for those keys). The fire proceeded — the app remains the enforcer — but the record says honestly which conditions were taken on faith (D18 rung-killer fix).
id
id:
string
Defined in: src/atom/types.ts:1220
runtimeStageId — the join key into the footprintjs commit log.
materialized?
optionalmaterialized?:false
Defined in: src/atom/types.ts:1342
Present (false) only on an allowed unmaterialized fire (the
allowUnmaterializedFires tour): the fire invoked NOTHING — nothing was
bound to execute it — so every effect on this record is a claim, including
any navigation. The same honesty stance as toNodeClaimed and
guardUnevaluated: absence means normal, a stamped false means the
library is telling you what it could not do.
observations?
optionalobservations?:ExternalObservation[]
Defined in: src/atom/types.ts:1244
WHAT SOMEBODY ELSE SAW about this fire's effect — every Session.observeEffect report, in arrival order, appended and never rewritten. Absent until one arrives; a fire nobody reported on has no key, which is the honest shape of "nothing was said".
The FIRST report decides the settlement; later ones ride the live record
beside a receipt that is never rewritten (the arrival: 'observed'
precedent). Nothing here is proof the effect happened — it is proof a source
the app named reported that it did.
offerId?
optionalofferId?:string
Defined in: src/atom/types.ts:1333
The served row this fire cited (FireOptions.offerId), when it cited
one. Recorded whether or not any freshness axis enforces, because it is a
fact about the fire: this occurrence was planned against that row, and the
join from here to session.offerFor(offerId) — and on to any
StaleAcknowledgement naming the same offer — is what makes the chain
auditable from the transition log alone, exactly as askId does for the
confirm chain. Absent on a fire that cited nothing.
outcome
outcome:
Settlement
Defined in: src/atom/types.ts:1248
payload?
optionalpayload?:unknown
Defined in: src/atom/types.ts:1247
produced?
optionalproduced?:unknown
Defined in: src/atom/types.ts:1312
Data the fired handler RETURNED (search results, a looked-up record) — sanitized + capped. This is the "act → get data back" channel: an action that produces something the agent needs to pick from (a list of ids to open next) hands it back here. It rides the DATA channel, so untrusted content (user-generated names) is safe — it is never planner instructions. Populated once the handler resolves (await the settlement to read it).
timestamp
timestamp:
number
Defined in: src/atom/types.ts:1246
Epoch milliseconds when the transition was created.
toNode?
optionaltoNode?:string
Defined in: src/atom/types.ts:1258
toNodeClaimed?
optionaltoNodeClaimed?:boolean
Defined in: src/atom/types.ts:1263
True when toNode came from the affordance's declared navigatesTo — a CLAIM about the app, not an observation. sync() records observations.
unverifiedEdge?
optionalunverifiedEdge?:boolean
Defined in: src/atom/types.ts:1296
True on sync()-recorded hops: the cursor moved without passing any guard. Backward slices must treat the hop as inferred, not authorized.