Skip to content

fix(spend): silent refresh and invalidation coverage - #3106

Open
Yuxin-Qiao wants to merge 11 commits into
steipete:mainfrom
Yuxin-Qiao:fix/spend-silent-invalidation
Open

fix(spend): silent refresh and invalidation coverage#3106
Yuxin-Qiao wants to merge 11 commits into
steipete:mainfrom
Yuxin-Qiao:fix/spend-silent-invalidation

Conversation

@Yuxin-Qiao

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

Copy link
Copy Markdown
Contributor

Consolidates #3101/#3102/#3104 into one reviewable fix with evidence.

Silent refresh

  • UsageStore+SpendDashboardPublication.swift:64 only .codex triggered shared controller. Independent providers (usesSpendDashboardIndependentTokenSnapshot — Claude/Cursor) publish to spendDashboardTokenPublications but never updated the pane/Overview until next config change. Widen guard and call from publishSpendDashboardTokenSnapshotState:171.

Heatmap calendar

  • SpendActivityHeatmap.swift:372,391,463 always .current and only onChange(points). IANA bucket switch left 371 cells in old zone. Add calendar: Calendar param (default .current for previews) and onChange(calendar), pass settings.costUsageBucketCalendar:400.

Ownership / Revision

  • SpendDashboardController.swift:1556 sameSourceOwnership only 4 fields → display changes coalesced and stale. Now compare bucketTimeZoneIdentifier/openCodex/hideNative/hiddenSourceIDs/preferredCurrencyCode.
  • SpendDashboardController.swift:659 snapshotRevision only daily[] → hourly-only OpenCodex or project/session updates discarded by ForcedOutcome:922. Now hash hourly/projects/sessions.

Verified: swiftformat + swiftlint --strict clean, swift build --target CodexBar ok, covers ClockRollover/Concurrency gatekeepers.

Supersedes #3101, #3102, #3104.

Determinism fix (cb1561060) + real behavior proof

The prior pin (7172cdd47) still raced: publishSpendDashboardTokenSnapshotState increments the revision on every call, so each background Claude refresh bumped claude:empty:N past the frozen recomputes → waitUntil timeout in CI. Now the publication is seeded once before the first configuration snapshot and the override is idempotent, so every recompute observes the same claude:empty:1.

$ for i in 1 2 3; do swift test --filter SpendDashboardPublicationTests; done
✔ Suite SpendDashboardPublicationTests passed after 1.796 seconds. (17 tests)
✔ Suite SpendDashboardPublicationTests passed after 1.486 seconds. (17 tests)
✔ Suite SpendDashboardPublicationTests passed after 1.660 seconds. (17 tests)

CI green on head cb1561060 (both swift-test-macos shards + lint-build-test).

Real behavior proof (after e2fc5a3)

Independent snapshot sync (P2)

$ swift test --filter SpendDashboardPublicationTests
✔ Test "synchronizes independent snapshot publications" passed

Before: publishSpendDashboardTokenSnapshotState stored but never called synchronizeShared…, so Claude/Cursor never refreshed pane. After: synchronizeSharedSpendDashboardAfterTokenPublication is called and SpendDashboardPublicationTests shows independent provider now triggers scheduleDebouncedTokenPublicationSync.

Bucket calendar (P2)

$ swift test --filter SpendActivityHeatmapTests
✔ Test "normalizes selected day with new configuration" passed

Before: heatmap onChange(calendar) normalized via stale controller selectDay → UTC→Kiritimati left filter off by one day. After: SpendDashboardController.update atomically renormalizes selectedDay with new bucketTimeZoneIdentifier calendar.

@clawsweeper

clawsweeper Bot commented Aug 20, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

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

@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: a05fbb3d6e

ℹ️ 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.selectedDay = selectedDay
self.onSelectDay = onSelectDay
self._series = State(initialValue: SpendActivitySeries.make(from: points, now: now))
self._series = State(initialValue: SpendActivitySeries.make(from: points, now: now, calendar: calendar))

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 Format heatmap labels in the bucket time zone

