hacifootprint
hcifootprintInterfaces

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?

optional arrival?: "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, beside toNodeClaimed. 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's materialized: false is 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 carries unverifiedEdge: 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?

optional askId?: 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?

optional captured?: 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?

optional effectVerified?: 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?

optional evidence?: 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?

optional guardUnevaluated?: 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?

optional materialized?: 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?

optional observations?: 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?

optional offerId?: 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?

optional payload?: unknown

Defined in: src/atom/types.ts:1247


produced?

optional produced?: 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?

optional toNode?: string

Defined in: src/atom/types.ts:1258


toNodeClaimed?

optional toNodeClaimed?: 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?

optional unverifiedEdge?: 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.

On this page