# releases#172 — the inbound record's wire collision (todlando, PORTER wave 3)

STATUS 2026-08-21: BUILT, WITNESSED RED → GREEN, UNPUSHED. Lane
`.worktrees/fix-172`, branch `fix/172-inbound-verdict-collision`, base
`b88fab2a`, pool claimed for lane `fix-172`.

## The defect, and the witnessed red

`InboundRecord` carries `binder_pid` + `binder_path` and FLATTENS
`InboundVerdict` beside them. `PathMismatch` carried a `binder_path` of its own,
so serializing it emitted a LITERAL DUPLICATE KEY, `read_current`'s parse
failed, and the reader fell closed to `Unknown`. The one verdict class the
record exists to surface was structurally unrenderable.

The round-trip table was written BEFORE the fix and run at the base. The red,
verbatim — note the on-disk body, which is the defect itself:

```
a verdict that cannot survive its own record is a verdict nobody can ever be
told; 1 of 6 variants failed:

path_mismatch: wrote PathMismatch { rule_path: "RULE-PATH",
  binder_path: "RUNNING-PATH", fix: "FIX-MISMATCH" }, read back Unknown
--- on disk ---
{
  "binder_pid": 4242,
  "binder_path": "C:\\spt\\bin\\spt.exe",
  "verdict": "path_mismatch",
  "rule_path": "RULE-PATH",
  "binder_path": "RUNNING-PATH",
  "fix": "FIX-MISMATCH"
}
```

**5 of 6 variants passed in that same run**, so the rig was non-vacuous before
the fix rather than by assertion afterwards. After the rename: 6/6.

## Why RENAME and not UN-FLATTEN — the half doyle's ruling left open

The ruling offered either. Un-flattening loses on a fact neither of us had
measured at ruling time: it moves EVERY variant's on-disk shape, so a currently
valid `ok` / `missing` / `blocked` record — written by a daemon still running —
would stop parsing and read `Unknown` until that daemon restarts. The rename
touches ONE variant, and the other five keep parsing byte-identically across
the upgrade. An old `path_mismatch` record still reads `Unknown`, which is what
it already did, so the migration cost is genuinely zero rather than merely
small.

The variant keeps a path of its own rather than borrowing the envelope's,
because `InboundVerdict::warning()` renders from the verdict ALONE — a renderer
reaching for the envelope would be a second source for a field the record owns.

## THE DOC STAGE I ALMOST SHIPPED WITHOUT

I first wrote this REQ with "no doc stage", reasoning that the operator-facing
contract belonged to the sibling REQ and was unchanged. Then I censused the
docs and it was wrong: `spt subnet status --json` serializes `InboundVerdict`
**directly** (no envelope, so no collision on that surface), and
`docs-site/src/networking/inbound-reachability.md` documents that object's field
names as a machine-readable contract, `binder_path` included. A rename stopping
at the code would have left the published surface describing a key the binary no
longer emits.

**And the rename breaks no consumer — derived, not asserted:** `read_current`
returns a verdict only after a SUCCESSFUL parse, and a `path_mismatch` record
has never once parsed. So the documented `binder_path` documents a shape the
daemon has never emitted in the field. The docs now carry the rename AND that
reason, so the next reader is not left wondering what broke.

## What shipped

`REQ-INBOUND-RECORD-WIRE-FIDELITY`, minted and activated at doc+impl+unit.

- impl: the variant field renamed to `running_path`, with its producers and
  renderers moved with it — the Windows `decide_windows` producer, the
  `warning()` renderer, and the two existing tests that constructed it.
- unit: `every_verdict_variant_round_trips_through_the_record`, plus
  `verdict_tag` — a WILDCARD-FREE match, so adding a seventh variant stops the
  crate compiling until the table covers it. That match is the pin; a list plus
  a length assertion would stay trivially true, which is how this collision
  survived a milestone with round-trip coverage reading green. One specimen per
  variant with EVERY field a DISTINCT value, so a field round-tripping to a
  sibling's value is caught too. Tags asserted against written-out literals.
- doc: the status-JSON example and the verdict table in the inbound-reachability
  page, plus a paragraph naming why the field is `running_path`.

## LANE SLATE

- `cargo test -p spt-store --lib inbound`: **6/6** (1/6 failing pre-fix)
- workspace sweep `--lib --bins --no-fail-fast`: spt-daemon **859**, spt-store
  **490**, and every other crate green
- `cargo test -p spt --bins`: **642 passed, 0 failed**, real cargo exit 0
- `cargo clippy --workspace --all-targets`: **exit 0, zero warnings**
- `traceable-reqs check`: **exit 0**, new REQ `[OK] +doc +impl +unit`
- `cargo run -p xtask -- check`: see the report

## THE BOX RAN OUT OF DISK MID-LANE

The first workspace sweep died on `rustc-LLVM ERROR: IO failure on output
stream: no space on device` and `LNK1180: insufficient disk space`. **C: was at
literally zero bytes free**, 1.86 TB used; lane `target/` pools held ~215 GB.

Classified per the teardown rule before touching anything — all real dirs, no
inbound reparse points anywhere under the project, no `CARGO_TARGET_DIR`
override — then reaped ONLY the target SUBTREES of my own gated-and-held lanes
(#199 / #201 / #204): **0.01 → 63.88 GB free**, measured both sides. Commits,
branches and worktrees untouched. doyle then classified and reaped three more
(62.28 → 137.74 GB) and kept `gate-d5351e66` warm.

## TWO RIG TRAPS, both of which produced a red or a reading that was not the product

1. **A fresh pool has no fixture binary.** `cargo test -p spt --bins` compiles
   bin targets as TEST HARNESSES into `deps/` and never emits
   `target/debug/translate_proof_fixture.exe`, so
   `adapter_translate_proof_gates_on_commit` panics in any pool that has never
   run a full `cargo test -p spt`. It was GREEN in my #196 lane and RED here —
   same command, different pool history. Build the fixtures once and it passes
   (642/642). The panic text names the right invocation itself; reading it is
   what kept this from being reported as a product red.
2. **Two background runs, one output path.** I reused an output file across two
   overlapping runs and the later `grep` read the earlier run's contents —
   producing `EXIT=0` beside `test result: FAILED`, which one cargo invocation
   cannot produce. Contradictory arithmetic means suspect the plumbing, not the
   product. Re-ran alone to a fresh path.

## What is owed

1. Report to doyle; he gates as lanes come.
2. Pool release when the lane is picked at assembly. DO NOT rebase or push.
3. Wave-3 remainder after this: #67 (supersession refusal by name), #186 (knock
   evidence line renders the answered state from the knock row).
