# W2 (#246 + #147 + #17 rider) gate checklist — doyle, pre-staged 2026-09-07 04:20Z while todlando builds

Source of truth: `WEBSERVE-272-JIT.md` §W2 + ADR-0058 (incl. Amendment 1, reference-served ruling)
+ ADR-0061 (incl. its ADR-0020 supersession section) + the five REQ texts minted in
`traceable-reqs.toml` on `build/ws272-w2` (REQ-WEB-ATTACHMENT-PULL, REQ-WEB-FETCH-VERB,
REQ-MSG-SHORT-ID, REQ-WEB-ENTRY-AUDIENCE, REQ-NOW-SIGNAL-FILE-ACCESS-HELPER) + the amended
REQ-SEND-REPLYTO-REMOVE. Base = `9489ef60` (W1). Gate reads go to SOURCE, never the PR body.
Head at staging time: `58f0e2c8` (2 commits: 76f058e7 source, 58f0e2c8 register-on-my-behalf wire),
32 files / +4114 −67, `merge-base --is-ancestor origin/main HEAD` = YES. Anchors below name the
files his diff-stat touches; line numbers are read at the tip, never guessed here.

My rulings that bind this gate (sent to todlando 03:44Z):
- **#17 remote arm = ORDER, not a drop** — it builds FIRST once the pool is his, and the PR body
  states the order. Present as commit 58f0e2c8 at staging; verify it is not stubbed.
- **Envelope-consequence cells** (every send now carries a msg-id → typed envelope): every
  existing cell that changed its assertion is named + repinned IN-LANE, ONE commit for the family,
  ADR-0061 cited per cell. A WIDENED assert (accepts more than before) = finding.
- **`--reply-to`**: REQ-SEND-REPLYTO-REMOVE amended BY REPLACEMENT (the target fallback + the
  REPLIED label are what died, and stay dead), its unit cell repinned to those two surviving
  properties against the LIVE flag, ADR-0061 carries a supersession paragraph naming ADR-0020,
  spelling kept. Both present in the staging diff (treqs title + ADR-0061 section) — verify the
  CELL asserts the properties, not the absence of the string.
- His one open treqs finding at 03:44Z = REQ-NOW-SIGNAL-FILE-ACCESS-HELPER `int` — closes with the
  two-host cell, not with a unit stand-in.

## 0. Pre-flight (before any command)
- [ ] Open GATE-TEST-INDEX.md (memory) — first touch of a gate. Then CI-INFRA-INDEX.md's
      battery-on-both-boxes entry (2nd face: the ff push to main fires the full run too).
- [ ] `git fetch` then assert origin/main == GitHub main (`gh api …/branches/main`).
- [x] hertz's row-46 lane LANDED FIRST: PR #197 ff, **main = bfb5d58a** 04:32:01Z (tested == merged;
      CI 34082336298 5/5, Windows unit 16m37s = the pool the red came from; my source read PASS at
      that sha, seam monotonic by construction :1338/:2827). W2 REBASES onto bfb5d58a before its
      battery (test-only sibling; shared file = docs/FLAKE-LEDGER.md, rows 46 + 49 both verified).
- [ ] `git merge-base --is-ancestor origin/main <tip>` at the W2 tip — if false, rebase BEFORE gating.
- [ ] No CI run in progress on either box (`gh run list --limit 3`: a `push` run on main after a
      land counts). One battery per box; census cargo by cwd/parent, kill only mine.
- [ ] IR-76 three-arm golden check; free GB beside the floor line (`xtask disk-floor`).
      **Disk plan (04:10Z census):** C: 122 GB free with the runner's unit target REGROWING (~50 GB
      comes back during any Windows CI job) → ~70 GB real. `ws272-w1/target` = **137.3 GB** and W1
      is LANDED (9489ef60): its reap is the W2 headroom. Owner todlando; ask "nothing named worth
      keeping" (gate records already at `.spt/preserved/gate-w1-9489ef60/`, 165 files), classify
      (`Get-Item -Force`: DIR vs link), sweep inbound reparse, size before/after → the number goes here.
      Want ≥80 GB free BEFORE his nextest leg (test-profile pool grows 10–55 GB per suite).
      **REAPED by todlando ~04:17Z (his numbers):** classified REAL dir (ReparsePoint None, LinkType
      empty), inbound sweep 0 reparse points, `CARGO_TARGET_DIR` empty in his shell; size before
      147,451,792,461 B = 137.33 GB / 17,059 files; free 110.79 → **245.41 GB** (+134.62; the 2.7 GB
      gap = concurrent activity, path reads absent); target SUBTREE only in 12.9 s, worktree kept.
- [ ] Pool plan: his `ws272-w2/target` (2.9 GB at 04:00Z, warming). My legs run SEQUENTIALLY in his
      pool after his explicit `pool-release`, via ONE hatch-wrapped
      `SPT_POOL_UNCHECKED=1 cargo run -p xtask -- pool-claim --foreign-pool --pool <his target>
      --label gate-w2` from MY gate worktree (`.worktrees/gate-w2-<sha>`, detached at the tip); every
      later build runs WITHOUT the hatch and must Proceed as owner == my tree. A replayed
      `guard DISABLED` line in a later raw is cargo replaying the cached build-script output
      (W1 §1), not a live hatch — check the driver's env-leak line.
