{
  "summary": "RCA: `emphasys` is not being restored as a live broker session. Its ONLINE+CONTROLLED presentation is durable-file resurrection: an old harness-hosted `ready_agent` record was incorrectly converted to daemon-authoritative `status:\"online\"`; the recorded owner PID is dead, but all liveness/address readers consequently ignore that PID. On each cold daemon start the new broker begins with an empty in-memory session table, while livehost skips `emphasys` because it is `ready_agent` rather than `live_agent`; its control cleanup is additionally restricted to `controllable==Some(true)`, while `emphasys` is `false`. Thus restart neither reconstructs a session nor corrects the stale status/control/address/ready artifacts. This is unrelated to the prior rest-state carry defect (Issue/Defect A) and to endpoint-create/no-op rest transitions; it is the exact field activation of the gateway RCA's previously latent Defect B (`cmd_listen` manifest-only ONLINE stamping), plus a separate overly narrow boot reconciliation/control cleanup defect. `/exit` shares the missed-reconciliation mechanism when the endpoint record has this wrong `ready_agent`/`controllable=false` classification. Abrupt raw PTY/controller close is a separate transport-lifecycle defect: the client can disappear without a stream FIN, leaving the broker controller slot alive; restart persistence is then amplified by the same overly narrow boot cleanup.",
  "files": [
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/owlery/emphasys/info.json",
      "description": "Current one-line durable truth: `state:\"ready_agent\"`, dead `pid:31352`, session `019f657c-b509-7000-86f2-0cc67e63a2b7`, `status:\"online\"`, `controlled:true`, `driven_by:<local node>`, `rest_state:\"active\"`, `adapter:\"omp-spt\"`, and `controllable:false`. This internally inconsistent combination is the stale presentation source."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/owlery/emphasys/sessions.log",
      "description": "Historical ledger only. Five boot rows: 2026-07-15 09:59:11/12, 10:29:27 twice, and latest 11:14:59Z for the session ID still in info.json. A ledger row is resume material, not evidence of a live broker session."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/owlery/emphasys/ready",
      "description": "Zero-byte ready marker still exists. Directory evidence also shows info.json last changed ~14h ago and ready/address-era files ~15h ago; no lifecycle owner removed them after the harness disappeared."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/owlery/.registry",
      "description": "SQLite relay-address registry currently contains the stale `emphasys` route reported by the read-only CLI as `127.0.0.1:61088`; the read-only TCP probe failed. The row survives because registry cleanup delegates to status-authoritative liveness."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/logs/daemon.stderr.log",
      "description": "Latest observed cold-start sequence: lines 1-3 broker starts (pids 73156 then 91480), lines 8-9 brain pid 47668 connects with `start-reason cold`; lines 42-62 immediately reap/offline sessionless `deployah`, `doyle`, `lia`, and `perri`, while no corresponding `emphasys` line occurs. Line 25's pid 82868 is a competing start that fails bind at lines 27-28, not a restored emph session. Searches across current log ranges through line 14000 found no `emphasys` spawn, attach, detach, resume, reconcile, or control-reap event."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/logs/daemon.stderr.log.1",
      "description": "Prior cold restart shows the same contrast: lines 897-901 create a new broker/brain and identify `start-reason cold`; lines 923-934 sweep sessionless live-agent records, but no `emphasys` event appears. Earlier lines 1-17 are brain-only update generations and explicitly resume seven broker cursors, demonstrating the distinction between brain restart (broker/session table survives) and full daemon restart (new broker/table)."
    },
    {
      "path": "crates/spt/src/api/startup.rs",
      "description": "Primary earliest wrong write. `establish_perch` writes the post-bind state and ready marker at lines 277-463. Harness-hosted bind stamps `controllable=false`. At lines 625-640, `cmd_listen` derives `live_capable` solely from manifest `[session.psyche_init]` and writes `status=online` without checking the post-bind endpoint state. For an omp-spt `ready_agent`, that turns an external PID-owned relay into status-authoritative liveness. Lines 673-684 run the relay indefinitely; the parent watchdog at lines 498-530 exits the process but performs no state/ready/address cleanup, and its claim that PID death flips the perch offline is false once status was written."
    },
    {
      "path": "crates/spt-store/src/liveness.rs",
      "description": "Amplifier. `is_perch_alive` lines 115-146 returns true immediately for any `status==online` and never probes PID. `is_registry_entry_alive` lines 151-169 likewise preserves an online registry row regardless of its dead registered/recorded PID. This is why endpoint list/status and relay address survive restart."
    },
    {
      "path": "crates/spt-store/src/registry.rs",
      "description": "Lines 56-79 register relay address+owning PID; lines 109-143 clean stale rows through `is_registry_entry_alive`. Because emph carries `status=online`, the dead relay PID cannot evict its `127.0.0.1:61088` row."
    },
    {
      "path": "crates/spt-daemon/src/broker.rs",
      "description": "Broker session-table truth and control lifecycle. `Broker` owns `sessions: Arc<Mutex<HashMap<...>>>` at lines 2517-2530 and every new broker constructs it with `HashMap::new()` at lines 2688-2695; there is no disk restoration of PTY sessions. The PTY exit waiter at lines 3349-3399 emits exit, clears control/viewer stamps via `stamp_reaped`, then removes the session. `stamp_reaped` clears driven_by, controlled, and viewer_count at lines 1340-1355. A concurrency risk remains: KIND_SESSIONS convergence can snapshot the still-present session and reassert controlled after `stamp_reaped` but before/after removal."
    },
    {
      "path": "crates/spt-daemon/src/livehost.rs",
      "description": "Boot restoration/reconciliation gap. `resume_restart_orphaned_endpoints` lines 529-608 only resumes eligible previously-online spt-hosted live agents and skips relay-present/non-live states. `reconcile_hosted_liveness` lines 644-747 first skips every non-`live_agent`; its stamp cleanup then additionally requires `controllable==Some(true)`. Therefore emph (`ready_agent`, false) receives neither control cleanup nor offline transition. `query_live_session_endpoints` lines 749-761 reads the real broker table. The boot loop lines 983-1045 runs resume then session reconciliation from tick 1, but these predicates exclude emph."
    },
    {
      "path": "crates/spt-daemon/tests/control_stamp_lifetime.rs",
      "description": "Existing tests prove normal PTY child reap and boot cleanup only for `live_agent` + `controllable=true`. The B3 scenario at lines 299-445 should be extended with ready-agent/false/None arms and `viewer_count`, exposing the exact emph hole."
    },
    {
      "path": "crates/spt-daemon/tests/endpoint_survival.rs",
      "description": "Existing full-daemon restart coverage focuses on previously-online spt-hosted live agents that should be respawned. It does not cover a dead harness-hosted ready-agent relay that must remain offline and must not be reconstructed."
    },
    {
      "path": "docs/GATEWAY-LIVENESS-DISPATCH.md",
      "description": "Prior classification evidence. Lines 19-26 identify rest-state carry as separate Defect A and manifest-only `cmd_listen` ONLINE stamping as latent Defect B, explicitly warning of orphan-listener falsely-ONLINE amplification. `emphasys` is that amplification now realized."
    },
    {
      "path": "docs/KNOWN-HAZARDS.md",
      "description": "Load-bearing constraints: daemon-hosted liveness must use explicit lifecycle truth; external listeners use PID truth; soft cleanup preserves durable state but removes online/ready ownership; control stamps must never outlive broker sessions; reconciliation must skip mutation when broker truth is unreachable."
    }
  ],
  "architecture": "CAUSAL TIMELINE AND CURRENT SESSION TRUTH\n\n1. Historical endpoint boots: `sessions.log` records five boots on 2026-07-15, ending at 11:14:59Z with session `019f657c-b509-7000-86f2-0cc67e63a2b7`. The current `info.json` still names that session, but the ledger is historical resume material only.\n2. Earliest wrong durable state: a later harness-hosted bind/listen produced `state=ready_agent`, `controllable=false`, and an actual relay-process PID. `cmd_listen` then inspected only the omp-spt manifest's `psyche_init`, decided it was `live_capable`, and wrote `status=online`. That is the first category error: endpoint state/hosting mode says external PID-owned ready relay; status says daemon-owned lifecycle.\n3. The relay/harness subsequently disappeared. PID 31352 is confirmed dead; TCP 127.0.0.1:61088 refuses; no live harness or PTY is observable. The listener has no robust teardown owner: the watchdog calls process exit, while normal/abrupt process loss leaves ready/status/address durable artifacts. Once `status` exists, PID death no longer affects liveness.\n4. Latest full daemon cold start creates a fresh broker. Source constructs `sessions=HashMap::new()`; current logs show `start-reason cold`, not a brain-only update. The logs show other configured/resumable sessions being attached or swept, but no emph spawn/attach/resume. [INFERENCE] The current broker has no `emphasys` session: there is no direct public read-only session-table command, so this is established by the new empty-table construction, cold-start logs, absence of every emph session event through the searched current/prior log ranges, `controllable=false`, dead PID, and failed relay probe. It is not presented as a directly queried table row.\n5. Restart does not reconstruct emph. `resume_restart_orphaned_endpoints` excludes the non-live/relay-present shape. The next boot reconciliation reads the real empty broker set, but immediately skips `state!=live_agent`; even if that gate moved, the existing control cleanup requires `controllable=true`. Hence no OFFLINE write and no control-stamp clear.\n6. Every reader then reproduces the stale presentation from disk: endpoint liveness sees status online and ignores PID; registry cleanup sees status online and retains the dead address; endpoint-info derives `attached_node` from driven_by/controlled. No live object is restored—the UI is faithfully rendering wrong durable metadata.\n\nRELATION CLASSIFICATION\n\n• Prior stale-rest/rest-state carry Defect A: NOT causal. emph still has `rest_state:\"active\"`; no wake/suspend/create transition runs during this restart path. The carry-forward fix at startup.rs:414-423 is present. The endpoint-create/effective-rest NoOp defect is likewise separate.\n• Prior gateway-RCA latent Defect B: DIRECT causal match. The exact warned-about shape was manifest-only `cmd_listen` ONLINE stamping causing an orphan listener to remain falsely ONLINE. emph's omp-spt ready_agent activates it.\n• Daemon restart: exposure/amplifier, not creator. A full restart deletes the actual in-memory session table but preserves info.json/ready/registry by design; boot reconciliation should make those artifacts honest and currently does not for this state/mode.\n• `/exit`: normal spt-hosted `live_agent` behavior has two stages—PTY child exit waiter clears stamps/removes the broker session; livehost's next session-table reconciliation marks status offline. `/exit` itself does not write OFFLINE. If the same endpoint has been preserved as `ready_agent`/`controllable=false`, stage two is skipped, so the observed not-offline result is the same classification/reconciliation defect. If reproduced on a correctly classified `live_agent`/true record, it is a separate lifecycle/race defect and should be treated as such rather than blamed on rest state.\n• Abrupt raw PTY/controller close without `ctrl+b,d`: SEPARATE transport lifecycle defect. A client can die without sending net-stream FIN; the broker-retained stream outlives the client Brain connection, `serve_attach` never reaches EOF/detach, and the controller slot remains. A full broker restart erases that in-memory slot, but the stale disk stamps survive because the boot sweep excludes ready_agent/false. Thus the raw-close origin is separate; restart persistence shares the reconciliation hole.\n\nSOURCE-LEVEL FIX FOR DOYLE TRIAGE\n\nA. Correct the creator (`startup.rs`): after `establish_perch`, gate daemon `status=online` on the actual persisted endpoint state and hosting semantics, not manifest capability alone. A `ready_agent` harness relay must remain PID-authoritative (status absent) even if its adapter also declares psyche_init. Preserve live-agent psyche hosting deliberately; do not globally remove the live-capable behavior.\nB. Add compatibility/self-heal for already-written rows (`livehost.rs`): on a reachable broker query, inspect relay-owned/non-live rows that carry status online. When their recorded listener PID is dead, mark them offline and clean stale ready/address ownership. This is required to heal emph and existing installs; fixing only the creator strands old records forever. Never mass-offline on broker-query failure.\nC. Split reconciliation predicates (`livehost.rs`): control metadata is broker-owned independently of endpoint type/hosting mode. For every perch absent from the reachable broker session set, clear `controlled`, `driven_by`, and `viewer_count` regardless of `state` and `controllable`. Keep the `live_agent && controllable==true` predicate only around the OFFLINE transition, because a healthy harness-hosted relay legitimately has no broker PTY. This is the minimal safe controlled-stamp restart fix.\nD. Make listener teardown ownership explicit: normal relay return/parent-watch exit should session-CAS cleanup its own ready/address and online status. Keep PID/boot reconciliation as the crash belt because hard process termination bypasses RAII/Drop and `std::process::exit` does not unwind.\nE. Fix controller transport independently: bind attach-stream lifetime to the owning client connection or a bounded lease/heartbeat, so physical client death cancels retained net streams and executes detach. `ctrl+b,d` can remain an explicit fast path, but correctness cannot depend on it.\nF. Close the reap/convergence race: the current exit waiter clears stamps while the session can still be snapshotted by KIND_SESSIONS convergence. Remove/deactivate the session first and ensure a previously captured convergence snapshot cannot reassert stamps after reap—e.g. session/controller generation validation at the write boundary or a serialized broker-owned stamp transition. Merely swapping two calls is insufficient if an old off-lock snapshot can write late.\n\nRISKS/INVARIANTS\n\n• Do not use absence from the broker table to offline all harness-hosted relay endpoints; they legitimately have no broker PTY. Split metadata cleanup from liveness transition.\n• Clear stamps only after a successful broker sessions query; unreachable broker is unknown truth, not an empty set.\n• Do not clear a new session's metadata from an old session's teardown. Cleanup must be session/generation guarded.\n• Ready/address cleanup must remain soft: preserve info, spool, digest, history, and session ledger.\n• The current address row illustrates why `lookup_address` is diagnostic only; delivery should continue through `resolve_address`, with fixed ownership classification allowing its stale cleanup to work.\n\nFOCUSED TESTS\n\n1. Startup regression: seed a prior `ready_agent`, invoke the live-capable omp/mock `cmd_listen --once` bind seam, and assert it does not gain daemon-authoritative status; after its owner PID dies, `is_perch_alive==false` and registry resolution removes the address. This must fail against the current manifest-only predicate.\n2. Legacy compatibility test: seed the exact emph shape—ready_agent, controllable=false, status online, dead PID, ready file, address, controlled/driven_by/viewer_count—and run a boot tick against a reachable empty real broker. Assert offline, no ready/address, all three control fields clear, durable history/spool preserved, and no session spawned.\n3. Extend `control_stamp_lifetime` B3 with `controllable=false` and `None`, plus non-live states, and assert sessionless reconciliation clears controlled, driven_by, and viewer_count without incorrectly offlining a live PID-owned relay. Keep the existing true/live-agent arm asserting OFFLINE.\n4. `/exit` real-broker test: spawn an actual hosted child, attach controller, make the child exit, query sessions until absent, run reconciliation, then assert status offline and all three stamps clear. Repeat with a prior ready-agent skeleton promoted through the real bind path to catch state-preservation/classification mistakes.\n5. Exit-vs-KIND_SESSIONS race test: barrier the exit waiter after/deactivation and a concurrent sessions snapshot/convergence; after both complete, stamps must remain clear. This defends the plausible late-reassert bug rather than call order.\n6. Listener parent-death subprocess test: run real `cmd_listen`, terminate/reap its parent without an explicit detach, and assert bounded convergence to offline plus ready/address removal after the next daemon tick/restart.\n7. Raw-controller close integration: attach over the real transport, kill the client without FIN or `ctrl+b,d`, and assert the broker eventually removes the controller slot and clears stamps while leaving the PTY session itself alive/attachable. Then cold-restart and assert no stale controlled/viewer metadata returns.\n8. Endpoint-survival negative arm: cold restart with a dead harness-hosted ready-agent relay must not resume a PTY from sessions.log. This distinguishes historical ledger material from a live session and prevents a fix from converting cleanup into accidental resurrection."
}