{
  "summary": "## Corrected RCA\n\n### Established field facts\n\n- **[FIELD FACT]** `gaki-n` was genuinely **spt-hosted**; it was launched from an **elevated Windows Terminal**. The former “probably harness-hosted / harness-only” explanation is retracted.\n- **[FIELD FACT]** `spt rc gaki-n` reached a routable registry owner and returned the exact remote-session refusal: `no live session ... it may have ended, or the registry row is stale`.\n- **[FIELD FACT]** On the same physical node, `spt rc slammie-n` still worked.\n- **[FIELD FACT]** A canonical `perri -> gaki-n` send landed. A later canonical shortform `slammie-n -> gaki-n` send failed.\n\n### What the exact RC error proves\n\nThe error is not a generic pipe, ACL, QUIC, or daemon-connect failure. In `crates/spt/src/rc.rs`, the node-qualified stale-row wording is emitted only after the client has resolved a remote owner and the remote attach serve returns `NoLiveSession`. On the target node, `crates/spt-daemon/src/attach.rs::resolve_local_session` resolves the requested endpoint solely from that reached broker's `brain.sessions()` reply. Therefore:\n\n1. the operator-side daemon/broker was reachable;\n2. registry resolution selected a routable target node;\n3. the QUIC attach stream reached that node's dispatcher/attach server;\n4. the server-side brain could query its broker session table;\n5. **that reached broker table had no `HostedSession.endpoint == \"gaki-n\"` at lookup time**.\n\nThe working `slammie-n` attach further falsifies a node-wide attach failure. The differential is endpoint/session-table-specific, or it is a same-node split between more than one broker/socket universe.\n\n## Ranked causal candidates\n\n### 1. Highest-value candidate: two broker/socket universes over one physical Windows state tree\n\n**Mechanism, source-grounded:**\n\n- `spt_store::perch::spt_home()` returns the raw non-empty `SPT_HOME` as a `PathBuf`; it does not canonicalize path spelling.\n- `spt_daemon::endpoint::home_tag()` hashes that `PathBuf` directly, and `broker_socket_name()` / `seed_socket_name()` incorporate the hash.\n- **[INFERENCE]** Windows normally treats path case and several alias spellings as the same filesystem location, while Rust `Path` hashing is lexical. Thus strings such as `C:\\Users\\X\\...\\spt-core` and `c:\\users\\x\\...\\spt-core` can address the same owlery and `identity/node.key` but derive different broker and seed socket names.\n- The Windows de-elevation path deliberately preserves an explicit `SPT_HOME` override verbatim. `deelevate.rs::apply_env_overrides` overlays it into the desktop user's `CreateEnvironmentBlock`; the comments name preventing a wrong-home daemon/socket as the reason. Therefore elevation does not normalize away an alias: an elevated launch carrying alias B can de-elevate to the ordinary user token while retaining alias B.\n- Broker spawn stores session truth only in its in-memory `sessions: HashMap<u64, HostedSession>`. The spawned PTY child inherits the hosting broker's environment, so its bind writes through that broker's `SPT_HOME` spelling.\n- Registry truth is separate: `RegistryHost::advertise_local` enumerates the on-disk owlery and derives status from the perch record. It does **not** join each row against `Broker.sessions`.\n\nThis admits the exact split:\n\n- broker/daemon **A** hosts `slammie-n`;\n- broker/daemon **B** hosts `gaki-n`;\n- A and B use lexically different home strings/socket names but reach the same physical owlery and node identity;\n- A scans the shared gaki perch and authors an Active row although A has no gaki `HostedSession`;\n- the remote node's last-known direct address for the shared node key reaches A;\n- remote `rc slammie-n` succeeds against A, while remote `rc gaki-n` reaches A and returns the exact stale-row error.\n\n**Why the message differential is compatible:** the WAN receiver first checks that the perch exists, then tries live TCP, then broker-native injection, and finally atomically spools. `WanOutcome::Spooled` is a confirmed successful WAN outcome. A can therefore accept/spool a message for the shared gaki perch without owning gaki's PTY; B can later drain/inject the same physical spool. A same-node shortform or force-native path originating under slammie's A universe, by contrast, can require A's broker session/translation record and fail. The captured WAN outcome token (`spooled` versus `delivered`) is therefore load-bearing evidence.\n\n**Predictions:**\n\n- Two daemon/broker process trees or two distinct broker/seed pipe-name pairs exist, likely under the same desktop user token after de-elevation.\n- Their read-only `KIND_SESSIONS` replies are disjoint: A contains slammie and not gaki; B contains gaki and not slammie.\n- Their exact `SPT_HOME`/`LOCALAPPDATA` strings differ, while filesystem identity/canonical path shows they reach the same physical directory and load the same `identity/node.key`.\n- Switching only the caller's home spelling changes which broker the local probe reaches.\n- Remote behavior can flip with whichever same-key daemon address most recently populated the peer-address cache.\n- The single physical `daemon.pid` breadcrumb can be overwritten by either process and is not enough to disprove two live daemons.\n\n**Falsifiers:** one broker/daemon PID, one derived broker socket name, identical exact home strings, and a read-only session query proving that same reached broker contained gaki at the failure instant. Also falsified if the two candidate homes have different physical filesystem identities and there is no copied/shared owlery or copied node key.\n\n### 2. Strong fallback: ordinary broker reap followed by a stale Active window, prolonged by a stalled reconcile/advertisement path\n\n`broker.rs` removes a session from the table in the PTY exit waiter immediately after the child is reaped. Perch status is not cleared atomically with that removal; `livehost::reconcile_hosted_liveness` later pulls `KIND_SESSIONS` and offlines an online, controllable perch absent from the broker set. Registry advertisement is another asynchronous scan/push. Thus a real source path exists for a transient Active row with no session:\n\n1. gaki is correctly spawned and bound;\n2. child/session exits or a daemon restart destroys the broker-held PTY;\n3. broker table no longer contains gaki;\n4. local/remote registry snapshots still carry the last Active row until reconciliation plus a newer advertisement arrives.\n\nThe v0.23-era lifecycle record strengthens this candidate. `docs/NEXT-MILESTONE-LIFECYCLETRUTH-TRIAGE.md`, written after v0.23, states that `daemon stop` + `start` killed all hosted endpoints and they stayed offline; automatic re-run-on-start was a later W3 design. The v0.23 changelog fixed duplicate-run and stale-control cases, but it did not claim daemon-restart endpoint survival.\n\n**Predictions:** one broker contains slammie but not gaki; gaki's PTY/harness is actually dead, or the process the operator sees is an orphan no longer broker-owned. With healthy livehost and pump, the stale row should converge away within a reconcile and gossip cadence. If it persists, `pump_heartbeat` should be stalled, the livehost broker query should be failing/skipped, or a lower-level record-shape exclusion should apply. The exact `NoLiveSession` reply, rather than an IPC deadline, argues that the broker/dispatcher was healthy enough to answer and against a total broker wedge.\n\n**Falsifiers:** gaki's PTY child is verifiably owned by the same broker that answered RC and its `KIND_SESSIONS` row exists at that instant. Persistence for many healthy reconcile/gossip intervals also falsifies a mere timing window and promotes candidates 1, 3, or 4.\n\n### 3. Persistent malformed pre-bind online record that reconcile intentionally exempts\n\n`docs/KNOWN-HAZARDS.md` §5.16 records a field-proven race: a daemon `mutate_info` RMW could overwrite a completed bind with its stale pre-bind snapshot plus `status=online`. The surviving record had `status=online` but the wrong `state` or missing `controllable=Some(true)`. The broker could initially serve the session; after child death, `reconcile_hosted_liveness` silently skipped it because it was not shaped as a broker-hosted live agent. Registry advertisement then continued treating the online record as alive/Active.\n\nThis is almost the exact durable “Active row, no HostedSession” producer. It was a known/fixed v0.23-era class, so it is not the first explanation for a correctly running v0.23 image; however, it remains relevant if:\n\n- the resident broker/brain was older than the installed CLI;\n- the perch was corrupted before the fix and never cleanly rebound;\n- an analogous multi-writer race recreated the malformed shape; or\n- the elevated launch talked to a different resident image/universe than assumed.\n\nThe v0.21+ `daemon status` surface explicitly distinguishes installed CLI version from resident `broker_image`; the v0.23 changelog also says one agent could no longer corrupt another's session identity, confirming that cross-session/perch corruption was active field pressure in this release family.\n\n**Prediction:** gaki `info.json` says `status: online`, but `state != live_agent` or `controllable != true`; broker sessions omit gaki; pump heartbeat can remain healthy; no `LIVENESS_RECONCILE_OFFLINE:gaki-n` appears because the guard skips it. Remote row can remain Active indefinitely.\n\n**Falsifier:** a coherent `state=live_agent`, `controllable=true`, `status=online` record plus a healthy, repeated reconcile against the same broker should be offlined when no session exists.\n\n### 4. Receiver-held stale epoch lease / epoch reset\n\nRegistry merge is per `(endpoint_id,node)` and accepts only a strictly greater monotonic epoch. `KNOWN-HAZARDS` §4.11 documents that losing/resetting `identity/epoch` while retaining the node key makes peers drop every fresh lower-epoch update. A pre-existing gaki Active row can therefore remain frozen after the owner has corrected it, while slammie's equally old Active row happens still to be true.\n\nThis is field-consistent but has no direct elevation-specific trigger unless elevation selected a copied/alternate state universe retaining `node.key` but not its epoch counter. It is lower-ranked than the shared-physical-home split.\n\n**Predictions:** owner's local gaki view is already suspended/offline, but remote snapshots retain a higher-epoch Active row; all newly authored rows from that node are rejected as stale until the counter catches up. Other recently changed endpoints on the node also fail to converge.\n\n**Falsifier:** remote gaki row epoch advances normally from the owner, or owner's current epoch is greater than the receiver's stored gaki epoch.\n\n### 5. Duplicate endpoint instance / wrong node selection\n\nThe resolver chooses an explicit `@node` match, else local-node wins, else the sole routable instance, and refuses rather than guessing across distinct active nodes. A stale/colliding row could route RC to a node that owns a gaki perch but no gaki session. Compare the full node key in the chosen row/error context, not only a hostname label. This is less explanatory if the row was explicitly pinned to the intended node key.\n\n### Direct elevation/integrity mismatch is not a sufficient selective cause\n\nThe code explicitly guards against an elevated daemon: on Windows it obtains the unelevated desktop shell primary token, builds that user's environment, preserves explicit `SPT_HOME`, respawns detached, and exits the elevated copy. If no unelevated target exists, it serves consistently elevated and logs that fact.\n\nAn integrity/ACL mismatch by itself predicts a **pipe- or daemon-wide** failure for an unelevated local client, not “gaki absent while slammie is attachable from the same reached broker.” A remote attach also enters through QUIC and performs the session lookup inside the target daemon's own token context; it does not require the remote operator to open the target's local elevated named pipe. Therefore:\n\n- **[SOURCE-GROUNDED CONCLUSION]** elevation is a plausible selector of a different user/home/socket universe;\n- **[SOURCE-GROUNDED CONCLUSION]** elevation is not, by itself, a mechanism that deletes only gaki from one broker's session table while leaving slammie attachable.\n\n## Minimal non-mutating field probes, in discriminating order\n\n1. **Recover existing evidence; do not resend.** Record the perri WAN acknowledgment token: `how=spooled` versus `how=delivered`. `spooled` proves only that the reached node had a perch and accepted the spool row. For a relay-less spt-hosted endpoint, a contemporaneous `delivered` normally means live broker-native injection succeeded on that reached daemon; if gaki displayed a message that the sender reported as `spooled`, later drain by a second broker remains fully possible.\n2. **Compare exact environment strings in the elevated and ordinary shells:** `SPT_HOME` including case/slashes/trailing components, `LOCALAPPDATA`, `USERPROFILE`, username/SID, logon session, and integrity level. Preserve exact strings; do not normalize before comparison.\n3. **Resolve physical directory identity read-only:** compare canonical final path and Windows file ID/volume serial for each candidate home. The high-ranked split needs distinct lexical values and socket hashes but the same physical owlery/identity.\n4. **Inventory live process trees read-only:** PID, parent PID, creation time, image/version, user SID, logon session, and integrity level for every `spt` daemon/broker/brain and gaki/slammie child. Two broker parents are decisive. Do not trust only `daemon.pid` because aliases over one physical home share that file.\n5. **Use a one-shot read-only diagnostic against each derived broker socket.** It should print: exact `spt_home`, derived broker/seed names, existing node-key public ID without creating one, broker image, and the `KIND_SESSIONS` rows `(session_id, endpoint, pid if available)`. Run it once under each captured environment. The critical matrix is A `{slammie, !gaki}` versus B `{gaki, !slammie}`.\n6. **Read raw state, not rendered summaries:** gaki/slammie `info.json`; relevant `identity/registry/*.json` snapshots on gaki, slammie, and perri; `identity/epoch`; `pump-heartbeat.json`; daemon logs around spawn, bind, exit/reap, reconcile, and advertisement. Key fields are `state`, `status`, `controllable`, session ID, custody/parent PID, node key, registry epoch, row status, and row node.\n7. **Correlate timeline:** gaki broker spawn/insertion → bind → Active advertisement → perri send disposition → any child exit/daemon restart → failed RC server lookup → slammie successful lookup → later shortform failure. This separates “same broker lost session later” from “two brokers were split throughout.”\n8. **Check resident image independently of installed CLI.** `daemon status --json` exposes `broker_image`/`broker_stale`; do this per candidate home/socket. A stale resident image reopens v0.23-era fixed races.\n\n## Minimal real-seam reproduction design\n\n### Repro A: lexical-home shared-disk split — preferred\n\nWindows-only, isolated temp state, no production endpoint mutation:\n\n1. Create one temporary home on a normal case-insensitive volume and derive two lexical spellings that resolve to the same file ID but are not `Path`-equal, e.g. case variation. Assert `broker_socket_name()` and `seed_socket_name()` differ under the two values; this is the necessary unit seam.\n2. Start full daemon/broker A under spelling A and full daemon/broker B under spelling B. Confirm both load the same node public key but answer on different local sockets.\n3. Launch a real dummy-harness PTY `slammie-n` through A and `gaki-n` through B; wait for real bind records and real `KIND_SESSIONS` replies.\n4. Have A run the production `advertise_local` scan after both binds. Assert A authors routable rows for both from the shared owlery although A's sessions reply contains only slammie.\n5. From isolated remote node C, ensure the cached direct address for the shared node key reaches A, then use the production RC cross-node path. Assert `rc slammie-n` receives a known tick while `rc gaki-n` exits with the exact stale-row wording.\n6. Send one WAN message from C and assert the receiver disposition is `spooled` on A; then show B drains/delivers the shared spool. This reproduces “remote canonical landed” without falsely implying A owned gaki.\n7. Run the same setup with A started normally and B initiated from an elevated shell carrying lexical alias B; assert B is de-elevated but retains alias B. This isolates home/socket selection from integrity level.\n\nThe test must fail early if two full network endpoints with one node key cannot coexist on the chosen transport. In that case use distinct broker sockets plus one production registry/dispatcher owner address at a time; the required invariant is that A advertises shared-disk gaki while A's real broker lacks gaki.\n\n### Repro B: deterministic stale lifecycle window\n\n1. One real broker spawns bound slammie and gaki dummy-harness PTYs; one real remote peer receives Active rows.\n2. Kill only gaki's PTY child and wait until the broker exit waiter removes gaki while slammie remains.\n3. Pause only the reconcile/advertisement driver at its injectable seam, not the broker or dispatcher.\n4. Assert remote RC produces the exact stale-row message for gaki and still attaches to slammie.\n5. Resume one production reconciliation + advertisement cycle and assert gaki stops resolving Active. This proves the ordinary timing source and its expected bounded convergence.\n\n### Repro C: persistent malformed online record\n\n1. Seed a real perch with the KH 5.16 post-race shape: `status=online` but pre-bind/non-live-agent state or missing `controllable=true`; broker has no matching session.\n2. Run production `reconcile_hosted_liveness`; assert it does not offline the exempt shape.\n3. Run production `advertise_local`; on the v0.23-target worktree assert the resulting row is Active/routable.\n4. Exercise remote RC and assert the same stale-row message while slammie's coherent row/session attaches.\n\n## Bottom line\n\nThe strongest corrected hypothesis is not “elevation made gaki harness-only.” It is **registry/broker split-brain selected by home/socket universe**, with the particularly sharp Windows variant being two lexical `SPT_HOME` values hashing to different sockets while addressing the same physical owlery and node identity. It alone naturally explains all three discriminators: same-node slammie attach works, gaki registry row is Active but absent from the reached broker, and remote WAN can land through spool while a same-node broker-session-dependent shortform fails. The next most likely family is a real gaki session teardown plus stale registry propagation; persistent healthy-cadence staleness then points to malformed record guards or epoch-lease strand rather than raw token integrity.",
  "files": [
    {
      "path": "crates/spt-store/src/perch.rs",
      "description": "Canonical home derivation. `spt_home()` preserves a raw explicit `SPT_HOME`; all owlery and identity paths derive from it."
    },
    {
      "path": "crates/spt-daemon/src/endpoint.rs",
      "description": "IPC rendezvous derivation. `home_tag()` hashes the lexical `PathBuf`; broker/seed socket names are per-home-hash, while `daemon.pid` is a file under the home."
    },
    {
      "path": "crates/spt-daemon/src/deelevate.rs",
      "description": "Windows token and environment logic. Uses the desktop shell primary token, `CreateEnvironmentBlock`, and verbatim explicit `SPT_HOME` overlay across de-elevation."
    },
    {
      "path": "crates/spt-daemon/src/daemon.rs",
      "description": "Daemon entry/spawn elevation guards and environment inheritance. Direct elevated daemon launch respawns de-elevated when a target exists; no-target case serves consistently elevated."
    },
    {
      "path": "crates/spt-daemon/src/broker.rs",
      "description": "Authoritative in-memory `HostedSession` table. Spawn inserts endpoint-labelled sessions; the exit waiter removes them; `KIND_SESSIONS` snapshots exactly what RC/reconcile can attach."
    },
    {
      "path": "crates/spt-daemon/src/attach.rs",
      "description": "Remote attach server. `resolve_local_session` maps endpoint to session exclusively through the reached broker's `brain.sessions()` result."
    },
    {
      "path": "crates/spt/src/rc.rs",
      "description": "Operator RC stage ordering and exact public stale-row message. Remote `NoLiveSession` renders `no live session ... on <node> ... registry row is stale`."
    },
    {
      "path": "crates/spt/src/wansend.rs",
      "description": "Owner resolution and own-node degradation. RC/WAN resolve registry snapshots; a local registry owner after a local session miss is not loopback-dialed as a remote fallback."
    },
    {
      "path": "crates/spt-daemon/src/registryhost.rs",
      "description": "Registry advertisement is an on-disk owlery scan with fresh epochs. Status is derived from perch liveness/rest state, not atomically joined to broker sessions."
    },
    {
      "path": "crates/spt-daemon/src/livehost.rs",
      "description": "Pull reconciliation from broker sessions. Only coherent live-agent online/unbound spt-hosted shapes are offlined when absent; malformed/harness-hosted shapes are intentionally exempt."
    },
    {
      "path": "crates/spt-daemon/src/wan.rs",
      "description": "WAN receive disposition. Existing perch can be delivered by TCP/injection or confirmed as `spooled`; a successful WAN send does not necessarily prove a matching broker session."
    },
    {
      "path": "crates/spt-net/src/net/registry.rs",
      "description": "Resolution and epoch lease. Routable row selection, local-node preference, ambiguity refusal, and strict per-node monotonically greater epoch merge."
    },
    {
      "path": "docs/KNOWN-HAZARDS.md",
      "description": "Relevant historical evidence: epoch-reset strand (§4.11), Windows elevation universe (§5.7 context), malformed pre-bind online record/reconcile skip (§5.16), and broker/session lifecycle invariants."
    },
    {
      "path": "CHANGELOG.md",
      "description": "v0.21 resident broker image observability and v0.23 run-truth claims/fixes; establishes version-skew and lifecycle context without claiming daemon-restart survival."
    },
    {
      "path": "docs/NEXT-MILESTONE-LIFECYCLETRUTH-TRIAGE.md",
      "description": "Post-v0.23 field evidence that daemon stop/start destroyed hosted sessions and automatic endpoint re-run was still a later design."
    },
    {
      "path": "docs/NEXT-MILESTONE-RUNTRUTH-TRIAGE.md",
      "description": "v0.22/v0.23-era pump stall, stale control, and endpoint lifecycle field reports; useful for distinguishing a global IPC wedge from a session-table miss."
    }
  ],
  "architecture": "There are four independent truth planes. (1) **OS token/integrity** controls whether a local process may open a named pipe and which desktop-user environment a de-elevated daemon receives. (2) **State/socket universe** is selected by raw `spt_home`; its lexical hash determines local IPC names, while its filesystem path contains owlery records, node identity, epochs, snapshots, and pid breadcrumbs. (3) **Broker session truth** is volatile and authoritative for PTY control: `HashMap<session_id, HostedSession>`, exposed by `KIND_SESSIONS`; remote RC can attach only if the reached broker contains the endpoint. (4) **Registry presence truth** is eventually consistent and disk-derived: the daemon scans perches, authors status rows under its node key and epoch, and peers resolve those snapshots before dialing. There is deliberately no atomic transaction joining planes 3 and 4. Bind/status writes, broker reap, livehost reconciliation, advertisement, gossip, and remote resolution occur at separate stages. Consequently an Active registry row without a matching reached-broker session is structurally possible during teardown, indefinitely possible when record guards or epoch leases strand correction, and selectively reproducible when two socket universes share or alias one disk/node identity. Messaging is a fifth delivery stage layered over registry resolution: receiver-side spool acceptance requires a perch, not a HostedSession, so `spooled` success cannot be used as broker-session evidence."
}