feat(core): recognize the Claustrum custody tombstone and fail loud before refresh - #182
Merged
Merged
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
All reported issues were addressed across 37 files
Not reviewed (too large): packages/opencode/src/tests/index.test.ts (~4,414 lines) - if these are generated or fixture files, add them to ignored paths to exclude them from future reviews.
Tip: cubic can generate docs of your entire codebase and keep them up to date. Try it here.
Re-trigger cubic
iceteaSA
force-pushed
the
feat/custody-tombstone-guard
branch
from
September 2, 2026 03:51
0973efe to
ae8c0bf
Compare
iceteaSA
force-pushed
the
feat/custody-tombstone-guard
branch
5 times, most recently
from
September 2, 2026 09:34
bea02c3 to
d7bd593
Compare
iceteaSA
force-pushed
the
feat/custody-tombstone-guard
branch
from
September 2, 2026 11:36
e0c2af4 to
597b28e
Compare
Fail-loud preload network guard for the test suite: any non-loopback HTTP(S) fetch throws, including across redirects (manual redirect following, 20-hop cap, unparseable URLs fail closed). Replaces 44 live vendor requests per run with deterministic local stubs, isolates background intervals and temp dirs, and asserts no test leaves globalThis.fetch or an interval behind. Production fixes found by the guard: account-state membership treats a missing or unparseable config as UNKNOWN (no pruning) rather than empty, loader/membership agree on whitespace-normalized ids, and rotated credentials persist under the canonical key. Loopback classification tests call assertLoopback() directly instead of opening sockets (127.0.0.2:1 hangs to timeout on Darwin), and the upstream Fable 5.1 effort test restores globalThis.fetch after itself.
A fallback OAuth account can keep its credential in Claustrum, a local credential vault reached over an IPC daemon, instead of in the sidecar. Per-account opt-in, off by default: with no vault present, or no account opted in, nothing here runs. Main-account custody stays out of scope — a vault-managed main would send a placeholder to Anthropic's token endpoint, and our classifier marks that failure permanent with no way back. The vault's slow path is kept off the response path structurally. credential.get is bimodal — microseconds when resident, seconds when it lands in the refresh window with callers queued behind one upstream exchange — so serving only ever peeks synchronously, a bounded startup warm primes the cache, and refreshes run detached. A cold peek falls through to the sidecar rather than waiting. The vault owns refresh for an account it serves: that account's sidecar refresh token is a lineage the vault may already have rotated, and spending it returns invalid_grant, which is permanent. But a vault outage must never be worse than having no vault, so an unavailable vault still permits ordinary local recovery, and a resident credential clears whatever error that recovery persisted. Identity is explicit in both directions. consumerIdentity is forced to null because the client otherwise reads SUBC_MODULE_ID and SUBC_LAUNCH_NONCE from the environment and would authenticate as whichever supervised module spawned the host. A BindIdentity is supplied because the client requires one for every managed call; its session is derived from the account-store fingerprint, so it is stable across restarts without new persisted state. A 401 is reported only for a credential the vault actually served, carried on the response rather than looked up again at report time. Invalidation is version-gated and the version in hand is usually still current, so a report raised from a locally served token would pass that gate and invalidate a healthy credential — version-correct and provenance-wrong. Failures classify so the vault's shared rate limiter stays protected: a transport failure or a terminal route failure backs off per handle instead of issuing one credential.get per request, and an unrecognised error class retries boundedly and loudly rather than blocking the account, which is the most operator-visible action available and needs positive evidence. Credential handles never reach dump artifacts, sidebar state, or RPC responses; a compile-time contract keeps them out of dump inputs.
…reports Also normalize the main TUI gate placeholder, clean test log sinks with finally, and make fake-daemon goodbye waits event-driven.
…an expired token 1. Resolve fallback quota credentials from the vault-first cache seam. 2. Skip vault-cold expired credentials and refresh non-vault expired credentials before polling. 3. Persist and seed cross-process fallback 429 backoff. 4. Fence auth-failure reports monotonically by credential record version. 5. Cancel the current response only when an eligible fallback actually sends. Anthropic returns 429, not 401, when the expired sidecar token reaches the usage endpoint.
Bytes unchanged (verified IDENTICAL x2); the previous pin named a commit off cortexkit/claustrum#28's history after its squash. Also: biome check in the pre-commit hook errored when every staged path was ignored, so any golden-only bump commit failed the hook. Pass --no-errors-on-unmatched.
Bytes unchanged (IDENTICAL x2); the prior pin named a pre-squash commit.
Bytes unchanged (IDENTICAL x2); PR cortexkit#28 rebased onto its upstream master.
iceteaSA
force-pushed
the
feat/custody-tombstone-guard
branch
from
September 2, 2026 12:14
62dcff5 to
25e1456
Compare
Bytes unchanged (IDENTICAL x2); ref verified via ls-remote.
Bytes unchanged (IDENTICAL x2); ref verified via ls-remote.
Bytes unchanged (IDENTICAL x2); ref verified via ls-remote.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #175 (base is
main; the diff includes #175's commit until it merges — reviewgit diff e5ae3aa..HEAD, 11 files, +474). Prepares the main slot for vault custody without implementing vault-served main.Why
Claustrum's custody plugin replaces a main-slot
auth.jsonentry with a non-secret tombstone:expires: 0is deliberate: any reader that doesn't recognize the shape sees an expired token and takes the refresh path. Today that path sends the sentinel to the OAuth token endpoint →400 invalid_grant→permanent: true→ the main account is latched dead. That is the failure that froze main-slot custody.What
isCustodyTombstoneOAuth(auth, provider)— exact, provider-bound match;readCustodyHandles(toleratessuperseded, serveshandleonly).CustodyTombstoneRefreshErrorcarries none of theProviderHttpErrormarkers (nostatus,isRefreshError,permanent), so it structurally cannot arm refresh backoff or latch an account. Refresh-error persistence additionally skips it.auth.ts) covers every refresh entrypoint: background refresh, 401 retry, per-request refresh, prime refresh paths,FallbackAccountManager, Pi OAuth + fallback refresh. The loader additionally branches on the tombstone before the expiry check and throws (this branch becomes the vault path in the takeover PR).legion-works/claustrum@7cf41ca(SOURCE.jsonrecords repo/ref/paths); the test derives every expectation from the fixture.bun run check:claustrum-goldenfetches the pinned ref and byte-diffs (a script, not a test — the test network guard blocks it).biome.jsonexcludes the fixture dir so the formatter can't perturb the byte-identical copies.Proof
/v1/oauth/tokencalled 0 times, nopermanent/needsReauth/backoff persisted.invalid_grantlatches → test reddens (4/1); restored 5/0.lastRefreshError.permanent.Out of scope: vault-served main (the loader branch is the seam), the shared handle-file reader wiring,
serve:ownership conjunction — takeover PR.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.Summary by cubic
Adds optional Claustrum custody for fallback OAuth accounts and rejects custody tombstones before OAuth refresh. Previously, tombstones reached Anthropic and could persist permanent refresh failures; now refresh fails locally without a token request or persisted refresh error. Main-account vault serving remains out of scope.
Features
Tests
bun run check:claustrum-goldenbyte-verifies them, including golden-only updates.Written for commit d0256c8. Summary will update on new commits.