Skip to content

[G1] Tool-result fidelity: output bytes, truncation markers, content hash, ordering indexes, out-of-band error status, subagent-notification linkage #171

Closed

Description

@willwashburn

Part of #160 (group 1 — independent).

Problem

burn's hotspots, tool_output_bloat, context_delta, and span-tree features are driven by per-tool-result facts that relayhistory does not record. relayhistory stores a tool result as a session_events row (role='tool_result', kind='tool_result', text=<content>) and sets tool_calls.is_error (crates/ai-hist/src/lib.rs Claude :3142-3298, Codex :2101-2508). Missing, with burn's reader/consumer for each (crates/relayburn-sdk/src/):

Fact burn producer burn consumer
output_bytes / content_length of the raw result payload (before any truncation relayhistory applies to text) reader/claude/tool_results.rs:25-112 analyze/tool_output_bloat.rs (Signal B), analyze/context_delta.rs:48-68 (÷4 token estimate), hotspots --rank-by bytes
output_truncated — harness truncation markers: <system-truncated>, [truncated], output truncated, result truncated, response truncated, truncated to tool_results.rs:163-176 bloat detection
content_hash (sha256 of stable-stringified content, 16 hex) reader/hash.rs:32-38 dedup / edit-revert detection
call_index (n-th result for the same tool_use_id) + event_index (global order in the transcript) tool_results.rs:25-112 span tree ordering when timestamps tie
`status: running completed errored
`event_source: tool_result subagent_notification queue_event
Codex out-of-band error back-patching: exec_command_end.exit_code != 0, patch_apply_end.success == false applied to buffered results at task_complete codex/incremental.rs:294-319 is_error correctness
Subagent notification → {subagent_session_id, agent_id} on the result tool_results.rs:178-240 subagent tree
usage / usage_attribution per result (OpenCode even-split) opencode.rs:724-828 stays in burn (derived)
UserTurnRecord blocks: per-user-row `{kind: tool_result text, tool_use_id, byte_len, approx_tokens, is_error}` reader/user_turn.rs

Also: relayhistory's Claude is_error comes only from the tool_result block; Codex's from exit_code/patch_apply_end.success/mcp_tool_call_end.result.Err — good, but the event row does not say which signal set it.

Scope

  1. Schema: add to session_events (tool_result rows) payload_bytes INTEGER, payload_truncated INTEGER, payload_hash TEXT, call_index INTEGER, event_index INTEGER, result_status TEXT, event_source TEXT, error_signal TEXT (tool_result.is_error | exit_code | patch_apply | mcp_err | subagent_status), subagent_session_id TEXT, agent_id TEXT. Migration marker + HYDRATION_PARSER_VERSION bump.
  2. Claude: compute bytes/hash/truncation over the raw content (string or array, stable-stringified with sorted keys to match burn's stable_stringify), before the text column is filled; maintain per-tool_use_id call_index and a transcript-global event_index counter (persist the last index in the hydration checkpoint so incremental hydration continues the sequence — coordinate with the incremental-hydration issue).
  3. Codex: buffer results per turn and back-patch error_signal/result_status at task_complete exactly as burn does; function_call_output rows get event_source='function_call_output'.
  4. OpenCode/Grok/Cursor: same columns from their parsers (lands with each parity issue; this issue provides the helper ToolResultFacts::from_payload(&Value) in core they all call).
  5. Per-user-row blocks: expose session_user_turns_page(source, session_id) returning, per user message, the ordered [{kind, tool_use_id, byte_len, is_error}] — derivable from session_events (no new table) but computed once in core so every consumer agrees. approx_tokens is not computed here (burn's heuristic; a real tokenizer can be added later).
  6. SessionEvent struct, napi, TS contracts, docs/session-catalog.md matrix.

Acceptance

  • Corpus oversized-bash-output: the tool_result event has payload_bytes equal to burn's value for the same fixture (assert the number, taken from burn's reader/claude/tests.rs), payload_truncated = 1.
  • replacement-meta: event_source and marker linkage present.
  • Codex oversized-shell-output + with-tool-call: error_signal = 'exit_code' on the failing call; result_status = 'errored'.
  • system-subagent-notification: result row with event_source='subagent_notification', subagent_session_id set.
  • session_user_turns_page on user-turn-blocks (Claude, Codex, OpenCode) returns the same block sequence burn's UserTurnRecord tests assert.

Out of scope

Token estimation, usage attribution to tool calls, cost.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions