Skip to content

fix: Claude OAuth 429時に前回表示を保持 / Preserve Claude OAuth display on 429#1956

Open
ruushu wants to merge 3 commits into
steipete:mainfrom
ruushu:fix/claude-oauth-rate-limit-stale-cache
Open

fix: Claude OAuth 429時に前回表示を保持 / Preserve Claude OAuth display on 429#1956
ruushu wants to merge 3 commits into
steipete:mainfrom
ruushu:fix/claude-oauth-rate-limit-stale-cache

Conversation

@ruushu

@ruushu ruushu commented Jul 6, 2026

Copy link
Copy Markdown

Summary

  • Preserve the last-good Claude OAuth display during HTTP 429 cooldowns without recording cached rows as fresh history.
  • Scope the existing five-minute background cooldown by a SHA-256 token fingerprint; never persist the raw access token.
  • Serialize cooldown reads/writes and clean legacy or expired entries without racing concurrent accounts.
  • Keep user-initiated refresh able to bypass cooldown and clear it after a successful recovery.
  • Isolate provider cards, reset metadata, availability, sources, and failure grace by Claude token-account credential/scope identity, including in-place account edits and stacked rows.
  • Preserve Auto fallback and explicit OAuth source behavior.

This keeps @ruushu's original resilience goal while fixing Linux hashing, account-switch leakage, stale-history recording, cooldown races, and credential-edit edge cases found during review.

Validation

Exact head: 58fe37bee29212c2bf27e0cfeaa0fd74947aa736

  • swift test --filter ClaudeOAuthRateLimitResilienceTests: 13/13 passed.
  • swift test --filter ClaudeOAuthTests: 39/39 passed.
  • make check: passed; SwiftFormat and SwiftLint report zero violations.
  • make test: all 50/50 shards passed.
  • autoreview --mode local: clean; no actionable findings.
  • Signed Debug package: codesign --verify --deep --strict passed; Gatekeeper accepted the bundle as Developer ID; embedded commit 58fe37be.
  • Packaged app launched and remained running; the CodexBar Debug menu opened and the Claude pane rendered its current unauthenticated state.
  • Packaged OAuth CLI returned the expected missing-credential classification on this host. Auto fallback also had no usable Claude usage source here, so no authenticated live-success claim is made.
  • Controlled compiled transport coverage proves success -> 429 -> background cooldown -> user bypass -> success recovery. A real provider 429 was not intentionally induced.

Public Model Identifier Gate: PASS (no model-bearing mutation).

Dependency freshness: PASS (no dependency changes).

Landing boundary

Code and local proof are ready. This changes credential-scoped cache/cooldown persistence behavior, so it remains unmerged pending explicit owner sign-off for that auth/persistence boundary.

Copilot AI review requested due to automatic review settings July 6, 2026 22:30

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@clawsweeper

clawsweeper Bot commented Jul 6, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed July 9, 2026, 1:30 PM ET / 17:30 UTC.

Summary
The branch scopes Claude OAuth 429 cooldowns and cached display state by credential/account identity, preserves last-good snapshots without recording fresh history, and adds focused OAuth rate-limit coverage.

Reproducibility: yes. from source inspection: current main uses one Claude OAuth cooldown key and does not preserve OAuth 429 snapshots the way it preserves CLI rate-limit data. I did not run live OAuth or Keychain probes because AGENTS.md warns against prompt-prone provider validation without explicit request.

