Conversation
There was a problem hiding this comment.
All reported issues were addressed across 6 files
You’re at about 91% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Architecture diagram
sequenceDiagram
participant Client as Client / Caller
participant Wrapper as sendWithAccessToken
participant SendOnce as sendWithAccessTokenOnce
participant Cache as ClaustrumCredentialCache
participant Vault as Vault (Credential Provider)
participant Report as reportCapturedClaustrumAuthFailure
Note over Client,Report: HIGH-LEVEL FLOW: 401 Handling with Rotation Retry & Bound
Client->>Wrapper: Send request (with credential)
Wrapper->>SendOnce: sendWithAccessTokenOnce(credential)
SendOnce->>Client: Serve credential (record version tracked)
SendOnce-->>Wrapper: Response
alt 401 received
Wrapper->>Cache: get(handle, 0, { bypassCache: true })
Note over Cache: Bypass resident cache (rotation does not change local expiry)
Cache->>Vault: Fetch fresh credential record
Vault-->>Cache: New credential record (possibly advanced version)
Cache-->>Wrapper: Fresh credential + version
alt Version advanced (rotation detected)
Wrapper->>SendOnce: Retry once with fresh credential
SendOnce-->>Wrapper: Response (usually 200)
Note over Wrapper: Do NOT report 401 (self-healing race)
else Version unchanged OR retry also 401
Wrapper->>Report: Report credential failure
Report->>Vault: reportAuthFailure(record)
Note over Report: Single-shot per served version<br/>Checks cache freshness before report
Vault-->>Report: Acknowledged
Report-->>Wrapper: Outcome
end
else Non-401 response
Wrapper-->>Client: Return response
end
Note over Cache: Bounded by per-handle backoff & timeout<br/>At most 1 vault get per 401
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
You’re at about 92% of the monthly reviewed-line limit. You may want to disable incremental reviews to conserve quota. Reviews will continue until that limit is exceeded. If you need help avoiding interruptions, please contact contact@cubic.dev.
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
13496a4 to
fe5ff5f
Compare
|
Pushed Why these two sitesThis morning at 05:24:08Z and 05:24:19Z two live processes failed CacheKeep prewarm with The retry wrapper already on this branch covered only Quota poll and profile hydration are closed, not deferredI set out to widen five sites. Two of them turn out to have no vault-report path at all: // packages/core/src/accounts.ts:4805-4813 — quota poll catch
if (
!message.includes('Claude quota check failed: 401') ||
vaultEnabled || // ← vault accounts disqualified
access.source !== 'sidecar'
) {
throw error
}A vault-served quota 401 is re-thrown; the forced-refresh retry below runs only for sidecar credentials. That Semantics
VerificationRe-ran all three mutations myself rather than accepting the implementer's report:
Gates: core 200/0 · opencode 1914/0 · typecheck clean · Note on the logging half
The swallow stays correct for the transient case (a vault blip behind a valid cached token is a non-event). Only |
Six gates treated local credential bytes as a proxy for usability. A vault-served account's local slot is the provider tombstone, so quota recovery, profile hydration, /claude-quota and the killswitch's eager refresh all skipped healthy accounts once custody emptied that slot. Each site now admits a live vault binding alongside local access; none admits an account with no credential anywhere.
liveMainVaultAccess hand-rolled its sibling and dropped the sibling's stale-version guard, so main profile hydration and /claude-quota could bearer a version already reported auth-failed. It now delegates to resolveClaustrumAccess, inheriting both the guard and the warm schedule. mainServedAccessToken is cleared on a successful main report only: a suppressed or failed report tells the vault nothing, so local belief must not diverge from what the vault received.
dd89048 to
7e13789
Compare
| const credential = result.credential | ||
| const accessToken = usableClaustrumAccessToken(credential, claustrumNow()) | ||
| if ( | ||
| !credential || | ||
| !accessToken || | ||
| credential.recordVersion <= served.recordVersion | ||
| ) { | ||
| return { outcome: 'unchanged', vaultGetAttempted: true } | ||
| } | ||
| return { |
There was a problem hiding this comment.
Retry skips account identity check
If a handle’s newer record belongs to account B while the persisted binding identifies account A, this helper accepts B solely because its token is usable and its version increased. The message, CacheKeep, and prime paths then retry using B, although ordinary credential resolution would refuse that mismatch. For fallback requests, identity hydration can also persist B’s UUID into A’s account entry. Validate the fresh credential against the bound account before returning a retry resolution.
How this was verified: Ordinary resolution explicitly rejects differing persisted and credential account UUIDs, while the new helper constructs a retry resolution without that check and the retry sender directly uses its bearer.
| if (claustrumWarmBackoffActive(served.handle)) { | ||
| return { outcome: 'backoff-active', vaultGetAttempted: false } | ||
| } | ||
| try { | ||
| // Bypass only the resident cache: the RPC itself must not rotate a token. | ||
| const result = await getBoundedClaustrumCredential( | ||
| cache, | ||
| served.handle, | ||
| 0, | ||
| '401-retry', | ||
| { bypassCache: true }, |
There was a problem hiding this comment.
Concurrent recovery gets multiply
Concurrent 401 handlers can all pass this backoff check before the first get settles, and bypassCache skips the cache’s in-flight map. Backoff is installed only after a timeout or qualifying error, so simultaneous turns or prewarms holding the same superseded credential each issue a separate vault RPC. This adds avoidable load during rotation or vault latency. A dedicated per-handle recovery promise would let these callers share a get while remaining independent of proactive loads started before the 401.
This comment has been minimized.
This comment has been minimized.
7e13789 to
b03e6bb
Compare
v1.23.0 types fetchImpl as typeof fetch, which requires preconnect. The bare async stub no longer satisfies it.
b03e6bb to
c490e57
Compare
The get-before-report wrapper introduced in this branch sat between the caller and sendWithAccessTokenOnce without carrying scopedAttempt, so a v1.23.0 zero-bind scoped 401 reached the report arm with the attempt undefined and was never reported to the vault. tsc could not see it: the caller's 13th argument landed on the wrapper's 13th parameter, whose type it structurally satisfied.
c490e57 to
7478159
Compare
Stacked on #232 — review the top commit
bb3033d9only; the two below it are #232's.The gap
Under vault custody the vault owns rotation, and Anthropic invalidates the prior access token the instant it rotates — measured on the live vault: a consumer holding v44 took a genuine 401 within 42s of the v45 commit, another at 0.1s. Our resident cache advances only on a
get; a rotation does not push. So any process whose cache predates a rotation serves dead material on its next turn and the user sees a failed turn.Before this commit we reported the 401 to the vault and returned it to the caller. No re-fetch, no retry.
Why now
This is not a new mitigation — it restores a recovery path custody deleted. Pre-custody we already did exactly this against
auth.json(ARCHITECTURE.md:47: "a sticky request whose old access token receives 401 re-reads host auth and directly retries with a concurrently rotated, still-valid access token"). Custody replaced the authority that retry re-read with a tombstone and did not replace the mechanism, so every rotation since the flip has been unprotected.Rotation period is forced by our own poll, not by a vault schedule: every ~60s each process calls
cache.get(handle, 270m)(minTtl = getRefreshBeforeExpiryMs + 30m), and the vault refreshes atnow + min_ttl >= expires_at, so an 8h token rotates every480 - 270 = 210m. Confirmed on live data — 101 of 106 gaps exactly 210m on one account. Pre-custody our own loop used a 240m threshold, so the exposure change is 240m → 210m, a 1.14× increase in rotation frequency on a credential that now has no local fallback behind it.Shape
sendWithAccessTokenOnceis the former send path with its immediate 401 report removed; it now only records the served credential. A wrappersendWithAccessTokencalls it and, on401 + served, does a boundedcache.get(handle, …, { bypassCache: true }):bypassCacheis new onClaustrumCredentialCache.getand is load-bearing. A rotation does not change local expiry, so a plain get returns the dead cached credential and the feature would be inert.Placing the retry at the wrapper rather than at each call site also fixes two latent defects in the sticky-route 401 arms without touching them. Arm A (main + vault-served) set
permanentAuthFailure = true, classifying a transient, self-healing rotation race as permanent and migrating main away. Arm C (fallback + vault-served) "retried" viaresolveClaustrumAccess, which iscache.peek— resident-only, so post-rotation it re-sent the same superseded token. Both now only ever see credentials that are genuinely dead, which makes A's classification correct and C's retry harmless.Observability
Neither side could measure how often this race fires: our logs had no vault-served-401 logging, and the vault's chain never sees direct-path races because our own freshness check suppresses the report once the cache has rotated — a guard whose success erases the evidence it was needed. The new log records handle (redacted), served and current record versions, whether a retry was attempted and its outcome, and whether a report was suppressed and by which branch.
Verification
Five isolated-hunk revert proofs, one per behaviour:
Gates: core build 0, core 200 pass, opencode 1894 pass, typecheck 0, biome 0.
Independent cross-family review: APPROVE, 0 must / 0 should, with the choke-point claim verified by call-site enumeration —
sendWithAccessTokenOnceis called exactly twice, both inside the wrapper, and the wrapper is the sole caller from all three external sites. Rate-limit bound checked at ~12 RPCs/min worst case per process against the vault's 64/60s limit;bypassCache: truereachable from exactly one call site.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Vault-served requests that received a 401 previously returned it immediately after reporting; replayable requests on the message, CacheKeep prewarm, and prime request paths now fetch fresh vault credentials and retry once when the record advances. Non-replayable requests, including streamed bodies, still return the original 401; unchanged or failed refreshes report without repeated retries, and the scoped attempt now reaches the report arm.
Bug Fixes
credential.getwithin the timeout and backoff window./claude-quota./claude-quota, and killswitch eager refresh; cached quota is admitted only while a live vault binding still serves the account.vault-served 401 recoverymessage is pinned by tests because a peer system consumes it.Written for commit 7478159. Summary will update on new commits.
The PR should not merge until the previously reported retry account-identity check is addressed.
Findings
Summary
Adds recovery for vault-served 401 responses by fetching credentials independently of the resident cache and retrying replayable requests when the vault record advances.
Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Vault-served request] --> B{Response is 401?} B -->|No| C[Return response] B -->|Yes| D{Request replayable?} D -->|No| H[Apply auth-failure reporting guards] D -->|Yes| E[Bounded cache-bypassing credential get] E --> F{Usable record advanced?} F -->|No| H F -->|Yes| G[Retry once with newer credential] G --> I{Retry returns 401?} I -->|Yes| H I -->|No| C H --> CReviews (3) · Last reviewed commit: "fix(claustrum): forward the scoped attem..."