- [ ] Reuse `.spt/preserved/gate-w1-9489ef60/*.sh` corrected forms (PORT_B=7470, WAIT env, PATH
      export for kitsubito) + `launch-battery.py` (explicit env=, identity trio scrubbed, child env
      READ BACK). Kitsubito: `bash -lc` (traceable-reqs on PATH), `export PATH=$HOME/.cargo/bin:$PATH`,
      `cd … || exit`, lockfile per worktree, log `procs-before: 0`; detach on purpose, kill by remote pid.
- [ ] `traceable-reqs --version` = 0.2.0 on BOTH boxes before the treqs leg (CI pins WANT=0.2.0,
      ci.yml:246 / golden.yml:1320; the box exe flipped under W1's gate by an unknown hand).

## 1. Mechanical legs — TARGETED (ruling 02:40Z; exit FILES read, never the harness notification)
- [ ] `traceable-reqs check` (exit 2 = did not parse — read the code; no `"` in titles). Expect
      the five W2 ids ACTIVATED with real stages + REQ-SEND-REPLYTO-REMOVE's amended title; every
      W2 tag on or immediately above its evidence, never a file-top banner.
- [ ] workspace-bins prebuild (`cargo build -p spt -p mock-adapter --bins`, ONE `--bins`) →
      `xtask check` (docs drift + spacerun + internal-codes scan). W2 adds a docs page → the
      SUMMARY.md line is in the diff (+1); **`llms.txt` is NOT in the diff-stat** — W0's gate found
      the serving page missing from the curated index; check whether `attachments.md` must be listed
      (finding if the index enumerates serving pages).
- [ ] clippy strict (workspace, all targets).
- [ ] `nextest --no-fail-fast` FILTERED to the touched crates' units + the lane's own bins:
      spt-store (msgid, serving, spool, perch, iolog), spt-daemon (webserve, webproxy, servehost,
      iobus), spt-net (webmsg), spt-proto (event), spt (cli, fetchverb, msgverb, serveverb, attach,
      api/nowsignal, api/delivery, api/ioevents) + `webserve_attachment_e2e` + `webserve_cross_node_e2e`
      (+ `webserve_e2e` from W0, unchanged expected). Expected population = W1's filtered slice (1765
      at 9489ef60 across 6 binaries) + W2's new cells: count them from the diff (`#[test]`/`#[tokio::test]`
      adds) BEFORE the run so the run count is a check, not a report. `grep -c Summary` == 1 before
      any FAIL read; count `panicked at`, not FAIL lines. Full sweep = golden (deployah), not here.
      **FILTER GAP caught 04:50Z (his driver `.github/ci/ws272-w2.py`, battery #1 at 37e31324):** filter
      `(package(spt-proto)+package(spt-store)+package(spt-daemon)+package(spt)) & (kind(lib)+kind(bin))
      + binary(webserve_attachment_e2e)` — `kind(test)` (crates/*/tests) enters ONLY by `binary()`, so
      `webserve_cross_node_e2e` (F1 cells (i)–(vii) + the helper's int arm) was OUTSIDE the selection
      and his 200-test POPULATION floor passed without it. Agreed: (1) running driver untouched;
      (2) `nextest list -E binary(webserve_cross_node_e2e)` FIRST, cell names read back; (3) that
      binary as its OWN leg, own .exit, `grep -c Summary` == 1; (4) `binary(webserve_cross_node_e2e)`
      added to the driver filter in the lane commit. GATE: assert the PR's driver filter names BOTH
      e2e binaries, and run `nextest list` against the gate's filter before the gate's nextest leg —
      the listing must contain both rig binaries BY NAME.
      **CORRECTED 05:05Z (his measurement):** both rigs are ONE `#[test]` per binary by construction
      (`SPT_HOME` is process-global): `spt::webserve_attachment_e2e
      an_attachment_is_snapshot_served_fetched_back_and_named_by_its_message` and
      `spt::webserve_cross_node_e2e a_peers_url_is_served_by_its_owner_through_the_local_listener`.
      The F1 conjuncts (i)–(vii) are ARMS inside the second, verifiable only in the RUN output. So the
      gate runs that binary `--no-capture` and reads ONE NAMED BREADCRUMB PER ARM from the raw (asked
      05:05Z: e.g. `F1_ARM=iii verdict=refused registry_empty=true`); a green raw with no arm lines
      is indistinguishable from a rig that skipped its arms.
      **Battery #1 REFUSED by his own POPULATION meter** (`NEXTEST_POPULATION:REFUSE selected=1
      floor=200`): the counter looked for "N tests across"/"N binaries" phrases this nextest never
      prints, fell through to counting 4-space-indented lines (exactly one). Real selection 1673
      (`^\S+ \S*::` rows, bin-target cells present). Fixed in the lane commit: counter counts the rows;
      `binary(webserve_cross_node_e2e)` added → 2441 selected. Six legs before it were 0 at ~178 GB
      free. Failed in the RED direction (a guard against a false green minted a false red) — right
      direction, still an instrument defect, the second instrument to move under a measurement in
      this lane tonight. Battery #2 in flight, same driver.
      **05:10Z his self-report:** the breadcrumb patch script APPLIED (he meant to inspect) while #2
      ran; `webserve_cross_node_e2e.rs` modified ~1 min, `git checkout --` restored bytes (mtime
      bumped → next cargo rebuilds it, harmless). RULED: #2's cross_node line is VOID regardless of
      the timestamp forensics — the solo breadcrumb re-run of that binary was already the decider;
      forensics are recorded, not argued. Every other leg's .exit predates the window = unaffected.
      Patched copy moved from /tmp into the worktree's `.spt/` (a reap party sweeps TEMP).
      **BATTERY #2 (his exit files, 05:20Z):** treqs/claim/prebuild/xtask/clippy/population 0, floors
      181→178 GB; population 2441 (meter == hand count). nextest **6 FAIL / 2441, ALL in his new
      code, ZERO pre-existing cells** → the predicted envelope-consequence family is EMPTY (nothing
      in the estate asserted a plain send spools a raw body) — PR body must carry the grep that shows
      it. The six, each at a mechanism, none rerun: (1+4) extractor `see "C:\x\notes.md".` →
      trailing `"` kept (quote-trim then dot-trim ONCE in fixed order) → fix = trim to a FIXED POINT;
      (2) helperline torn tail: crash mid-append left a fragment with no newline, next append FUSED
      two records → fix = close a torn tail with `\n` before appending (the doc comment had claimed
      the property, the code had not); (3) `fetch` help about-line 70 chars vs the 80-col unwrapped
      table → reflowed; (5) attachment rig precondition: `endpoint create --adapter dummy` refused
      `ENDPOINT_RUN_ADAPTER_UNREGISTERED` (product right, rig never needed bringup) → rig creates the
      target perch directly, reason written down — GATE: confirm the rig still drives the REAL
      spool/deliver path and only the perch's existence is shortcut; (6) cross_node VOID per ruling
      (FAIL at 29.8 s into the leg, edit window ~1 min around it — the void was right, not generous).
      Next: breadcrumbs (preserved at `.spt/preserved/`, sha verified) → solo cross_node leg → the 4
      fixed cells re-run → commit + PR.
      **SOLO cross_node leg (05:28Z, his exit file): exit 100, `grep -c Summary` = 1, ZERO F1_ARM
      lines — failed BEFORE arm (i):** `the owner answered: "dial failed: brain IPC read deadline
      elapsed"` at webserve_cross_node_e2e.rs:629, 28.23 s, first `request_serve_for` call. His
      diagnosis (accepted): RIG-SHAPE defect — production's `request_serve_for` client runs INSIDE
      the receiving daemon (ingress thread); the arm drove it from the TEST PROCESS with its own
      Brain on A's seed socket dialing B as an outside client, a path production never takes. Not
      rerun, deadline not widened. **RULED 05:30Z = (a):** the int stage is minted "end to end"; (b)
      owner-side direct call = the four spt-store unit cells already passing, cannot close an int
      stage; (c) twohost_web is HEAVY/golden-only → thin CI would carry no helper evidence. Shape:
      a USER-attributed send on A to an endpoint on B quoting an absolute path on A → B's helperline
      gains the fetch line (proves ingress-after-delivery + daemon-to-daemon request) → A's registry
      shows File/24h/audience/origin (vi) → B fetches byte-equal (vii); refusal arms driven the same
      way, one varied property each, asserting registry AND helperline unchanged (the no-origin arm
      stays owner-side and says so in its breadcrumb). GATE MUTATION ARM: disable the ingress caller
      → (vi)/(vii) RED, refusal arms green; an arm that passes with the caller disabled is not
      driving the daemon. todlando at 70% context, communing across; next session builds (a).
      **SUPERSEDED 05:41Z (his measurement refuted my premise): the spt-store msgid cells cover the
      LOOKUP only; NO unit cell exercised the four conjuncts, and (i)(ii)(iv)(v) are undrivable end
      to end by construction (the receiver only asks for what the user's words held). RULED shape A:
      the conjunct is a PURE predicate in spt-store beside `local_msg_out_in`, taking the looked-up
      ROW's attribution field + audience + path + origin option (never a requester header), FOUR
      unit cells one conjunct each (agent row refuses where a user row admits), `serve_for` calls it
      at conjunct (3)'s seat and refuses with `deny_message()`. Int arm = (iii) end to end + (vi) +
      (vii), THREE F1_ARM breadcrumbs, (iii) asserts registry AND helperline unchanged. Falsifiers,
      separate invocations on a green baseline: no-op `request_serve_for` → (vi)/(vii) RED, (iii)
      GREEN; predicate forced to Admit → refusal unit cells RED, int unchanged. GATE READS: the call
      site (a predicate that exists but is bypassed), the predicate's inputs (row field, not
      header), the four cell names, the PR body's sentence that the conjuncts had no evidence
      outside the reshaped arm.**
- [ ] `twohost` stays out of this gate unless W2 touched the twohost bin (diff-stat says no); the
      cross-node int cells ride `webserve_cross_node_e2e` (+83) and the field pair rig.
- [ ] mdbook build (docs moved: 5 docs-site files).
- [ ] Same legs on kitsubito, sequential, one battery per box, exit files read.

## 2. Source reads at the tip (PASS/FAIL per line, cite file:line)
### REQ-WEB-ATTACHMENT-PULL (ADR-0058; spool.rs, serving.rs, servehost.rs, webserve.rs, cli.rs, livehost.rs)
- [ ] `spt send --attachment <path>` COPIES bytes at send time into `$SPT_HOME/serve/snapshots/`;
      registers `ServedKind::Attachment` (variant existed since W0; W0's `serve_entry` 404'd it ON
      PURPOSE — find that arm and confirm W2 flips it to serve, not a second path).
- [ ] Envelope `attachments: [{name, url, bytes}]` ADDITIVE; url node-prefixed `/<node>/f/<name>`;
      bytes = snapshot size. Delivery path tolerates unknown keys: grep `deny_unknown_fields` on the
      envelope types = 0 usages (W0 census: zero, all comments), and a cell exercises an
      unknown-key receiver.
- [ ] Served-name disambiguation UNCHANGED (Am.2 allocator serving.rs `owner.path==path && kind ⇒
      reclaim`): for a snapshot the `path` is the SNAPSHOT path, so two sends of one basename mint
      distinct stable names (`report.md`, `report~1.md`) and neither URL changes meaning. Cell.
- [ ] TTL default 30 d, `--ttl <dur>` parse; entry records expiry; reaper in `livehost.rs
      reconcile_once` (the 5 s tick that runs worker_reap) deletes snapshot FILE and registry ENTRY
      TOGETHER and logs the count (a reaped link answers 404, never a hole). Cell for each.
- [ ] Missing/unreadable `--attachment` path REFUSES THE SEND BY NAME (no message delivered with a
      dead link). Several `--attachment` flags on one send → one entry each.
- [ ] Immutability cells: post-send EDIT of the source → fetch unchanged; post-send DELETE → still 200.
### REQ-WEB-FETCH-VERB (fetchverb.rs, cli.rs, main.rs)
- [ ] Accepts full URL and bare `<node>/f/<name>`; default dest = URL basename in cwd; refuses to
      clobber without `--force`; prints the written path on success.
- [ ] Exit 0 wrote / 3 REFUSED (403; an access decision) / 1 everything else (unreachable, 404,
      deadline, local write error), each naming its cause on stderr. Cell per code.
- [ ] Rides W1's cross-node client path (no second HTTP client minted — grep for a new client);
      a local-node URL goes through the same loopback server.
- [ ] Body streamed to a temp file then RENAMED into place; an interrupted/refused fetch leaves NO
      partial at dest. Cell.
### REQ-MSG-SHORT-ID (ADR-0061; msgid.rs +429, spool.rs, perch.rs, iolog.rs, iobus.rs, event.rs, delivery.rs, ioevents.rs, msgverb.rs, webserve.rs)
- [ ] Minted AT COMMIT (spool/store write), not at render; 8 base32 chars over the message's EXISTING
      hash; STABLE across a re-read (cell).
- [ ] Collision detected at mint; resolved by LENGTHENING that one id (9, then 10); never rejects the
      message; never re-mints an issued id (forced-collision cell leaves the incumbent alone).
- [ ] The SAME token in the delivery envelope AND in `MSG_IN` AND `MSG_OUT` io-event rows (one cell
      reads all three); readers treat it as opaque.
- [ ] `/<node>/m/<id>` HTML + `?json` twin (W0 reserved `m/`); `spt msg show <id>` + `--json` render
      the message with attachment URLs.
- [ ] `spt send --reply-to <id>` carries the parent as an ADDITIVE key; UNKNOWN parent carried, not
      refused (cell). `target` stays a REQUIRED positional; the flag cannot stand in for it; no
      REPLIED label, no delivery change — the repinned REQ-SEND-REPLYTO-REMOVE cell asserts THESE
      against the live flag (a cell that asserts "string does not parse" = finding, contradicts the
      amendment).
- [ ] ADR-0061 supersession section names ADR-0020 and keeps the spelling (present at 58f0e2c8;
      re-read at the tip for placement as an amendment, not a rewrite of the Decision).
- [ ] Envelope-consequence family: list every EXISTING cell whose assertion moved (diff of
      `crates/*/tests` + `#[cfg(test)]` blocks vs 9489ef60); each cites ADR-0061 in the ONE family
      commit; no assert widened. If the family is empty because the key is additive, say so with the
      grep that proves it.
### REQ-WEB-ENTRY-AUDIENCE (ADR-0058 Am.1; serving.rs, webproxy.rs `serve_web`, serveverb.rs)
- [ ] `ServedEntry.audience` existed since W0 (forward-compat, round-trips); W2 = ENFORCEMENT in
      `webproxy.rs serve_web` beside the existing `access_check`, keyed on the handshake-PROVEN origin
      the dispatcher passes (REQ-HAZARD-WAN-ORIGIN-AUTH) — never on a header or a claimed id.
- [ ] Absent audience admits; matching admits; NON-matching → 403 with the SAME body shape as a WEB
      deny rule (compare the bytes, not the status — the registry must not become an oracle).
- [ ] Loopback served regardless of audience, and the docs (serving/overview.md entry-fields) STATE it.
- [ ] `spt serve list` renders audience beside ttl and origin. Cell + field.
### REQ-NOW-SIGNAL-FILE-ACCESS-HELPER (ADR-0058 Am.1; nowsignal.rs +284, attach.rs +182, webmsg.rs +47, servehost.rs)
- [ ] Trigger (a): delivered message with attachments → one `spt fetch <url>` line per attachment,
      taken VERBATIM from the envelope (not rebuilt).
- [ ] Trigger (b): a USER's message quoting a filepath → REFERENCE-served file/dir entry (NEVER a
      snapshot; operator ruling), ttl 24 h, origin = the message short-ID, audience = the ONE receiving
      endpoint; the signal hands that endpoint the fetch line.
- [ ] Guards, each its own cell: path must EXIST on the owning node (else emits NOTHING); absolute or
      `~`-rooted only; cap 5 per message; a directory registers a dir entry under the same ttl/audience.
- [ ] Same-node user+agent: registers NOTHING, the signal says the path is local and readable.
- [ ] Delta discipline: once per (message, path); a re-poll in the same session emits nothing (cell).
- [ ] REMOTE user (the #17 case): registration happens on the USER's node on the agent's behalf —
      the "register-on-my-behalf" request (58f0e2c8: webmsg.rs frame, servehost.rs owner handler,
      attach.rs requester) rides W1's stream family and is AUTHORIZED BY THE USER'S ATTACH SESSION —
      read what "authorized" binds to in code: the request must be tied to a live attach session of
      that user, not accepted from any peer stream. Owner-side guards re-run on the owner (existence,
      abs-only, cap), not trusted from the requester.
- [ ] Entries enumerable in `spt serve list` with origin = short-ID.
- [ ] **Carrier of the helper's URLs (todlando's own correction, 04:17Z, gate must confirm):** the
      URLs returned by register-on-my-behalf are NOT folded into the delivered envelope's
      `attachments` attr — that attr is the SENDER-authored class (his proto cell pins it) and a
      receiver-side write into it would be a forgery. Carrier = `spt_store::helperline` (receiver-side
      record store); the delivered message says only what its sender said. Read: (a) no code path
      writes `attachments` after delivery; (b) the WAN-ingress caller fires AFTER delivery on its own
      thread, so a slow/absent peer never delays or fails a delivery (cell); (c) the helperline store's
      on-disk location under `$SPT_HOME`, its cleanup/TTL, and that a re-poll reads it once
      (delta discipline) — a second durable store is a second thing to get wrong.
- [ ] Remote arm shape at his report (72527fde): `ServeFor`/`ServeForReply` on the webmsg family;
      owner-side `serve_for` refusals in order: (a) WEB access gate at NODE scope, (b) audience
      endpoint must be hosted on the handshake-proven requester node, (c) serve-add path rules
      (absolute, exists); (a)/(b) answer `deny_message()`. Requester `request_serve_for`; user-msg only.
- [ ] **F1 (raised 04:36Z, before his battery): the user's-attach-session AUTHORIZATION is absent
      from that list.** In the default-on subnet posture (a) admits every subnet node, (b) only ties
      the audience to the requester, so any subnet node can have any absolute path on the owner
      served to its own endpoint for 24 h with no user on the owner having said anything. Required:
      owner resolves ITS OWN `MSG_OUT` row by `origin` = short-ID and refuses unless the row exists
      here, its sender is a USER attach session, its target == the audience endpoint, and its body
      contains the exact path; deny shape = `deny_message()`. Cells: unknown id / agent-sent / wrong
      target / path-not-in-body / positive. Closes only with the cell names or the built arm.
      Gate reads the lookup at the tip; a requester-supplied "proof" is not one.
      **BUILT (todlando 04:40Z, confirmed REAL, "not an omission"):** `spt_store::msgid::local_msg_out_in
      (home, short_id) -> SentMessage{sender,target,body}` reads THIS node's own MSG_OUT row (io-log,
      not the index — the index records where a message is HELD, i.e. the target); sweeps flat AND
      nested perches; read bounded to the last 512 rows (older = refused, the safe direction).
      `serve_for` conjunct (3) sits between the audience check and the path rules: origin REQUIRED +
      row exists + user-msg + target == audience + path inside the user's words; `deny_message()`.
      Cells in the rewritten two-daemon arm: (i) no origin, (ii) never-sent origin, (iii) AGENT message
      of the same shape, (iv) audience mismatch vs a real user msg, (v) path the user never named,
      (vi) positive: kind=File ttl 24h audience origin, (vii) the audience's node pulls it; EVERY
      refusal arm also asserts the registry holds NOTHING. + 2 unit cells on the lookup (own sent
      found / never-sent None; nested perch found). His old int arm (origin BCDFGH23 never sent)
      PASSED before F1 = the hole; rewritten, not extended. GATE at the tip: read how conjunct
      "user-msg" is decided (the row's attribution field, not a header the requester can set); count
      the 7+2 cells by name; run arm (v) as a mutation candidate (drop the path conjunct → (v) RED,
      (vi) still green).
- [ ] `int` = the two-host cell (remote user's quoted path served to the named endpoint end to end),
      in `webserve_cross_node_e2e` or the pair rig — this is the finding that was open at 03:44Z.
- [ ] Docs: `harness-contract/api.md` now-signal category list must name FILE_ACCESS_HELPER — **api.md
      is NOT in the diff-stat**; if the category list lives there, this is a docs FINDING (REQ doc
      stage names it). `shells/frames.md` +8 is where his docs delta went — read both.
### Docs / surfaces
- [ ] `serving/attachments.md` (new, +133: send/fetch/ttl/helper sections), `messaging/overview.md`
      (short-ID + reply-to), `serving/overview.md` (entry fields incl. audience + loopback sentence),
      `shells/frames.md`, `SUMMARY.md` +1. CONTEXT.md terms CITED not re-worded (attachment, fetch,
      message short-ID, served name). `reference.md` via `--help` regenerated if the CLI grew verbs
      (`fetch`, `msg show`, `send --attachment/--ttl/--reply-to`, `serve add --audience`?) — drift gate.
- [ ] CHANGELOG untouched by the lane (release shapes it); any hit = doc-tag comments only.
- [ ] Trailers by RAW BODY (`Co-authored by: todlando`, never `%(trailers:)`); 0 wip/checkpoint
      subjects; PR body `Fixes BigscreenVR/spt-bs-releases#246`, `#147`, `#17` lines + the #17 order
      statement; his own `WEBSERVE-272-W2-JIT.md` (+271) and `.github/ci/ws272-w2.py` (+386, the
      targeted driver) are lane artifacts — diff his JIT against mine for silent scope drops.

**06:22Z todlando's f1-attach chain (three reds, each named): (1) rig wrote a bare directory for the
target perch, perch_exists reads info.json → record written; (2) fetch 404 from `localhost:5474` =
the FLEET daemon answering (rig's own daemon was on an ephemeral port) → RIG-SAFETY class; (3) the
ephemeral switch did not fix it because `serveverb::node_and_port` mints the URL from
`DaemonConfig.docs_port`/`SPT_DOCS_PORT`, never from the bound listener → RULED DEFECT, filed on the
board (URL must come from the bound port); rig pins SPT_DOCS_PORT=5493 on daemon + every CLI call.
GATE: assert the attachment rig's URL port == its daemon's `DOCS_SERVER_UP` port in the raw; a fetch
that answers from 5474 on this box is the fleet, not the rig. Sweep of the other rigs → hertz, gates
his PR. f1-storecells 8/8 (extractor fixed point, helperline torn tail).**

**06:26Z–06:50Z rulings (post-yield window, hertz #198 landing first):**
- Attachment rig reds 5+6 (todlando): registry right + surface wrong = the PREVIOUS run's autostarted daemon
  on the fixed port (pid 54684, own SPT_HOME); fix = per-run bind-:0 port fed to daemon AND every CLI call,
  ephemeral flag OFF (IR-78), `DaemonReaper` Drop guard armed before the first CLI call. GATE: raw shows
  `DOCS_SERVER_UP` port == every minted URL's port; reaper breadcrumb (`DAEMON_STOPPED`); post-leg census by
  the rig's SPT_HOME/exe path = 0. Memory: e2e-leaked-daemons-shared-box.md 2026-09-07 section.
- **HEAVY after the rebase onto #198 (ff4b405d):** #198 puts `webserve_cross_node_e2e` into HEAVY in BOTH
  `.config/nextest.toml` and golden.yml's job env and adds `check_heavy_integration_classification` (grep for
  `"daemon","run"` / `"daemon","brain"` / `supervise_brain(`). Consequences the gate asserts at the tip:
  (1) arm (iii) is golden-only → coverage sentence rewritten for THAT sha (thin CI = five predicate cells,
  nothing cross-node; golden = arm (iii) + the twohost positive in its two env-gated role steps);
  (2) `webserve_attachment_e2e` autostarts (no `"daemon","start"` pair, only `"daemon","stop"` :74/:367 at
  2925e602) so the checker is BLIND to it → hand-added to HEAVY in BOTH files in the rebase commit, or it
  runs in the ordinary suite while spawning a daemon (the rotating-victim mechanism). hertz's IR-37 rider
  widens the literal by `"daemon","start"` (7 binaries) and names this rig as standing proof #2 for (c).
- **attach8 = REAL W2 DEFECT, RULED IN-LANE (06:50Z):** `spool_message_identified_at`/`IdentifiedInsert`
  have ZERO callers; `insert_message` passes `identity: None`; no UPDATE sets short_id → every spool row is
  NULL and resolve_in's spool leg is unreachable by construction (universal, not offline-conditional).
  Index IS minted (cli.rs:11475, owner = target). Shape: ONE insert path (dead one deleted or every insert
  identified, body cites the zero-caller grep); spt-store unit cell = spool to an OFFLINE target, read back
  BY short_id non-NULL; miss 3 (io-log leg reads OWNER's log for a MSG_OUT held in the SENDER's) fixed only
  after the three-count panel names it, cell either way; MSG_NOT_FOUND stays the one public code with a
  per-miss stderr reason line (internal-codes scan green); falsifier = revert the insert fix alone → the
  unit cell RED + attach8 arm RED at `msg show`, nothing else moves.
- Leg 1 (twohost-web-local none/C) first attempt build.exit=101: `RegistryUpdate` lives in
  `spt_net::net::replicate` not `::registry` (blind-rig cost); fixed, rerun. Harness notification said 0
  because the runner is piped to tail — read build.exit.
- Box order: todlando's two short legs on hfenduleam → his yield → I land #198 ff at ff4b405d (tested ==
  merged, run 34090992646 5/5) → post-land push run both boxes ~20 min → W2 PR opens, queues behind.
  hertz's golden discriminator pre-registered: Phase A count −(eleven binaries' cells), Phase B +same,
  TOTAL unchanged; a dropped total = a binary running nowhere.

**GOLDEN REPARTITION DISCRIMINATOR — baseline half (hertz 07:14Z, no box):** #198 moves TWELVE binaries
into HEAVY (package(spt) 33→44, package(spt-daemon) 34→35 `twohost_web`), not eleven. Baseline = golden
34017906638 @ 04e32c8c (2026-09-06, success, ancestor of ff4b405d, `grep -c Summary` = 2 per box = one per
phase): Linux A 3183 / B 199 / total 3382; Windows A 3208 / B 214 / total 3422; skipped 1 (Phase A) each.
Repartition term = 14 cells (exact, off the run's per-test lines, identical per box). Growth term since
04e32c8c = +12 attributes (twohost_web 0→4 B, cross_node 0→1 B, webserve_e2e 0→4 A, echo_direct_route_int
0→1 A, io_events_undriven_kinds 4→6 A) → +5 B, +7 A. **PREDICTED next golden AT ff4b405d:** Linux A 3176 /
B 218 / 3394; Windows A 3201 / B 233 / 3434. TOTAL is NOT unchanged (+12); a golden run at a later sha
needs W2's cells as a third term (its attachment rig → B by hand-add). Rider-1 forward cost = 13 cells.

## 2.5 Mutation arms — pre-registered, SEPARATE invocations so sibling-intact is WITNESSED
- [ ] Arm A: audience check → always admit ⇒ the non-audience-403 cell RED, its admit siblings GREEN;
      revert, green.
- [ ] Arm B: attachment served from the SOURCE path instead of the snapshot ⇒ the post-send-edit
      immutability cell RED, the fetch-byte-equal cell still GREEN; revert, green.
- [ ] Arm C (if time): collision lengthening → no-op ⇒ the forced-collision cell RED alone.
      Each arm on a GREEN baseline only (W1 lesson: the pair wrapper's exit was the last grep's).

## 3. Field acceptance — two RIG daemons (fresh subnet, ports per the corrected pair scripts)
**RIG PAIR STAGED 05:42Z (operator-run ceremony, elevation):** homes `C:\Users\decid\spt-rig-a`
(hfenduleam, installed 0.67.0, daemon pid 50088, docs on ephemeral 55369) and `/home/reavus/spt-rig-b`
(kitsubito, installed 0.67.1 after the operator's `spt update`, docs on 44015). Both launched with
`SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1` + `SPT_DOCS_PORT=5480`; the flag silently ate the override on
both boxes (memory: ephemeral-ports-flag-silently-beats-spt-docs-port). **MISFIRE 05:45Z:** the
operator's elevated `subnet create ws272-rig` landed in the FLEET home (`AppData\Local\spt-core\
identity\subnet.json`, open mode, admin seed there), fleet node HFENDULEAM joined it, rig B paired to
the FLEET node (roster pubkey 14efb80c…). Cleanup handed to the operator 05:50Z: measure `node status`
under SPT_HOME in the elevated shell (pid 50088 = honored), fleet `subnet leave ws272-rig`, re-create
in rig A, rig B leave + join + chown. Field runs on the tip's bins in the SAME homes (identity +
subnet.json persist across a binary swap); relaunch WITHOUT the flag if a fixed port is needed, or
read `DOCS_SERVER_UP`. Label collision to avoid: rig A and the fleet share `COMPUTERNAME=HFENDULEAM`;
the fleet must have LEFT before rig A joins, or the proxy route `/hfenduleam/` is ambiguous.
**PAIRED 05:57Z (third pass; second pass ALSO landed in the fleet home because step 2's
`Remove-Item Env:SPT_HOME` was not re-set before create — env is plain override, perch.rs:34):**
seed `fdaf2eaa`, rig A = node `79984cca…` (HFENDULEAM), rig B = `b54a9139…` (KITSUBITO), fleet
home holds NO ws272-rig, both `peer reachability: healthy (1/1)`. Residue: rig B's registry kept
the dead fleet id `14efb80c…` (heard.meta last 05:54:23Z, 12 endpoint rows, SAME label HFENDULEAM
as rig A) → `subnet prune` (elevation-gated) handed to the operator 06:00Z. **CORRECTED 06:22Z:** prune resolves
candidates from the ROSTER only (cli.rs:14484) and the ghost lived only in the REGISTRY after join #3, so
the full-hex prune was NO_MATCH by construction and the rows were never targeted (my "re-saved from
memory" read was WRONG; retracted on the issue). Worse: B's roster gained a TOMBSTONE for the LIVE rig A
(79984cca, stamp 05:59:05Z; operator ran the LABEL form `prune hfenduleam`, the roster's only
HFENDULEAM was the live rig, output `PRUNED:79984cca…` went unread by both of us) which zeroed the pump's fan-out (`members_in` skips tombstoned; peers_total
0, no dial, across TWO restarts) while `subnet status` still read as held. Stripping the tombstone
(roster.json.pre-tombstone-strip kept) restored the dial in one round. Registry ghost cleared by moving
the snapshot aside across a restart. **releases#281** filed 06:08Z + corrected by comment 06:22Z, BUGFIX,
backlog, not W2's lane; todlando's restart-forgets read stands as face (2). Rig B pid 3635780.
**PAIR STAGED 06:20Z: A healthy 1/1, B peers_total 1 connected 79984cca, fleet home clean, new firewall
rule `spt-fallback inbound UDP` (operator, 06:10Z) admits the installed daemon.** Also found: the box's
spt inbound-UDP firewall rule admits the CI runner's `target\debug\spt.exe`, not the installed
daemon → fleet inbound UDP blocked (6/8 peers unreachable for 8 days); netsh fix offered, operator's
call. For the field on the tip bins the rig daemon's exe will differ from the rule too → expect
relay-path dials, not direct; a 502-timing arm must budget for that or the rule must admit the
gate's exe.
- [ ] A: `spt send --attachment <f> B`; B's delivered envelope carries `attachments[0].url`
      node-prefixed + `bytes` == file size. `spt fetch <url>` on B → exit 0, sha256 equal, path printed.
- [ ] Edit `<f>` on A → fetch again → sha UNCHANGED. Delete `<f>` on A → fetch still 200.
- [ ] `--ttl 1s` send → after the 5 s pulse: fetch = 404 + A's log carries the reap count line.
- [ ] Two sends of one basename → two distinct stable URLs; `serve list` shows both with ttl/origin.
- [ ] `spt send --attachment /nonexistent B` → refused by name, exit ≠ 0, NOTHING delivered to B.
- [ ] `spt msg show <id>` on A and on B; `/<node>/m/<id>` HTML 200 + `?json` twin; `--reply-to <id>`
      shows the parent in B's envelope; `--reply-to ZZZZZZZZ` (unknown) still delivers; bare
      `spt send --reply-to <id>` with NO target → usage error (the fallback stays dead).
- [ ] Audience: `serve add … --audience <B endpoint>` on A → B fetch 200; a third endpoint / A's
      other endpoint → 403 whose BODY is byte-identical to a WEB deny body; `curl` on A's loopback →
      200 regardless; `serve list` shows the audience.
- [ ] Denied fetch → exit 3; stop A's daemon → B's fetch exit 1 naming the cause, within the deadline.
- [ ] FILE_ACCESS_HELPER remote: user attached on A quotes an existing absolute path to the agent on
      B → A's `serve list` gains a FILE entry (24 h, audience = B's endpoint, origin = the short-ID),
      B's now-signal carries the exact fetch line ONCE; second poll: nothing; relative path: nothing;
      nonexistent: nothing; 6 paths: 5 entries; a directory: dir entry. Same-node: no entry, "local".
- [ ] Both rigs `node stop --force` 0; no `spt.exe` left from either rig pool (census by exe path).

## 4. Land
- [ ] CI green at the tested sha (thin CI = a battery on both boxes: open the PR only when both are
      free, and expect the post-land `push` run to occupy both boxes ~20 min more); re-run the
      ancestor check at land; ff-only; tested == merged; pick-audit.
- [ ] Alchemy sweep → #246, #147, #17 ACCEPTANCE (no `--` tokens in any note). W3 dispatch (#265
      #268 #266); hertz's drift cells (`test/ws272-w3-drift` @1839fba8) rebase only when
      `build/ws272-w3` exists and ride INSIDE todlando's W3 PR.
- [ ] Pools: todlando releases ws272-w2; hertz's IR-37 pin-bump PR opens in a free window AFTER this
      land (it is a full CI run on both boxes).
- [ ] Records preserved at `.spt/preserved/gate-w2-<sha>/` (main checkout, outside any target)
      BEFORE any reap; the reap is its own step after "preservation confirmed".
