Skip to content

fix: resolve Codex fork duplication when parent is unresolved (#2108)#2121

Closed
Yuxin-Qiao wants to merge 9 commits into
steipete:mainfrom
Yuxin-Qiao:fix-codex-fork-duplication-2108
Closed

fix: resolve Codex fork duplication when parent is unresolved (#2108)#2121
Yuxin-Qiao wants to merge 9 commits into
steipete:mainfrom
Yuxin-Qiao:fix-codex-fork-duplication-2108

Conversation

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor

This PR resolves #2108.

Problem

When a child session is forked from a parent, the child session logs often replay the parent session's token usage events at the beginning of the file.
If the parent session is unresolved/missing, and the logs only contain last_token_usage (without total_token_usage), CodexBar previously had no watermark and no way to filter out the replayed parent events. Sibling child sessions would thus repeat-count the parent prefix, leading to duplicate token usage counting.

Solution

Use the parent's session ID (forkedFromId) instead of the child's sessionId as the key-namespace for row deduplication keys when forkedFromId is present.
This ensures that any replayed parent turns (which have the same turn ID in all sibling child sessions) are recognized as duplicates of the parent session and are counted exactly once across all sibling sessions, rather than being multiplied for each child session.

@Yuxin-Qiao
Yuxin-Qiao force-pushed the fix-codex-fork-duplication-2108 branch from 7cce315 to 0a9acd4 Compare July 13, 2026 09:28

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7cce3156bc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Self.rememberCodexRows(
rows,
sessionId: session.id,
sessionId: forkedFromId ?? session.id,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Regenerate the Codex parser hash

Because this changes the Codex row de-duplication semantics, the producer key needs to change as well; otherwise existing caches written with the old child-scoped row keys are still loaded as valid and unchanged forked files keep their previously double-counted days until a manual force rescan. I checked Scripts/regenerate-codex-parser-hash.sh --check, and it reports Sources/CodexBarCore/Generated/CodexParserHash.generated.swift is stale, so normal refresh will not invalidate those old cache entries.

Useful? React with 👍 / 👎.

let uniqueRows = Self.uniqueCodexRows(
rows: parsed.rows,
sessionId: sessionId,
sessionId: forkedFromId ?? sessionId,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Do not key all fork rows by parent session

When two forked child sessions from the same unresolved parent have real child token_count rows without turn_id and the same model/day/token delta at the same event index, this parent-scoped key treats the second child's real usage as a duplicate and drops it. The replayed parent prefix needs cross-child de-duping, but applying forkedFromId to every parsed row also collapses legitimate child work in last-usage-only logs that lack turn IDs.

Useful? React with 👍 / 👎.

Self.rememberScannedCodexFile(
input: input,
session: CodexScannedSession(id: current.sessionId, days: current.days),
forkedFromId: current.forkedFromId,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reparse cached siblings when fork ownership changes

If the child file that previously owned the replayed parent prefix is later deleted or falls out of the scan roots, this fresh-cache path keeps the remaining forked siblings exactly as previously filtered and only records their parent-scoped keys after accepting their cached days. Removing the old owner then subtracts the sole cached copy of the replay, and the remaining sibling is never reparsed to reclaim those rows, so the report undercounts until a force rescan.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 13, 2026
@clawsweeper

clawsweeper Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed July 14, 2026, 2:57 AM ET / 06:57 UTC.

Summary
The branch parent-scopes provenance-backed Codex fork rows, changes fork-cache invalidation and replay filtering, derives turn identity from turn_context, adds scanner regressions, refreshes the parser hash, and serializes one Linux test suite.

Reproducibility: yes. at source level: the redacted fork-family fixture and issues #2037 and #2108 establish replay overcount, but this exact head has not been run against the affected frozen corpus.

Review metrics: 3 noteworthy metrics.

  • Patch surface: 5 files, +245/-19. A small production diff changes persisted cache and accounting semantics, with most added lines in focused regressions.
  • Focused regression coverage: 82 scanner tests reported passing. The suite exercises unresolved-parent and cache transitions but remains supplemental to affected-corpus proof.
  • Review continuity: 2 unresolved P2 findings on unchanged head. The current SHA matches the previous completed review, so both blockers remain active.

Merge readiness
Overall: 🦪 silver shellfish
Proof: 🦪 silver shellfish
Patch quality: 🦐 gold shrimp
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Fix the parent-removal and stale-turn-ID findings on the current branch.
  • Attach redacted cold and repeated warm totals from the frozen affected corpus.
  • Have the likely owner choose and document one consolidated fork identity and cache contract.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The committed redacted fixture, scanner oracle, and focused tests are useful supplemental evidence, but this head still needs redacted cold-scan and repeated warm-scan totals from the frozen affected corpus; redact paths, IDs, account data, endpoints, and credentials, then update the PR body to trigger review or ask a maintainer for @clawsweeper re-review.

Risk before merge

  • [P1] Deleting or losing a cached parent outside the active date window can leave retained child cache entries missing inherited rows, causing persistent undercount until a wider rescan or cache reset.
  • [P1] A turn_context without an ID can retain a preceding parent turn ID and incorrectly parent-scope genuine child usage, silently suppressing billable rows.
  • [P1] This branch, the merged fail-open design, and Fix Codex fork parent cache invalidation #2118 encode overlapping but different identity and cache contracts; merging without consolidation could create two partial sources of truth.
  • [P1] The parser-hash bump invalidates old cache entries, but no affected real-corpus cold/warm output demonstrates that the new cache ownership remains stable across refreshes and parent appearance or removal.

Maintainer options:

  1. Fix and consolidate before merge (recommended)
    Resolve both current-head findings, choose one fork identity and cache contract with the related PR, and attach redacted cold and warm affected-corpus totals.
  2. Accept possible undercount
    Merge the current semantics while explicitly accepting that parent removal and stale turn provenance can suppress genuine usage until cache repair.
  3. Pause for the canonical ledger
    Keep this PR open or close it after transferring its useful tests to the canonical cross-file provenance implementation.

Next step before merge

  • [P1] The contributor must fix the two concrete defects and supply real-corpus proof, after which a maintainer must choose and consolidate the canonical fork-accounting design.

Maintainer decision needed

  • Question: Should CodexBar adopt this turn-ID parent-scoped row ownership model, consolidate it with the parent-fingerprint and leaf-identity design in Fix Codex fork parent cache invalidation #2118, or retain the merged fail-open policy until a fuller family ledger is implemented?
  • Rationale: The merged design intentionally avoids destructive missing-parent deduplication, while two open PRs propose different partial provenance and cache contracts; code review alone cannot choose the permanent accounting contract safely.
  • Likely owner: steipete — He merged the existing intentional fail-open design and is best positioned to choose the repository's permanent accounting contract.
  • Options:
    • Consolidate the designs (recommended): Use one branch to combine reliable leaf identity, parent dependency invalidation, turn provenance, cross-window ownership migration, and affected-corpus proof.
    • Narrow this PR: Limit this PR to mechanics that do not change ambiguous missing-parent ownership and leave full sibling deduplication to the canonical ledger work.
    • Keep fail-open: Do not merge either destructive deduplication path until a complete family ledger and collision policy are proven on the affected corpus.

Security
Cleared: The diff changes local scanner and cache logic, a generated hash, tests, and test serialization without adding dependency, secret, permission, download, publishing, or supply-chain exposure.

Review findings

  • [P2] Invalidate retained fork children when their parent disappears — Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+CacheHelpers.swift:1180
  • [P2] Clear the active turn ID on every turn context — Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift:2135-2137
Review details

Best possible solution:

Adopt one provenance contract for the canonical fork-accounting issue, fix the two cache/turn-state defects, integrate complementary leaf-identity and parent-fingerprint work from the proof-positive related PR, and verify identical redacted cold and repeated warm totals on the frozen affected corpus.

Do we have a high-confidence way to reproduce the issue?

Yes at source level: the redacted fork-family fixture and issues #2037 and #2108 establish replay overcount, but this exact head has not been run against the affected frozen corpus.

Is this the best way to solve the issue?

Unclear: turn provenance can support safe deduplication, but the current patch still mishandles parent removal outside the scan window and stale turn IDs, and maintainers must consolidate it with the competing identity and cache design.

Full review comments:

  • [P2] Invalidate retained fork children when their parent disappears — Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+CacheHelpers.swift:1180
    The new invalidation path limits affected children to paths in the current scan set. A cached child outside the narrow date window can therefore retain rows computed while its parent existed after that parent is removed; the wider cache later reuses the stale child and undercounts until a force or wider rescan. Invalidate every retained cached child whose forkedFromId matches the removed parent while preserving or rebuilding rows needed outside the active window.
    Confidence: 0.98
  • [P2] Clear the active turn ID on every turn context — Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift:2135-2137
    This only assigns currentTurnID when the new turn_context carries an ID. If a replayed parent task_started is followed by a child context without one, genuine child token rows keep the parent ID and are deduplicated in the parent namespace. Set the active ID from the optional value on every context, including clearing it to nil, in both fast and fallback parsers.
    Confidence: 0.99

Overall correctness: patch is incorrect
Overall confidence: 0.98

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against b41715f3e3fb.

Label changes

Label justifications:

  • P2: The PR targets a real, limited-scope cost-accounting defect but still has two normal-priority correctness blockers.
  • merge-risk: 🚨 compatibility: Merging changes persisted cache identity and can silently alter existing users' reported usage totals across upgrades and refresh windows.
  • rating: 🦪 silver shellfish: Overall readiness is 🦪 silver shellfish; proof is 🦪 silver shellfish and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The committed redacted fixture, scanner oracle, and focused tests are useful supplemental evidence, but this head still needs redacted cold-scan and repeated warm-scan totals from the frozen affected corpus; redact paths, IDs, account data, endpoints, and credentials, then update the PR body to trigger review or ask a maintainer for @clawsweeper re-review.
Evidence reviewed

What I checked:

Likely related people:

  • Zihao-Qi: Authored the merged fork-containment and provenance design in Contain Codex interleaved overcount and add fork provenance fixtures (#2037) #2082, including the explicit missing-parent fail-open decision and deferred family-ledger work. (role: introduced behavior; confidence: high; commits: 5441ff75, 2433b97a36; files: Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift, Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+CacheHelpers.swift, Tests/CodexBarTests/CostUsageScannerBreakdownTests.swift)
  • steipete: Merged the current-main fork-containment design and is the clearest available owner for choosing between the overlapping fork-accounting approaches. (role: merger; confidence: high; files: Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift, Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner+CacheHelpers.swift)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (16 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-13T15:05:51.674Z sha 27980d8 :: needs real behavior proof before merge. :: [P2] Preserve prior row keys when rescanning fork siblings | [P2] Rescan fork children when dropping a parent file | [P2] Require reliable provenance before using parent scope
  • reviewed 2026-07-13T15:21:17.889Z sha 27980d8 :: needs real behavior proof before merge. :: [P2] Preserve prior row keys when rescanning fork siblings | [P2] Rescan fork children when removing their parent | [P2] Require reliable provenance before using parent scope
  • reviewed 2026-07-14T03:59:56.363Z sha 2aec564 :: needs real behavior proof before merge. :: [P2] Invalidate fork children outside the active scan window | [P2] Clear the active turn ID on every new turn context
  • reviewed 2026-07-14T04:33:30.392Z sha 2aec564 :: needs real behavior proof before merge. :: [P2] Invalidate cached fork children outside the active window | [P2] Clear the active turn ID at every new turn context
  • reviewed 2026-07-14T05:02:50.920Z sha 2aec564 :: needs real behavior proof before merge. :: [P2] Invalidate cached fork children outside the active window | [P2] Clear the active turn ID at every new turn context
  • reviewed 2026-07-14T05:31:48.137Z sha 2aec564 :: needs real behavior proof before merge. :: [P2] Invalidate cached fork children outside the active window | [P2] Clear the active turn ID at every new turn context
  • reviewed 2026-07-14T05:52:27.169Z sha 2aec564 :: needs real behavior proof before merge. :: [P2] Invalidate all cached children when a parent disappears | [P2] Clear the turn ID on every turn context
  • reviewed 2026-07-14T06:37:56.518Z sha 2aec564 :: needs real behavior proof before merge. :: [P2] Invalidate cached children outside the active scan window | [P2] Clear the active turn ID on every turn context

@Yuxin-Qiao
Yuxin-Qiao force-pushed the fix-codex-fork-duplication-2108 branch from 0a9acd4 to a27cdf4 Compare July 13, 2026 09:48
@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@Yuxin-Qiao
Yuxin-Qiao force-pushed the fix-codex-fork-duplication-2108 branch from a27cdf4 to be123f1 Compare July 13, 2026 09:50
@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: be123f1e2e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Self.rememberCodexRows(
rows,
sessionId: session.id,
sessionId: forkedFromId ?? session.id,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve child scope when remembering cached fork rows

When a forked session is kept from a fresh cache and the same session also exists as another copied file/root, child-only token_count rows that lack turn_id are remembered here under forkedFromId instead of the child session.id. The duplicate file's uniqueCodexRows checks the child session namespace for those untagged rows, does not see the first cached copy, and counts the child work again; pass the child session id through with the separate forkedFromId argument so only turn-tagged replay rows use the parent namespace.

Useful? React with 👍 / 👎.

Comment on lines +905 to +907
if let forkedFromId = cached.forkedFromId {
let parentIsResolved = (try? context.resources.fileIndex.fileURL(for: forkedFromId)) != nil
if !parentIsResolved {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reparse forks when a missing parent reappears

When a child fork was cached while its parent was unresolved, its cached days can include the replayed parent prefix. If that parent file later becomes available and sorts before the child in the scan, this branch now treats the child cache as fresh because parentIsResolved is true, so the parent file contributes the same rows and the stale child totals are kept without row-key filtering; that double-counts the replay until a force rescan, so cache freshness needs to account for the parent-resolution transition.

Useful? React with 👍 / 👎.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Addressed the cache-ownership review finding.

  • when a cached fork owner disappears, remaining siblings in the same fork family are invalidated and reparsed
  • added regression coverage for initial scan, owner removal, and repeat scan
  • focused validation: swift test --filter CostUsageScannerBreakdownTests — 81 tests passed

@codex review
@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: afcb524161

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +905 to +908
if let forkedFromId = cached.forkedFromId {
let parentIsResolved = (try? context.resources.fileIndex.fileURL(for: forkedFromId)) != nil
if !parentIsResolved {
return false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Reuse clean unresolved-fork cache entries

When a cached child still points at a deleted/missing parent, this block returns false before the fresh-cache path can reuse the repaired codexRows, so the same unchanged fork files are reparsed on every refresh for as long as the parent log remains absent. The sibling invalidation below already repairs ownership after a disappearance, and cachedCodexRowsNeedIdentityRescan already rejects entries without stable rows, so this turns the missing-parent case into a persistent cache miss and can make menu refreshes expensive for large fork families.

Useful? React with 👍 / 👎.

Self.rememberCodexRows(
rows,
sessionId: session.id,
sessionId: forkedFromId ?? session.id,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve child scope for untagged fork rows

This call passes the parent ID as sessionId and leaves the new forkedFromId argument nil, so rememberCodexRows stores even fork rows with turnID == nil in the parent namespace. uniqueCodexRows only parent-scopes rows that actually have a turn ID; when a fresh cached forked file is kept and another copy of the same session is encountered later, untagged rows are looked up under the child session and do not match the remembered keys, allowing duplicate usage to be counted. Pass session.id plus forkedFromId to keep the remembered keys consistent with the uniqueness check.

Useful? React with 👍 / 👎.

Comment on lines +2594 to +2595
let siblingPaths = cache.files.compactMap { path, usage in
forkFamiliesNeedingRescan.contains(usage.forkedFromId ?? "") ? path : nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't drop unrescanned siblings outside the window

When the cache retains a wider window, this selects every cached file in the fork family, including siblings whose days are outside the current scan window and therefore are not present in files. Those paths are removed from cache.files, but only siblingFiles from the current files list are rescanned; the code then keeps the old retained since/until keys, so a later report inside that supposedly retained range can be served from cache with those historical sibling days missing until another refresh happens to rescan them.

Useful? React with 👍 / 👎.

Comment on lines +954 to 955
forkedFromId: current.forkedFromId,
rows: cachedRows,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Filter cached fork rows against earlier contributors

This fresh-cache path only remembers cachedRows; it never re-runs uniqueCodexRows unless the same child session already contributed. If a real parent file is later restored, or an earlier sibling is parsed before this cached child, the already-seen parent-scoped turn keys are ignored and current.days can keep counting replayed parent rows that should now be removed. Cached fork files need the same row-level filtering whenever their parent-scoped keys collide with state, not just when sessionAlreadyContributed is true.

Useful? React with 👍 / 👎.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Follow-up pushed as c15ef6e: regenerated Sources/CodexBarCore/Generated/CodexParserHash.generated.swift with the repository script. The prior lint failure was the stale generated hash; local ./Scripts/lint.sh lint-linux now passes with 0 violations. @clawsweeper re-review

@clawsweeper clawsweeper Bot removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 13, 2026
@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Follow-up pushed as f233116: regenerated the parser hash again after the explicit lint annotation changed the hashed parser source. The latest CI log identified only this generated-artifact mismatch. @clawsweeper re-review

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 13, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 13, 2026
@Yuxin-Qiao

Yuxin-Qiao commented Jul 13, 2026

Copy link
Copy Markdown
Contributor Author

Rechecked the current PR head f2331160: the focused Codex fork/cache regression suite remains green with 81 tests passed.

The tests cover the unresolved-parent and fork-family cache transitions in the production scanner/cache path. I also checked the local machine for a real fork-transition corpus, but it does not contain a usable fork metadata sample, so I am not claiming a live corpus reproduction or attaching private session data. The remaining proof boundary is specifically a public/redacted unresolved-parent corpus supplied by the maintainer or CI environment.
@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Fixed the four cache-transition findings on 53ea045:

  • clean unresolved-fork children now reuse their cache instead of reparsing every refresh;
  • untagged child rows stay in the child session namespace while provenance-backed turns use the parent scope;
  • fork-family invalidation no longer removes retained siblings outside the active scan window;
  • cached fork rows are filtered against earlier parent/sibling contributors before reuse.

Validation: swift test --filter 'CostUsageScannerBreakdownTests|Issue2037ScannerIntegrationTests' — 84 tests passed.\n\n@clawsweeper re-review

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Follow-up: commit 827cbfb refreshes the repository-required CodexParserHash.generated.swift after the scanner cache changes.

Verified locally:

  • Scripts/regenerate-codex-parser-hash.sh --check — current (08ed55552fb30dfe)
  • focused fork scanner suites — 84 tests passed (reported in prior update)

The fixture is the committed, redacted 4d90→52bf fork family with a documented scanner oracle (deduped 52,185,847 vs naive 100,916,095 units); it is executable evidence, not UI imagery.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 827cbfbb96

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
}
let siblingFiles = files.filter { siblingPaths.contains($0.path) }
scanState = CodexScanState()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve prior row keys when rescanning fork siblings

When a deleted cached fork causes this sibling-rescan path to run, resetting scanState here drops all row keys already remembered from the first pass (including a real parent file or earlier contributor whose days remain in cache). For fork logs whose parent baseline is still unresolved (for example missing/unparseable fork timestamps), the sibling reparse then no longer sees those parent-scoped keys and can count the replayed parent rows again on top of the retained parent/earlier-file totals. Rebuild the state from retained cache entries or avoid discarding the earlier scan state before rescanning just the sibling files.

Useful? React with 👍 / 👎.

Comment on lines +2571 to +2573
if let forkedFromId = old.forkedFromId {
forkFamiliesNeedingRescan.insert(forkedFromId)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Rescan fork children when dropping a parent file

When an unscanned cached file is removed, this only records the removed file's own forkedFromId. If the removed file is the real parent of cached fork children (old.sessionId == P and old.forkedFromId == nil), those children were previously parsed with a resolved baseline and their cached rows omit the replayed parent prefix; after the parent file is deleted or leaves the roots, no family rescan is scheduled for children with forkedFromId == P, so the parent's usage is subtracted from the cache and never reclaimed until a force rescan.

Useful? React with 👍 / 👎.

Comment on lines +637 to +638
let useParentScope = forkedFromId != nil && row.turnID != nil
let activeSessionId = useParentScope ? forkedFromId : sessionId

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid parent-scoping stale turn IDs

This treats any non-nil row turn ID as parent provenance, but currentTurnID is only updated from task_started; turn_context IDs are ignored. In fork logs where child work starts with a turn_context carrying the child ID but no intervening task_started, the child token rows keep the replayed parent turn ID, so sibling children with matching event index/model/delta are deduped under the parent even though they are legitimate child usage.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jul 13, 2026
@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Current-head follow-up: 27980d8 resolves the Linux CI race by serializing only PlatformGatingTests, whose Claude test seams otherwise overlap under swift test --parallel. Production code is unchanged.

Validated locally: swift test --filter PlatformGatingTests — 10 tests passed.

Please review the current head together with the prior redacted fork-corpus evidence.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jul 13, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Follow-up pushed in 2aec564 for the remaining fork-cache correctness threads.

Addressed behavior:

  • regenerate CodexParserHash so pre-fix cache entries are invalidated instead of silently preserving the old row-key semantics;
  • treat a turn_context turn ID as the active provenance, so child-only work is not accidentally parent-scoped;
  • when a cached parent disappears, schedule its fork children for reparse;
  • rebuild the sibling-rescan state from retained cache rows, preserving parent/earlier row identities while reparsing only the affected children.

Validation:

  • swift test --filter 'CostUsageScannerBreakdownTests' — 82 tests, 0 failures\n- Scripts/regenerate-codex-parser-hash.sh --check\n- git diff --check\n\nAdded regression coverage for turn_context-provided turn identity.\n\n@clawsweeper re-review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2aec564a49

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


if !forkFamiliesNeedingRescan.isEmpty {
let siblingPaths = cache.files.compactMap { path, usage in
forkFamiliesNeedingRescan.contains(usage.forkedFromId ?? "") && filePathsInScan.contains(path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Invalidate fork siblings outside the current window

Fresh evidence in this revision is the new filePathsInScan.contains(path) filter: when a cached parent file is deleted during a narrow refresh for the parent day, fork children parsed while that parent was resolved usually have only child-day days, so they are not in files and are left with cached rows that omitted the replayed parent prefix. Because the cache then retains the wider window, a later child-day report can reuse those stale child entries after the parent contribution was removed, undercounting until a force rescan; invalidate or rescan all cached children in the fork family, not only paths in the current scan list.

Useful? React with 👍 / 👎.

Comment on lines +2137 to +2138
if let turnID {
currentTurnID = turnID

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Clear stale turn IDs on new turn contexts

Fresh evidence in this revision is the new non-nil-only assignment here: when a fork replay leaves currentTurnID set to a parent task_started and the following child turn_context has no turn ID, this branch keeps the parent ID active. Subsequent token_count rows without their own turn_id are then keyed under forkedFromId with the parent turn and can be dropped as replay duplicates, so a new turn context should clear the active turn before applying a non-nil ID (with the same behavior mirrored in the JSON fallback).

Useful? React with 👍 / 👎.

@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

Closing this duplicate candidate to reduce competing Codex fork-accounting contracts. The underlying replay-overcount report remains important in #2108 / canonical #2037.\n\nThe safer merge-ready landing vehicle is #2118: it uses canonical leaf-session identity plus parent-file cache dependencies, includes focused cold/warm cache regressions and frozen-corpus evidence, and avoids this branch's unresolved missing-parent and stale-turn-ID undercount risks.\n\nPlease consolidate any unique coverage only if it is demonstrably absent from #2118; otherwise maintaining one canonical implementation will make review and release validation substantially clearer.

@Yuxin-Qiao Yuxin-Qiao closed this Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Codex real fork corpus: 5,427 replayed parent events across rewritten timestamps

2 participants