Skip to content

Serve the vault bearer for a tombstoned main - #155

Merged
ualtinok merged 2 commits into
cortexkit:mainfrom
iceteaSA:fix/main-vault-bearer
Sep 18, 2026
Merged

ualtinok merged 2 commits into
cortexkit:mainfrom
iceteaSA:fix/main-vault-bearer

Conversation

@iceteaSA

@iceteaSA iceteaSA commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Fixes #154. Two commits: the resolver and catch fix, then the auth-menu quota deps the same census turned up.

The resolver

resolveMainAccessForCustody sits beside the fallback custody resolution in index.ts, and mirrors resolveFallbackAccess rather than inventing a second shape: no-handleblockedreauthpeek → expiry, each a named refusal. Peek-only, so the request path still never blocks on the vault; refill stays on the tick.

The catch, which you called the actual bug

A custody-owned main now resolves through the resolver and never enters the refresh/catch path at all — the branch that reads currentAuth.access ?? '' is structurally unreachable for a tombstoned slot. CustodyTombstoneRefreshError no longer arrives at a handler written for transient errors, because the refusal is decided before the refresh is attempted rather than caught after it.

Custody refusals log at warn on the custody channel with their reason. That is deliberate beyond readability: Claustrum's auth_events only sees a report if we send one, so an empty-bearer 401 swallowed into a stale-token fallback never reaches the vault side at all — and from their chain, a successful credential.get followed by an upstream 401 is indistinguishable from a genuine expiry. A silent client does not just fail to inform them, it produces a plausible wrong answer on their side.

Fail closed, no local fallback

Your constraint is the one I checked hardest, since it is the invariant the feature rests on. A refused main:

  • yields an empty candidate roster (index.ts:3209), so it is excluded rather than degraded
  • returns a synthetic 401 (:4129) instead of calling sendWithAccessToken, so no empty bearer ever reaches the wire
  • never reads currentAuth.access — that assignment lives in the non-custody else branch, so the local slot is unreachable from a custody-owned main under every failure mode

Cold, needs_reauth, identity_mismatch and no_handle all land there. The second owner the tombstone exists to prevent cannot be created by this path.

Tests

Your red proof is the acceptance gate and it passes. Three mutations, each reverting one change alone:

(fail) uses the vault bearer for a tombstoned main send
(fail) refuses a tombstoned main without a cached vault bearer and serves a fallback
(fail) Check quotas serves a custody fallback through the injected vault resolver

The refusal test asserts the fallback's bearer on the wire, not that no error was thrown — a refusal that silently served nothing would pass the weaker form. Local mode is pinned byte-identical.

Scope

No general empty-bearer guard here, per your note that you are taking it and holding it so the two do not collide. Worth saying that yours is the stronger of the two fixes: mine stops this defect reaching the wire, yours stops the whole class announcing itself as somebody else's 401.

Gates from the repo root: build, format:check, lint, types, test all pass. Core 146, opencode 1340 / 1 skip / 0 fail, pi 14.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Fixes #154 by serving the vault bearer for a tombstoned main instead of sending an empty local bearer. A custody-owned main is now resolved through the vault cache before any refresh is attempted; if the cache cannot serve it, the main is refused with a synthetic 401 and excluded from the roster so a fallback can be used.

  • Refusals are logged with their reason on the custody channel.
  • The refresh/catch path is unreachable for custody-owned slots, so transient refresh errors no longer surface from this path.
  • The same resolver is wired into the check-quotas auth-menu path, and local mode remains unchanged.

Written for commit fc20beb. Summary will update on new commits.

Review in cubic

@ualtinok
ualtinok merged commit 2ddcd62 into cortexkit:main Sep 18, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tombstoned main sends an empty bearer under claustrum mode

2 participants