{
  "summary": "Classification and causal result:\n\n1. `emphasys` is not a normal current spt-hosted lifecycle record. Its persisted `info.json` is internally hybrid: `state=\"ready_agent\"`, `status=\"online\"`, `controllable=false`, `controlled=true`, `driven_by=\"14ef…85f2d\"`, `adapter=\"omp-spt\"`, and `rest_state=\"active\"`; the perch directory also contains a `ready` marker. The reported real harness owner is gone. Because `status` is present, `spt-store` treats it as daemon-authoritative and `status=\"online\"` wins without consulting the recorded owner PID, endpoint type, or ready marker. This directly produces the false ONLINE half.\n\n2. A daemon stop/start cannot repair that hybrid with the current gates. `restart_resume_gate` skips every `state != live_agent` record and every `controllable != Some(true)` record. `reconcile_hosted_liveness` also skips `state != live_agent` before both its control-stamp sweep and its offline transition, and exempts `controllable=false` from broker-session liveness. `reconcile_once` likewise skips the non-`live_agent`, so no `BrainLifecycle` owner/orphan watcher is hosted for it. Therefore `emphasys` is neither resumed, offlined, nor unlatched after a bounce. [INFERENCE] The wrong `ready_agent` durable type is the residue/amplifier of the prior create/type defect (Issue B); current creation code now writes a `live_agent` skeleton, but `establish_perch` still preserves a pre-existing nonempty type on an ordinary live-agent bind, so an already-corrupt `ready_agent` record is sticky across every rebind. The prior rest-state carry defect (Issue A) is not causal: `rest_state=\"active\"` neither supplies liveness nor owns controller stamps.\n\n3. A correctly typed current spt-hosted `/exit` is already handled, and the existing tests cover more than control stamps. The harness child exits; the broker exit waiter emits `Exit`, calls `OutputLog::stamp_reaped()` to clear `driven_by`, `controlled`, and `viewer_count`, then removes the session. On the next reachable-broker lifecycle sweep, an online `state=live_agent`, `controllable=true` perch absent from the broker session set is marked offline. `control_stamp_lifetime.rs` tests the real child-reap control clear and its B3 arm explicitly asserts that the online/sessionless perch is also offlined. Thus the `/exit` anecdote is not evidence of a new child-wait/reap defect in the current correctly classified path; for `emphasys`, the same wrong state/hosting classification prevents the tested reconcile from running. An older running broker could also predate `stamp_reaped`, but that was not established from the inspected state.\n\n4. `api session-end` is intentionally not an offline writer and must not simply be changed to one. It is the soft session boundary used by `/clear`: it removes `ready`, preserves `info`/spool/history, and deliberately preserves a still-live listener. OMP terminal shutdown calls this soft operation, but actual liveness for a correctly hosted endpoint must come from child reap or owner-death supervision. Conflating every SessionEnd with endpoint death would regress session rotation.\n\n5. Abruptly closing an RC/raw PTY without `ctrl+b,d` is a separate transport/stream lifecycle defect. The explicit path is `NetStreamEof -> feed RestEvent::Detach -> detach_session`, and ordinary broker connection cleanup calls `detach_if`. If abrupt client death leaves its broker-retained stream unfinished, the serve loop never receives `NetStreamEof` and therefore never releases the role. `reap_dead_controller` only reaps a finished writer or a writer blocked past its deadline; its source explicitly says a truly idle severed controller whose writer is parked on `recv()` is not covered. That can create the stale `+CONTROLLED` stamp independently. A daemon bounce would clear it for a correctly classified spt-hosted record, but `emphasys` skips the boot sweep because of its `ready_agent`/`controllable=false` hybrid.\n\n6. There is also a distinct core liveness-writer omission in graceful/crash owner signoff: `BrainLifecycle::signoff_with` calls its teardown after the grace/recheck but only removes `ready`; it does not set the daemon-authoritative `status` offline. Existing graceful/crash tests assert echo ordering and ready removal, not `is_perch_alive == false`. This is important for harness-owner death/raw host termination, though it is not sufficient by itself to repair `emphasys`, because its wrong `state` prevents the lifecycle host/orphan watcher from being started.",
  "files": [
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/owlery/emphasys/info.json",
      "description": "Exact persisted hybrid state: `ready_agent` plus daemon `online`, `controllable=false`, stale `controlled`/`driven_by`, OMP adapter, and active rest intent."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/owlery/emphasys/",
      "description": "Perch listing showing durable files, including the `ready` marker; confirms this is persistent state rather than only a remote UI projection."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/owlery/emphasys/sessions.log",
      "description": "OMP boot ledger rows; establishes prior OMP sessions and gives the restart/resume input that is ignored because of the state/hosting gates."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/logs/daemon.stderr.log",
      "description": "Lifecycle log evidence: other endpoints receive `CONTROL_REAP_NO_SESSION`/self-heal events, while the inspected searches found no equivalent `emphasys` repair event, consistent with the early state gate."
    },
    {
      "path": "crates/spt-store/src/liveness.rs",
      "description": "Authoritative liveness rule: any present `status` selects daemon-hosted semantics; only `status == online` matters and PID is not consulted."
    },
    {
      "path": "crates/spt-daemon/src/livehost.rs",
      "description": "`reconcile_once`, `restart_resume_gate`, restart orphan resume, and `reconcile_hosted_liveness`. Shows the exact `live_agent` and `controllable=true` gates that exclude `emphasys`, plus the normal no-session offline/control-reap behavior."
    },
    {
      "path": "crates/spt-daemon/src/broker.rs",
      "description": "Broker controller ownership, connection cleanup, idle-controller limitations, exit waiter, and `OutputLog::stamp_reaped()` control/viewer cleanup."
    },
    {
      "path": "crates/spt-daemon/src/attach.rs",
      "description": "Remote attach lifecycle. Explicit `NetStreamEof` feeds detach/rest and calls `detach_session`; error/exit branches and retained streams explain why abrupt transport death needs guaranteed stream-close propagation."
    },
    {
      "path": "crates/spt-daemon/src/lifecycle.rs",
      "description": "Graceful and supervised-crash signoff sequencing. The teardown removes only `ready`, exposing the missing daemon-status offline write."
    },
    {
      "path": "crates/spt/src/api/reporting.rs",
      "description": "`cmd_session_end` soft-boundary semantics. Its comments explicitly preserve a live listener across `/clear`, proving this command cannot globally mean endpoint-offline."
    },
    {
      "path": "crates/spt/src/api/startup.rs",
      "description": "Bind establishment and record rebuilding. Current bind carries a prior nonempty endpoint type when the requested default is `live_agent`, making a legacy `ready_agent` type sticky; listen/bind establish ready and online state."
    },
    {
      "path": "crates/spt/src/cli.rs",
      "description": "Current endpoint-run skeleton creation writes `state=live_agent` and `status=unbound`, showing future normal creates use the corrected type and that `emphasys` is legacy/inconsistent durable state."
    },
    {
      "path": "crates/spt-daemon/tests/control_stamp_lifetime.rs",
      "description": "Real-broker tests for child-reap stamp cleanup and B3 boot/no-session repair. Arm A explicitly requires both control clear and offline status for a correctly classified spt-hosted live agent; Arm B covers already-offline sticky stamps."
    },
    {
      "path": "crates/spt-daemon/tests/endpoint_survival.rs",
      "description": "Existing real-broker daemon restart survival contract for valid spt-hosted records; any repair must preserve restart-resume ordering and avoid offlining a legitimate survivor."
    },
    {
      "path": "C:/Users/decid/AppData/Local/spt-core/adapters/_github/BigscreenVR-omp-spt/strings/omp-spt.mjs",
      "description": "Installed OMP extension sequence: `session_shutdown -> shutdownWithinBudget -> teardownSession -> endSessionWithRetry -> spt api session-end`; establishes that the adapter invokes the deliberately soft boundary on terminal shutdown."
    }
  ],
  "architecture": "Expected and observed flows\n\nA. Correct spt-hosted `/exit`\n\n`/exit` in harness\n→ harness process terminates\n→ PTY child `wait()` completes\n→ broker exit waiter sends `KIND_EXIT`\n→ `OutputLog::stamp_reaped()` clears `driven_by`, `controlled`, `viewer_count`\n→ broker removes the session\n→ daemon successfully queries the fresh broker session set\n→ `reconcile_hosted_liveness` sees `live_agent + controllable=true + status=online + no session`\n→ `BrainLifecycle::mark_offline`\n→ subsequent lifecycle/registry reconciliation unhosts and advertises the cold/resting state.\n\nThat path is source-complete and behavior-tested for a valid record.\n\nB. Actual `emphasys` bounce\n\nPersisted hybrid `ready_agent + status=online + controllable=false + stale control stamps`\n→ full daemon stop destroys broker sessions/PTY ownership\n→ fresh daemon obtains an empty/no-`emphasys` broker-session truth\n→ restart resume rejects it at `state != live_agent` (and would also reject `controllable=false`)\n→ hosted-liveness reconcile rejects it at `state != live_agent` before control cleanup and offline logic\n→ regular lifecycle hosting rejects it at `state != live_agent`, so owner-death supervision never starts\n→ `spt-store` reads the still-present `status=online` as authoritative\n→ stale ONLINE and CONTROLLED remain durable and can be re-gossiped.\n\nThis is a composition: prior create/type corruption prevents current lifecycle repair; a separate earlier detach/transport failure can be the producer of the stale control stamp. Rest-state carry is orthogonal.\n\nC. Abrupt RC/raw PTY close\n\nExpected: operator transport closes\n→ stream EOF reaches `serve_attach`\n→ controller rest edge\n→ `detach_session`\n→ broker clears controller and stamps.\n\nFailure: operator dies without explicit detach\n→ retained transport stream never becomes EOF\n→ serve worker remains attached\n→ controller writer is idle on its queue, neither finished nor write-blocked\n→ `reap_dead_controller` deliberately cannot prove it dead\n→ `controlled` remains latched even though the viewport is gone.\n\nThis is a transport ownership/stream-finalization defect, not a child-reap defect. The endpoint child can remain legitimately online while only CONTROLLED must clear.\n\nD. Harness-owner graceful/crash signoff\n\nOwner watcher detects the recorded harness owner is gone\n→ echo/commune ordering and grace recheck run\n→ signoff teardown removes `ready`\n→ current code does not change daemon-authoritative `status`\n→ the endpoint can remain logically online or be re-hosted despite teardown.\n\nSource-level fix proposal\n\n1. Repair endpoint-type provenance at the bind seam. A live harness bind must promote a legacy `ready_agent` prior record to `live_agent` instead of blindly preserving it. Preserve genuine custom endpoint types, but do not preserve a known ReadyAgent type through a LiveAgent bind. Current fresh endpoint-run skeletons already write `live_agent`; this closes the legacy/rebind hole without inventing another convention.\n\n2. Add a conservative boot repair for existing hybrid records before restart-resume/reconcile decisions. Only normalize when core-owned evidence is conclusive—for example, daemon `status` is present and the recorded adapter resolves to a harness/live-capable bind provenance. Do not convert arbitrary `ready_agent` records based only on their name. For a dead-owner legacy hybrid that cannot safely be resumed, mark it offline and clear impossible control stamps rather than guessing a launch.\n\n3. Move no-session control cleanup before the `state == live_agent` liveness gate, or make it a separate broker-ownership reconciliation. When a successful broker query proves no session owns an endpoint, persisted broker-owned `controlled`/`driven_by`/`viewer_count` cannot remain. Keep the current fail-safe behavior of doing nothing when the broker is unreachable. This repairs stale stamps independently of endpoint taxonomy and handles legacy hybrids such as `emphasys`.\n\n4. Make `BrainLifecycle` terminal signoff an actual liveness transition: after echo and the grace/recheck, atomically/conditionally remove `ready` and set daemon-managed `status=offline`. The mutation must be conditional on the same session/owner generation used by the watcher so a late old watcher cannot offline a newly rebound session. Keep `api session-end` soft; globally offlining it would break `/clear` and listener continuity.\n\n5. Fix raw RC close at stream ownership, not with a display special case. A physical operator-connection close must synthesize/propagate terminal EOF for every attach stream it owns, so `serve_attach` executes the existing detach path. Also use a session/controller-generation guard so cleanup from an old stream cannot detach a newer `--take` controller. If the transport permits a blackhole without a close signal, add an explicit attach-stream lease/heartbeat; a mere output-write test cannot detect an idle dead controller.\n\n6. Preserve restart ordering: valid previously-online spt-hosted endpoints must still pass restart-resume before the no-session offline sweep. The repair must not turn a legitimate daemon restart into mass-offline and must continue skipping all destructive inference when broker truth is unavailable.\n\nFocused regression tests\n\n- Correct spt-hosted terminal exit: real broker + hosted child; terminate the child while controller remains connected; assert session disappears, all control/viewer stamps clear, status becomes offline after the real reconcile, and no endpoint is resurrected. Retain/extend the existing `control_stamp_lifetime` gate.\n- Soft session boundary: call `api session-end` for a live listener as `/clear` does; assert spool/info/relay and online liveness remain. This prevents the tempting but incorrect global `session-end -> offline` fix.\n- Graceful terminal signoff: seed `status=online`; execute `graceful_signoff`; assert echo precedes teardown, ready is removed, status is offline, and `is_perch_alive` is false.\n- Crash/owner-death signoff: dead stable `parent_pid`, real grace/recheck; assert the same offline result. Add a rebound race arm where session/owner generation changes during the grace window and the old watcher must not offline the replacement.\n- Legacy `emphasys`-shape boot repair: `state=ready_agent`, `status=online`, `controllable=false`, dead owner/no broker session, `controlled=true`, nonempty `driven_by`; run the real boot repair/reconcile and assert offline plus all control stamps cleared. Assert a genuine ReadyAgent without live-harness provenance is unchanged.\n- Valid harness-hosted live owner: `live_agent`, `controllable=false`, live parent/relay; run boot repair and hosted reconciliation; assert it remains online and is never misclassified as broker-sessionless.\n- Valid daemon restart survival: previously-online `live_agent`, `controllable=true`, resumable ledger; use a fresh real broker and assert restart resume occurs before offline reconcile and the endpoint returns online. Preserve `endpoint_survival` coverage.\n- Abrupt raw RC close: keep hosted child alive and idle, acquire control, kill/drop the operator transport without sending detach, then assert the stream closes, broker session remains, endpoint remains online, and `controlled`/`driven_by` clear within a bounded interval. This must not rely on child output, because the defect is specifically the idle-writer case.\n- Takeover race: close the old raw connection concurrently with a new `--take`; old close cleanup must not detach or clear the new controller generation.\n- Broker unavailable: run all cleanup passes with session query failure and assert no endpoint is offlined or unlatched from guessed absence."
}