---
name: gateway-liveness-and-f035-progress
description: GATEWAY-LIVENESS #70 MERGED (rides counter 54); F-035 reclassified REAL (relay leg), re-RCA in progress
metadata: 
  node_type: memory
  type: project
  originSessionId: 63fa684a-a93e-4405-a6c5-115f9bccac2a
---

Two flynn/operator field bugs, todlando build, doyle gate, 2026-07-09. Both target **counter 54** (followup release, HELD for doyle GO after both gate).

**GATEWAY-LIVENESS — PR #70 ✅ MERGED to main @9079198** (2026-07-09 10:59). Design-PASS @30b1c13 (doyle reviewed in worktree, did NOT double-run local nextest — hfenduleam IS the Win CI runner, starvation rule; leaned on CI 2-platform clean-room + todlando preflight green). Two REQs:
  - `REQ-LIST-JSON-LIVENESS-PARITY` (impl+int): `endpoint list --json` self-owned reconcile in cli --json builder (cli.rs cmd_endpoint_list) — mirrors picker `local_rows` (alive||unbound→Active), reads roster truth in consumer layer NOT resource_projection (dep-inversion avoided), does NOT force-online (DEFECT B/seed-#5 avoided). ROOT: `--json` emitted un-reconciled WAN snapshot status verbatim (Suspended) while human path DISCARDS own-node gossip rows (`group_remote_nodes`) → showed roster truth. int `tests/list_json_liveness_parity_e2e.rs` RED-FIRST.
  - `REQ-HAZARD-BIND-REST-STATE-CARRY` (impl+unit): establish_perch (startup.rs) carries `prior.rest_state` + `dormant_since_ms` on re-bind, like cwd sibling.
  - flynn post-54 verify pass = these 2 gateway checks (reader-parity human==--json==ONLINE survives suspend-honor + rest_state-survives-rebind). flynn HOLDS for 54 (53=W2-only, no #70).
  - ✅ **FIELD-VERIFY PASS 2026-07-09** (flynn, HFENDULEAM, spt 0.30.4 = #70 via 0.30.3): (1) reader-parity — cold `endpoint run --id mobile-gw` (pid 70972), t+30s & t+120s human list ONLINE + `--json --show-all` Active in all 3 subnets AGREE, survived 120s suspend-honor soak, no self-suspend (pre-#70 = death ~3s); (2) rest_state-carry — `wake` wrote active, bind_gateway re-bind + t+120s preserved it (pre-#70 wiped). GATEWAY-LIVENESS RCA CLOSED field-side, zero spt-mobile changes as ruled.

**F-035 — RECLASSIFIED REAL, RCA HIT WRONG CLASS (operator-corrected 2026-07-09).** `REQ-SEND-WINDOW-DRAIN-HONOR` (branch f-035-window-drain-honor, worktree .worktrees/f-035; WIP STASHED stash@{0}, conflict+RCA docs committed @b943e26; NO PR).
- **Real symptom (operator ground-truth):** in **lia's** session — a full **LIVE AGENT** (relay-for-idle, poll-for-busy) — a busy→idle transition delivered an `--active-only` msg **via her RELAY**. `active_only`'s SOLE purpose = **NEVER drain to a relay, ONLY to a poll**. THAT is the bug.
- **The RCA class error:** todlando's RCA (docs/F-035-RCA.md) + carrier table analyzed the **spt-hosted relay-LESS** class (`claim_idle_edge_inner`, guarded `is_spt_hosted_no_relay`). lia HAS a relay → never hits that leg. WRONG CLASS.
- **Superseded rulings:** doyle's COLLAPSE ruling = WRONG (would break F-023). doyle's PRELIM-B/retire = WRONG (based on the wrong class). The F-023 conflict (idle_edge_drain_e2e.rs:89, REQ-MSG-IDLE-EDGE-DRAIN) **EVAPORATES** — different class; spt-hosted-relay-less idle-edge active_only delivery STAYS correct (F-023 anti-starvation right for THAT class).
- **doyle redirect (2026-07-09):** re-RCA the **RELAY / live-agent** path. doyle finding: `relay.rs:67 drain_backlog` ALREADY uses `drain_non_deferred_audited_at` (excludes active_only) → the leak is NOT drain_backlog. Trace how active_only reached lia's idle relay delivery anyway — candidates: relay cycle's live-poll-FORWARD (relay.rs:75), the busy→idle transition re-offer, or a send-path routing active_only to a relay target. Corrected REQ scope: active_only = POLL-ONLY for a relay-bearing live agent (idle_only/default still relay-deliver). **Report-before-fix STANDS.** WIP stays STASHED (wrong leg).

**LESSON (reusable):** `active_only` = **poll-only, never-relay** (poll=busy carrier, relay=idle carrier for a live agent). RCA a delivery-window bug against the ENDPOINT CLASS first — spt-hosted-relay-less (idle-edge is sole carrier, active_only delivers by F-023 anti-starvation) vs live-agent-with-relay (has a poll carrier, active_only must NEVER hit the relay). A carrier table on the wrong class nearly shipped a real regression (COLLAPSE) then nearly retired a real bug (B). See [[dont-solo-across-role-lines]].

**RELAY RE-RCA DONE** (docs/F-035-RELAY-RCA.md @18466d3, pushed, report-before-fix, NO fix): traced every active_only→relay carrier on main@2c05dc9 — ALL ALREADY GUARDED: send_windowed:217 guards local deliver_tcp; cli.rs:5762 keeps cross-node active_only LOCAL-ONLY (WanMessage has NO window field); drain_backlog=drain_non_deferred excludes deferred=1(=active_only); livehost BELT-1 skips relay-bearing; relay-start run()→drain_backlog same exclusion. ONLY carrier for a spooled active_only = lia's POLL→stdout, never relay. **Corrected-scope REQ appears ALREADY SATISFIED — can't repro the leak vs current main.** Escalated 3 possibilities to doyle: (1) lia on OLDER pre-guard spt = version-lag not a main bug; (2) adapter-side busy→idle poll→relay HANDOFF (spt-claude-code/perri lane, not spt-core api-state-idle); (3) need exact repro (send form + node topology + lia relay/controllable state).

**F-035 LOCKED (2026-07-09) — ADAPTER root, spt-core EXONERATED.** doyle ruled #1 out (lia on hfenduleam = v0.30.2 = traced main). perri traced the live root: for a live agent, the busy hook polls (UPS hook.rs:978 + PreToolUse:1147) pass `api poll --include-deferred`, which DRAINS the spooled active_only into additionalContext. UPS fires on a RELAY-injected EVENT — so an UNRELATED relay msg wakes lia, and that woken turn's poll drags the sitting active_only SELF-CONFIRM in. spt-core clean: active_only correctly stayed SPOOLED (never relay-delivered — todlando's trace holds); the POLL (its legit carrier) surfaced it into a turn woken by something else. 'never wakes' technically honored.
- **Ownership:** ADAPTER fix (perri, spt-claude-code, own cadence) = stop round-tripping the self-confirm via `spt send`; emit it INLINE as PreToolUse additionalContext on the dispatching hook (rides its own active window) + DROP on Stop/end-of-turn. **KEEP `--include-deferred`** (load-bearing for F-021 peer delivery — the defect was the self-confirm ROUND-TRIP, not the drain). NO min_spt_core floor bump (spt-core behavior unchanged).
- **spt-core deliverable** = todlando's REGRESSION-GUARD only (REQ-SEND-WINDOW-DRAIN-HONOR [unit,int], tests-only, locks the 3 active_only-never-relay guards: send_windowed:217, cli.rs:5762 cross-node local-only, drain_backlog exclusion). COLLAPSE WIP dropped (wrong leg).
- **Open gate:** bounce-window repro (perri, operator-timed) must rule out GENUINE-SPURIOUS (active_only ALONE ever wakes lia, no other relay EVENT) — instrument relay-EVENT stream vs hook-poll-drain. If active_only-alone-wakes → reopens an spt-core delivery bug. If only-ever-rides-a-real-wake → pure adapter, closed.

**F-035 REGRESSION GUARD — BUILT + GATED + PR #71** (@2b45d58, branch f-035-window-drain-honor). REQ-SEND-WINDOW-DRAIN-HONOR activated [unit,int], tests-only NO behavior change. 3 guards locked: unit `active_only_never_tcp_delivers_to_a_live_relay` (deliver.rs, send_windowed:217) + `relay_backlog_never_drains_active_only` (relay.rs, drain_non_deferred deferred=0); int `cross_node_active_only_stays_local_only_never_wan` (spt/tests, cli.rs:5762 + default-DOES-WAN contrast). GATES GREEN: clippy --workspace clean, traceable exit0 [OK] +unit+int, nextest 3/3. Branch carries full RCA trail (RCA v1 + CONFLICT + RELAY-RCA docs). COLLAPSE WIP stash DROPPED. Awaiting doyle gate on #71.

#71 doyle DESIGN-PASS; was CONFLICTING (toml append-conflict — branch off pre-#70 2c05dc9; both #70 + F-035 appended REQs at the toml tail). RESOLVED: merged origin/main @f1d3b46, kept BOTH toml blocks (GATEWAY 2 REQs + F-035, each once), traceable exit0 all 3 [OK]. #71 now MERGEABLE, CI RUNNING (run 29014948585, test+n1-gate+traceability both platforms). doyle merges on CI-green. (Starvation rule: hfenduleam runs the Win CI test job — no local gate suites meanwhile.)

**counter 54 scope** = gateway-liveness (#70, MERGED @9079198) + F-035 regression-guard (#71, mergeable, CI running). NEXT on resume: check #71 CI-green + doyle merge → deployah GO counter 54. See [[dont-solo-across-role-lines]].
