Execution, traces, and decisions
This page explains how a Run records what actually happened.
A trace is the server's structured account of execution, including the decisions that selected branches and loops.
The plan describes possible behavior before execution. The trace records reached behavior after execution. Its steps form one flat list in execution order. Invoking steps name the catalog entry in calls and, at full level, include resolved input, output, and step outcome.
Control-flow entries carry decisions. A branch records the arm it selected and the evaluated reason. A loop records continuation and exit decisions. Steps in untaken arms are absent. This is what makes “the run succeeded but did nothing” inspectable: the plan shows what could happen, and the trace shows which path did.
Harborview captured this branch decision:
{
"id": "gate",
"outcome": {
"ok": true,
"status": "success",
"error": null
},
"decisions": [
{
"at": "gate",
"took": "then",
"because": "{\"gt\":[\"$.steps.occ.output.count\",0]} → true"
}
]
}The surrounding run returned output.path_taken: "then", and the trace contained warm, the step from that arm. The eco step from the untaken arm was absent.
Trace levels are summary and full; none is an execute-time request value that suppresses only the inline trace. It does not decide the record's fate: store and the declared retention policy do, so a stored run executed at none can still be fetched later. A conformant Client does not request none for an unverified program.
One trace, two doors#
The trace is one layer with two access paths. One trace, two doors: it rides the execute response; if the run was stored, the same trace can be fetched later by run_id.
- Inline door (mandatory where execute exists). The trace envelope rides the execute response, per the requested trace level. There is no second round trip for what the engine just knew.
- Fetch door (optional; requires storage). The trace tool takes
{ run_id, trace_level?, question? }and returns{ run_id, outcome, output?, trace, narration? }, the same stored envelope. An unknown or unstoredrun_idyields a request errornot_found.
An execute request may carry an optional store boolean. Omitted, the engine's declared retention policy governs. store: true obliges the engine to retain the run record for later trace fetch; an engine with retention none rejects the request with kind unsupported, never silently ignores it. store: false obliges the engine not to retain the record beyond the response. run_id is always returned either way; it identifies the run in-band even when nothing is stored.
question and narration are optional and only for engines declaring trace_fetch: { "narrate": true }. The facts (the trace) are the contract; narration is optional interpretation layered on top, never a substitute for the record.
In the nautical register: the trace is the voyage log: written during the voyage (inline), readable from the archive later (fetch).
Formal rules: Part II §5.8, Trace, Part II §5.8.4, Plan–trace correspondence, and Part II §6.6, Trace: the fetch door.