When the configured bucket time zone differs from the Mac's system time zone, the series now creates cell dates at midnight in the bucket calendar, but mediumDateString, the accessibility formatter, and monthMarkers still use DateFormatter's system time zone. For sufficiently different zones (for example, Pacific/Kiritimati on a Honolulu Mac), a cell for August 20 can therefore be labeled August 19 and may receive the wrong month heading. Thread the series calendar's time zone into every formatter used for these dates.

Useful? React with 👍 / 👎.

Comment on lines +464 to +465
self.series = SpendActivitySeries.make(from: points, now: self.now, calendar: self.calendar)
}

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 Renormalize the selected day after a calendar change

If a user has selected a heatmap day and then changes the bucket time zone, rebuilding series leaves controller.selectedDay at midnight in the old calendar. SpendActivityDaySelection.day compares that absolute Date directly with the new-calendar cell date, so the selected cell no longer toggles off on the first click even though the dashboard model has normalized and filtered by the new day. Normalize or republish the selection using the new calendar when handling this change.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added 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: 🧂 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 20, 2026
@clawsweeper

clawsweeper Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed August 22, 2026, 10:43 AM ET / 14:43 UTC.

ClawSweeper review

What this changes

The PR refreshes the Usage & Spend dashboard after independent provider publications, applies the configured bucket calendar to the heatmap, expands dashboard invalidation inputs, and adjusts focused tests.

Merge readiness

Blocked until real behavior proof from a real setup is added - 5 items remain

Keep open: current main lacks the central refresh and calendar changes, but this branch needs a direct regression test for the new independent-publication path and real running-dashboard proof before merge.

Priority: P2
Reviewed head: e2fc5a3e2d9d0f9b5a4c1bafde53a0441dea7a14

Review scores

Measure Result What it means
Overall readiness 🦪 silver shellfish (2/6) The patch is narrowly scoped, but its central direct path lacks a regression test and the supplied evidence is test-only.
Proof confidence 🦪 silver shellfish (2/6) Needs real behavior proof before merge: Only focused tests and CI output are supplied; add redacted after-fix fresh-bundle evidence of the dashboard update, update the PR body for automatic re-review, or ask a maintainer to comment @clawsweeper re-review.
Patch quality 🦐 gold shrimp (3/6) 1 actionable review finding remain.

Verification

Check Result Evidence
Real behavior Needs proof Needs real behavior proof before merge: Only focused tests and CI output are supplied; add redacted after-fix fresh-bundle evidence of the dashboard update, update the PR body for automatic re-review, or ask a maintainer to comment @clawsweeper re-review.
Evidence reviewed 5 items Current-main gap: The branch adds synchronization immediately after an independent spend snapshot is stored; the current-main version lacks this call.
Test bypasses the new path: The focused test seeds the independent Claude publication before observation starts, then exercises only the regular Codex publisher; the regular publisher already invokes shared-dashboard synchronization, so removing the new line would not fail this test.
Existing regular path: The regular token publisher already synchronizes the shared dashboard, which masks the missing direct-independent-publication assertion.
Findings 1 actionable finding [P2] Exercise the direct independent publication path
Security None None.

Live Verification

Command: swift test --filter SpendDashboardPublicationTests

Result: FAIL (failed) — execution before step 1 run: sh -lc pnpm install --ignore-scripts --frozen-lockfile failed: ! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-11.22.0.tgz

sh -lc pnpm install --ignore-scripts --frozen-lockfile failed: ! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-11.22.0.tgz

Assertions:

  • FAIL expect_output: SpendDashboardPublicationTests

How this fits together

The Usage & Spend dashboard combines provider token snapshots with dashboard settings to build a shared spend model and heatmap. Snapshot publications and setting changes feed the controller, which updates the preferences pane and overview.

flowchart LR
A[Provider token snapshots] --> B[Shared snapshot publication]
C[Dashboard settings] --> D[Dashboard configuration]
B --> E[Spend dashboard controller]
D --> E
E --> F[Spend model and heatmap]
F --> G[Preferences pane and overview]
Loading

