
## RIDER 7 (doyle-ruled 10:55Z) — the `fetch` kind collision: harmless by CONVENTION, not by construction

doyle's ruling: this does **not** fold into F17. It is its own rider, because F17 is a defect that
dropped traffic and this is a latent shape that currently drops nothing. Keeping them separate keeps
F17's verdict clean.

**The measurement** (source read at `f3c8495b`, part of the 11-enum / 49-variant wire census in
RIDER 6):

- `crates/spt-net/src/net/update.rs` — `UpdRecord::Fetch` serializes `kind: "fetch"`.
- `crates/spt-net/src/net/xfer.rs` — `XferRecord::Fetch` serializes `kind: "fetch"`.
- `crates/spt-daemon/src/dispatch.rs` — `Some("fetch") | Some("push") => StreamFamily::Xfer`,
  unconditionally, with no discriminating field guard (unlike the five `Some("request")` arms above
  it, which each discriminate on a companion field: `sync_id`, `session_id`, `endpoint`+`event`,
  `owner`+`shell_ref`, `serve_probe`, `endpoint`+`digest_pull`).

**Why nothing is broken today:** an update stream's FIRST line is `query` or `status_query`
(`Some("query") => Update`, `Some("status_query") => Update`). `UpdRecord::Fetch` only ever appears
mid-stream, after the family is already resolved and the line is being decoded by the update
decoder, not by `classify_first_line`. So the collision is unreachable.

**Why it is still worth a rider:** the thing keeping it unreachable is a convention — "update streams
never open with `fetch`" — held nowhere in the type system and asserted by no test. It is exactly the
shape F17 turned out to have: a variant whose first-line status is decided by custom rather than by
construction. The day a variant is promoted to an opener (which is precisely what W2 did to
`ServeFor`), the convention silently stops holding and the line resolves to the WRONG family rather
than to `Unknown` — a misroute, which is strictly worse than a drop, because a drop is visible as
absence and a misroute is served by a decoder that will mostly succeed.

**The fix is already the RIDER 6 change, at no extra cost.** The per-variant census forces
`UpdRecord::Fetch => NeverFirst`, which turns the convention into a compile-checked declaration and
makes the promotion-day mistake a build error naming the variant. Nothing else needs to change: do
NOT rename either kind and do NOT add a discriminating field guard for a case that cannot occur —
either would be a wire change paid for a hazard that the census removes for free.

**Contrast worth keeping visible:** the `Some("request")` arms show the house pattern when a kind
genuinely IS shared across families — discriminate on a companion field, one arm per family. That
pattern is available if `fetch` ever needs it. It is not needed now, and reaching for it now would
put a wire-shape change in a lane whose whole point is a guard.
