Settle it: the gate is a credential, not a format

One write, clean session, unambiguous. Key offer at +5.31 s, our
`RideOn 01 02` + 64-byte key out, the pod's `RideOn 02 03` + 64 **zero**
bytes back at +5.40 s, stream all zeros from +5.49 s. `play-rideon`
alone causes both effects the sweep had confused together.

The zero frames are seven bytes — the exact length of a button frame — so
the pod is emitting correctly-shaped frames with the contents blanked.
That is a refusal mode somebody implemented, not a crash.

Which closes the question this line of work was asking. The v2
understands the documented handshake, answers in the documented shape,
and returns a zeroed key. We tried the protobuf envelope four ways and
the Play format verbatim; the device declined all five, in two distinct
and deliberate ways. What the Zwift app presents and we cannot — a token,
a signature, or a correctly computed field 3 — is what is being checked,
and no amount of well-formed framing substitutes for it. It cannot be
inferred from the device half of the conversation, and the device half is
all anyone here has.

So: closed until someone captures a real unlock. One HCI snoop would
settle it; nothing short of that will. The workarounds stand — the `+`
pod, which reportedly never needed the blessing, or re-linking the `−`
pod inside its own ~50 s window.

The variant stays in the probe so the finding can be reproduced, with a
note that it reliably blanks the pod and costs a recovery wait.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-27 19:48:01 +02:00
co-authored by Claude Opus 5
parent 34861e4e04
commit b1e6c08d07
+23
View File
@@ -277,6 +277,29 @@ the daily unlock is needed on this path are both answered: it is, and this is th
> key it never agreed, or a firmware path nobody meant to reach, is unknown. It is > key it never agreed, or a firmware path nobody meant to reach, is unknown. It is
> recoverable: the pod came back on its own by the next session. > recoverable: the pod came back on its own by the next session.
> >
> **Settled with one write, 2026-08-27.** `--variant play-rideon` on a clean session: key
> offer at +5.31 s, our `RideOn 01 02` + 64-byte key sent, the pod's `RideOn 02 03` + 64
> zero bytes back at +5.40 s, and the stream all zeros from +5.49 s. That single frame
> causes both. The zero frames are **7 bytes** — the exact length of a button frame — so the
> pod is emitting correctly-shaped frames with the contents blanked, which is a refusal
> mode rather than a crash.
>
> **The gate is a credential, not a format.** The v2 understands the handshake, answers in
> the right shape, and returns a zeroed key. No framing we can construct changes that: we
> tried the protobuf envelope four ways and the Play format verbatim, and the device
> declined all five in two distinct, deliberate ways. What the Zwift app presents that we
> cannot — an account token, a signed blob, or a correctly *computed* field 3 — is the
> thing being checked, and it cannot be inferred from the device half of the conversation.
>
> **So this line is closed until someone captures the app's side.** One HCI snoop of one
> real unlock would settle it; nothing short of that will. Until then the workarounds stand:
> the `+` pod, which reportedly never needed the blessing, or re-linking the `−` pod inside
> its ~50 s window.
> **Do not send `play-rideon` casually.** It reliably blanks the pod's output stream and
> costs a recovery wait. It is kept in the probe because reproducing a finding matters, not
> because it is safe to leave running.
> **Attribution is not yet sound.** All five variants went out inside six seconds and every > **Attribution is not yet sound.** All five variants went out inside six seconds and every
> reply arrived in one burst at +11.37 s, so which write triggered the zeros is not > reply arrived in one burst at +11.37 s, so which write triggered the zeros is not
> established. `probe unlock --variant <name>` sends exactly one per connection, which is > established. `probe unlock --variant <name>` sends exactly one per connection, which is