Fix nested compact Codex subagent attribution#2396
Conversation
Separate raw cumulative fork-boundary proof from owned usage subtraction and parent invalidation. Selectively migrate legacy parent-dependent cache rows, including known-model artifacts and later last-only snapshots.
There was a problem hiding this comment.
Pull request overview
This PR addresses incorrect token attribution for nested compact Codex subagents when a child rollout copies its parent’s raw cumulative counter at the fork boundary (previously leading to large “Unknown model” buckets). It introduces a raw-cumulative proof path (separate from owned/deduplicated totals) and adds a narrowly scoped cache migration to selectively quarantine/reparse only legacy parent-dependent fork artifacts.
Changes:
- Add a raw-cumulative snapshot path to
CodexInheritedTotalsResolverand use it only for copied-prefix detection (exact raw equality). - Introduce a fork-attribution migration marker and logic to quarantine/hide legacy parent-dependent cached rows until repaired, while preserving sentinel-owned unknown usage.
- Add/extend tests covering known-model copied-prefix suppression, raw-proof requirements (cumulative totals only), and cache migration behaviors.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/CodexBarTests/CostUsageScannerBreakdownTests.swift | Adds regression coverage for raw-parent-prefix suppression (including known-model legacy artifacts) and ensures last-only events can’t serve as raw proof. |
| Tests/CodexBarTests/CodexForkAttributionMigrationTests.swift | Adds targeted migration tests ensuring legacy parent-dependent candidates are quarantined/reparsed while legitimate sentinel-owned “unknown” remains visible. |
| Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+CacheHelpers.swift | Implements legacy fork-candidate detection, forces reparsing for those candidates, and hides them from cache-backed presentation until migration completes. |
| Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift | Splits owned vs raw parent snapshots, switches copied-prefix proof to raw totals, and adds migration planning/removal of out-of-window legacy suspects. |
| Sources/CodexBarCore/Vendored/CostUsage/CostUsageCache.swift | Allows loading a prior compatible producer key and adds cache/file migration markers for fork-attribution repair. |
| Sources/CodexBarCore/Generated/CodexParserHash.generated.swift | Rotates the Codex parser producer hash to reflect the attribution logic change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Require complete file parses before fresh-cache reuse, centralize provenance-based presentation projection, and add growing-rollout plus mixed-breakdown regressions.
|
Follow-up hardening is now on
Validation: |
|
CI triage update for exact head
No scanner change is needed here. Rerunning this head would reuse the same old merge ref and fail again; after #2386 lands, I will rebase this PR so CI runs against the repaired base. |
|
ClawSweeper status: review started. I am starting a fresh review of this pull request: Fix nested compact Codex subagent attribution This is item 1/1 in the current shard. Shard 0/1. This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking. Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted. |
Summary
parsedBytes == size, so an appended first-turn marker can reclassify a provisional compact child.Refs #2037, #2108, #2118, #2228, and #2285.
Evidence
This was reproduced from a real July 21 nested child/parent rollout. The UI symptom before the fix was a 409M-token
Unknown modelbucket:The child copied this exact raw cumulative boundary from its parent:
The prior comparison used the parent's owned/deduplicated total. That value is correct for ordinary fork subtraction, but it is the wrong accounting domain for proving that a compact child's prefix was copied.
Frozen-oracle results on the same rollout pair:
cc8da27cUnknown modelgpt-5.6-solcodex-auto-reviewCold, warm, and forced scans produced the same patched result.
Changes
CodexInheritedTotalsResolver.total_token_usagerecords.last_token_usage-only record cannot erase that proof.forkedFromId;parent context not requiredsentinel.mtimeandsizeas insufficient freshness whenparsedBytesproves the prior parse was incomplete.Maintainer invariants
Fork-cache migration is keyed by persisted provenance and dependency semantics, never by the user-visible
Unknown modellabel. A copied prefix can already have a known model.File freshness means both stable filesystem metadata and a complete parse (
parsedBytes == size). A parser that retained a valid prefix after a later read failure must not certify the full observed file as parsed.Parser behavior rotates the producer key; the cache artifact version is reserved for incompatible stored schema/layout changes. This avoids another cycle of model-label heuristics or blind
codex-vN.jsonbumps.Safety
Validation
make check— passed at766a8d83; parser hash60c110df71a146ea, SwiftFormat clean, SwiftLint 0 violations.CodexForkAttributionMigrationTests,CostUsageScannerBreakdownTests,CodexCompactSubagentAccountingTests,CodexSubagentAccountingIntegrationTests, andCostUsageFetcherCacheSnapshotTests.make testreached group 12/61 after 11 successful groups, then hit the unrelatedClaudeOAuthCredentialsStoreTemporaryKeychainCacheTeststest-store baseline. The same four assertions reproduce on cleanorigin/main@cc8da27c; this PR changes no Claude/Keychain files.766a8d83passed 73/74 groups in macOS shard 0, including every fork/cache suite changed here. The sole failed group was the unrelatedSpendDashboardTokenProvenanceTests: an earlier rollover test persisted the 7-day selection inUserDefaults.standard, so its fixed July 16 fixture fell outside the July 23 window. The same three assertions reproduce on cleanorigin/main@cc8da27c. Isolate dashboard rollover test defaults #2386 is the isolated base-test repair and is exact-head green/CLEAN; this PR should rebase after it lands rather than rerun the unchanged merge ref.