Skip to content

fix: keep recently modified files out of cost-store window pruning (refs #2760) - #2764

Merged
steipete merged 4 commits into
steipete:mainfrom
Yuxin-Qiao:codex/cost-store-retention-mtime
Aug 8, 2026
Merged

fix: keep recently modified files out of cost-store window pruning (refs #2760)#2764
steipete merged 4 commits into
steipete:mainfrom
Yuxin-Qiao:codex/cost-store-retention-mtime

Conversation

@Yuxin-Qiao

@Yuxin-Qiao Yuxin-Qiao commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • retentionCandidates (the window prune, also reached from enforceBudgets when the store is over budget) now mirrors the JSON path's isRecentlyActive exemption: a session file whose mtime falls inside the retained window is not pruned, even when all its usage coverage days are out of window.
  • The exemption uses inclusive calendar-day bounds: from 00:00 of sinceDay through 24:00 of untilDay (computed via CostUsageScanner.CostUsageDayRange.localGregorianCalendar, then passed to SQL as AND (f.mtime_ms < ? OR f.mtime_ms >= ?)). This addresses the review findings:
    • Start boundary: parseDayKey anchors at noon, which would have pruned files modified during the morning of sinceDay. The cutoff now starts at day start.
    • End boundary: files modified after untilDay are candidates again instead of being retained indefinitely.
  • The budget-deletion path (deleteOldestRetainedFile) keeps its own narrower zeroDayRecentlyActive guard on purpose: hard caps still need an escape valve when every remaining file is recently active.

Real behavior proof (production refresh path, synthetic corpus)

Drives the production refresh path (CostUsageScanner.loadDailyReport for .codex with a synthetic CODEX_HOME + injected cache root, no credentials, no real user data): one still-active session whose usage rows are all out of window (coverage 2026-05-10, mtime 2026-08-02) plus 30 idle stale sessions, then an over-budget enforceBudgets (1-file row budget, the same function saveCodexCache calls on every refresh).

[retention-proof] stale-coverage file retained after over-budget prune: /private/var/folders/.../codex-home/sessions/2026/08/02/stale-active.jsonl
[retention-proof] warm refresh reused the cached row, headParses=0

The 30 idle files are pruned; the active stale-coverage file survives the over-budget pass, and the warm refresh performs zero head parses (the row's validation anchor is reused instead of re-parsing the file).

Test

  • Boundary regression tests (explicit UTC calendar, deterministic):
    • retention keeps recently modified file with stale coverage (mtime = 06:00 on sinceDay)
    • retention prunes stale file modified before the window
    • retention prunes stale file modified after the window
    • retention keeps stale file modified at the window edges (00:00 of sinceDay, 23:59:59 of untilDay)
  • Refresh-path proof: over budget prune retains stale coverage file modified inside the window (in CostUsagePerformanceGateTests)
  • swift test --filter "CostUsageStoreTests|CostUsagePerformanceGateTests" (73 tests, green)
  • make check (0 violations)

@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: 6ef23bc53e

ℹ️ 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 +123 to +124
let activeSinceMs = CostUsageScanner.parseDayKey(sinceDay, calendar: calendar)
.map { Int64($0.timeIntervalSince1970 * 1000) }

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 Start the activity cutoff at midnight

When a file was modified during the morning of sinceDay, this cutoff still classifies it as stale: CostUsageScanner.parseDayKey constructs the date at 12:00, so f.mtime_ms < ? deletes files from midnight through noon even though their modification day is inside the retained window. Those files can therefore re-enter the expensive prune/rediscover/full-parse cycle this change is intended to prevent; derive the cutoff with calendar.startOfDay(for:) or compare day keys instead.

Useful? React with 👍 / 👎.

Comment on lines +140 to +142
if activeSinceMs != nil {
sql += "\n AND f.mtime_ms < ?"
}

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 Bound active mtimes by untilDay

When pruning a historical or otherwise bounded window, this one-sided predicate preserves every file modified after sinceDay, including files modified after untilDay. For example, an Aug 4 file is treated as active for an Aug 1–3 window, unlike the former day-key isInRange check; this can leave out-of-window rows behind and force hard-budget deletion to remove retained rows instead. Add an upper boundary for the end of untilDay (or compare the mtime day key against both bounds).

Useful? React with 👍 / 👎.

@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. P2 Normal priority bug or improvement with limited blast radius. labels Aug 8, 2026
@clawsweeper

clawsweeper Bot commented Aug 8, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed August 8, 2026, 2:22 PM ET / 18:22 UTC.

ClawSweeper review

What this changes

The PR retains recently modified Codex session-cache rows during SQLite window pruning only within the requested inclusive local calendar-day range.

Regression provenance

Possible regression — probable (reviewed change; reproduction). No predecessor PR is attributed.

Merge readiness

⚠️ Ready for maintainer review - 1 item remains

The earlier calendar-boundary defects are fixed on the current PR head. This remains a focused, proof-backed correction to current-main cache retention and should stay open for routine maintainer merge review.

Priority: P2
Reviewed head: 2493b987500a2b47ce2806c26bdd1b7beb37bd0f

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A focused, review-corrected cache-retention fix with strong production-path evidence and no remaining actionable defect found.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (terminal): The PR body provides after-fix terminal output from the real loadDailyReport refresh path using an isolated synthetic corpus, showing retained cache reuse and zero warm-refresh head parses.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (terminal): The PR body provides after-fix terminal output from the real loadDailyReport refresh path using an isolated synthetic corpus, showing retained cache reuse and zero warm-refresh head parses.
Evidence reviewed 4 items Current-main boundary defect: Current main derives the active-window lower bound through parseDayKey, which anchors dates at noon; a file modified during the first retained morning falls outside that range.
PR fixes both calendar boundaries: The diff derives local day starts and uses the next day as the exclusive upper bound, covering both edges of the requested calendar range.
Feature provenance: The current retention behavior dates to the SQLite cutover follow-up that restored JSON-cache retention semantics.
Findings None None.
Security None None.

How this fits together

CodexBar scans Codex session files and stores parsed usage in a SQLite cost cache. Window and budget pruning decide which cached rows survive for reuse during subsequent refreshes.

flowchart LR
A[Codex session files] --> B[Cost usage scanner]
B --> C[SQLite cost store]
C --> D[Window and budget pruning]
D --> E{Modified within scan days?}
E -->|Yes| F[Keep cached row]
E -->|No| G[Prune stale row]
F --> H[Reuse on refresh]
G --> H
Loading

Before merge

  • Resolve merge risk (P1) - Merging intentionally keeps some out-of-coverage cache rows until their modification day leaves the requested window; existing row and byte budgets remain the storage-growth guardrails.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production vs. test delta production +15/-3, tests +206/-0 The small retention change is accompanied by edge-boundary and production refresh-path regression coverage.

Merge-risk options

Maintainer options:

  1. Accept bounded cache retention (recommended)
    Merge with the intended behavior that a recently modified session row remains reusable only within the requested local calendar-day window.
  2. Pause for a different retention policy
    Do not merge if out-of-coverage rows must be removed immediately regardless of modification time.

Technical review

Best possible solution:

Merge the day-bounded retention correction after routine confirmation that preserving active cache rows matches the SQLite retention contract.

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

Yes. Current main’s noon-anchored parser excludes first-day morning modifications; the PR adds deterministic boundary cases and a production refresh-path scenario.

Is this the best way to solve the issue?

Yes. Local day starts plus the next local day as the exclusive upper bound is the narrowest fix for inclusive calendar-day retention without altering hard-budget escape behavior.

AGENTS.md: found and applied where relevant.

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

Labels

Label justifications:

  • P2: This is a focused cache-retention correctness repair with bounded impact.
  • merge-risk: 🚨 compatibility: The PR deliberately changes which previously pruned cache rows remain across refreshes.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body provides after-fix terminal output from the real loadDailyReport refresh path using an isolated synthetic corpus, showing retained cache reuse and zero warm-refresh head parses.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body provides after-fix terminal output from the real loadDailyReport refresh path using an isolated synthetic corpus, showing retained cache reuse and zero warm-refresh head parses.

Evidence

What I checked:

Likely related people:

  • Peter Steinberger: Authored the SQLite retention implementation and the preceding store-foundation/cutover series on current main. (role: recent feature owner; confidence: high; commits: 38ca30ab93bc, 26fd0bbd7eed, 56a763eaa34c; files: Sources/CodexBarCore/Vendored/CostUsage/CostUsageStore+Retention.swift, Tests/CodexBarTests/CostUsageStoreTests.swift)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
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.

Workflow

  • 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.

History

Review history (7 earlier review cycles)
  • reviewed 2026-08-08T11:43:45.479Z sha 6ef23bc :: needs real behavior proof before merge. :: [P2] Use the start of sinceDay for the activity cutoff
  • reviewed 2026-08-08T12:25:36.081Z sha 6ef23bc :: needs real behavior proof before merge. :: [P2] Start the activity cutoff at the beginning of sinceDay | [P2] Limit active mtimes to the requested end day
  • reviewed 2026-08-08T13:46:42.009Z sha 6ef23bc :: needs real behavior proof before merge. :: [P2] Use the start of sinceDay for the activity cutoff | [P2] Bound active mtimes by untilDay
  • reviewed 2026-08-08T16:52:04.930Z sha 6be86b8 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-08T16:55:23.466Z sha 6be86b8 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-08T17:10:43.004Z sha 6be86b8 :: needs maintainer review before merge. :: none
  • reviewed 2026-08-08T17:43:31.018Z sha 2493b98 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Aug 8, 2026
@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 8, 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: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and 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. labels Aug 8, 2026
@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Aug 8, 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: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@steipete
steipete merged commit c41a419 into steipete:main Aug 8, 2026
5 of 8 checks passed
@steipete

steipete commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Landed. Verified before merge: complementary to #2767, not duplicative — the shared activeWindowMs boundary was noon-anchored via parseDayKey, leaving first-day-morning files unprotected and bleeding into the morning after the final day; this pins protection to local midnight boundaries with tests on both edges plus an over-budget refresh proving cached-row reuse. Thanks @Yuxin-Qiao!

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. proof: sufficient Contributor real behavior proof is sufficient. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants