Skip to content

Add SQLite CostUsageStore foundation - #2761

Merged
steipete merged 1 commit into
mainfrom
feat/cost-store-sqlite-foundation
Aug 8, 2026
Merged

Add SQLite CostUsageStore foundation#2761
steipete merged 1 commit into
mainfrom
feat/cost-store-sqlite-foundation

Conversation

@steipete

@steipete steipete commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the Phase 1 SQLite persistence foundation from #2760 with zero production call sites.

The new actor-owned CostUsageStore creates cost-usage/cost-usage.sqlite with WAL, a 5-second busy timeout, foreign keys, and incremental auto-vacuum. Schema compatibility combines an explicit base schema version with the generated Codex parser hash in PRAGMA user_version, with the exact parser hash also retained in metadata. Version, open, integrity, and runtime SQLite failures drop the database plus WAL/SHM artifacts and recreate it because this is derived data.

Schema decisions

  • files keeps source identity, inode/size/mtime, parsed bytes, validation anchors, typed scan-state payload, coverage, and update ordering.
  • token_snapshots is append-addressed by file/event index.
  • file_day_aggregates retains each file's replaceable contribution so Phase 2 can subtract or replace changed sources safely.
  • day_aggregates stores report-ready day/model totals with cost, token, request, and priority breakdowns.
  • fork_lineage, buffered_lines, discovery_state, and lookback_state preserve fork/subagent/retry/discovery state.
  • accumulators persists terminal cumulative-token state following the linear append concept from fix: make Codex cost catch-up append-linear #2726, with credit to @xx205.
  • Query indexes cover path, day range, model, model/day, session lineage, timestamps, coverage, and retention order.

The actor makes single-writer ownership explicit while WAL permits independent app/CLI read-only connections. Window retention is inclusive, protects incomplete/buffered/parent-dependent files, prunes stale discovery references, and trims both per-file and global aggregates. Budget enforcement applies remembered-window retention, row caps, byte caps, WAL checkpoints, and incremental vacuum.

Storage-only CostUsageStore* files are excluded from the parser-source hash generator. Store layout changes are instead required to bump the explicit store schema version; adding this zero-call-site persistence code therefore does not rotate current parser/cache behavior.

No scanner/cache call sites, JSON cutover, changelog, or behavior changes are included.

Proof

swift test --filter CostUsageStoreTests
41 tests passed

swift test --filter CostUsage
423 tests passed across 25 suites

make check
0 SwiftLint violations; SwiftFormat clean; all repository checks passed

docker run --rm -v "$PWD":/src -w /src swift:6.3.3 bash -c "apt-get update -qq >/dev/null 2>&1 && apt-get install -y -qq libsqlite3-dev >/dev/null 2>&1 && swift build 2>&1 | tail -3"
Build complete! (20.60s)

autoreview --mode local
TruffleHog clean; autoreview clean: no accepted/actionable findings reported

Refs #2760

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal priority bug or improvement with limited blast radius. labels Aug 8, 2026

@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: 8b435e986f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".


private static func deleteOldestRetainedRow(_ database: OpaquePointer) throws -> Bool {
let statements = [
"DELETE FROM files WHERE id = (SELECT id FROM files ORDER BY updated_at_ms, id LIMIT 1)",

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 Reconcile day aggregates before deleting file rows

When row or byte budget enforcement trims a file that has already contributed to day_aggregates, this delete cascades away the file_day_aggregates row but leaves the global aggregate intact. readReport reads from day_aggregates, so after a budget trim the report can still include usage for a file that no longer exists and whose per-file contribution can no longer be subtracted; subtract the file contribution or mark/rebuild the report state before deleting the file row.

Useful? React with 👍 / 👎.

state.filePathBySessionID = state.filePathBySessionID.filter {
!sessionIDs.contains($0.key) && !paths.contains($0.value)
}
state.nextFileIndex = min(state.nextFileIndex, state.filePaths.count)

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 Reset discovery cursors after pruning file paths

If retention removes a path before the current discovery cursor, this min can leave nextFileIndex pointing past an unprocessed survivor; for example [old, remaining] with nextFileIndex == 1 becomes [remaining] and nextFileIndex == 1, so the remaining file is treated as already scanned. Reset or recompute the discovery cursors after filtering paths so the next discovery pass re-enqueues the shortened list correctly.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 session-state 🚨 Merging this PR could lose, corrupt, stale, or mis-associate session or agent state. labels Aug 8, 2026
@clawsweeper

clawsweeper Bot commented Aug 8, 2026

Copy link
Copy Markdown

Codex review: needs changes before merge. Reviewed August 8, 2026, 2:39 AM ET / 06:39 UTC.

ClawSweeper review

What this changes

Adds a zero-call-site SQLite CostUsageStore with schema, read/write, retention, and test foundations for a later Codex cost-usage migration.

Merge readiness

⚠️ Ready for maintainer review - 6 items remain

This owner-authored Phase 1 foundation is still required by the open SQLite migration plan, but three retention defects make the patch incorrect before its later scanner/report cutover.

Priority: P2
Reviewed head: 8b435e986f3eaa9aae9381ad2dfea32bf70cc00d

Review scores

Measure Result What it means
Overall readiness 🦐 gold shrimp (3/6) The migration phase has clear direction and substantial focused coverage, but the three retention defects prevent merge readiness.
Proof confidence 🌊 off-meta tidepool Not applicable: This owner-authored internal persistence PR is exempt from the external-contributor real-behavior proof gate; the provided focused tests remain useful supplemental evidence.
Patch quality 🦐 gold shrimp (3/6) 3 actionable review findings remain.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: This owner-authored internal persistence PR is exempt from the external-contributor real-behavior proof gate; the provided focused tests remain useful supplemental evidence.
Evidence reviewed 5 items Current main does not contain the store: The proposed CostUsageStore symbols are absent from current main; this is a new seven-file foundation rather than already-implemented work.
Budget eviction bypasses retention safeguards: Budget enforcement deletes the oldest file directly, unlike window pruning, so it can evict incomplete, buffered, or parent-dependent file state.
File eviction leaves report aggregates stale: Deleting a files row cascades its per-file aggregate, but the direct budget path does not subtract its contribution from day_aggregates, which reports read.
Findings 3 actionable findings [P2] Preserve protected files during budget eviction
[P2] Reconcile aggregates before evicting a file
[P2] Recompute discovery cursors after removing paths
Security None None.

How this fits together

Codex cost scanning derives usage from local session files and cache state. This store is intended to persist file scan state and aggregates so a later phase can serve app and CLI reports from SQLite.

flowchart LR
  A[Codex session files] --> B[Future cost scanner]
  B --> C[SQLite usage store]
  C --> D[File scan state]
  C --> E[Usage aggregates]
  C --> F[Retention and budgets]
  E --> G[Future app and CLI reports]
Loading

Before merge

  • Preserve protected files during budget eviction (P2) - deleteOldestRetainedRow deletes the oldest file without the incomplete, buffered-line, or parent-dependency checks used by retentionCandidates. A row or byte cap can therefore discard state that the store promises to retain for a later safe replay.
  • Reconcile aggregates before evicting a file (P2) - Deleting a file cascades its file_day_aggregates, but leaves its contribution in day_aggregates; readReport can then show usage for data no longer retained. Subtract or rebuild affected global aggregates in the same transaction.
  • Recompute discovery cursors after removing paths (P2) - Clamping the old cursor to the shortened path count can skip a surviving path that shifted before it. Reset or recompute the cursor against the filtered list before persisting discovery state.
  • Resolve merge risk (P1) - Budget eviction can discard deferred or dependency-required scan state and can leave report totals inconsistent with the retained file set.
  • Resolve merge risk (P1) - The planned SQLite cutover would inherit these latent retention errors if this foundation lands unchanged.
  • Complete next step (P2) - The three defects are localized to retention code and have a clear focused regression-test repair on this branch.

Findings

  • [P2] Preserve protected files during budget eviction — Sources/CodexBarCore/Vendored/CostUsage/CostUsageStore+Retention.swift:222
  • [P2] Reconcile aggregates before evicting a file — Sources/CodexBarCore/Vendored/CostUsage/CostUsageStore+Retention.swift:222
  • [P2] Recompute discovery cursors after removing paths — Sources/CodexBarCore/Vendored/CostUsage/CostUsageStore+Retention.swift:169
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Code and test growth production +1,826, tests +866 This is a substantial persistence foundation with no production call sites, so its storage invariants need to be correct before later adoption.
Changed files 7 files affected The patch is narrowly scoped to the store, parser-hash exclusion, and focused tests.

Merge-risk options

Maintainer options:

  1. Repair retention invariants before merge (recommended)
    Preserve protected files during budget enforcement, reconcile aggregate contributions before file deletion, and reset discovery cursors after filtering paths.
  2. Pause the foundation
    Hold this phase until its internal retention guarantees are consistent enough for the planned scanner and report cutover.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Repair the retention invariants and add deterministic regression coverage for protected-file eviction, aggregate reconciliation, and discovery cursor recomputation.

Technical review

Best possible solution:

Keep the Phase 1 no-call-site boundary, but make every budget eviction honor retention protections, reconcile global aggregates, and recompute discovery progress before later phases consume the store.

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

Yes. Focused store tests can deterministically create protected files, per-file aggregates, and a shifted discovery list before invoking budget enforcement or retention.

Is this the best way to solve the issue?

No. The Phase 1 shape is owner-approved, but direct eviction must use the same protection and aggregate-reconciliation rules as normal retention before this is a safe foundation.

Full review comments:

  • [P2] Preserve protected files during budget eviction — Sources/CodexBarCore/Vendored/CostUsage/CostUsageStore+Retention.swift:222
    deleteOldestRetainedRow deletes the oldest file without the incomplete, buffered-line, or parent-dependency checks used by retentionCandidates. A row or byte cap can therefore discard state that the store promises to retain for a later safe replay.
    Confidence: 0.98
  • [P2] Reconcile aggregates before evicting a file — Sources/CodexBarCore/Vendored/CostUsage/CostUsageStore+Retention.swift:222
    Deleting a file cascades its file_day_aggregates, but leaves its contribution in day_aggregates; readReport can then show usage for data no longer retained. Subtract or rebuild affected global aggregates in the same transaction.
    Confidence: 0.98
  • [P2] Recompute discovery cursors after removing paths — Sources/CodexBarCore/Vendored/CostUsage/CostUsageStore+Retention.swift:169
    Clamping the old cursor to the shortened path count can skip a surviving path that shifted before it. Reset or recompute the cursor against the filtered list before persisting discovery state.
    Confidence: 0.96

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 8a06c21c0ddf.

Labels

Label changes:

  • add merge-risk: 🚨 compatibility: The new persisted-store contract must preserve existing cost-history completeness and accuracy when it replaces the current cache.
  • add merge-risk: 🚨 session-state: Budget eviction can remove protected scan state or make stored report aggregates disagree with retained source state.

Label justifications:

  • P2: The new persistence foundation has bounded but concrete correctness defects that should be fixed before its planned cutover.
  • merge-risk: 🚨 session-state: Budget eviction can remove protected scan state or make stored report aggregates disagree with retained source state.
  • merge-risk: 🚨 compatibility: The new persisted-store contract must preserve existing cost-history completeness and accuracy when it replaces the current cache.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🌊 off-meta tidepool and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Not applicable: This owner-authored internal persistence PR is exempt from the external-contributor real-behavior proof gate; the provided focused tests remain useful supplemental evidence.

Evidence

Acceptance criteria:

  • [P1] swift test --filter CostUsageStoreTests.
  • [P1] make check.

What I checked:

Likely related people:

  • steipete: Authored the submitted store foundation and the linked owner decision defining its three-phase migration boundary. (role: feature owner; confidence: high; commits: 8b435e986f3e, 556e3c6c6282; files: Sources/CodexBarCore/Vendored/CostUsage/CostUsageStore.swift, Sources/CodexBarCore/Vendored/CostUsage/CostUsageStore+Retention.swift)
  • Yuxin Qiao: Recent current-main work adjusted the existing Codex cost-cache budget contract that this migration is intended to replace. (role: recent area contributor; confidence: medium; commits: 6a91900514fc; files: Sources/CodexBarCore/Vendored/CostUsage)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Repair the three retention invariants and add focused regressions that fail on the current head.

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.

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. merge-risk: 🚨 session-state 🚨 Merging this PR could lose, corrupt, stale, or mis-associate session or agent state. P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant