fix(spend): widen ownership and revision coverage - #3104
Conversation
sameSourceOwnership only compared 4 fields, so switching bucketTimeZoneIdentifier / openCodexUsageLogsEnabled / hideNativeCodexCostWhenOpenCodexPresent / hiddenSourceIDs / preferredCurrencyCode during an in-flight forceRefresh was coalesced as same-owner and left daily/hourly/chartDomain stale. Compare the display-affecting fields explicitly. snapshotRevision only hashed daily[]. An OpenCodex hourly-only change or project/session update did not bump sourceRevisions, so ForcedOutcome.incorporating treated it as not newer and discarded the confirmedNonempty input. Hash hourly / projects / sessions as well.
|
🦞👀 Pull request received. I will update this pull request when review starts. |
|
Codex review: needs real behavior proof before merge. Reviewed August 20, 2026, 6:17 AM ET / 10:17 UTC. ClawSweeper reviewWhat this changesThe PR expands spend-dashboard refresh ownership checks and snapshot revision inputs so configuration changes and hourly, project, and session updates trigger a fresh displayed result. Merge readiness⛔ Blocked until real behavior proof is added - 9 items remain Keep open: the patch is targeted but does not actually publish hourly-only OpenCodex data and still omits rendered project/session fields from its revision hash. Priority: P2 Review scores
Verification
Live VerificationCommand: Result: FAIL (failed) — execution before step 1 Assertions:
How this fits togetherCodexBar’s spend dashboard combines provider usage snapshots with display configuration during refresh. It coalesces compatible in-flight refreshes, then publishes charts, totals, project rows, and session rows. flowchart LR
A[Provider usage snapshots] --> B[Spend refresh]
C[Dashboard display settings] --> D[Ownership comparison]
D --> B
B --> E[Snapshot revision]
E --> F[Coalesce or reload]
F --> G[Dashboard charts and totals]
Before merge
Findings
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Define an OpenCodex refresh revision that reaches reconciliation, publish hourly-only snapshots, and hash every project/session field used by rendered dashboard rows. Do we have a high-confidence way to reproduce the issue? Yes, from source: an OpenCodex snapshot containing only hourly entries is rejected, while same-count project-daily or same-ID session activity/model changes leave the added hash unchanged. Is this the best way to solve the issue? No; widening the hash is the right direction, but the OpenCodex data never enters that revision path and the hash must cover all rendered fields. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against a3457dafbe63. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
|
|
Superseded by larger invalidation PR |
Two coalesce/revision gaps kept the dashboard stale:
1.
sameSourceOwnership:1536too narrowOnly compared
costUsageEnabled/providerIDs/codexAccountIdentities/sourceOwnershipFingerprints. ChangingbucketTimeZoneIdentifier/openCodexUsageLogsEnabled/hideNativeCodexCostWhenOpenCodexPresent/hiddenSourceIDs/preferredCurrencyCodeduring an in-flightforceRefresh(#3041path) was treated as same-owner, adoptedrequest.configurationwithout a newload, leavingdaily/hourly/chartDomainstale. Now compare the 5 display-affecting fields.2.
snapshotRevision:659ignoredhourly/projects/sessionsOnly hashed
daily[]. An OpenCodex per-request-hour update or project/session addition didn't bumpsourceRevisions, soForcedOutcome.incorporating:922saw!hasNewerSourceRevisionand discarded theconfirmedNonemptyinput. Now hashhourly(hour+cost),projects(name/path/tokens/cost/dailyCount),sessions(id/tokens/cost).Both fixes keep
#3041coalesce behavior for true same-owner churn while ensuring display changes and hourly-only OpenCodex updates invalidate.Verified:
swiftformat+swiftlint --strictclean. Gatekeeper anchors: no new provider clusters, only widened predicate + revision.