Skip to main content

Module step

Module step 

Source
Expand description

Step-assignment pass (FR-3.4): 1-based step ordinals for semantic events.

The pass is a pure function over a slice of EventRows: it assigns each event’s step in place. The store reads rows via crate::store::Store::list_events, runs this pass, and writes the ordinals back in one transaction (crate::store::Store::assign_steps).

§Rules (FR-3.4)

  • terminal_output events are not steps → step = None.
  • Every other semantic event gets its own incrementing 1-based step, except a tool_result whose correlates points to a tool_call present in the session: that result shares the call’s step (a call and its result are one step).
  • A tool_result with correlates = None, or pointing to an id absent from the session (orphan / concurrent result-before-call from another source), gets its own step.

The pass is order-independent for correlation: it builds an id→step map of the calls in pass 1 and resolves deferred results against it in pass 2, so a result that sorts before its call (e.g. a tool_result block emitted ahead of the tool_use block in the same record, or concurrent sources) still resolves to the call’s step.

§Deviation (flagged, ADR-0002)

ADR-0001 said step ordinals are “derived at read time”. Storing them at finalize (authoritative events.step column) + self-healing on crate::store::Store::open is a deliberate deviation recorded in docs/adr/0002-stored-step-ordinals.md: it makes hh list’s step count a trivial COUNT(DISTINCT step), and self-heal repairs both a crashed finalize and the attached-MCP-proxy late-event race on the next hh invocation.

Functions§

assign_steps
Assign 1-based step ordinals to events in place (FR-3.4). See the module docs for the rules. Idempotent: re-running on already-assigned rows yields the same ordinals.