# releases#186 — the cross-node knock whose answer this node can prove (todlando, PORTER wave 3)

STATUS 2026-08-21: BUILT, UNPUSHED. Lane `.worktrees/fix-186`, branch
`fix/186-unlisted-answered-evidence`, base `b88fab2a`, pool claimed for lane
`fix-186`. The last wave-3 lane before assembly.

## MEASURED FIRST, and the filing's mechanism is WRONG IN ITS SPECIFICS

The issue says the answer "IS known on this node — the receipt landed (knock row
state Answered)" and suggests rendering "Answered + routed_to". Read at the base:

1. **There is no `Answered` state.** `KnockState` is Pending / Approved / Denied
   / Expired. `routed_to` is a BUILDER setting `target_node` at knock time — it
   carries no answer.
2. **The receipt does not land on the knock row.** `receipt_ms` has exactly ONE
   production writer: `cli.rs` `cmd_knock_approve` → `KnockStore::record_receipt`,
   whose own doc binds it to the notification-produce site, "the one place that
   knows the knocker is reachable from this node's own notification store —
   which is to say, that they are on this machine." Same-node by construction.
3. **What a cross-node answer touches is `pre_auths`.** `apply_answer_receipt`
   matches a `MutualPreAuth` on keyspace, correlation id, unconsumed, the
   answerer against the endpoint knocked, and `answerer_node` against the
   HANDSHAKE-PROVEN origin bound at arm time. Approval sets `consumed = true`.
   **Denial REMOVES the record** — deliberately, per its own comment: a consumed
   record means the reverse rule was written, so a flagged denial would read back
   as the approval it was not.

Reported to doyle before building. He ruled the narrow version, adding the stale
module doc to this lane and a corrected-mechanism comment on the board.

## The half of the filing that IS right, and it is the point

The receipt wire **is built** (`spt-net` answermsg, `spt-daemon` answerop — "the
KNOCKER's half", DOORBELL W5). So the old line's reason — *no wire carries an
answer* — became false, and it was asserted in prose at three sites that all
said the family was `unbuilt`. A lane that fixed the render and left those would
ship a contradiction, so they are corrected in the same commit.

## What shipped

`REQ-UNLISTED-ANSWERED-CROSS-NODE`, minted and activated at impl+unit.

- `receipt_proven_knock_ids` — the consumed-pre-authorization join, over the
  store `evidence_from_knocks` is already handed, so it costs no read. Keyed on
  BOTH keyspace and correlation id: a code redemption arms a pre-authorization
  too, and an id-only match would let a redeemed code report an answer for a
  knock.
- The cross-node arm splits: proven → "they approved (answer receipt proven
  here)"; everything else → "no answer has reached this node".
- The three stale `unbuilt` prose sites corrected (`knock.rs` ×2, `cli.rs` ×1).
  A fourth site already retired its own caveat correctly and was left alone.

**The render reports the proof; it does not re-derive it.** Everything
`apply_answer_receipt` verified stays verified there — this side must not weaken
it, which is why the join reads `consumed` rather than re-checking nodes itself.

## THE THREE SILENCES, none of which may be read as an answer

1. **armed but not consumed** — the answer has not arrived.
2. **never armed** — a non-mutual knocker has nothing for a receipt to land on,
   so an approval leaves no trace here AT ALL.
3. **denied** — the record is REMOVED, so declined and never-armed are the same
   bytes.

So the line still never says "unanswered" and never anything readable as
declined. It now says `no answer has reached this node` — a fact about US rather
than a claim about the world, which is what the old `(releases#87)` citation had
become.

## PER-ARM MUTATION, three builds, predictions registered first

- **MUT-A** — both conditions dropped at once: the silences cell RED, the proven
  cell and the discriminator cell GREEN.
- **MUT-B** — only `consumed` dropped: RED, and the panic names the row —
  `armed but not consumed: this is a silence, not an answer`.
- **MUT-C** — only the keyspace dropped: RED, naming `a CODE redemption sharing
  the id — a different keyspace`, while the proven cell stayed GREEN.

**Stated honestly:** B and C redden the SAME cell, because both rows live in one
table. The per-arm evidence is the labelled panic, not cell-level separation —
each mutation names which row it broke. I ran three builds rather than claiming
the collapsed MUT-A proved both conditions.

## LANE SLATE (tip `99b7da2e` + the lane record)

- 3 unit cells green (proven, the three silences, the discriminator pair)
- `cargo test -p spt --bins`: **644 passed, 0 failed**
- `cargo test -p spt-store --lib`: **489 passed, 0 failed** (the prose sweep
  touched `knock.rs`)
- `cargo clippy --workspace --all-targets`: **exit 0, zero warnings**
- `traceable-reqs check` / `xtask check`: see the report

## What is owed

1. Report to doyle — the last wave-3 gate.
2. Board comment on releases#186 with the corrected mechanism (doyle's second
   addition): the source cites, the three cases, the two refusals, and that the
   fix satisfies the filing's INTENT even though its mechanism was wrong.
3. Pool release when the lane is picked at assembly. DO NOT rebase or push.
