Skip to content

Show validated cached spend while refreshing#2397

Open
hhh2210 wants to merge 1 commit into
steipete:mainfrom
hhh2210:codex/show-cached-spend-refreshing
Open

Show validated cached spend while refreshing#2397
hhh2210 wants to merge 1 commit into
steipete:mainfrom
hhh2210:codex/show-cached-spend-refreshing

Conversation

@hhh2210

@hhh2210 hhh2210 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Render validated cached Usage & Spend data immediately, then replace it with the normal live refresh result.
  • Stop indexing the live Codex session corpus twice by reusing the existing ambient cache for .liveSystem.
  • Keep managed/profile homes account-scoped and preserve the existing UsageStore rule that scoped cache hydration is opt-in.

Refs #2116.

Depends on #2396. This PR exposes cached history before live validation, so the fork-attribution correction and migration guard must land first.

Evidence

Current first-open behavior can remain blank while the local corpus is indexed:

spend-dashboard-blank-before.png

Before this patch, the same live session corpus existed in two v10 cache files on this machine:

  • ambient cache: 9.2 MB;
  • dashboard account cache: 9.2 MB;
  • both contained the same 1,045 source paths.

That duplicate cache identity forced the dashboard to build a second index instead of reusing the provider-level local telemetry already maintained by UsageStore.

Changes

  • Add an explicit cache-priming phase to SpendDashboardController:
    1. capture current provider inputs without forcing network or disk refreshes;
    2. hydrate available validated Codex cache data;
    3. run the ordinary fresh validation pass;
    4. replace primed rows with the fresh result.
  • Treat a cache miss as pending validation, not as a provider failure.
  • Reject stale cache completions after cancellation, generation/config changes, or Codex auth-fingerprint rotation.
  • Route cache roots by source ownership:
    • .liveSystem reuses the ambient CodexBar cache;
    • managed/profile homes remain under cost-usage/accounts/<identity>.
  • Add a package-scoped cache API for the dashboard. The public/default cached loader still refuses a non-empty Codex home, so UsageStore cannot accidentally hydrate managed data.
  • Keep roots, requested-window, and auth checks in the read path.
  • Skip Pi merging and project/session reconstruction during lightweight dashboard hydration.
  • Show a Refreshing state while the first cache/live validation pass is pending.

Scope boundaries

This PR does not change fork attribution, migration selection, same-day activation behavior, model-label localization, or the meaning of provider-owned telemetry. Those remain separate concerns.

Validation

  • make check — passed; SwiftFormat and SwiftLint clean.
  • UI/cache focused gate — 22 tests in 4 suites passed, including:
    • the default managed-home hydration rejection;
    • a production composition test that reads a real validated scoped cache;
    • live ambient vs managed/profile cache-root routing;
    • cache-first rendering, miss, replacement-generation, and auth-rotation behavior.
  • Combined correctness/UI integration gate — 121 tests in 7 suites passed.
  • Baseline-aware full-suite run — 59/60 groups passed. The remaining three assertions reproduce identically on clean origin/main because fixed 2026-07-16 data crossed out of the default 7-day window on July 23. Existing Keychain-suppression and date-fixture baseline suites were kept out of the no-prompt run.

Prime Usage & Spend from validated scoped Codex caches before the live refresh completes.

Reuse the ambient cache for live-system history while keeping managed and profile homes isolated.
Copilot AI review requested due to automatic review settings July 22, 2026 16:21
@clawsweeper

clawsweeper Bot commented Jul 22, 2026

Copy link
Copy Markdown

ClawSweeper status: review started.

I am starting a fresh review of this pull request: Show validated cached spend while refreshing This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Usage & Spend dashboard flow to render validated cached Codex spend immediately (when available) while the normal live validation refresh is still running, and to avoid redundant indexing by reusing the ambient cache for .liveSystem.

Changes:

  • Add a cache-priming load phase in SpendDashboardController and a new SpendDashboardSource.loadCached(...) path to hydrate validated cached Codex data before the ordinary refresh completes.
  • Extend cached Codex snapshot loading to support lightweight hydration options (skip Pi merge, skip project/session reconstruction) and add a package-scoped API for scoped homes.
  • Update the dashboard empty-state presentation to show a “Refreshing” state while validation is pending, and add targeted test coverage for cache-first rendering and cache-root routing.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Tests/CodexBarTests/SpendDashboardScopedCacheTests.swift Adds a production-like test ensuring the cached dashboard loader can read a validated scoped cache.
Tests/CodexBarTests/SpendDashboardPresentationTests.swift Adds coverage for the “Refreshing” vs “No local cost history yet” empty-state titles.
Tests/CodexBarTests/SpendDashboardCachedRefreshTestSupport.swift Adds test gates/recorders to deterministically control priming vs live refresh sequencing.
Tests/CodexBarTests/SpendDashboardCachedRefreshTests.swift Validates cache-first rendering, generation staleness rejection, cache-miss behavior, auth rotation rejection, and cache-root routing.
Tests/CodexBarTests/CostUsageFetcherCacheSnapshotTests.swift Expands cached snapshot tests to cover “native-only” hydration and scoped-home opt-in + root validation.
Sources/CodexBarCore/CostUsageFetcher.swift Adds cached-snapshot options (scoped opt-in, Pi inclusion, breakdown inclusion) and package-scoped scoped-home cached loader.
Sources/CodexBar/SpendDashboardController.swift Implements cache priming in the controller and routes .liveSystem to the ambient cache root; adds SpendDashboardSource.loadCached.
Sources/CodexBar/PreferencesSpendDashboardPane.swift Wires the cached loader into the pane and adds a refresh-aware empty-state model.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +317 to +318
// A cache miss is still pending fresh validation, not a provider failure.
return SpendDashboardLoadResult(inputs: inputs, failedSourceIDs: [])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants