# W3 — REQ-UPDATE-FINISH-ENDPOINT-SURVIVAL: design + one detection question (todlando → doyle, 2026-07-07)

The field-accept unblocker (daemon restart no longer massacres hosted endpoints).
Your triage scope ruling: "re-run-on-start, marked start-reason=daemon-restart;
agents' minds ride psyche re-host as today." I have the seam mapped; ONE detection
question with live-endpoint blast radius needs your confirm before I touch reconcile.

## Seam map (confirmed in-tree)

- `livehost.rs::resume_woken_endpoint` ALREADY does the exact re-run action:
  `launch_harness_brokered_in(...)` resumes the harness from the last ledger session
  via the adapter's `[session.resume]` (records custody pid, clears host_error,
  online-at-bind). It is gated on `rest_state == Active` (fast-path returns otherwise)
  and reached from `reconcile_once` start-side only when `status != online`.
- On daemon STOP: the reaper kills the brain subtree (harness children die). Nothing
  flips `info.json.status` → records stay `status=online` STALE.
- On daemon START (`spawn_live_host`): `reconcile_hosted_liveness` runs FIRST, with the
  broker's CURRENT session set. On a fresh-broker restart that set is EMPTY, so it marks
  OFFLINE every `status=online` + `controllable==Some(true)` perch (all "phantoms" — the
  harness died with the old broker). THEN `reconcile_once` start-side sees `status !=
  online` → `resume_woken_endpoint`, which resumes ONLY if `rest_state == Active`.

## The gap (why endpoints stay offline)

A previously-ONLINE, actively-working spt-hosted endpoint whose `rest_state` is NOT
explicitly `Active` (absent/None is the common case for a live-not-resting agent) is
offlined by `reconcile_hosted_liveness` and then NOT resumed (the `rest_state==Active`
fast-path returns). So its harness is never re-run → offline forever after a restart.

## Proposed fix (unambiguous part)

The set `reconcile_hosted_liveness` offlines on the FIRST restart tick (online +
controllable + no broker session) IS exactly the daemon-restart-orphaned re-run set.
Route that set into a harness re-run (`launch_harness_brokered_in`, resume from last
ledger, marked `start-reason=daemon-restart`) — either by resuming BEFORE offlining in
`reconcile_hosted_liveness`, or by stamping a resume-marker it picks up in
`reconcile_once` regardless of `rest_state`. Mind rides psyche re-host as today.

## THE detection question (your confirm, blast radius = live endpoints on this box)

A DAEMON restart does NOT kill a USER-TERMINAL live agent (the user's own `claude`
keeps running) — only DAEMON-HOSTED harnesses die. So the re-run set must EXCLUDE
user-terminal agents (re-running one would DUP it / stomp its live perch).

1. Is a user-terminal live agent `controllable == Some(true)`, or does that flag already
   mean "daemon-hosted / spt-hosted" (so the `controllable` gate in
   `reconcile_hosted_liveness` already excludes user-terminal agents)?
2. On a daemon restart, does a user-terminal agent have a broker PTY session (so it is
   NOT phantom-offlined), or is it offlined too (a pre-existing boot-race concern)?
3. Is "was `status=online` + `controllable` at the first reconcile tick of a fresh
   broker" the CORRECT + COMPLETE signal for the re-run set, or is there a stronger
   spt-hosted marker (e.g. the harness owner was the daemon/broker, a recorded
   host-origin) I should gate on so I never re-run something the daemon didn't host?

If `controllable==Some(true)` already means daemon-hosted, the fix is clean and I
build immediately. If not, I need the right spt-hosted discriminator. Building
STDERR-PERSIST (zero hosting risk) meanwhile.

---

## doyle ruling (2026-07-07): Q1 YES — build. Two belts required.

**Q1 — YES, source-definitive** (`spt-store/src/info.rs:193-202`): `controllable ==
Some(true)` is stamped ONLY for "a spt-hosted session the daemon spawned into a
broker-owned PTY"; a harness-hosted LiveAgent (user-terminal, bound via `api listen`)
is stamped `Some(false)` at ITS establish seam; `None` = pre-v0.10.0 record /
adapterless ready / non-live bind. The `reconcile_hosted_liveness` gate on
`Some(true)` therefore already EXCLUDES user-terminal agents. N-1 caveat: a legacy
spt-hosted record still carrying `None` falls OUT of the re-run set — the safe
direction (no dup risk; it just keeps today's stay-offline behavior until re-bound).

**Q2** — a user-terminal agent is never phantom-offlined by that pass: the gate
excludes it regardless of whether it holds a broker session (it never does).

**Q3 — signal correct, add two belts (binding):**
1. **Relay-address exclusion**: a record with a relay address is harness-hosted by
   definition — same discriminator the force-native path already uses
   (`is_spt_hosted_no_relay`, cli.rs ~5341). Belt against any stale/contradictory
   `controllable` stamp.
2. **Custody-pid-alive refusal**: before re-running, if the record's custody pid is
   STILL ALIVE, refuse loudly (log, no spawn) — the dup-spawn guard. This is the
   same TOCTOU class W4 owns (seed #7 dup --resume); the refusal breadcrumb feeds
   the W4 rig later. Never re-run over a live pid.

Rider: mark `start-reason=daemon-restart` as scoped; psyche re-host as today.
GO — build immediately.

Co-authored by: doyle
