Skip to content

Add OpenCode local history adapter into the cost-usage store (#4752) - #4757

Closed
Danielweng0902 wants to merge 4 commits into
steipete:mainfrom
Danielweng0902:feat/opencode-coststore-adapter
Closed

Danielweng0902 wants to merge 4 commits into
steipete:mainfrom
Danielweng0902:feat/opencode-coststore-adapter

Conversation

@Danielweng0902

Copy link
Copy Markdown

Draft PR per the #4752 flow — structural foundation first, opened early so the shape can be reviewed before the full test matrix. This branch implements the approved direction: a dedicated OpenCode adapter driven by the scanner, feeding the existing CostUsageStore persistence, bounded publication, and completion tracking. No new parallel store, no SQL schema migration.

What this commit contains (structural seam, per adjustment 1)

  • CostUsageStoreScanState.source discriminator (nativeCodexSessionLogs / opencodeLocalHistory), optional in the files.scan_state JSON. Records persisted before this seam decode as native Codex by default — proven by a legacy-payload test; no SQL migration or table rebuild.
  • OpenCodeSourceCheckpoint — versioned, typed JSON progress carried in scan_state.resumePayload for adapter records: source identity + WAL-aware DB fingerprint, per-table [low, high] rowid windows, per-table time_updated watermarks (mutation-aware future passes), a strict (messageRowid, partRowid) in-flight continuation (oversized-message regression from Add opt-in OpenCode local history with incremental rowid-window ingestion #4744), and resumable reconciliation progress. Rowids never enter the byte-oriented fields; a newer version never decodes as trusted progress.
  • Source-aware restore dispatch: the Codex cache restore and reconciliation loops skip adapter records rather than decoding their payloads as StoredFileDetails / CostUsageJsonl.ResumeState. Native behavior is unchanged (guards are no-ops for every existing record).
  • Tests (4): legacy-payload upgrade path, discriminator round trip through the actual store (upsertFile → readSnapshot), checkpoint encode/decode + version gating.

Adjustment checklist for the follow-up commits on this branch

#4752 adjustment Status
1. Typed progress in files.scan_state, source discriminator, no migration, source-aware dispatch ✅ this commit
2. Provenance via registered file_id + bounded source summary in the read view (no aggregate columns, no model markers, presence over cost > 0) ⬜ adapter write + read-view extension
3. Recorded $0 must surface like any other recorded cost (OpenCode-only / mixed / single-source windows) ⬜ with the write path + regressions
4. Mutation-aware ingestion (session_message create-then-update, deletes; bounded rechecks, no per-refresh restart; short source transaction → atomic store commit under the writer lock) ⬜ scan passes (checkpoint fields already carry updatedMs watermarks)
5. Store performance contract (no per-refresh full counts / whole-table filter+sort / all-parts joins / whole-DB arrays / per-append day rebuilds; bounded rows+bytes+SQL time with cancellation; in-message checkpointing; retention must not turn file-scoped ops into whole-history work; fixtures at 1k/10k/100k + oversized row; measure SQL page work) ⬜ scan passes + fixture tests
6. The three #4744 cursor regressions as explicit tests ⬜ with the scan passes
7. Completion/scope wiring (opt-in ambient-only inclusion in read views + catch-up; calendar-pinned bucketing; no unproven window-completeness claims; opt-out/DB-change excludes prior contribution; scoped home / managed account / dashboard exclusion tests) ⬜ wiring on top of the seam

The #3273 contract (unchanged)

Opt-in default-off; read-only source access; exact OpenAI-provider assistant rows; valid step-finish parts (one per part) with message fallback; recorded cost surfaced as-is ($0 for subscription usage); ambient Codex scope only — never scoped CODEX_HOME homes, managed accounts, or Spend Dashboard; no account attribution.

Marked draft: please point the review at the seam (discriminator placement, the checkpoint payload shape, dispatch gate) before the scan passes land.

Structural foundation for the steipete#4752-approved adapter direction: a
versioned, backward-compatible source discriminator on the files
scan_state JSON (absent = native Codex, so upgrade needs no migration),
a typed versioned OpenCodeSourceCheckpoint payload for the adapter's
table windows, part continuation, updated-watermarks and reconciliation
progress, and source-aware restore dispatch so adapter records never
decode as Codex JSONL state. Tests cover the legacy-payload upgrade
path, checkpoint version gating, and a discriminated round trip through
upsert/readSnapshot.
@clawsweeper

clawsweeper Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

ClawSweeper review complete

ClawSweeper finished reviewing this revision. The review result is being finalized.

View the workflow run.

@clawsweeper clawsweeper Bot added P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. 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 Oct 24, 2026
@clawsweeper

clawsweeper Bot commented Oct 24, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge.

What this changes

This PR adds an OpenCode checkpoint model, a backward-compatible source discriminator, and source-aware native cache restoration.

Example: An OpenCode assistant message records $0 in /data/opencode.db.

  • Before: Its local history is excluded from ambient Codex totals.
  • After: It remains excluded at this draft stage; the PR adds checkpoint storage types but no ingestion or publication path.

Review scores

Measure Result What it means
Overall readiness 🧂 unranked krab (1/6) The structural direction is approved and no concrete defect was found, but this draft is partial and its supplied evidence is limited to tests.
Proof confidence 🧂 unranked krab (1/6) Real behavior proof is necessary before merge. See Before merge.
Patch quality 🦐 gold shrimp (3/6) No actionable review findings were identified.

Product

Kind: Feature · Worth it: Yes · Fix scope: Partial
User problem: Ordinary OpenCode sessions using OpenAI are missing from ambient Codex local token and cost history.
Reason: The owner approved this shared-store adapter and explicitly requested an early draft; this PR intentionally delivers only its structural foundation.

Merge readiness

⛔ Blocked before merge - 2 items remain

Keep this PR open as the owner-requested early draft: the source seam follows the approved design, and inspection found no concrete introduced defect.

Priority: P3
Reviewed head: 9a440424c4cf1346271478a42ae782d6203ba0fa

Before merge

  • Add real behavior proof - The body supplies tests but no terminal output, logs, recording, or artifact exercising the changed restoration path through the shipped app or CLI; when ready, provide redacted evidence of native restoration alongside adapter records, omitting credentials and private paths. After adding proof, update the PR body, then request a new review with @clawsweeper re-review. The PR author or someone with repository write access can request it.
  • Add data-model compatibility proof - The review found that existing stored data may not work after upgrade. Show that existing data still loads and works with this change.

Findings

None.

Tests

  • Missing end-to-end proof: No shipped-entry-point demonstration or latest-stable store upgrade run is supplied, and base-failing/head-passing regression execution is not shown.
Agent review details

How this fits together

CostUsageStore persists derived local usage in SQLite; this seam identifies the source owning each file record and keeps OpenCode checkpoints out of native Codex cache restoration.

flowchart LR
  A[Native Codex logs] --> B[Native scanner]
  B --> C[SQLite history store]
  D[OpenCode checkpoint model] --> C
  C --> E[Source-aware restore]
  E --> F[Native Codex cache]
Loading

Technical review

Best possible solution:

Complete the approved bounded adapter using the existing scanner, transaction, read-view, and completion owners.

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

This is an approved feature foundation rather than a bug reproduction; source confirms that ordinary OpenCode session ingestion remains absent.

Is this the best way to solve the issue?

The seam uses the approved persistence owner and preserves native decoding defaults, but checkpoint fields alone do not establish bounded ingestion or correct publication.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning medium; reviewed against c1ce9a4e6f1f.

Provenance checked

  • Native cache restore and reconciliation keeps the original intent (26fd0bb: The SQLite cutover restored native scanner state and reports through CostUsageStore; the later baseline refactor retained that ownership.)
  • Persisted scan-state JSON keeps the original intent (56a763e: The store foundation placed typed scan progress in files.scan_state; the approved design extends that existing payload without changing SQL tables.)

Testing

Proof path: in-process harness.

Security

None.

Evidence

What I checked:

Root-cause cluster

Relationship: partial_overlap
Canonical: #4752
Summary: The design issue owns the implementation contract, and this PR supplies its initial structural seam.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Labels

Label changes:

  • add P3: This is an intentionally staged foundation for an optional history source, with no demonstrated regression in existing supported behavior.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Label justifications:

  • P3: This is an intentionally staged foundation for an optional history source, with no demonstrated regression in existing supported behavior.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Rank-up moves

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

  • Demonstrate source-aware restoration through the shipped app or CLI.
  • Show a latest-stable store reopening with native rows and checkpoints preserved without rebuilding.

Rating scale

6/6 🦀 challenger crab · 5/6 🦞 diamond lobster · 4/6 🐚 platinum hermit · 3/6 🦐 gold shrimp · 2/6 🦪 silver shellfish · 1/6 🧂 unranked krab. Overall follows the weaker of proof and patch quality; ✨ marks media proof (a screenshot, video, or linked artifact) that directly shows the changed behavior.

Workflow

ClawSweeper edits this one comment on every review. Comment @clawsweeper re-review for a fresh review only. Repair and merge execution lanes are retired.

Reviewed October 24, 2026, 3:06 AM ET / 07:06 UTC.

Stage 1+2 of the steipete#4752 checklist. The adapter decodes OpenCode assistant
turns inside short read-only source transactions and commits usage rows,
per-file day aggregates, global deltas and its typed checkpoint
atomically through applyOpenCodeLocalHistoryPass (baseline
revalidation, rollback on stale). Turns keep hash-stable identities
over <table>:<sourceID>; windows walk by exclusive rowid boundaries
pinned by their own SELECT with raw-lookahead exhaustion.

Explicit regressions for the three steipete#4744 cursor failures: invalid rows
consume budget without starving older valid rows, oversized messages
checkpoint a strict (messageRowid, partRowid) continuation and resume
mid-message without re-emitting, and appends after a snapshot stay
eligible because boundaries never come from a later MAX(rowid). Tests:
5 adapter tests + 4 checkpoint seam tests, all passing.
Upstream UPDATEs rows in place while streaming, so the pass now walks
time_updated watermarks per table and re-evaluates the containing
message (or session row), replacing the prior contribution at the same
identity: old payloads resolve via the store's readUsagePayloads point
lookup, their negation folds into the global merge, and per-file
aggregates recompute as absolute stored+new-old values. A pure delete
(a session row that becomes excluded or invalid) removes its footprint.
Late step-finish parts swap the fallback row for the part. Tests:
covered-code mutation, late parts, and session updates all pass
(8 adapter tests total).
Stage 4 of the steipete#4752 checklist. The adapter's contribution now lands in
the Codex daily report with provenance resolved at read time:

- sourceRecorded marker on ModelBreakdown (report-model case only, never
  persisted in store enums); merge keeps recorded and priced breakdowns
  of the same model apart via provenanceKey, so a recorded /bin/zsh
  subscription day can never fold into a same-named priced estimate.
- Recorded zero stays a PRESENT zero in costUSD — presence is the
  signal, per the recorded-cost-as-is contract.
- CostUsageStoreAccess.sharedScanStore gives the adapter the scanner's
  own shared store actor (one persistence owner); the pass runs in the
  fetcher's async seam beside the synchronous scan executor.
- Options.includeOpenCodeLocalHistory (default off) flows from
  SettingsStore.openCodeLocalHistoryEnabled through UsageStore into the
  fetcher; the ambient gate excludes any scan with an explicit
  codexSessionsRoot or CODEX_HOME override.
- Preferences toggle under the Codex provider detail.

Tests: 4 new stage-4 tests (recorded-/bin/zsh conversion + provenance, merge
keeps recorded/priced apart, ambient gate matrix, default-off). All 12
adapter tests pass; full-suite regressions are unrelated environment
clusters (keychain access absent in this shell, one keyboard-layout-
dependent shortcut test, load-timing flakes that pass in isolation).
@Danielweng0902

Copy link
Copy Markdown
Author

Stages 1–4 of the #4752 checklist are now implemented on this branch (4 commits):

1+2: adapter pass + cursor regressions (83e0bb0) — turns decode inside short read-only source transactions and commit usage rows, per-file aggregates, global deltas, and the typed checkpoint atomically through applyOpenCodeLocalHistoryPass (baseline revalidation, rollback on stale). Windows walk by exclusive rowid boundaries pinned by their own SELECT (never a later MAX), budgets count raw rows with lookahead exhaustion, and oversized messages carry a strict (messageRowid, partRowid) continuation. Explicit regression tests for all three #4744 failures pass.

3: mutation probe (1f47dff) — per-table time_updated watermarks re-evaluate the containing message / session row and replace the prior contribution at the same identity (old payloads resolve via point lookup, their negation folds into the same global merge; late step-finish parts swap the fallback out exactly once).

4: provenance, scope, recorded-zero (a075ed6) — sourceRecorded is a report-model case (never a persisted enum); merges keep recorded vs priced breakdowns of the same model apart via provenanceKey; recorded $0 stays a present zero. The adapter writes/reads through the scanner's shared store actor (CostUsageStoreAccess.sharedScanStore) from the fetcher's async seam; the opt-in flows Settings → UsageStore → Options (default off) with an ambient gate that excludes any explicit root or CODEX_HOME override.

Verification

  • Adapter tests: 12/12 (store-write correctness, idempotence, 3 cursor regressions, 3 mutation swaps, entry conversion with provenance + $0, merge non-folding, ambient matrix, default-off)
  • Full app target builds (Core + macOS app incl. preferences toggle)
  • Full suite: no failures in any cost/merge/provenance/adapter area; observed failures are unrelated environment clusters (no keychain in this shell, one US-keyboard-layout-dependent shortcut test, load flakes that pass in isolation)

Known remaining (out of scope so far)

  • Resumable deletion reconciliation sweep — update probes can't see upstream deletions; checkpoint field reserved
  • Performance fixtures at 1k/10k/100k + oversized row
  • CLI cost flag exposure and clear-cost-cache wiping the adapter row
  • Project/session attribution is intentionally absent (rows are never attributed, per Feature request: include OpenCode sessions in Codex usage tracking #3273)

@steipete

Copy link
Copy Markdown
Owner

Thanks @Danielweng0902 — this is the right direction, and it follows the #4752 design closely: the typed source checkpoint, file-qualified aggregates, and the recorded-$0 handling are solid foundations.

I audited the head against the design with extra synthetic diagnostics, and a few contract points still need work: duplicate contributions when two parts of one parent update, part continuations lost on reevaluation, timestamp ties across a budget boundary, deleted rows that stay counted, a native full save that drops the adapter's file row, cached publication that omits the source, and Spend Dashboard including it. The raw SQL work also still grows linearly with sparse history under a fixed row budget.

No need to rework it yourself — I'm finishing it in place on your branch with maintainer commits (your commits and credit stay), and will turn the diagnostics into regression tests. I'll post here when it's ready.

@Danielweng0902

Copy link
Copy Markdown
Author

Thanks for the thorough audit — acknowledged on all eight points (the duplicate re-evaluation of one parent across part hits, the timestamp-tie watermark, and the cached-publication/dashboard paths especially). Stepping back from the branch now so your maintainer commits land cleanly. Happy to re-verify behavior locally once you post.

@steipete

Copy link
Copy Markdown
Owner

Quick update @Danielweng0902: the remaining contract work is done, but GitHub won't let me push to this branch — your fork is a fork of nesszer/Win-CodexBar, so "allow edits by maintainers" doesn't reach it. I opened #4786 from a branch in this repo instead. Your four commits are preserved unchanged in its history, with one maintainer commit on top, and the changelog thanks you. I'll close this PR in favor of #4786 once it lands. Nothing needed from you — thank you for carrying this through four rounds.

steipete added a commit that referenced this pull request Oct 26, 2026
OpenCode's local history (opencode.db) can feed the existing cost-usage store as an opt-in source for the ambient Codex ledger, implementing the design approved in #4752 and finishing #4757 by @Danielweng0902. A typed, versioned checkpoint lives in the existing files row; native saves preserve the source's rows; one resumable raw-row sweep reconciles mutated and deleted upstream rows within fixed row, payload and SQLite work budgets (flat across 1k/10k/100k histories) with cancellation; fresh, cached and catch-up views include it only for the opted-in ambient ledger, never scoped CODEX_HOME roots, managed accounts or Spend Dashboard; buckets follow the reporting calendar and recorded $0 stays authoritative. Closes #4752; supersedes #4757.

Co-authored-by: Daniel930902 <daniel0902life@gmail.com>
@steipete

Copy link
Copy Markdown
Owner

Landed via #4786 (914204f) with your four commits preserved in its history — thank you @Danielweng0902 for working through the design and the adapter. Closing this one in favor of #4786; it'll ship in the next release.

@steipete steipete closed this Oct 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants