fix: Give widget token rows their own updated time instead of inheriting snapshot freshness#1967
fix: Give widget token rows their own updated time instead of inheriting snapshot freshness#1967irresi wants to merge 4 commits into
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 7, 2026, 3:21 PM ET / 19:21 UTC. Summary Reproducibility: yes. The linked issue is source-reproducible and maintainer-confirmed: current main can persist a fresh widget snapshot before the slower token-cost refresh updates tokenSnapshots. Review metrics: 2 noteworthy metrics.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Next step before merge
Security Review detailsBest possible solution: Land this PR after the repository's required checks and maintainer merge review, keeping the optional snapshot timestamp contract and focused cache/widget coverage intact. Do we have a high-confidence way to reproduce the issue? Yes. The linked issue is source-reproducible and maintainer-confirmed: current main can persist a fresh widget snapshot before the slower token-cost refresh updates tokenSnapshots. Is this the best way to solve the issue? Yes. Persisting token-specific updatedAt and disclosing stale token row age is a narrow fix that avoids coupling every widget snapshot write to slow token-cost scans, and the latest head preserves cached native/Pi scan times. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against aa401f1d8b74. Label changesLabel changes:
Label justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
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. How this review workflow works
Review history (7 earlier review cycles)
|
…hot freshness Token-cost rows refresh on a slower cadence than quota rows, so a fresh widget snapshot could present hour-old token data as current (steipete#1964). Persist a token-specific updatedAt on WidgetSnapshot.TokenUsageSummary, suffix widget row titles with the token snapshot's own age once it lags the entry's freshness signal past ten minutes, and clear the token-fetch TTL on fast failures so the next scheduled pass retries instead of serving stale rows for the rest of the TTL. Legacy snapshots without the new field decode as fresh. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
24c60f0 to
fc27b17
Compare
|
Maintainer verification on exact head
Patch surface: 9 files, +232/-15. Merge remains blocked only on real WidgetKit rendering proof (or an explicit proof waiver). |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fc27b17620
ℹ️ 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".
Hydrating from the persisted codex scan cache rebuilt the token snapshot with the hydration time as updatedAt while returning the real cache scan time separately, so a stale cached token row could inherit app-start freshness and skip the widget's stale-age suffix for the rest of the fetch TTL. Cached snapshots now carry the cache's lastScan time; paths without a known scan time keep the previous behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Merged cached codex snapshots dropped the known scan times entirely, so a hydrated snapshot that included cached pi sessions fell back to the hydration time as updatedAt. Expose the pi cache's lastScan time and use the oldest constituent scan as the merged snapshot's updatedAt, while keeping TTL bookkeeping native-only so merged loads never suppress a pending rescan. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
02225b5 to
412750a
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |

Summary
updatedAtonWidgetSnapshot.TokenUsageSummaryso thewidget's cost rows (
Today,30d) carry their own freshness instead of inheritingthe provider entry's (Widget token usage can stay stale while usage snapshot shows as recently updated #1964)
Today · 42 min. ago; compactmetrics render
Today cost · 42 min. ago) once the token snapshot trails theentry's freshness by more than 10 minutes; fresher rows render unchanged
while timed-out scans keep the TTL so a slow corpus cannot thrash back-to-back rescans
renders exactly as before
Fixes #1964.
Why a token-specific
updatedAtand not coalescing the refreshRegular refreshes schedule the token-cost refresh asynchronously and immediately
persist a widget snapshot that reads whatever
tokenSnapshotscurrently holds, sothe snapshot's
generatedAtand the entry'supdatedAtgo fresh whiletokenUsagestill carries the previous scan. The issue triage offered two shapes: make snapshot
writes wait for the in-flight cost refresh, or persist a token-specific updated time.
This PR takes the second. Waiting/coalescing would couple every snapshot write to the
slowest cost scan (which can legitimately take minutes over a large corpus and is
exactly the case that times out), while the disclosure fix keeps provider scanners
and refresh scheduling untouched — the shape the triage review recommended.
Illustrative snapshot shape (same provider entry, before vs after):
The TTL change covers the second half of the report: when a cost scan fails fast,
lastTokenFetchAtused to block any retry for the remainder of the fetch TTL, so thestale rows outlived the next scheduled passes too. Fast failures now clear the TTL;
timeouts keep it (
tokenFetchFailureAllowsEarlyRetry).Testing
swift test --filter "WidgetSnapshotTests|UsageStoreWidgetSnapshotTests|UsageStoreTokenRetryPolicyTests"—18 tests in 4 suites passed, including the new
token usage summary round trips updatedAt and tolerates legacy payloads,token usage staleness discloses only meaningful lag,widget snapshot carries token usage age separately from entry freshness, andtimed out token scans keep the fetch TTL while fast failures retry earlymake check— SwiftFormat and SwiftLint cleanswift build— cleanmake testhas one failing suite on my machine (AdaptiveRefreshTimerTests,timing-sensitive); it fails identically on unmodified
mainwith the sameexpectations, so it is unrelated to this change