Skip to content

refactor(stop): cost-tracker shares one usage-record def and one sentinel row (#379) - #386

Merged
wasikarn merged 1 commit into
developfrom
claude/perf-379-cost-shared-defs
Oct 3, 2026
Merged

wasikarn merged 1 commit into
developfrom
claude/perf-379-cost-shared-defs

Conversation

@wasikarn

@wasikarn wasikarn commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Refs #379 (item 3 of 3; items 1 and 2 merged in #380 and #384).

What

Proof

Equivalence. The develop copy (with #384 merged) was frozen and both copies ran on the same inputs.
Each run had a throwaway HOME, settle 0, and a date shim. Every run compared costs.jsonl, the marker,
stdout, stderr and the exit code byte for byte. The only normalization: bash's <script path>: line N:
prefix.

corpus bash 3.2 bash 5
316 real sessions (all 276 with subagents, 5 with codex calls, 40 without subagents) 1,531 rows, 0 diffs 1,531 rows, 0 diffs
8 hand-made sessions: both sentinel paths, 1h/multi-iteration writes, codex in main and subagents, every meta shape 61 rows, 0 diffs 61 rows, 0 diffs

Tests. Phase 6 of test-cost-tracker.sh:

  • The same two-iteration line (1h writes 300 + 400, flat 1000) sits in the main transcript and in a subagent
    file. Both rows must be cw 300 / cw1h 700. No test covered the subagent path's split before.
  • A usage: "not-an-object" line in each stream must give each stream the exact sentinel row (all keys)
    and its stderr line.

Red on a develop copy whose raw_records copy alone drifts (ignores iterations), which is the bug class
this removes. It passes on the develop copy and on the new code under bash 3.2 and 5. Mutants killed
(across test-cost-tracker.sh and test-session-stop.sh), 10 of 10:

  • t dropped or f wrong at either call site
  • the def ignores iterations
  • the def's t fixed to null
  • sentinel args swapped
  • sentinel files emptied
  • sentinel stream key dropped

Timing. Whole hook, 20 interleaved runs, medians (p90): unchanged, as expected for a refactor. At
193 subagents: 3,783 (3,968) -> 3,783 (4,044) ms on bash 3.2, 3,891 (4,248) -> 3,847 (4,059) ms on bash 5.
At 6 subagents: 155 -> 157 / 176 -> 176 ms.

Skipped: single-pass codex tally

emit_codex_invocations re-reads the subagent files that raw_records already read. On the 193-subagent
session that second read costs about 1.15 s (5 runs, 1,122-1,197 ms), about 30% of the hook. Folding it
into raw_records would merge two failure domains: today a malformed subagent line gives a sentinel row,
and the codex tally still counts. Keeping them apart needs the per-field try/catch that scan_transcript
uses. The local corpus has 0 subagent files with a codex call, so only hand-made fixtures could cover it.
Left as a follow-up rather than mixed into this refactor.

…inel row (GH #379)

raw_records and scan_transcript each carried a copy of the usage-record
builder (they differed only in t: and f:), and emit_rows and the
orchestrator path each built the jq_failed sentinel. Now usage_def
(def usage_rec($t; $f)) sits beside adv_def, and jq_failed_row <stream>
<files> builds the sentinel.

Byte-identical costs.jsonl, marker, stdout, stderr and rc against the
develop copy on 316 real sessions (1,531 rows) plus 8 hand-made sessions
(61 rows, both sentinel paths), under bash 3.2 and bash 5. Timing
unchanged (193 subagents: 3783 -> 3783 ms, bash 3.2).

Test phase 6: the same two-iteration 1h line in main and in a subagent
splits cw/cw1h alike, and each stream writes the same sentinel shape.
Red on a develop copy whose raw_records copy drifts; 10 mutants killed.
@wasikarn
wasikarn merged commit 24e09cf into develop Oct 3, 2026
3 checks passed
@wasikarn
wasikarn deleted the claude/perf-379-cost-shared-defs branch October 3, 2026 14:58
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.

1 participant