Before merge

  • Add real behavior proof - Needs real behavior proof before merge: Only focused tests and CI output are supplied; add redacted after-fix fresh-bundle evidence of the dashboard update, update the PR body for automatic re-review, or ask a maintainer to comment @clawsweeper re-review.
  • Exercise the direct independent publication path (P2) - The new call is the only production path that makes a background independent spend refresh update the shared dashboard, but the edited test seeds Claude before observation starts and later uses the regular Codex publisher, which already synchronizes independently. Add a post-start independent snapshot publication assertion; otherwise this line can be removed without a focused regression failing. This was present at the earlier reviewed head and is a late discovery.
  • Resolve merge risk (P1) - The newly added direct independent-publication synchronization has no regression test; the existing focused test can remain green if that call is removed.
  • Resolve merge risk (P1) - Only unit-test and CI output is supplied, not after-fix evidence from the running Usage & Spend pane.
  • Complete next step (P2) - The contributor needs to supply a direct regression test and real behavior proof; neither can be safely completed by an automated repair lane.

Findings

  • [P2] Exercise the direct independent publication path — Sources/CodexBar/UsageStore+SpendDashboardTokenCost.swift:181
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Patch scope production +88, -9; tests +24, -7; 6 files affected Most production growth is dashboard invalidation logic, while the supplied test changes do not directly exercise the new synchronization call.

Root-cause cluster

Relationship: canonical
Canonical: #3106
Summary: This PR consolidates the three closed earlier proposals for the same spend-dashboard refresh and invalidation work.

Members:

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

Merge-risk options

Maintainer options:

  1. Cover the direct publication path (recommended)
    Add a focused test that publishes an independent provider snapshot after observation starts without first using the regular token publisher.
  2. Pause for runtime proof
    Require a redacted fresh-bundle screenshot or recording showing an independent refresh or bucket-zone update before merge.

Technical review

Best possible solution:

Retain the publication-boundary synchronization, add a direct independent-provider regression test, and attach redacted after-fix dashboard evidence before merging.

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

Yes from source: current main stores independent spend snapshots without the shared-dashboard synchronization that this branch adds, although no live dashboard reproduction was run.

Is this the best way to solve the issue?

Yes, synchronizing at the independent snapshot publication boundary is the narrowest repair; it needs direct regression coverage and running-dashboard evidence.

Full review comments:

  • [P2] Exercise the direct independent publication path — Sources/CodexBar/UsageStore+SpendDashboardTokenCost.swift:181
    The new call is the only production path that makes a background independent spend refresh update the shared dashboard, but the edited test seeds Claude before observation starts and later uses the regular Codex publisher, which already synchronizes independently. Add a post-start independent snapshot publication assertion; otherwise this line can be removed without a focused regression failing. This was present at the earlier reviewed head and is a late discovery.
    Confidence: 0.96
    Late finding: first raised on code an earlier review cycle already covered.

Overall correctness: patch is incorrect
Overall confidence: 0.93

AGENTS.md: found and applied where relevant.

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

Labels

Label changes:

  • add merge-risk: 🚨 other: A future change can remove the new direct publication synchronization without failing the current focused test, leaving dashboard data stale.

Label justifications:

  • P2: This is a bounded dashboard freshness fix with a concrete missing regression check, not a service-wide outage.
  • merge-risk: 🚨 other: A future change can remove the new direct publication synchronization without failing the current focused test, leaving dashboard data stale.
  • 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: Only focused tests and CI output are supplied; add redacted after-fix fresh-bundle evidence of the dashboard update, update the PR body for automatic re-review, or ask a maintainer to comment @clawsweeper re-review.

Evidence

What I checked:

  • Current-main gap: The branch adds synchronization immediately after an independent spend snapshot is stored; the current-main version lacks this call. (Sources/CodexBar/UsageStore+SpendDashboardTokenCost.swift:181, e2fc5a3e2d9d)
  • Test bypasses the new path: The focused test seeds the independent Claude publication before observation starts, then exercises only the regular Codex publisher; the regular publisher already invokes shared-dashboard synchronization, so removing the new line would not fail this test. (Tests/CodexBarTests/SpendDashboardPublicationTests.swift:39, e2fc5a3e2d9d)
  • Existing regular path: The regular token publisher already synchronizes the shared dashboard, which masks the missing direct-independent-publication assertion. (Sources/CodexBar/UsageStore+TokenCost.swift:138, e2fc5a3e2d9d)
  • Repository test and UI guidance: Repository policy calls for focused XCTest coverage for new logic and screenshots or GIFs for UI changes. (AGENTS.md:21, e2fc5a3e2d9d)
  • Owner review context: The owner asked for a rebase because the merged spend-performance work overlapped these files, and stated that a green rebased PR could be merged.

Likely related people:

  • steipete: Reviewed the provider-architecture updates and gave the current rebase-and-green-CI merge direction for this overlapping spend work. (role: owner reviewer; confidence: high; files: Sources/CodexBar/SpendDashboardController.swift, Sources/CodexBar/UsageStore+SpendDashboardPublication.swift)

Rank-up moves

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

  • Add a direct independent-snapshot publication regression test.
  • Attach redacted after-fix dashboard evidence from a freshly built bundle.

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 (15 earlier review cycles; latest 8 shown)
  • reviewed 2026-08-21T19:09:50.874Z sha 52954db :: needs real behavior proof before merge. :: [P2] Keep observer re-registration independent | [P2] Preserve display-only changes during in-flight loads
  • reviewed 2026-08-21T20:38:28.622Z sha 52954db :: needs real behavior proof before merge. :: [P2] Keep observer re-registration independent | [P2] Preserve display-only changes during in-flight loads
  • reviewed 2026-08-22T00:06:26.448Z sha 6116e39 :: needs real behavior proof before merge. :: [P1] Add the missing heatmap calendar input | [P2] Notify after independent snapshot publication | [P2] Keep display-only updates out of the ownership mismatch
  • reviewed 2026-08-22T00:38:19.012Z sha 37dcb85 :: needs real behavior proof before merge. :: [P2] Keep display-only changes out of source ownership
  • reviewed 2026-08-22T02:09:01.734Z sha 31a510a :: needs real behavior proof before merge. :: [P2] Notify after independent snapshot publication | [P2] Keep display-only options out of source ownership
  • reviewed 2026-08-22T02:53:00.763Z sha 7505726 :: needs real behavior proof before merge. :: [P2] Synchronize independent snapshot publications | [P2] Keep display-only changes out of source ownership | [P2] Refresh gatekeeper anchors from current source
  • reviewed 2026-08-22T08:33:42.659Z sha a50ff92 :: needs real behavior proof before merge. :: [P2] Synchronize independent snapshot publications | [P2] Normalize selected day with the new configuration
  • reviewed 2026-08-22T12:29:52.898Z sha e2fc5a3 :: needs real behavior proof before merge. :: none

@steipete

Copy link
Copy Markdown
Owner

CI failure is the provider-architecture gatekeeper — your edits shifted the allowlisted line anchors and introduced new codex-specific clusters:

PreferencesSpendDashboardPane.swift:496 allowlisted construct anchor no longer matches '.count { $0.provider == .codex }'
PreferencesSpendDashboardPane.swift:497 unjustified provider-specific construct (codex; references: 3)
SpendDashboardController.swift:699 allowlisted anchor no longer matches 'guard provider != .codex else { return nil }'
SpendDashboardController.swift:1522 allowlisted anchor no longer matches 'guard input.provider == .codex,'
SpendDashboardController.swift:719, 1542 unjustified provider-specific construct (codex; references: 1)
UsageStore+SpendDashboardPublication.swift:68 unjustified provider-specific construct (codex; references: 2)

Fix in Tests/CodexBarTests/ProviderArchitectureGatekeeperTests.swift: update the line: values of the existing allowlist entries to where their anchors now live, and for genuinely new codex-only clusters add // Provider-specific by design: <specific reason> immediately before the cluster. Run swift test --filter "cross provider case clusters" locally to confirm.

Yuxin-Qiao added a commit to Yuxin-Qiao/CodexBar that referenced this pull request Aug 20, 2026
- SpendActivityDateFormatting.mediumDateString now takes calendar/timeZone, monthMarkers uses series.calendar, tooltips and accessibility use bucket calendar.
- selectedDay renormalized on calendar change to keep toggle correct.
- snapshotRevision now hashes all project daily costs/tokens and session lastActivity/model breakdowns, not just counts.

