Fix restarted Codex subagent usage accounting#2208
Conversation
0dbfc16 to
4104822
Compare
7d1cba7 to
9986f43
Compare
9986f43 to
507bd7e
Compare
|
Maintainer closeout on
Merged as |
|
This merge regresses the copied-parent-prefix I froze 2,010 local JSONL files and ran the same CodexBarCLI cost scan with empty isolated caches. Only the scanner revision changed:
A warm repeat on the #2208 cache was identical. #2118 cannot repair this because #2208's subagent branch bypasses the parent resolver. One representative child starts with a leaf
A conservative same-spawn-second check across 38 Jul 16 subagent rollouts finds 18 non-empty copied prefixes totaling 3,527,023,205 tokens. Their later growth totals 387,607,038 tokens. The Unknown spike has the same cause: copied parent rows arrive before the leaf The unconditional branch in The follow-up needs phase-aware accounting:
Please do not ship the current scanner state. Unless a patch is already in flight, I will take the follow-up and provide a real-shape fixture plus frozen-corpus proof. |
|
Follow-up implemented in #2228. The patch keeps #2208's reset-only behavior, but moves the decision to a rollout-shape classifier. A subagent with only its leaf metadata owns an independent counter; a subagent with embedded ancestor metadata is a copied-prefix rollout. For the copied shape, the scanner either starts at the verified local leaf marker or retains the parent-baseline fallback. That removes the unconditional The PR also keeps #1042's producer-hash contract: parser semantics rotate the generated hash; |
Summary
source.subagentprovenance in both fast and fallback metadata parsersid, not the multi-agent tree's sharedsession_idRefs #2193.
Why
The reporter's follow-up showed that CodexBar found and scanned all rollouts. The undercount happened later:
forked_from_idmade CodexBar subtract the parent's cumulative total from a subagent whose counter restarted at zero.Codex protocol metadata marks spawned children with
source.subagent. Those counters are independent. A bareparent_thread_idremains an ordinary fork because it can carry a continuing parent counter. Current multi-agent metadata also uses one sharedsession_idfor the tree and a uniqueidfor each thread, so rollout identity must preferidacross both supported metadata locations.Verification
swift test --filter CostUsageScannerBreakdownTests— 87 tests passedswift test --filter CostUsageScannerTests— passedmake check— 0 SwiftLint violations; parser hash, formatting, shell, docs, and repository checks passedsession_idbut distinct root-levelidvaluesBehavior proof
An isolated production-style parent fixture reports 60,000,000 input / 48,000,000 cached / 3,000,000 output tokens. Its restarted subagent ends at 62,200 / 51,000 / 3,200. The combined report now returns 60,062,200 / 48,051,000 / 3,003,200, including the child exactly once.
The negative control remains intact: an ordinary continuing fork at 1,001 / 900 / 101 against a 1,000 / 900 / 100 parent baseline reports only 1 / 0 / 1.
AI assistance
Codex assisted with investigation, implementation, tests, review, and proof preparation.