Review metrics: 2 noteworthy metrics.

  • PR scope: 13 files changed; 1417 added, 74 removed. The diff is bounded to Claude OAuth/store/test surfaces but large enough that auth-provider upgrade review matters.
  • Focused coverage: 13 new resilience tests plus 1 Linux gate test. The tests cover the prior code blockers and edge cases, but synthetic coverage does not replace real behavior proof.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🦞 diamond lobster
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Add redacted real OAuth 429 preservation proof, such as terminal/live output, runtime logs, or a reproducible diagnostic transcript with private data removed.
  • Get explicit owner sign-off or a proof override for the credential-scoped cooldown/cache persistence boundary.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body provides tests, synthetic transport coverage, and unrelated launch/CLI checks, but not redacted real after-fix proof for the OAuth 429 preservation path. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] The PR changes persisted Claude OAuth cooldown keying and token-account cache ownership, so existing users with stored cooldown/cache state need owner-reviewed upgrade safety before merge.
  • [P1] The current proof is synthetic or unrelated to the changed path; it does not show a real after-fix OAuth 429 preservation run, redacted diagnostic transcript, or explicit proof override.

Maintainer options:

  1. Require owner sign-off and proof (recommended)
    Have the owner approve the cooldown/cache persistence boundary, then require real behavior proof or an explicit proof override before merge.
  2. Tighten upgrade behavior first
    If the persistence change is too broad, narrow the migration and add upgrade-focused coverage before landing.
  3. Pause if the boundary is not wanted
    Close or hold the branch if maintainers decide OAuth 429 display preservation should not change stored cooldown or cache ownership rules.

Next step before merge

  • [P1] Human review is needed for owner sign-off and proof or proof override; there is no narrow code repair for ClawSweeper to attempt right now.

Maintainer decision needed

  • Question: Should CodexBar accept the credential-scoped Claude OAuth cooldown and account-cache persistence boundary once real behavior proof is supplied or overridden?
  • Rationale: The diff stores token-derived cooldown keys and changes account-scoped display/cache ownership; ClawSweeper cannot choose that auth/persistence boundary without maintainer intent.
  • Likely owner: steipete — The current head includes steipete-authored rewrites of the same boundary and current-main history points to steipete for the affected Claude OAuth/account-state code.
  • Options:
    • Approve after proof (recommended): Merge once steipete accepts the credential-scoped cooldown/cache behavior and real behavior proof or a proof override is present.
    • Request a narrower migration: Keep the PR open and ask for a smaller compatibility path if the V2 keying or cache ownership behavior feels too broad.
    • Pause the direction: Hold or close the branch if maintainers do not want OAuth 429 display preservation to change persisted cooldown/cache semantics.

Security
Cleared: No concrete security or supply-chain concern was found; the diff uses existing crypto dependencies and persists token-derived cooldown keys rather than raw Claude tokens.

Review details

Best possible solution:

Land the credential-scoped Claude OAuth 429 preservation only after the owner accepts the auth/persistence boundary and the proof gate is satisfied or explicitly overridden.

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

Yes from source inspection: current main uses one Claude OAuth cooldown key and does not preserve OAuth 429 snapshots the way it preserves CLI rate-limit data. I did not run live OAuth or Keychain probes because AGENTS.md warns against prompt-prone provider validation without explicit request.

Is this the best way to solve the issue?

Mostly yes: the current head addresses the prior Linux hashing, stale-history, account-switch, and credential-edit blockers with focused tests. The remaining blocker is merge readiness for proof and owner acceptance, not a discrete code defect I can point to in the diff.

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P2: This is a normal-priority Claude OAuth reliability fix with limited blast radius but real provider-display impact.
  • merge-risk: 🚨 compatibility: The PR changes persisted OAuth cooldown keys and token-account cache ownership, so upgrade behavior needs owner-reviewed compatibility safety.
  • merge-risk: 🚨 auth-provider: The diff changes Claude OAuth token routing, cooldown behavior, fallback handling, and provider display state.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🦞 diamond lobster.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body provides tests, synthetic transport coverage, and unrelated launch/CLI checks, but not redacted real after-fix proof for the OAuth 429 preservation path. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

What I checked:

Likely related people:

  • steipete: Current-main blame for the OAuth rate-limit gate points to the v0.41.0 release commit, recent UsageStore history is concentrated under this owner, and the PR head includes maintainer-authored commits that rework the auth/persistence boundary. (role: recent Claude OAuth and account-state owner; confidence: high; commits: a83a83fa4131, b8955d1ac4f3, 842213048988; files: Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageRateLimitGate.swift, Sources/CodexBar/UsageStore+Refresh.swift, Sources/CodexBar/UsageStore+TokenAccounts.swift)
  • LeoLin990405: The merged Claude OAuth 429 handling PR introduced the earlier dedicated rate-limit guidance, cooldown gate, and tests that this PR extends. (role: adjacent OAuth 429 contributor; confidence: medium; commits: 539f3c4ba4ee, d8d02179bcec, 0a0e8cabc7ed; files: Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageFetcher.swift, Sources/CodexBarCore/Providers/Claude/ClaudeOAuth/ClaudeOAuthUsageRateLimitGate.swift, Tests/CodexBarTests/ClaudeOAuthTests.swift)
  • Vincent Peng: Recent history shows adjacent work on selected Claude OAuth pace identity near the provider/account isolation surface. (role: recent adjacent Claude account-state contributor; confidence: low; commits: f34ca8a1d9b3, 5023a79ffc56, a8c8e98edf68; files: Sources/CodexBar/UsageStore+TokenAccounts.swift, Sources/CodexBar/UsageStore+Refresh.swift)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • 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.
Review history (4 earlier review cycles)
  • reviewed 2026-07-06T22:35:30.760Z sha c5a95f2 :: needs real behavior proof before merge. :: [P2] Avoid recording cached 429 rows as fresh history
  • reviewed 2026-07-06T22:58:10.604Z sha c5a95f2 :: needs real behavior proof before merge. :: [P2] Use a cross-platform token fingerprint | [P2] Avoid recording cached 429 rows as fresh history
  • reviewed 2026-07-06T23:05:14.780Z sha c5a95f2 :: needs real behavior proof before merge. :: [P2] Use a cross-platform token fingerprint | [P2] Avoid recording cached 429 rows as fresh history
  • reviewed 2026-07-09T17:23:59.813Z sha 58fe37b :: needs real behavior proof before merge. :: none

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

ℹ️ 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".


private static func blockedUntilKey(accessToken: String) -> String {
let data = Data(accessToken.utf8)
let fingerprint = ClaudeOAuthCredentialsStore.sha256Prefix(data) ?? "unavailable"

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 Fix token hash fallback for Linux OAuth cooldowns

On Linux CLI builds, ClaudeOAuthCredentialsStore.sha256Prefix returns nil because that helper only uses CryptoKit while the package's Linux dependency is the Crypto module, so this fallback makes every access token use the same claudeOAuthUsageRateLimitBlockedUntilV2.unavailable key. In multi-account OAuth usage, a 429 from one Claude account will therefore block background refreshes for all other accounts for the cooldown window, defeating the token-scoped gate and leaving valid accounts stale. Use the existing Crypto fallback path here instead of collapsing to a shared key.

Useful? React with 👍 / 👎.

Comment on lines +1124 to +1127
return ResolvedAccountOutcome(
snapshot: snapshot,
usage: priorUsage,
sourceLabel: priorSnapshot.sourceLabel)

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 Avoid recording cached 429 rows as fresh history

When a stacked Claude token-account refresh hits an OAuth 429, this returns the prior cached snapshot as usage; refreshTokenAccounts treats every non-nil resolved.usage as a newly fetched sample and later records it with the current Date(). During a cooldown/outage, each retry can write stale usage points into plan-utilization history and reset detection as if they were real observations. Preserve the row via snapshot, but don't mark cached 429 data as a fetched usage sample.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added 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. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. labels Jul 6, 2026
@steipete steipete force-pushed the fix/claude-oauth-rate-limit-stale-cache branch from c5a95f2 to 58fe37b Compare July 9, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 auth-provider 🚨 Merging this PR could break OAuth, tokens, provider routing, model choice, or credentials. 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants