feat(core): recognize the Claustrum custody tombstone and fail loud before refresh
Stacked on #175 (base is main; the diff includes #175's commit until it merges — review git 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.json entry with a non-secret tombstone:
"anthropic": { "type":"oauth", "refresh":"claustrum-tombstone:v1:anthropic", "access":"claustrum-tombstone:v1:anthropic", "expires": 0 }
expires: 0 is 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.- One guard at the shared token-refresh function (
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). - Golden pin: fixtures vendored from
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
- Tombstone on main → loader throws typed error,
/v1/oauth/tokencalled 0 times, nopermanent/needsReauth/backoff persisted. - Mutation (guard removed): token endpoint called 1×, stubbed
invalid_grantlatches → test reddens (4/1); restored 5/0. - Fallback account with tombstone refresh → typed error, no network, no
lastRefreshError.permanent. - Root 1461/0 (second run: known Miniflare load timeout, solo 4/4), e2e 29/0, typecheck/format/biome clean. Golden check: both files IDENTICAL at the pinned SHA.
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-bot with 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
- Connects opted-in fallback accounts to Claustrum over authenticated local IPC with cached reads, detached refresh, shared reconnects, deduplicated 401 reporting, and sidecar fallback.
- Resolves fallback quota from the vault-first cache, avoids expired sidecar tokens, and persists 429 backoff across processes.
- Validates provider-bound handles and tombstones without exposing handles in dumps, sidebar state, or RPC payloads.
- Shows Claustrum, vault, and vault reauthentication status in account commands, dialogs, and the sidebar.
- Preserves scoped account state when configuration is missing, malformed, whitespace-padded, or changed by a stale writer.
Tests
- Adds a fail-closed network guard, deterministic provider stubs, and cleanup checks for leaked fetch mocks, timers, temporary directories, and log sinks.
- Covers custody failures, fallback behavior, tombstone refresh paths, typed errors, zero token requests, quota backoff, and refresh-error persistence.
- Pins the golden fixtures to the upstream Claustrum PR head;
bun run check:claustrum-goldenbyte-verifies them, including golden-only updates.