Skip to content

Populate execution-graph records from Codex parser (#87)#121

Merged
willwashburn merged 4 commits intomainfrom
feat/codex-execution-graph-87
Apr 26, 2026
Merged

Populate execution-graph records from Codex parser (#87)#121
willwashburn merged 4 commits intomainfrom
feat/codex-execution-graph-87

Conversation

@willwashburn
Copy link
Copy Markdown
Member

@willwashburn willwashburn commented Apr 26, 2026

Summary

  • Codex passive reader (parseCodexSession / parseCodexSessionIncremental) now returns relationships and toolResultEvents alongside the existing turns / content / userTurns arrays — mirroring the Claude population PR Execution graph substrate: SessionRelationshipRecord + ToolResultEventRecord (#42) #77 landed for Execution graph for passive readers: session relationships and tool-result event chronology #42.
  • function_call_output / custom_tool_call_output payloads become ToolResultEventRecords with eventSource: 'function_call_output'. Status is patched from exec_command_end.exit_code / patch_apply_end.success at task_complete time so errored calls surface with status: 'errored' and isError: true. Subagent terminal notifications (event_msg types matching subagent_*_complete / _done / _finished / _terminated) surface as ToolResultEventRecords with eventSource: 'subagent_notification'.
  • spawn_agent function calls produce a subagent SessionRelationshipRecord joining the spawned agent id (resolved from the call's args, the function_call_output payload, or the terminal notification — first hit wins, deduped) back to the spawning call_id via parentToolUseId. Each Codex session emits exactly one root row.
  • eventIndex, per-call_id callIndex counters, and the root-emitted flag are persisted in CodexResumeState and propagated through CodexCursor so resumed parses produce session-monotonic ids without double-emitting any (sessionId, toolUseId, eventIndex) tuple. Defers emission past committedEndOffset so an open turn's events stay buffered until its task_complete commits.
  • Wires the new arrays through packages/cli/src/ingest.ts (Codex path) and the burn codex runtime wrapper in packages/cli/src/commands/codex.ts into appendRelationships / appendToolResultEvents.

Test plan

  • pnpm run build passes.
  • pnpm run test:ts passes (465 tests, +13 new).
  • New parseCodexSession execution graph (#42 / #87) suite covers: exactly one root row per session; one ToolResultEventRecord per function-call output; monotonic unique eventIndex; errored status + isError: true from non-zero exec exit; completed status from successful patch_apply_end; subagent relationship row with parentToolUseId / agentId / subagentType / description populated from a spawn_agent fixture; subagent_notification event joined back by toolUseId; uncommitted-turn rows deferred.
  • New parseCodexSessionIncremental execution graph dedup (#87) suite covers re-parse + resume invariants — no duplicate (sessionId, toolUseId, eventIndex) tuples and exactly one root row across two passes split at a task_complete boundary.
  • New ingestCodexSessions execution graph passthrough (#87) suite verifies end-to-end that the writer appends both kinds of records to ~/.relayburn/ledger.jsonl for a Codex session with a spawn_agent call, and that a second ingest pass doesn't duplicate them.
  • New fixture: tests/fixtures/codex/with-spawn-agent.jsonl.

Refs

🤖 Generated with Claude Code


Open in Devin Review

The Codex passive reader now mirrors Claude's PR #77 substrate: every
function_call_output / custom_tool_call_output produces a
ToolResultEventRecord, spawn_agent function calls produce a subagent
SessionRelationshipRecord, and each session emits exactly one root row.
Status on tool-result events is patched from exec_command_end /
patch_apply_end at task_complete time so errored calls surface with
status: 'errored' and isError: true. Subagent terminal notifications
(event_msg payloads matching subagent_*_complete / _done / _finished /
_terminated) surface with eventSource: 'subagent_notification'.

eventIndex, per-call_id callIndex counters, and the root-emitted flag
are persisted in CodexResumeState (and propagated through CodexCursor)
so resumed parses produce session-monotonic ids without double-emitting
any (sessionId, toolUseId, eventIndex) tuple. Both the `burn ingest`
codex path and the `burn codex` runtime wrapper now persist the new
records via appendRelationships / appendToolResultEvents.

Closes #87.
Refs #42, #77.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

…graph-87

# Conflicts:
#	packages/cli/CHANGELOG.md
#	packages/cli/src/ingest.test.ts
#	packages/cli/src/ingest.ts
#	packages/ledger/CHANGELOG.md
#	packages/reader/CHANGELOG.md
#	packages/reader/src/codex.test.ts
#	packages/reader/src/codex.ts
devin-ai-integration[bot]

This comment was marked as resolved.

- packages/cli/src/commands/codex.ts: destructure and persist `userTurns`
  from `parseCodexSession` via `appendUserTurns`, matching the Claude
  wrapper. Without this, user-turn records emitted by the Codex parser
  (#94) are silently dropped from `burn codex` runs until `burn ingest`
  re-processes the session.
- packages/reader/src/codex.ts: flip `hasSessionRelationships` to `true`
  in `buildCodexFidelity`. The flag tracks capability, not presence —
  with #87 the parser now emits root/subagent relationship rows, so the
  Codex column of FULL_REQUIRED is satisfied. Token-complete Codex turns
  now classify as `full` instead of `usage-only`.
- packages/reader/src/codex.test.ts: update the two affected fidelity
  assertions to expect `class: 'full'` and `hasSessionRelationships:
  true`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex passive reader: populate SessionRelationshipRecord and ToolResultEventRecord

1 participant