# LIFECYCLE-TRUTH W4 — GATE VERDICT: **PASS** (doyle, 2026-07-07)

**Wave head `e09ba21`** (branch `lifecycle-truth`). Both REQs built + gated, both legs green.

| REQ | stages |
|-----|--------|
| REQ-SPAWN-COLLISION-GUARD-LIVE-DUP | impl+unit+int |
| REQ-HAZARD-LISTEN-ORPHAN | impl+unit |

## Gate legs — both green
- **Windows (HFENDULEAM), isolated worktree `.worktrees/gate-e09ba21`, fresh target, `CARGO_INCREMENTAL=0`:**
  clippy `--workspace --all-targets` 0 · nextest `--workspace --no-fail-fast` **1696/1696** (8 leaky, 1 skip) 0 · `xtask check` **OK** (after scoped sweep of 4 pinned dev-daemons — the known recurring gotcha) · traceable 0.
- **Linux (kitsubito), bundle-deploy @e09ba21, fresh, `CARGO_INCREMENTAL=0`:**
  clippy `--workspace --all-targets` 0 · nextest `--workspace --no-fail-fast` **1684/1684** (2 leaky, 1 skip) 0.

## Diff review (both faithful to the W4 ruling)
- **REQ-SPAWN-COLLISION-GUARD-LIVE-DUP** (`broker.rs`): single-flight wake, **broker-side claim** (ruling 1 — not a perch-record write). `wake_gate_decision` pure truth table (AlreadyLive / Racing / Claim); `dispatch_spawn` reads the live-session check + the `wake_inflight` claim **together under one atomic critical section** (sessions then wake_inflight — wake_inflight is a leaf lock, taken alone only in the RAII drop, no inversion), **no I/O under lock** (cached `process_id`). Serialized so no double-claim; a duplicate wake for a live-or-in-flight endpoint **no-op acks** the existing session; a leaked claim past `WAKE_DEDUP_WAIT` (2s) is taken over (availability over a vanishingly rare dup); empty endpoint ungated. `WakeClaimGuard` RAII releases on success/`?`/panic. RED-first int (`wake_single_flight.rs`): 2 concurrent wakes → 1 session (drop gate → 2, the dup). Complementary to the CLI-side `run_no_dup_session_e2e` refuse path — a second belt at the spawn choke.
- **REQ-HAZARD-LISTEN-ORPHAN** (`startup.rs`): `--parent-pid` **poll watchdog** (ruling 2 — POLL baseline, OS-native optional). 2s poll of `parent_is_gone`, loud `exit(3)` (`EXIT_PARENT_GONE`) so the perch pid dies → liveness flips OFFLINE → dead-owner rebind unblocks. **Persistent-relay branch ONLY** (spawned after the `--once` early return) — verified against every listen e2e (all `--once`) so no test listener is killed. Win reaped-`Child`-holds-handle test gotcha correctly handled (drop before poll; production listener holds no handle to a separate parent host). perri's spt-mobile job-object guard stays as independent defense-in-depth.

## Verdict
**W4 GATED PASS.** LIFECYCLE-TRUTH W1–W4 all gated. Remaining milestone content: **W5** (delivery integrity — INJECT-MULTILINE-INTEGRITY + IDLE-PARKED-DELIVERY + SPOOL-TAKE-AUDIT) then **W6** (docs). Release counter 49 + W1 field-accept swap window still operator/deployah-gated.
