
## Gate fixups @ 71a676a1 (2026-09-27, todlando) — against gate-fixups-8cea2af4.md

Subject: `feat/351-w4-shells` = **71a676a10bcecf32342ee83fcee25f6bef5b8656**, tree **d7aa5a2b15531c71324a17c95a3f6115cc555049**. One commit on 8cea2af4. Every run below ran on this committed sha with a clean worktree (`dirty=0` is recorded in the bins log).

### What each fixup became
- **F1:** `submit` settles only when its own drain was NOT held. Unit `a_held_submit_makes_exactly_one_attempt`: one attempt, and a second submit behind the held head is still one attempt at that head.
- **F2:** `submit` appends FIRST, then drains under the lock. The fast path is "the only pending row is mine, with an active instance known".
  - A delivered fast row is DELETED under the lock (`spool::delete_outbound_at`); its audit is MSG_OUT for text and the SENSORY_* line for sensory. A vacancy row is kept, via `mark_delivered_at`.
  - Units: `a_fast_path_hold_keeps_its_place_ahead_of_a_later_submit` (A in flight → B appends → A Hold → order A,B) and `a_delivered_fast_row_is_deleted_and_a_vacancy_row_is_kept`.
- **F3:** one rule, shared as `shellout::deliver_sensory_live` (is_online + deliver_tcp).
  - `receive_wan`: a shell-marked sensory frame is delivered live or answered with the new token `not_live` (`WanOutcome::NotLive` / `WanRequestOutcome::NotLive`, took_custody=false). It is never spooled and never claimed.
  - Shipper: `Ship::NotLive`. `drain_queue` drops it only when it is the fast row (`Submitted::Dropped`, printed as SENSORY_DROPPED). A queued row HOLDS, and the text behind it waits.
  - N-1 receiver: named as a mixed-version limit in frames.md and CONTEXT.
  - Units: `a_queued_sensory_frame_holds_until_live_then_arrives_with_its_sent_at` runs through the PRODUCTION `LiveShipper` with a real listener. The frame holds while not live, and the text behind waits. Once live, both arrive in order, and the frame carries sent-at=t0 (this also covers **Q3**). The fast path then drops and leaves no row.
  - Cross-node unit: `a_crossing_sensory_frame_is_never_inbox_spooled` (not_live, not in the inbox, not claimed; control: shell text still spools; token round-trip).
- **F4:** `tests/shell_outbound_local.rs` rewritten. After the wake the owner is active but not live: text1 lands in the inbox, the frame holds, and text2 waits (pending 2, held 300 ms). The owner then goes live, the next `nudge_drain` delivers the frame (sent-at 1234) and then text2.
- **F5:** `fate` reads `spool::outbound_refused_at` for a row another drain closed. Unit `a_row_another_drain_refused_is_not_reported_sent` (control: a delivered row reads Delivered).
- **F6:** `shellout::owner_perch` (= `resolve_perch_path_in(owlery, owner, Infer)`) is the one path source for the resolver, LiveShipper, submit_live, drain_owner, the new `has_queued`, and dispatch.rs (which now calls `has_queued`).
- **F7:** the file-top tags on daemon shellout.rs are removed. The evidence tags on the fns stand.
- **G1:** `LiveShipper::stamps` is the production decision `ship_remote` uses. Unit `the_live_shipper_stamps_only_for_its_own_uid`: the uid comes from info.json via `LiveShipper::new`; a mismatch gives no stamp, the same uid stamps, and unproven never stamps.
- **G2 (justified in writing at wan.rs, the contacts ledger comment):** the ledger records the stamped OWNER on purpose.
  - It is the one endpoint the daemon proved, and a shell id is not an endpoint key.
  - It feeds only the UNLISTED contact listing. It is not the reply window (`classify_inbound` reads the target's recent outbound) and not the visible sender.
  - MSG_IN `with_peer(delivered_from)` and the delivered row carry `msg.from` = the shell id. The existing unit `a_shell_payload_never_steals_and_shows_the_shell` asserts the row's from = shell on the stamped form.
- **G3:** pure `runs_local_send_trigger`, with unit `a_shell_send_skips_the_local_trigger` (control: a plain send triggers).
- **G4:** pure `shell_sender_for`, with unit `a_compat_shell_sender_is_never_proven`. Flipping the compat arm to `true` fails its first assert.
- **S1:** a `RESWEEP` flag. A nudge during a sweep makes the pass sweep again instead of being dropped. The serial-sweep limit is named in the doc.
- **S2:** the comment now says AT-LEAST-ONCE.
- **S3:** `queued_shells` requires pending > 0, not just file existence.
- **S4:** the frames.md bullet is split back out.
- **Rig cell 7:**
  - 7a gains a not-live leg: L's sensory frame is `Dropped` with no row, and W's inbox holds nothing.
  - W then goes live, with a capture listener (`go_live`, `LIVE_ROWS`).
  - 7a and 7c now read W's live deliveries.
  - The barriers were renumbered sequentially (9 = SENSORY_DROPPED, 10 = W_LIVE, … 17 = DONE), because `barrier` compares with `>=`.

### Battery (all at 71a676a1, this box HFENDULEAM unless noted)
- `cargo clippy -j 8 -p spt-store -p spt-daemon -p spt --all-targets -- -D warnings`: rc 0 (the second run, after the test and rig edits; log `%TEMP%\w4f-clippy2.raw`).
- `cargo nextest run -j 8 -p spt-store -p spt-daemon -p spt --lib --test shell_outbound_local --test twohost_axes --no-fail-fast`: **1797 run, 1797 passed**, 1 skipped, 1 SLOW (`shellwake::tests::nonpersistent_same_boot_freeze_does_not_apply_to_persistent_watchers`, 62.5 s, PASS; I did not compare it against 8cea2af4). rc 0, wall 462 s. Log `%TEMP%\w4f-nextest.raw`.
- `cargo nextest run -j 8 -p spt --bins --no-fail-fast`: **852/852**, rc 0, dirty=0. Log `%TEMP%\w4f-bins.raw`.
- `cargo run -q -j 8 -p xtask -- check`: rc 0, `xtask check: OK`. Log `%TEMP%\w4f-xtask.raw`.
- `traceable-reqs check` on `git archive HEAD` extracted to `%TEMP%\w4f-arch`: rc 0. Log `%TEMP%\w4f-treqs.raw`.
- **Two-host cell 7 at 71a676a1: rc 0 on BOTH hosts.**
  - A = HFENDULEAM: `run-a4.sh <.worktrees/351-w4/target/debug/deps/twohost_axes-696f6adb438876c8.exe (built 23:54, after the 23:52 commit)> two_host_axes_role_a w4f7 <secret> <scratchpad 7c736928>`. Result `rc=0 wall_ms=60699`, 1 passed. Log `<scratchpad 7c736928>\351w4-w4f7-a.raw`.
  - B = kitsubito `~/spt-351-w2`, HEAD read back as 71a676a1 (fetched from bundle `~/w4f-71a6.bundle`), exe `twohost_axes-06ae70918887d2cb` rebuilt 23:52:47: `~/351w3-run-b.sh twohost_axes two_host_axes_role_b w4f7 <secret>`. Result `rc=0 wall=63.9`, 1 passed. Log `kitsubito:~/351w3-w4f7-b.raw`.
  - 7a (B) `both shell payloads reached W's instance (461 ms)`; 7b on both; 7c A `drained L's queue (227 ms)`, B `drained to W in order (307 ms)`.
  - The 7a not-live drop leg and 7d print no OK line. Their evidence is their asserts passing: both roles reached P_DONE and reported `ok`.
