You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/trajectory is a DGM fitness ledger (prompt SHA, recipe SHA, parent, score). That job is correct and should stay. It is not a replay of what the model did, and the other local streams do not fill that gap either.
Compared with grok-build's session folder (events.jsonl + chat_history.jsonl + live updates.jsonl) on the same model (grok-4.6, effort high), a real graff session is unreadable as a trajectory. The data is split across three files; two of them lie or lag; /trajectory prints almost none of what they do contain.
Related but distinct: ADR 0019 (transcript shows decisions) and #246 (behavioral schema, closed). This issue is the inspect path — can a human, after or during a run, see the movie.
The same turn's recipe_outcome recorded tool_calls: 14. The extra four are meta (todo_write, peer_message, load_tool_schemas, attempt_completion) and never enter ToolSink. The transcript has the assistant narration; the turn node says the model produced nothing.
A no-tool greeting run (c60c75f7…, "hi there") correctly recorded resp_types=text+reasoning, resp_text_len=38. The shape field only works when the history does not end in function_call_output.
Same-day grok-build session of similar length (01a0220a…): 3.7k events.jsonl rows (turn_started / loop_started / phase_changed / first_token / tool_started / tool_completed / MCP start+end), live updates.jsonl, per-call terminal/ logs, signals.json with TTFT/ITL/context %.
Bugs in the recorder (not product taste)
finalResponseShape walks backward and stops on function_call_output.src/mainloop_trace.zig#270 was added so a text-only refusal and an empty turn could be told apart (see Agent returns unrelated Chinese refusal during benign coding task #270). On the Responses wire, a tool-using turn's tail is tool results, so every such turn archives resp_blocks=0. The unit tests only cover histories that still end on the model item.
DGM turn and session transcript write only on recipe_outcome. An in-flight turn is invisible to /trajectory, /resume, and a crash. Behavior already has turn_started for the live turn; the other two files do not.
Behavior lifecycle is incomplete on the interactive path. Schema in src/behavior_trace_types.zig has tool_started / tool_finished / text_delta / turn_committed / run_finished. Default (GRAFF_BEHAVIOR_TRACE unset) is lifecycle-only by design (docs/behavioral-trajectories.md); even that is not emitting turn_committed / run_finished. Rich kinds stay behind GRAFF_BEHAVIOR_TRACE=full — keep that privacy gate.
/trajectory ignores fields already on the turn node (tool bag, cache tokens, resp_*, model_calls, tool_errors). It prints turn N ✓ 95s · prompt <sha> · <task>.
Proposed work (ordered)
Do not mix tool events into the DGM JSONL. That file is the population archive; docs/behavioral-trajectories.md forbids merging it with the behavioral stream.
Fix finalResponseShape so it shapes the last model-authored run (skip trailing function_call_output). Extend the #270 tests with a Responses history that ends on tool results and still has a prior message + reasoning.
Flush a live turn stub when the turn begins (DGM turn with ok omitted / live: true, and a session-transcript checkpoint). Close it on recipe_outcome as today.
Teach /trajectory to print what the turn node already has: tools bag (or a count + errors), cache permille, resp_types, and an in-flight marker. Optionally a one-line pointer at the session transcript for that turn.
Finish default lifecycle on .graff/behavior/:turn_committed + run_finished. Add first_token + monotonic call_id to the operational trace (ev=tool / ev=api) — counters only, no args/text.
Periodic session-transcript flush so /resume and inspect match the wire mid-turn.
ADR 0019 (interpreted one-liners, collapsed infra, compact WORKING) is the display half of the same density problem; land it on its own. Line-REPL click-to-expand is explicitly not in scope (ADR 0019: /debug / TUI fold).
Non-goals
Default-on GRAFF_BEHAVIOR_TRACE=full (args + assistant text in plaintext).
Schema-constraining the agentic phase (ADR 0001).
Copying grok-build's updates.jsonl / rewind snapshots / per-call MCP dumps as a first slice.
Putting tool payloads into .graff/trajectories/.
Acceptance
A tool-using turn archives nonzero resp_blocks / resp_types when the model also emitted text or reasoning. The no-tool greeting fixture still works.
/trajectory during an in-flight turn shows that turn (not "3 turns" while trace is on turn 4).
/trajectory for a closed turn shows tool count or bag, errors, and cache hit when those fields are present.
Behavior file for an interactive session that starts and ends cleanly contains run_started, matching turn_started/turn_committed pairs, and run_finished.
Operational ev=tool rows can be paired by call_id (start optional; finish required).
Killing the process mid-turn leaves a transcript that includes in-flight function_call items already executed.
DGM record kinds are unchanged. Old archive readers still parse.
Summary
/trajectoryis a DGM fitness ledger (prompt SHA, recipe SHA, parent, score). That job is correct and should stay. It is not a replay of what the model did, and the other local streams do not fill that gap either.Compared with grok-build's session folder (
events.jsonl+chat_history.jsonl+ liveupdates.jsonl) on the same model (grok-4.6, effort high), a real graff session is unreadable as a trajectory. The data is split across three files; two of them lie or lag;/trajectoryprints almost none of what they do contain.Related but distinct: ADR 0019 (transcript shows decisions) and #246 (behavioral schema, closed). This issue is the inspect path — can a human, after or during a run, see the movie.
Evidence (run
28d9d52384b3fc6a, 2026-08-21, grok-4.6 / xAI / 0.0.267)Session: merge
release/v0.0.268intomain, pull/codesign0.269..graff/trajectories/28d9d52384b3fc6a.jsonl.graff/traces/28d9d52384b3fc6a.jsonlapi/tool/wsevents withname/ms/result_bytes/is_error. No args, no call id, no first_token..graff/behavior/28d9d52384b3fc6a.jsonlrun_started+turn_started1–5. Noturn_committed, norun_finished, no tool events..graff/sessions/merging-0-268-then-pulling-0-269.transcript.jsonlchat_history.jsonl./trajectorynever reads it. Last flushed at turn 3.Turn 1 DGM row:
The same turn's
recipe_outcomerecordedtool_calls: 14. The extra four are meta (todo_write,peer_message,load_tool_schemas,attempt_completion) and never enterToolSink. The transcript has the assistant narration; the turn node says the model produced nothing.A no-tool greeting run (
c60c75f7…, "hi there") correctly recordedresp_types=text+reasoning,resp_text_len=38. The shape field only works when the history does not end infunction_call_output.Same-day grok-build session of similar length (
01a0220a…): 3.7kevents.jsonlrows (turn_started/loop_started/phase_changed/first_token/tool_started/tool_completed/ MCP start+end), liveupdates.jsonl, per-callterminal/logs,signals.jsonwith TTFT/ITL/context %.Bugs in the recorder (not product taste)
finalResponseShapewalks backward and stops onfunction_call_output.src/mainloop_trace.zig#270was added so a text-only refusal and an empty turn could be told apart (see Agent returns unrelated Chinese refusal during benign coding task #270). On the Responses wire, a tool-using turn's tail is tool results, so every such turn archivesresp_blocks=0. The unit tests only cover histories that still end on the model item.DGM
turnand session transcript write only onrecipe_outcome. An in-flight turn is invisible to/trajectory,/resume, and a crash. Behavior already hasturn_startedfor the live turn; the other two files do not.Behavior lifecycle is incomplete on the interactive path. Schema in
src/behavior_trace_types.zighastool_started/tool_finished/text_delta/turn_committed/run_finished. Default (GRAFF_BEHAVIOR_TRACEunset) is lifecycle-only by design (docs/behavioral-trajectories.md); even that is not emittingturn_committed/run_finished. Rich kinds stay behindGRAFF_BEHAVIOR_TRACE=full— keep that privacy gate./trajectoryignores fields already on the turn node (tool bag, cache tokens,resp_*,model_calls,tool_errors). It printsturn N ✓ 95s · prompt <sha> · <task>.Proposed work (ordered)
Do not mix tool events into the DGM JSONL. That file is the population archive; docs/behavioral-trajectories.md forbids merging it with the behavioral stream.
finalResponseShapeso it shapes the last model-authored run (skip trailingfunction_call_output). Extend the#270tests with a Responses history that ends on tool results and still has a priormessage+reasoning.turnwithokomitted /live: true, and a session-transcript checkpoint). Close it onrecipe_outcomeas today./trajectoryto print what the turn node already has: tools bag (or a count + errors), cache permille,resp_types, and an in-flight marker. Optionally a one-line pointer at the session transcript for that turn..graff/behavior/:turn_committed+run_finished. Addfirst_token+ monotoniccall_idto the operational trace (ev=tool/ev=api) — counters only, no args/text./resumeand inspect match the wire mid-turn.ADR 0019 (interpreted one-liners, collapsed infra, compact WORKING) is the display half of the same density problem; land it on its own. Line-REPL click-to-expand is explicitly not in scope (ADR 0019:
/debug/ TUI fold).Non-goals
GRAFF_BEHAVIOR_TRACE=full(args + assistant text in plaintext).updates.jsonl/ rewind snapshots / per-call MCP dumps as a first slice..graff/trajectories/.Acceptance
resp_blocks/resp_typeswhen the model also emitted text or reasoning. The no-tool greeting fixture still works./trajectoryduring an in-flight turn shows that turn (not "3 turns" while trace is on turn 4)./trajectoryfor a closed turn shows tool count or bag, errors, and cache hit when those fields are present.run_started, matchingturn_started/turn_committedpairs, andrun_finished.ev=toolrows can be paired bycall_id(start optional; finish required).function_callitems already executed.Related
resp_*exists so empty vs text-only can be told apart; this run shows the Responses+tools path still cannot.