# F-035 RE-RCA — the RELAY/live-agent class (correct class, per doyle redirect)

**todlando, 2026-07-09. Report-before-fix. Off `origin/main@2c05dc9` (v0.30.2).**
Supersedes docs/F-035-RCA.md (wrong class: spt-hosted-relay-LESS). Real class = a full
live agent WITH a relay (lia: relay-for-idle, poll-for-busy). Corrected contract:
**`active_only` = poll-only for a relay-bearing live agent — NEVER relay-delivered.**

---

## Finding: every `active_only`→relay path on current main is ALREADY guarded

I traced every way an `active_only` row could reach lia's relay (its live PollListener
via `deliver_tcp`, OR its backlog via `drain_backlog`). **All are closed on current main:**

| path | carries active_only to the relay? | why not |
|---|---|---|
| Local `spt send` (`cmd_send`→`send_windowed`) | **NO** | `deliver.rs:217` — `if window != WINDOW_ACTIVE_ONLY && deliver_tcp(...)`. active_only skips the live TCP, spools. |
| Cross-node `spt send` (WAN) | **NO** | `cli.rs:5762` — a remote active_only that misses locally returns *"active-only stays local-only"* and does NOT `wan_send`. The `WanMessage` wire record has **no window field** (wanmsg.rs:38), and the sender deliberately keeps active_only local-only rather than drop the class over the wire. So active_only never reaches `receive_wan`/`deliver_tcp` (wan.rs:300). |
| Relay backlog (`relay.rs:63 drain_backlog`) | **NO** | `drain_non_deferred` = `WHERE delivered=0 AND deferred=0`; `deferred=1 IFF active_only` (spool.rs:46). Excluded. (doyle already confirmed.) |
| Relay live-poll-forward (`relay.rs:77 pump_once`) | **NO** | Its only feed is `deliver_tcp`→the PollListener; no unguarded `deliver_tcp` of an active_only user msg exists (`deliver::deliver` callers = ring/ready ping-pong + tests; `reporting.rs:456` is a notif frame; `reporting.rs:161` shell-context uses `send_deferred`→**spool**, not tcp). |
| Parked-idle re-offer belt (`livehost.rs:265 drain_idle_spool`) | **NO** | BELT-1 `relay_present → Skip` (livehost.rs:495); and `claim_idle_edge` (post-nothing) is guarded `is_spt_hosted_no_relay`. lia has a relay → never runs. |
| busy→idle relay start (`relay.rs:90 run`→`drain_backlog`) | **NO** | same `drain_non_deferred` exclusion — on going idle, only `default`+`idle_only` spooled-while-busy rows drain to the relay; active_only stays spooled for the next busy poll. |

The **only** carrier for a spooled active_only row is lia's hook **poll**
(`api poll`→`poll_drain`→`drain_active_window`, `WHERE "window" != 'idle_only'`, which
includes active_only) → delivered to the **polling session's stdout**, never the relay.

**Conclusion:** on current main, spt-core's send/deliver/relay/spool/poll legs do **not**
leak active_only to a relay. Corrected-scope `REQ-SEND-WINDOW-DRAIN-HONOR` (poll-only for
a relay-bearing live agent) appears **already satisfied** by these legs.

---

## What I need to close this (report-before-fix)

The field symptom is real (operator ground-truth), but I can't reproduce it against
current-main spt-core. Three possibilities, need doyle to disambiguate:

1. **Already fixed.** lia's box may run an spt-core **older** than the `send_windowed:217`
   / `cli.rs:5762` guards. → Confirm lia's `spt` version; if pre-guard, this is a
   version-lag, not a current-main bug (verify-on-upgrade, no code change).
2. **Adapter-side handoff.** The busy↔idle **poll→relay handoff** is the adapter's
   (spt-claude-code) job, not spt-core's `api state idle`. If the adapter does a final
   `api poll` on going idle (draining active_only) and injects the result into the
   now-idle session, that's an adapter route — outside these legs. → perri's lane.
3. **A repro detail I'm missing.** → Need the exact send form (`spt send --active-only`?
   a shell-context/`send_deferred`? a notify?), the sender's node vs lia's node
   (same-node/cross-node), and lia's controllable/relay state at send time.

**I did NOT fix anything** (the COLLAPSE WIP stays stashed — wrong leg). Which of 1/2/3,
or point me at the repro?