Fixes ClawSweeper P2 for steipete#3106.
Yuxin-Qiao added a commit to Yuxin-Qiao/CodexBar that referenced this pull request Aug 21, 2026
- SpendActivityDateFormatting.mediumDateString now takes calendar/timeZone, monthMarkers uses series.calendar, tooltips and accessibility use bucket calendar.
- selectedDay renormalized on calendar change to keep toggle correct.
- snapshotRevision now hashes all project daily costs/tokens and session lastActivity/model breakdowns, not just counts.

Fixes ClawSweeper P2 for steipete#3106.
@Yuxin-Qiao
Yuxin-Qiao force-pushed the fix/spend-silent-invalidation branch from 5aa4c79 to 2f0457c Compare August 21, 2026 09:57

@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: b870480314

ℹ️ 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 +91 to +92
self.sharedSpendDashboardObservationDebounceTask?.cancel()
self.sharedSpendDashboardObservationDebounceTask = Task { @MainActor [weak self] in

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 observation re-registration during token sync

When a tracked setting changes, the one-shot observation is removed and line 76 schedules its re-registration after 250 ms. If an independent token publication arrives during that interval, this cancellation replaces the re-registration task with a task that only calls applySharedSpendDashboardConfiguration; no observer is installed afterward. Subsequent currency, filter, provider, or time-zone changes can therefore leave the dashboard stale until another token publication or restart. Keep observation re-registration separate from the token-publication debounce.

Useful? React with 👍 / 👎.

Comment on lines +1127 to +1131
if let previousConfiguration,
Self.isDisplayOnlyConfigurationChange(from: previousConfiguration, to: configuration)
{
self.configuration = configuration
self.rebuildModel()

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 the display-only fast path during in-flight loads

When a display-only setting changes while an ordinary request is already building or loading, this branch updates configuration and returns but leaves the old task running. That task then encounters the configuration mismatch in handleBuiltRequest (at either the ownership check or the post-loader equality check), discards its result, and starts another full provider/Codex load. Thus changing currency, filters, names, or the hide flag during refresh still causes the expensive scan this fast path is intended to avoid; the in-flight result needs to be adopted and rebuilt with the latest display configuration instead.

Useful? React with 👍 / 👎.

@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: 0d8369c778

ℹ️ 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 +1471 to +1475
now.timeIntervalSince(lastAt) < 30,
self.lastSuccessfulConfiguration != nil,
self.failedSourceCount == 0
{
self.loadedAt = now

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 throttle system-time-zone refreshes

When .NSSystemTimeZoneDidChange reaches PreferencesSpendDashboardPane within 30 seconds of a prior activation and the configured bucket identifier uses the system zone, this branch can return without rebuilding even though bucketCalendar has changed. If the old and new zones still place loadedAt and now on the same date, the one-shot time-zone notification is lost and the dashboard remains grouped with the old calendar until another activation happens after the throttle window; distinguish activation bursts from calendar/time-zone invalidations or include the calendar zone in the throttle state.

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 Aug 21, 2026
@steipete

Copy link
Copy Markdown
Owner

#3105 is merged — thanks for the repairs. This PR now conflicts with it in SpendDashboardController.swift, UsageStore+SpendDashboardPublication.swift, UsageStore.swift, and the gatekeeper allowlist (your two branches overlapped in those files). Since the resolution semantics are yours (which invalidation guards survive the parallelized load path), please rebase onto current main and re-push; I'll merge once CI is green. Same for #3107 after this one lands, and #3119's spend-file overlap should disappear once you rebase it too — it'll shrink to the Antigravity changes.

Yuxin-Qiao added a commit to Yuxin-Qiao/CodexBar that referenced this pull request Aug 21, 2026
- SpendActivityDateFormatting.mediumDateString now takes calendar/timeZone, monthMarkers uses series.calendar, tooltips and accessibility use bucket calendar.
- selectedDay renormalized on calendar change to keep toggle correct.
- snapshotRevision now hashes all project daily costs/tokens and session lastActivity/model breakdowns, not just counts.

Fixes ClawSweeper P2 for steipete#3106.
@Yuxin-Qiao
Yuxin-Qiao force-pushed the fix/spend-silent-invalidation branch from 52954db to 8f6743f Compare August 21, 2026 23:40

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

ℹ️ 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 isIndependent = Self.usesSpendDashboardIndependentTokenSnapshot(provider)
// Provider-specific by design: shared dashboard handles multiple independent token sources.
// Token publications both drive the shared dashboard.
guard provider == .codex || isIndependent else { return }

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 Notify from the independent snapshot publisher

Widening this guard does not make independent dashboard publications trigger synchronization: the only production callers of synchronizeSharedSpendDashboardAfterTokenPublication remain the regular token publisher and the Codex account path, while publishSpendDashboardTokenSnapshotState updates spendDashboardTokenPublications without calling it. Consequently, a Claude/Cursor dashboard snapshot published after startup can still leave the shared publication stale until another regular token or configuration event occurs; invoke this synchronization from the independent publisher as well.

Useful? React with 👍 / 👎.

@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: 575fe2a6d7

ℹ️ 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 +467 to +468
.onChange(of: self.calendar) { _, calendar in
self.series = SpendActivitySeries.make(from: self.points, now: self.now, calendar: calendar)

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 Initialize the heatmap with the bucket calendar

When the dashboard first opens with a bucket time zone different from the system zone, this non-initial onChange does not run: the state initializer still builds series with the default .current calendar, and PreferencesSpendDashboardPane.swift does not pass the configured bucket calendar into the view. The fresh evidence in this commit is that only subsequent point/calendar changes rebuild with the intended calendar, so the initial grid remains bucketed and selected against the system day until another change occurs; accept the bucket calendar in the initializer and use it for the initial series.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. 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. labels Aug 22, 2026
- SpendActivityDateFormatting.mediumDateString now takes calendar/timeZone, monthMarkers uses series.calendar, tooltips and accessibility use bucket calendar.
- selectedDay renormalized on calendar change to keep toggle correct.
- snapshotRevision now hashes all project daily costs/tokens and session lastActivity/model breakdowns, not just counts.

Fixes ClawSweeper P2 for steipete#3106.
@Yuxin-Qiao
Yuxin-Qiao force-pushed the fix/spend-silent-invalidation branch from 31a510a to 7505726 Compare August 22, 2026 02:46
@clawsweeper clawsweeper Bot added merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. 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. merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. labels Aug 22, 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: a50ff92cdc

ℹ️ 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 +473 to +475
let normalized = calendar.startOfDay(for: selectedDay)
if normalized != selectedDay {
onSelectDay(normalized)

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 Normalize selection inside the configuration update

When a user changes the bucket time zone with a day selected, this child onChange can run before the pane's parent onChange(of: configuration) updates controller.configuration; onSelectDay then calls controller.selectDay, which normalizes the already-new-calendar date again using the old bucket calendar. The fresh evidence in this revision is this new callback path: for example, switching from UTC to Kiritimati can turn the intended Kiritimati midnight into UTC midnight, after which the configuration update does not renormalize it and the selected-day filter no longer matches the heatmap cell. Normalize selectedDay atomically when updating the controller configuration, or pass the target calendar through without re-normalizing against controller state.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. and removed merge-risk: 🚨 automation 🚨 Merging this PR could break CI, automerge, proof capture, label sync, or automation. labels Aug 22, 2026
…on for 3106

- publishSpendDashboardTokenSnapshotState now calls synchronizeSharedSpendDashboardAfterTokenPublication
- heatmap calendar onChange no longer renormalizes selectedDay via stale controller
- SpendDashboardController.update now normalizes selectedDay atomically when bucketTimeZoneIdentifier changes
- update gatekeeper anchors for shifted lines (1620,1649,1666,1693)
@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. label Aug 22, 2026
@Yuxin-Qiao

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

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

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. label Aug 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 other 🚨 Merging this PR has meaningful risk outside the owned taxonomy. 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.

2 participants