fix(setup): check that the client's bearer is alive, not that one is cached #142

Merged
jlxq0 merged 1 commit from setup-liveness into main 2026-08-28 02:42:45 +00:00
Owner

He pasted a correct recovery key three times, twice at an airport, the third from an incognito browser with a clean SSO. It could not have worked, and neither could a fourth.

Why incognito changed nothing

/setup/recover never uses the token a sign-in issues. It reuses the cached matrix-sdk client holding claude.ai's device-bound connector bearer, deliberately: routing /setup's unbound token in calls refresh_token_if_neededrestore_session and panics matrix-sdk 0.17 with AlreadyInitializedError, taking the pod down, verified 2026-05-18. So nothing done in a browser touches the token that was failing.

The gate asked the wrong question

MatrixClientCache::contains is true for a client whose bearer Synapse has already revoked. Presence, not liveness. A dead session passed the gate, the key form was shown, the import returned 401 M_UNKNOWN_TOKEN, and the page attributed it to the key.

It now asks whoami, the cheapest authenticated call there is, and refuses before the key form rather than after the paste, so the cause is named while the key is still in the clipboard.

The instruction was already written, on the branch he could not reach

The absent-client error has named the revoked connector bearer, the typical cause (signing the matrix-mcp device out from Element) and the exact remedy for eighteen months. The stale-client path said nothing about it. A right answer displayed only where the person who needs it cannot be is the same as not having it. One constant now, used by both branches.

The server cannot self-heal this, and the comment says so

Rebuilding the client needs a device-bound session and only claude.ai's grant issues one, so a retry cannot succeed however often it runs. Without that sentence in the code the next reader adds one.

Both gates were unreachable at first

Disabling either left the suite green, because each needs a live Client and a SetupState. setup_gate is a free function over two booleans for that reason, and the decision table is the test:

cached + live   Proceed
cached + dead   BearerDead
absent          NoClient, whatever the liveness answer

The last row matters: an absence wins over any probe result, or a failed probe against nothing would tell someone to re-add a connector they had not yet used. Mutating the dead case to proceed, and the absent case to trust the probe, each reddens it.

Two claims, two commits

#141 stopped the message misleading. This stops the import failing, and its acceptance is a successful import rather than a better sentence.

Gates: fmt, clippy -D warnings, 303 passed; 0 failed, audit clean, deny ok.

He pasted a correct recovery key three times, twice at an airport, the third from an incognito browser with a clean SSO. **It could not have worked, and neither could a fourth.** ## Why incognito changed nothing `/setup/recover` **never uses the token a sign-in issues.** It reuses the cached matrix-sdk client holding claude.ai's device-bound connector bearer, deliberately: routing `/setup`'s unbound token in calls `refresh_token_if_needed` → `restore_session` and **panics matrix-sdk 0.17 with `AlreadyInitializedError`, taking the pod down**, verified 2026-05-18. So nothing done in a browser touches the token that was failing. ## The gate asked the wrong question `MatrixClientCache::contains` is true for a client whose bearer Synapse has already revoked. **Presence, not liveness.** A dead session passed the gate, the key form was shown, the import returned `401 M_UNKNOWN_TOKEN`, and the page attributed it to the key. It now asks `whoami`, the cheapest authenticated call there is, and **refuses before the key form rather than after the paste**, so the cause is named while the key is still in the clipboard. ## The instruction was already written, on the branch he could not reach The absent-client error has named the revoked connector bearer, the typical cause (signing the matrix-mcp device out from Element) and the exact remedy **for eighteen months**. The stale-client path said nothing about it. **A right answer displayed only where the person who needs it cannot be is the same as not having it.** One constant now, used by both branches. ## The server cannot self-heal this, and the comment says so Rebuilding the client needs a device-bound session and only claude.ai's grant issues one, so a retry cannot succeed however often it runs. Without that sentence in the code the next reader adds one. ## Both gates were unreachable at first Disabling either left the suite green, because each needs a live `Client` and a `SetupState`. `setup_gate` is a free function over two booleans for that reason, and the decision table is the test: cached + live Proceed cached + dead BearerDead absent NoClient, whatever the liveness answer The last row matters: an absence wins over any probe result, or a failed probe against nothing would tell someone to re-add a connector they had not yet used. Mutating the dead case to proceed, and the absent case to trust the probe, each reddens it. ## Two claims, two commits #141 stopped the message misleading. **This stops the import failing**, and its acceptance is a successful import rather than a better sentence. Gates: fmt, clippy `-D warnings`, `303 passed; 0 failed`, audit clean, deny ok.
fix(setup): check that the client's bearer is alive, not that one is cached
All checks were successful
CI / cargo (pull_request) Successful in 1m36s
CI / docker (pull_request) Has been skipped
6e91238a1d
He pasted a correct recovery key three times, twice at an airport, and the
third attempt was from an incognito browser with a clean single sign-on. It
could not have worked, and neither could a fourth.

/setup/recover never uses the token a sign-in issues. It reuses the cached
matrix-sdk client holding claude.ai's device-bound connector bearer, on purpose
and for a real reason: routing setup's unbound token in calls
refresh_token_if_needed, restore_session, and panics matrix-sdk 0.17 with
AlreadyInitializedError, taking the pod down. So nothing done in a browser
touches the token that was failing.

The gate in front of it asked MatrixClientCache::contains, which is true for a
client whose bearer Synapse has already revoked. Presence rather than liveness.
A dead session passed, the key form was shown, the import returned 401
M_UNKNOWN_TOKEN, and the page attributed it to the key.

The gate now asks whoami, the cheapest authenticated call there is, and refuses
before the key form rather than after the paste, so the cause is named while
the key is still in the clipboard.

The instruction it gives was not written for this commit. It already existed on
the branch where no client is cached at all, naming the revoked connector
bearer, the typical cause and the exact remedy, and it had been there for
eighteen months being shown to nobody who arrived with a stale client. It is
one constant now and both branches use it. A right answer displayed only where
the person who needs it cannot be is the same as not having it.

The server cannot repair this itself and the comment says so, because the next
reader's instinct is to add a retry. Rebuilding the client needs a device-bound
session and only claude.ai's grant issues one.

Both gates' first form left the suite green when disabled, because each needs a
live Client and a SetupState. setup_gate is a free function over two booleans
for that reason, with the decision table as the test: cached-and-live proceeds,
cached-and-dead refuses, and an absence wins over any liveness answer, or a
probe failure against nothing would send someone to re-add a connector they had
not yet used. Mutating the dead case to proceed, and the absent case to trust
the probe, each reddens it.

This is the second of two commits and the claims stay separate. #141 stopped
the message misleading; this stops the import failing. Its acceptance is a
successful import rather than a better sentence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FEgtox6vnEkYPv9PrCCoYG
jlxq0 merged commit 8deddd020f into main 2026-08-28 02:42:45 +00:00
jlxq0 deleted branch setup-liveness 2026-08-28 02:42:46 +00:00
Sign in to join this conversation.
No description provided.