Skip to content

fix(widgets): isolate last-good retention by provider - #4095

Closed
steipete wants to merge 2 commits into
mainfrom
triage/20260921-widgets-3
Closed

steipete wants to merge 2 commits into
mainfrom
triage/20260921-widgets-3

Conversation

@steipete

Copy link
Copy Markdown
Owner

A failed refresh could still replace useful widget readings with placeholders when one other cached provider was disabled, invalidated, or handled by Claude's separate retention path. The previous fallback made one eligibility decision for the entire snapshot; a partially populated refresh also skipped retention entirely.

Preserve eligible last-good entries independently, retaining each measurement's original timestamp. Provider and account invalidation stays local to that provider and remains effective until replacement data is published. Generic disk entries still do not establish account ownership after a restart. This replaces the snapshot-wide preservation flag and removes seven net production lines.

The widget documentation also records the newer mapped-executable evidence from #2838. This patch does not add extension-process termination or claim to repair Homebrew-deleted placements or chronod archive acceptance.

Verification

All Swift runs used CODEXBAR_SUPPRESS_TEST_KEYCHAIN_ACCESS=1 CODEXBAR_TEST_CODEX_FILE_ISOLATION=1 CODEXBAR_TEST_SESSION_FILE_ISOLATION=1 and a task-owned RAM-backed TMPDIR after shared-disk build contention.

swift test -j 2 --filter WidgetEmptyProjectionTests

Baseline: 11 tests, 8 issues across two parameterized tests (four mixed-provider cases and four invalidation-boundary expectations). The fixed regression suite passes and retains the original measurement time and synthetic balance.

swift test -j 2 --filter 'WidgetEmptyProjectionTests|UsageStoreWidgetSnapshot|WidgetSnapshotTestIsolationTests|WidgetSnapshotCompatibilityTests|WidgetSnapshotTests|WidgetTokenOwnerTests|PiWidgetFreshnessTests|MistralWidgetSnapshotTests|ClaudeScopedWeeklyWidgetRowTests|ClaudeSwapWidgetSnapshotTests|CodexLegacyWidgetSnapshotTests|CodexBarWidgetProviderTests|WidgetProviderPagerTests|AppGroupSupportTests|WidgetAccountSnapshotTests|WidgetAccountCompatibilityTests|BurnDownWidgetConfigurationTests|WidgetBindingQuotaTests|ProviderArchitectureGatekeeperTests'
swift test --skip-build --filter WidgetSnapshotBoundedIOTests
make check

Final results: 228 tests in 24 suites passed, plus 4 bounded-I/O tests passed; make check passed with 0 formatting changes required and 0 lint violations. Codex autoreview found no actionable P0–P2 issues. The initial broad run caught a missing architecture-comment marker; restoring that marker made all 48 gatekeeper tests pass. Two earlier check attempts hit unrelated process-cleanup timing failures; the final check passed with isolated temporary storage.

Production LOC against main: 2 files changed, 16 insertions(+), 23 deletions(-) (−7 net). Tests: 1 file changed, 88 insertions(+), 4 deletions(-).

No live provider probes or running-app/extension restarts were used.

Synthetic before / after

Synthetic offscreen captures: baseline empty projection versus retained last-good balance with its original age. These prove the rendered snapshot result, not installed WidgetKit upgrade or archive acceptance.

Before:

Synthetic baseline placeholder

After:

Synthetic retained balance and original age

Refs #3500
Refs #3627
Refs #3339
Refs #2838

@clawsweeper

clawsweeper Bot commented Sep 28, 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 P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Sep 28, 2026
@clawsweeper

clawsweeper Bot commented Sep 28, 2026

Copy link
Copy Markdown

Codex review: blocked before merge. Reviewed September 28, 2026, 3:27 AM ET / 07:27 UTC.

ClawSweeper review

What this changes

The branch retains each eligible provider’s last widget reading independently after a failed refresh, adds focused regression tests, and updates widget documentation and release notes.

Merge readiness

⛔ Blocked before merge - 2 items remain

Current main and v0.68.0 still use a snapshot-wide fallback, so this focused improvement remains useful. The reviewed patch has no identified correctness defect. GitHub reports that the current head conflicts with main.

Priority: P2
Reviewed head: 9bf336e6631d6f3a76ac8eab359f11fc0d88769f

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) Focused regression coverage and direct synthetic rendering evidence support a good, bounded patch; the current merge conflict is a workflow blocker.
Proof confidence 🐚 platinum hermit (4/6) Not applicable: This owner-authored PR is exempt from contributor proof. Supplied synthetic captures exercise snapshot publication and the production Switcher view, showing the retained balance and original age; installed WidgetKit acceptance was outside the claimed fix. The serialized snapshot format is unchanged, so no stored-data migration is required.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Not applicable Not applicable: This owner-authored PR is exempt from contributor proof. Supplied synthetic captures exercise snapshot publication and the production Switcher view, showing the retained balance and original age; installed WidgetKit acceptance was outside the claimed fix. The serialized snapshot format is unchanged, so no stored-data migration is required.
Evidence reviewed 11 items Introduced writer change: The introduced hunk replaces the all-or-nothing fallback with per-provider eligibility checks and preserves the queued entry’s measurement time.
Account invalidation boundary: Generic provider invalidation now retires only that provider’s queued entry; the snapshot writer records blocked providers when publishing.
Refresh replacement path: A successful provider refresh publishes a replacement usage snapshot and removes that provider from the preservation block set.
Findings None None.
Security None None.

How this fits together

CodexBar’s usage store turns provider refresh results into a JSON snapshot in the app-group container. The widget extension reads that snapshot to display provider usage, balances, and measurement ages.

flowchart LR
  A[Provider refresh results] --> B[Usage store]
  C[Last queued readings] --> B
  D[Provider invalidation] --> B
  B --> E{Eligible reading?}
  E --> F[Widget JSON snapshot]
  F --> G[Widget extension]
  G --> H[Visible widget]
Loading

Before merge

  • Resolve merge risk (P1) - GitHub reports a conflict with current main; the resolved merge result needs review before this head can land.
  • Complete next step (P2) - Resolve the conflict against current main and verify the resulting widget snapshot behavior before merge.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Production and test lines production +16/-23 (net -7); tests +88/-4 (net +84) The writer becomes smaller while regression coverage expands across provider boundaries.

Merge-risk options

Maintainer options:

  1. Decide the mitigation before merge
    Keep the per-provider, in-session retention rule with original measurement ages and provider-local account invalidation.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Technical review

Best possible solution:

Keep the per-provider, in-session retention rule with original measurement ages and provider-local account invalidation.

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

Yes, from source: current main’s snapshot-wide guard drops eligible entries when another provider is ineligible or a refresh is partial. The contributor reports baseline failures and passing synthetic regression cases; this review did not execute them.

Is this the best way to solve the issue?

Yes. Provider-local retention fits the existing queued-snapshot boundary and leaves Claude ownership checks and restart behavior intact.

AGENTS.md: found and applied where relevant.

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

Labels

Label changes:

  • add P2: The change repairs limited-scope widget placeholders after failed refreshes without affecting the core app’s availability.
  • add proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. This owner-authored PR is exempt from contributor proof. Supplied synthetic captures exercise snapshot publication and the production Switcher view, showing the retained balance and original age; installed WidgetKit acceptance was outside the claimed fix. The serialized snapshot format is unchanged, so no stored-data migration is required.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: This owner-authored PR is exempt from contributor proof. Supplied synthetic captures exercise snapshot publication and the production Switcher view, showing the retained balance and original age; installed WidgetKit acceptance was outside the claimed fix. The serialized snapshot format is unchanged, so no stored-data migration is required.

Label justifications:

  • P2: The change repairs limited-scope widget placeholders after failed refreshes without affecting the core app’s availability.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🐚 platinum hermit and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Not applicable: This owner-authored PR is exempt from contributor proof. Supplied synthetic captures exercise snapshot publication and the production Switcher view, showing the retained balance and original age; installed WidgetKit acceptance was outside the claimed fix. The serialized snapshot format is unchanged, so no stored-data migration is required.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. This owner-authored PR is exempt from contributor proof. Supplied synthetic captures exercise snapshot publication and the production Switcher view, showing the retained balance and original age; installed WidgetKit acceptance was outside the claimed fix. The serialized snapshot format is unchanged, so no stored-data migration is required.

Evidence

What I checked:

Likely related people:

  • Peter Steinberger: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)
  • Tom Vaucourt: Suggested for follow-up; no historical authorship or introduction is verified. (role: unverified routing candidate; confidence: low)

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.

steipete added a commit that referenced this pull request Sep 28, 2026
Widget snapshots now retain each provider's last eligible reading with its original measurement time instead of an all-or-nothing guard, so a disabled, invalidated, or failing provider no longer blanks the others; an invalidated account stays retired until replacement usage is published. Refs #3500 #3627 #3339 #2838.

Thanks @jaxleezhang!
@steipete

Copy link
Copy Markdown
Owner Author

Landed on main as c33760e via merge train #4099 (one green CI run for the whole train).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Normal priority bug or improvement with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant