[{"body":"pty stream + input freezes every 10-20 seconds. the freeze lasts roughly 5-10 seconds, with all inputs enqueueing during the freeze. the whole input queue drains when it ends\n\ntested: enlyzeam-->gravity-nvidia-temp, enlyzeam local sessions, gravity-nvidia-temp local sessions all running spt-core v0.69.0\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":302,"title":"diagnose + fix: rc sessions frequently hitch"},{"body":"a \"Served Resources\" page was never in the planned design.\n\nper the design authority, that URL is meant to show the public docs site (which is currently only accessible at `localhost:5474/<node-name>/docs`\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":301,"title":"fix: `localhost:5474/<node-name>/` shows \"Served Resources\""},{"body":"Operator reproduced on v0.69.0 at both ends: enlyzeam controls lia on hfenduleam via spt rc; quoting C:\\Users\\decid\\Documents\\ShareX\\Screenshots\\2026-09\\Discord_f3TiABx34N.png did not register it or emit FILE_ACCESS_HELPER. #17 and ADR-0058 Am.1 explicitly require this remotely attached-user case: live reference, 24h TTL, receiving-agent audience, once-per-message/path guidance.\n\nLia reports initial fetch HTTP404 from two nodes and no helper frame; manual serve add then fetched16898 bytes. Operator confirms later manual registration. Current entry b29d528b has null TTL/audience/origin; read-only SSH verified source exists and registry. Current cross-node HTTP200/16898 verifies manual serving, NOT auto-serving.\n\nSource gap: wan.rs request_quoted_paths only triggers from user-msg envelopes; rc attach input goes as raw Input bytes into the PTY. now-signal checks quoted prompt paths on the receiving machine (file absent there). Owner authorization additionally requires its own user-msg MSG_OUT record; raw rc input does not supply that proof. This is missing trigger/provenance integration, not a firewall fix.\n\nDeliver the original rc case without weakening authorization or parsing arbitrary terminal keystrokes into file grants. Preserve authenticated controller origin plus committed user-message/path intent at a harness-independent seam. Acceptance must drive actual remote rc input, verify scoped24h reference + helper once, and prove edits visible/deletion404. Existing WAN-envelope test is not rc coverage.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":300,"title":"Remote spt rc input bypasses FILE_ACCESS_HELPER auto-serving promised by #17"},{"body":"Perri reports standalone spt-core 0.69.0 on HFENDULEAM: unpiped endpoint list --show-all takes 3822, 10120, 10105ms, each rc=0 and byte-identical complete 2497-byte output. Three adapter field traces also show long roster stages. No adapter-imposed subprocess timeout; bare CLI reproduces. Unreachable peers are correlated, not established cause.\n\nIdentify the waiting stage and remove the diagnosed unnecessary delay while preserving full roster, suspended rows, local merge and truthful unavailable state. Do not substitute an empty/partial roster, move reads past destructive consumption, or widen a harness-specific timeout. Distinguish network deadline, local contention and metadata cost before choosing a fix. Public docs promise bounded identity-only whoami, not a numerical full-roster latency bound; whoami is not an equivalent substitute. Clarify list freshness/blocking semantics with the remedy. Gate at the diagnosed seam and demonstrate complete output without that wait. Nonurgent per reporter; no adapter rework requested. Detailed measurements follow in a comment.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":299,"title":"Diagnose endpoint list --show-all recurring ~10s stalls with complete unchanged output"},{"body":"see the attached example. \"your machine's consent isn't in that token.\" how can we address this?\n\nAttachments:\n- ![6aba683b.rbf_lR6qHVysP8.png](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/1547827299250999388-6aba683b.rbf_lR6qHVysP8.png)\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":298,"title":"fix: cross-node agents don't trust wax seals"},{"body":"Operator reports enlyzeam serves /install locally after spt serve lan --bootstrap, but other machines cannot reach it; access is required over Tailscale.\n\nSource at f020c4c7: installer/install.ps1:175-192 and spt-daemon/src/firewall.rs:334-354 create only an executable-scoped inbound UDP rule. lanhost.rs:660-735 binds TCP 0.0.0.0 (default 5470) without firewall reconciliation. Local bind success is not remote reachability. The missing TCP rule is verified; enlyzeam's effective blocking layer is not yet measured.\n\nClose this gap in the bootstrap-start process: account for the actual selected TCP port and running binder; provide narrowly scoped Windows admission usable over Tailscale, including Public-profile interfaces, without opening arbitrary public ingress. If elevation/policy prevents repair, report the unmet condition and exact scoped elevated command; never imply end-to-end reachability from bind or rule creation. Distinguish Windows policy from Tailscale ACL/grants (do not modify tailnet policy automatically). Define rule ownership/lifecycle for stop/restart and repeated starts; preserve unrelated rules and loopback-only docs.\n\nAcceptance: remote tailnet IPv4 client can GET /install with host rule and tailnet policy admitting it; non-elevated/blocked policy has actionable diagnostics; port override honored; repeated start/stop is safe. Verify from a second machine, not localhost. Bootstrap currently binds IPv4 only. Existing UDP admission must remain intact.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":297,"title":"Windows serve lan --bootstrap leaves TCP listener inaccessible over Tailscale"},{"body":"Measured 2026-09-10 00:36Z on spt-core 0.68.0 / claude-spt 0.40.0, two independent observers (deployah: 8 messages; doyle: 12), all from ONE sender (todlando), each body byte-identical to an already-delivered message, each under a NEW msg-id, delivered in sender-chronological order in bulk drains AFTER the events that superseded them. Two replays instructed a gater to undo settled work (hold a finished census, reopen landed CHANGELOG text); they were caught only because the originals were still in the recipient's context. Sender-side trace (todlando session 01a08890): native checkpoint armed 00:35:50.717Z; COMMUNE seq1683 00:35:55.8Z; REPEATED AGENT_OUTPUT seq1684 00:35:56.9Z; fresh MSG_OUT seq1687 00:35:57.0Z; the native assistant body occurs once (00:04:59Z). Code read (deployah): msgid mint() derives the id from (from_id, body, created_at, salt) and a byte-identical repeat advances the salt, so fresh ids mean the SEND path ran twice; only the sender re-emitting can produce them. Working shape (hertz, not yet diagnosed): the checkpoint path re-reports assistant history as AGENT_OUTPUT and core's shortform ingest (dispatch_ingest_shortform then cmd_send_verdict) is not idempotent over it. Boundary (adapter re-report vs core re-ingest) is hertz's open RCA. Candidate member of milestone #294 (cross-node comms after the v0.68.0 flip); this is an instruction-channel correctness defect, not a cosmetic duplicate. Evidence: todlando .spt/preserved/replay-20260910/, deployah pair list, doyle drain spills.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":296,"title":"Checkpoint/recharge re-emits an endpoint's assistant history and re-dispatches its shortform peer tags with fresh msg-ids"},{"body":"Standing read is DOYLE'S, recorded as his: two workers with CONSTANT overlap, normally masked by the\npre-serve \"row already gone\" arm (dispatch.rs:1053-1060), unmasked under load. My read-only triage\nduring #272 golden r2 established the narrower half: ONE dispatcher generation cannot double-serve\n(dispatch.rs:746 InFlight insert under the claims mutex, :455-461 should_claim, :876 release after\nthe worker returns, 500 ms retry floor at :346 against a 25.3 ms observed gap). Two serve arms DID\nrun — first_line() query conn plus serve_rest subscribe conn, twice — and serve_rest has exactly one\ncaller (dispatch.rs:1243). So the surviving explanation is cross-generation, not intra-generation.\n\nData on hand: r2 attempt a3, 25 overlapping pairs; attempt a4, 2. Same sha, different attempts.\n\nAsk: treat this as the brain_respawn/brain_split hazard family and decide it with an INSTRUMENT, not\nwith timing. The instrument is a distinct-generation count on the Served path, which depends on the\nsibling ADDITION (emit dispatch_event naming the generation) — file that first and this becomes\nfalsifiable.\n\nExplicitly NOT claimed: my phase-offset prediction was refuted by my own falsifier and the\nsleep-after-work rescue I sketched is UNTESTED and must not be cited as support for anything here.\n\n#272 neither introduced nor widened this. Pre-existing.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":291,"title":"Two dispatcher generations can both serve one inbound REST stream at B (overlap window)."},{"body":"Measured during #272 golden r2 triage (2026-09-08, read-only, at the run's sha): host B's entire\nlog had `grep -c DISPATCH_EV` = 0 while two serve arms demonstrably ran. Every question of the form\n\"did ONE generation serve this twice, or did TWO generations each serve once?\" is therefore answered\nby timing inference rather than by evidence — and my own phase-offset inference on that data was\nREFUTED by its own falsifier (a3 inter-serve gaps 0-21 ms, median 4, scattered; no phase structure).\n\nAsk: emit a dispatch_event on the Served path — at minimum for the Rest arm — carrying the serving\ndispatcher's GENERATION. The claim path already does `served_w.fetch_add(1)`; the generation is\npresent at the point of service and is simply not written down.\n\nWhy it matters beyond tidiness: the sibling lane (two-dispatcher overlap) needs a DISTINCT-GENERATION\nCOUNT on the Served path to be decidable at all. Without this event that lane can only ever produce\ntiming arguments, which is precisely the class of evidence that already failed once here.\n\nScope: instrumentation only. No behaviour change to claiming, serving, or release. #272 did not\nintroduce or widen the gap — the claim path's only delta was the counter and the Rest arm's only\ndelta was a comment word — so this is not a regression fix, it is a missing instrument.\n\nType: ADDITION.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":290,"title":"The Served path emits no dispatch_event, so a serve cannot be attributed to a dispatcher generation."},{"body":"Measured 2026-09-08 (flynn, confirmed by doyle walking into it the same morning): `spt shell cmd alchemy-1 create` answers `unknown op create — the shell's vocabulary is [bags, bind-repo, …]`. That sentence is true of the `[shell.capabilities]` cmd set and false of the shell: alchemy's `create` and `comment` are SEND-payload verbs (line-1 verb over `spt shell send`, CONTEXT.md Agent surface), deliberately outside `[shell.capabilities]` because they carry free text and an optional --file. An agent reading the refusal concludes the verb does not exist and routes around the shell (doyle filed releases#287 via bare `gh issue create` + a `type` fill for exactly this reason).\n\nAsk: the unknown-op refusal should say what it enumerates (\"the cmd capability set is [...]\") and point at the shell's other surfaces (\"send-payload verbs and drive types are not listed here; see `spt shell cmd <instance> help` / the adapter's manifest\"), or list the manifest's send verbs when the adapter declares them. Small wording change, discoverability only; no behaviour change.\n\nOrigin: spt-progress-tool v0.25.0 fixes its own hint half (names create's send form); this is the core half.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":288,"title":"`spt shell cmd <instance> <unknown-op>` names the cmd capability set as THE shell's vocabulary, hiding every send-payload verb"},{"body":"currently, the `claude-spt` harness adapter is responsible for much of the agent education needed to operate their endpoint properly. consider working with perri to revoke all of its adapter [hints] which teach anything that's not adapter-specific, and turn them into spt-core-native monics. that way, every harness adapter would be relinquished of a majority of the spt-core education responsibilities, and would be educated equally.\n\nthis would be a new now-signal kind.\n\nanticipated gotcha: some of `claude-spt`'s hint education may point at tools unique to Claude Code. those may need to stay adapter-side in some capacity.\n\n### new hint idea: on `record`/`durable`/`durably`/`remember`\neducate the agent on spt-core's unique durable recording + dynamic surfacing offerings:\n- endpoint role\n- endpoint monic (about other agents)\n- general monics (about key words)\n- project-local monics (not yet implemented as of the time of writing)\n\n### tangential: now-signal kinds become opt-out for harness adapters\nin case a harness adapter/profile want some now-signal features but not all, their manifests can specify now-signal kinds to explicitly skip.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":284,"title":"idea: migrate core-relevant [hints] from `claude-spt`"},{"body":"as an endpoint operates, spt-core periodically checks its project directory for `./.spt/monics` (`.json`?)\n\nif the file exists, all monics listed within are loaded and treated the same as today's endpoint-owned monics, adapter hints, etc.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":283,"title":"idea: project-local monics"},{"body":"Measured 2026-09-07 06:22Z by todlando (W2 lane, webserve_attachment_e2e), ruled a defect by doyle. `serveverb::node_and_port` mints `http://localhost:<port>/<node>/f/<name>` from `DaemonConfig.docs_port` / `SPT_DOCS_PORT`; it never asks the running daemon what its docs listener bound. With `SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1` (the rig switch, documented as \"advisory listeners bind ephemeral ports\") the daemon's listener moves to an ephemeral port (measured 55369 / 44015) while every minted URL keeps the configured number: 5474 by default, which on a dev box or CI runner is the LIVE FLEET daemon's listener. Result: an ordinary-suite test fetched its attachment URL from the fleet daemon and got the fleet's 404 (an entry it never heard of); with a pinned SPT_DOCS_PORT the flag still wins the bind and the URL still lies (doyle 05:42Z, both boxes). Ask: the daemon exposes its BOUND docs port (the DOCS_SERVER_UP value) on the broker, and node_and_port takes it from a running daemon, falling back to config only when none runs; the switch's doc says minted URLs follow. Workaround in rigs: pin one SPT_DOCS_PORT on the daemon spawn and every CLI call (5493). Related: #281, IR-78 (flag silently overrides SPT_DOCS_PORT).\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":282,"title":"served URLs are minted from the configured docs port, not the port the listener bound: under the rig switch they point at the live fleet daemon"},{"body":"Found by emphasys (omp-spt 0.5.0 field, 2026-09-06), measured by doyle on this box: adapters/_github/BigscreenVR-omp-spt/strings/skills holds BOTH layouts — archive-shipped <name>/SKILL.md (epoch mtimes = extracted) beside stale flat live.md/ready.md/subnet.md/version.md/force-stop.md/setup.md/list-agents.md + strings/briefs/*.md + a stray claude-spt.exe, all mtime 2026-07-09 (first install). Later archives ship only skills/<name>/SKILL.md; nothing removed them.\n\nMechanism: crates/spt/src/cli.rs:20770-20776 apply_release_crc_swap is ADDITIVE by design — a file dropped by the new version is left in place, premise: a stale unreferenced file is harmless. That premise holds for binaries (the Windows exe-lock reason the CRC swap exists) and FAILS for strings/: a harness that discovers skills by scanning the dir REFERENCES every stale file, so an old skill keeps firing after the adapter retired it. Public harness contract states no update semantics at all, so an adapter builder cannot know files persist.\n\nAsk: on update, prune dest/strings/ entries absent from the staged archive (data only; binaries stay additive, .old litter rules untouched); state the semantics in the harness-contract update section. Owner ruling + shape in comment.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":278,"title":"adapter update never prunes strings/: files the new archive dropped stay installed (flat-layout skills beside SKILL.md dirs, a foreign claude-spt.exe)"},{"body":"## The gap\n\nA `ResidentService` is the only adapter-owned process that runs when no agent turn is running. That makes it the natural consumer of the IO funnel — and `harness-contract/api.md` says so itself, naming \"wake-marker-class constructs over commune and IO events\" as `api io-events`' motivating case.\n\nBut the two halves do not meet:\n\n- `manifest.schema.json` (`$defs/Service`): a service \"has **no perch, no identity, and no address**\", and ADR-0049's posture is outbound CLI only, under the anonymous `cli@<node>` from-label.\n- `api io-events <id>` is **authenticated**, and takes `--session-id <sid>` (a harness session identity) **or** a capability `--token` with `--after`. A service has neither, and nothing in `[service]` grants it one.\n\nSo the process that can watch is the one process that cannot read. Anything a service could observe about its own adapter's endpoints today has to come from its own gateway, polling, and config files — which is exactly what the funnel exists to replace.\n\nThere is a second, smaller half. A service is per **adapter option** (`<adapter>[:profile]`), while endpoints are many per node, and core scrubs `SPT_ENDPOINT_ID` from its environment. Even given a credential, no feed tells a service which endpoints of its adapter are live, or when that set changes. `endpoint list` polling is presumably the fallback, but the contract does not say it is intended.\n\n## Requested\n\nSome authenticated read path from a ResidentService to its **own adapter's** endpoints. Shape is yours — a service-scoped capability token minted at spawn (in `SPT_SERVICE_DIR`, rotated on the update quiesce→hold→swap→start cycle) would fit the existing `--token` + `--after` mode with no new verb, but that is a suggestion, not the ask. The ask is that the contract state *some* answer, including \"deliberately none\" — right now it states both halves and not their intersection, which reads as an oversight rather than a decision.\n\nIf a credential does land, one adjacent ruling would help: whether `spt send --from <eid> …` and `api state busy|idle <eid>` are legal from an identityless service. The published text says a service may invoke the CLI outbound under `cli@<node>` but does not say whether it may act *as* one of its adapter's endpoints. (deployah, 2026-09-06.)\n\n## Not blocking — priced accordingly\n\nclaude-spt hit this building an across-commune → `/clear` trigger. Our detector is keyed on the Write **tool**, so an agent that writes its commune with Bash gets no boundary — increasingly common. The funnel's `COMMUNE` kind is the right predicate, but it fires only when ingest completes (>15s later, per operator), by which time no hook is running; hence the service shape, hence this gap.\n\nWe then found a hook-side path that does not need any of this: stat the drop file at PostToolUse for **any** tool rather than inspecting the tool's arguments. Instrument-independent, and the drop is still on disk because ingest is slower than a hook cycle.\n\nSo this is filed as a real hole in the published surface, not as something we are waiting on. It becomes blocking only if ingest ever gets fast enough that the drop can vanish before a hook sees it.\n\nRelated: #274 (the `[service]` docs port; deployah asked for this to be filed so #274 can reference it).\n\n---\nRequester: perri. Hand-filed — no alchemy instance on this node is bound to this repo, so the mint never ran: needs `type #N addition` to complete it.\n","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":275,"title":"add: a ResidentService has no authenticated read path to its own adapter's endpoints"},{"body":"agents don't need a session brief if their *latest* session is being resumed, because there's no newer information the brief could possibly impart upon them.\n\nthe only exception would be if their newest session on the current node is **older than another node's instance's** sessions for the same endpoint.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":273,"title":"fix: full session brief fires on session *resume*"},{"body":"each shell can run its own webserver if it wants, made accessible thru core via `https://localhost:5474/<node>/[...]`\n\nthe original idea of a first implementer was a would-be \"files\" shell, which \"makes it easy for agents to supply files and subnet html artifacts to each other + users.\" but that is likely superseded by the more recent core-centered fileserving functionality.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2kyQ","name":"state: SHELVED","description":"Parked indefinitely; excluded from default list","color":"374a3f"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":271,"title":"idea: shell-serving cross-node http/s"},{"body":"--> bare `spt rc` then leverages that var to reattach to the given terminal window's last attached endpoint\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":270,"title":"idea: any session attach sets `SPT_ENDPOINT_LAST` env var"},{"body":"needs to be more helpful. only these line item types:\n- `<adapter-name> v<adapter-version>` --> all in cyan\n- `:<adapter-profile-name>` --> nested, dimmed white\n- `:<custom-adapter-profile-name> (custom)` --> nested, orange. for profiles that don't ship with the parent adapter\n\nand no more spt-internal jargon.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":269,"title":"change: `spt adapter list`"},{"body":"also happens after `spt update`\n\nall PTYs recover ok **after** an intentional detach + followup `spt rc`/`spt go` back to the same endpoint session\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":267,"title":"fix: `spt daemon refresh` stalls session PTYs"},{"body":"- check subnet nodes for the adapter\n  - is their adapter list + version-per-adapter published within nodes' peer pump registry entry?\n- transfer & install from the first discovered node which has the adapter\n- new: complimentary adapter [update] mode which \"knows\" if the initial installation happened using `--via-subnet`, and continues to use subnet p2p for updates.\n\n### tangential: `spt adapter list` has an \"available\" section\na second section at the end for all adapters found on other subnet nodes. any of them can be installed with `spt adapter add --via-subnet`\n++ color-coded by type\n- text at top: `Types: [HARNESS](orange), [GATEWAY](magenta), and [SHELL](cyan)`\ngrouped in that order, alphabetically per group\n\n### tangential: the potential for spt-core to ship with some inbuilt shells\n`fileshare` and `heartbeat` being the two first candidates.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":264,"title":"add: `spt adapter add <adapter-name> --via-subnet|-vs`"},{"body":"seems to happen after every turn end. this does not match legacy behavior. check claude_skill_owl sister project for the parity baseline, and compare against the design source of truth in CONTEXT.md\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":263,"title":"fix: `[echo_mirror]` is happening too frequently"},{"body":"when starting a new endpoint, the \"name\" screen in the creation flow shows a dimmed suggestion name based on the project name, i.e. `spt-core_edp01`. chooses the earliest available 2-digit index postfix based on existing endpoints.\n\nthe user can simply press enter to accept the suggestion name, or they can start typing to enter their own.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":262,"title":"idea: new endpoint picker flow --> offers placeholder name"},{"body":"periodically updates state of all its GUI elements so user can see changes to i.e. endpoint online/offline\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":261,"title":"improve: `spt endpoint run` picker updates state live"},{"body":"in the endpoint picker TUI. only applicable to online **spt-hosted** endpoints.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":260,"title":"add: `Suspend now` to bottom of endpoint options"},{"body":"anywhere an adapter shows up in the picker TUI, follow the `adapter[:profile]` text with ` v#.#.#` (whatever its actual version number is)\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":259,"title":"add: in the endpoint picker, show adapters' version"},{"body":"if an endpoint transitions to `suspended` while controlled, show a simple TUI which offers the following:\n**\"Endpoint `<id>` suspended. Options:\"**\n- Wake + control `<id>`\n- Exit to terminal + wake`<id>`\n- Leave `<id>` suspended + exit\n- More options (--> jumps to endpoint picker having preselected the given endpoint to show its options menu)\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":258,"title":"idea: options splash for controlled endpoints upon `suspended`"},{"body":"if an adapter declares that its suspension mode is \"lite\", any message routed to that endpoint while it's suspended will wake it + deliver the message.\n\nlikewise: manifest option for an endpoint to opt out of auto-suspend-during-dormant?\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":257,"title":"idea: manifest-declared `lite` suspension mode"},{"body":"`spt send --active-only` flag should change to `--busy-only`, for consistency across spt-core's seams (which elsewhere use \"busy\"/\"idle\" terminology --> `--idle-only` is already ok).\n\n`--active-only` can stay for compatibility, but as deprecated and undocumented.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":256,"title":"change: semantics consistency for `spt send`"},{"body":"some harnesses support mouse clicks on different items. so try sending click events (press/release edges even better) to the underlying app that spt-core's broker wraps\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":255,"title":"idea: PTY mouse events passthru"},{"body":"Measured + observed live (todlando, NOW-SIGNAL #23 verify-close, at dc07e215): the SHELLS category's ratified subsume-and-deprecate of the session-start spt-shells message is gated on the adapter declaring [io] compliance (reporting.rs:288-304) — sound scoping — but only cmd_listen (startup.rs:1049) passes the manifest; cmd_bind (startup.rs:1200) and cmd_boundary (reporting.rs:241, EVERY /clear) call the resurface_notifs(id) wrapper = manifest None, so superseded = is_some_and over None = FALSE unconditionally. claude-spt declares compliance = true (manifest.toml:1321-1322), the running 0.66.0 binary carries the gate (9c3a129a, tagged since v0.64.0), and the predicted legacy row was then OBSERVED at a live /clear boundary. cmd_bind carries adapter: Option<&str> in scope — the manifest is resolvable, just unresolved.\n\nAsk: resolve the manifest on both wrapper paths so the compliance gate fires wherever the legacy row can render. Deliberately NOT folded into #23 at close (clause is delivered on the cmd_listen path; this fix touches session-boundary plumbing and deserves its own gate). Recorded as verify-close exception (e) on #11.\nRequester: doyle (from todlando's verify-close measurement)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":254,"title":"spt-shells deprecation gate is inert on 2 of 3 session-start paths: cmd_bind and cmd_boundary resolve no manifest, so a compliance-declaring adapter still gets the legacy row"},{"body":"Measured 2026-08-30 (todlando, while measuring the premise of #133):\n\n`docs/MANIFEST.md` is 70KB and the authoritative manifest-contract document. It mentions `hints` **zero** times — the `[[hints]]` section has never been documented there.\n\nWhere hints ARE documented today:\n- `CONTEXT.md` §keyword hints (the ratification text)\n- `docs-site/src/harness-contract/*` (the hook table, in passing)\n- `docs-site/src/shells/frames.md` (the now-signal HINTS row)\n\nConsequence: an adapter author reading the manifest contract end to end never learns the section exists. This is the undiscoverable-shipped-surface shape — the capability is real and reachable only by someone who already knows it is there.\n\nScope: documentation only, no code. Add `[[hints]]` to MANIFEST.md beside the other manifest sections (fields, matching rule literal-vs-regex, once-per-session and per-source cap semantics), and cross-link the ratification text rather than restating it.\n\nNot folded into #133: that lane delivers the shell-side reader and documents hints where a SHELL adapter author looks (docs-site/src/shells). This is the harness-contract half of the same gap and belongs on its own.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":253,"title":"docs: MANIFEST.md never documents [[hints]] at all"},{"body":"> *pairs with: endpoint picker shows live statuses, picker GUI revamp*\ntoday, when finalizing a selection within the endpoint picker, the picker closes and the chosen event is invoked.\n\nthe new concept would have the final `Enter` keystroke spawning a fresh terminal window with the invoked event, and in the window with the picker, the picker just returns to its \"home screen\".\n\n`Space` keystroke would be the hotkey for the old behavior.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":252,"title":"idea: endpoint picker primarily spawns terminal windows"},{"body":"the normal chord `ctrl + b`, `d` doesn't do anything\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":251,"title":"fix: `spt rc --view` has no way to detach"},{"body":"the i.e. Windows Hello popup does show when the sealing ceremony begins. however, it arrives fully minimized. expected behavior: the auth popup should appear over top of all other windows and should be focused by default.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":250,"title":"fix: enrolled seal authentication on windows starts minimized"},{"body":"Measured 2026-08-30 (todlando, NOW-SIGNAL #23 W1 rider design): the now-signal EDGE_TRANSITIONS subnet-join arm renders from RosterEntry, which is a NODE record (pubkey_hex, subnet, label = OS hostname, machine_id). There is no endpoint-level join in that arm at all, and a node does not join a subnet 'from' a node — so #11's ask 'z joined <subnet> from <node>' is an UNBUILT DATA SOURCE, not a render defect. The render half (naming the subject as a node, labeling the pubkey fallback) ships in #23 W1; this request carries the other half so it is neither silently dropped nor quietly invented mid-rider.\n\nAsk: an endpoint-level subnet-join transition datum (which endpoint joined, which subnet, from which node) that EDGE_TRANSITIONS can render, with the endpoint-join vs node-join distinction visible in the line. Recorded as exception (d) on #11's close.\nRequester: doyle (from todlando's W1 measurement)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":247,"title":"EDGE_TRANSITIONS: endpoint-level subnet-join transitions with origin node (z joined <subnet> from <node>) — the data source does not exist"},{"body":"The v0.66.0/#242 golden RCA (RCA-242-R2-LINUX.md, BRAIN_PHASE breadcrumbs + harvest-loop repro) measured current_exe_hash() on the READY PATH at ~10.1s per boot on kitsubito under leg load (~1.5s on Windows). Every daemon boot pays it before readiness, inside the same ONLINE budget that bring-up tests and KNOWN-HAZARDS 5.13 guard — under load it manufactures deadline-burn bring-up failures (register IR-17's kitsubito family member is CLOSED under this mechanism at the 2026-08-30 sweep).\n\nAsk: compute the exe hash OFF the ready path (lazy/async/deferred-with-memo — mechanics to the lane), so readiness stops carrying a filesystem-scale hash cost. This is a behaviour change to the ADR-0018 Q7 ratified readiness semantic, so it needs operator triage, not a drive-by: the hash currently has a position in the readiness contract and moving it changes what a ready daemon has proven.\n\nOrigin: todlando-flagged during the RCA; figures doyle-measured, RCA-cited. Filed at the v0.66.0 close sweep per the register composition.\nRequester: doyle\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":244,"title":"Move current_exe_hash() off the daemon ready path — a ~10s synchronous hash per Linux boot sits inside the ONLINE window (ADR-0018 Q7 behaviour change)"},{"body":"The #241 emission lane converted its full censused population (486 sites; 495 eprintln! removals measured at ec6da9b0) and its golden is green — but the close-out re-census found the census generator truncated crates/spt/src/cli.rs at its first module-opening #[cfg(test)] (line 3007; module closes 3164; file runs to 39118) and never scanned the rest: 338 TOKEN-shaped shipping eprintln! sites remain bare (containment-classified, 0 in test modules), including the ENDPOINT_AUTOSTART_*/ENDPOINT_RUN family adjacent to IR-69's original torn token. Also SELECTION_PROBE (spt-daemon/src/daemon.rs:2768, TOKEN-space family, sealed-census membership unverified) and delivery.rs:149/313 + main.rs sites likely minted after the census cut by W2/W3 — the snapshot-vs-moving-main face. Ask: (1) convert the residual population onto spt_proto::emit_line_err!; (2) fix the generator's module-close-resumption blind spot and re-measure what the fix can now over/under-match; (3) prefer enforcement at the seam (deny bare TOKEN-shaped eprintln! in shipping code via xtask check) so post-cut minting cannot reopen the class. Evidence: EMISSION-RESIDUAL-CENSUS-FINDING.md at spt-core repo root (doyle, 2026-08-29); reconciliation requested from todlando/hertz against the sealed census artifacts. Register kin: IR-69 (stays OPEN with this addendum), IR-8, IR-58.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":243,"title":"Residual machine-parsed emitter population: census truncation left 338 shipping token-shaped eprintln! sites unconverted (cli.rs post-line-3164 + stragglers)"},{"body":"if a wax sealing ceremony fails due to i.e. no-attached-controller, the notifier message includes a retry ID. that ID can then be used with i.e. `spt seal retry <retry_id>` to attempt sealing the same message again.\n\nreason: help prevent unnecessary output tokens\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":232,"title":"idea: \"retry ID\" for failed seals"},{"body":"Field notes from the #222 acceptance session (operator, screenshots on file). The Windows Hello modal for seal ceremonies shows only \"Making sure it is you / Enter your PIN\" with the default fallback icon in the taskbar. One root cause, two faces: spt.exe is an UNPACKAGED Win32 console binary, and the KeyCredentialManager dialog (hosted by CredentialUIBroker.exe) brands itself from the caller PACKAGE IDENTITY, which spt lacks -> generic title, fallback icon. Additionally the KCM surface itself (RequestCreateAsync / RequestSignAsync) takes NO message or context parameter, so per-call purpose text does not exist on this API at all. Options: (a) give spt package identity (sparse MSIX manifest) so Windows attributes the dialog with name+icon; (b) the W2 FIDO2 backend (webauthn.dll) presents RP name + user display name in its dialog, so purpose text largely arrives with the already-named next backend; (c) cheap interim: strengthen the ceremony overlay wording so the terminal states what the imminent Hello modal is for and which action it signs. Recommend (c) now, and fold (a)/(b) into W2 FIDO2 ceremony design rather than investing in the KCM dialog we plan to supersede.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":231,"title":"Hello ceremony modal is generic: no purpose text, fallback icon (CredentialUIBroker)"},{"body":"A `spt go` viewer keeps executing the binary image it started with; `spt update` swaps spt.exe and restarts the daemon but never reaches open viewers, and nothing shows the skew. Field: minutes after v0.63.0 published, the #222/#223 acceptance ceremony ran in a viewer started 16h pre-update and reproduced BOTH just-fixed defects (ncrypt 0x80090027 refusal + admit PTY residue), reading as a failed release. Ask: a stale viewer must not be indistinguishable from a current one — e.g. daemon pushes a per-viewer notice after update. RCA detail in attachment.\n\nAttachments:\n- [alchemy-viewer-skew.txt](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/shx-1787716519165927500-alchemy-viewer-skew.txt)\n- [alchemy-viewer-skew-body.txt](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/shx-1787716557194237900-alchemy-viewer-skew-body.txt)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":230,"title":"Attach-viewer version skew after update is invisible — stale viewers replay retired bugs"},{"body":"Follow-up minted by doyle's W4/#215 ruling R6 (v0.63.0 FIELD-SEAL, 2026-08-25). The #215 fix normalizes the admission gate's three feeders to one MEANING: only a proven bare id ever reaches the subject chain, so notify now passes None and tier 1 ABSTAINS (falls to the node tier) — the stamp contract's documented behaviour for a sender who proved nothing. That is deliberately the SMALLER promise: a tier-1 rule about an endpoint still does not match on notify deliveries; it abstains by design instead of failing silently by shape mismatch.\n\nTHIS request is the bigger promise, tracked rather than dangling: stamp a PROVEN sender on the notify row at authorship (additive serde-default field; N-1 daemons ignore it; rows already on disk read as before) and pass it to the admission gate, so a tier-1 subject rule covers all three verbs (send, ring, notify). Requires its own measure-first: whether the author's proven identity is available at the notify mint site was NOT measured in the #215 arc.\n\nRefs: #215 (the delivered normalization + abstain-by-design), REQ-ACL-LOCAL-SUBJECT-ONE-SHAPE (minted by that lane), REQ-MSG-SENDER-STAMP, REQ-ACL-SUBJECT-CHAIN.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":227,"title":"notify rows carry a PROVEN sender so a tier-1 subject rule can match on notify"},{"body":"Surfaced by census during TURNKEY #212 W3 (releases#173), measured at `c62904e7` and live on HFENDULEAM. Filed as a QUESTION, not a defect: there is a real argument on both sides and it is the operator's to weigh.\n\n`inbound_block_hint()` (cli.rs:12914) has exactly two consumers — the coming-online banner (cli.rs:13283) and `spt subnet status` (cli.rs:13460). `spt daemon status` does not render it. On this node today `spt subnet status` prints the full path_mismatch warning (the firewall rule admits a CI-runner debug exe while the daemon runs the installed binder); `spt daemon status` says nothing and exits 0.\n\n**This is not a regression.** REQ-INSTALL-7's own registered comment states the hint is rendered in \"subnet status + the coming-online banner only\". Two consumers is the documented design, so nothing has failed a promise.\n\nThe question is only WHICH SURFACES read the existing hint. No change is proposed to the probe, the verdict record, or the warning text. releases#173 reconciles the rule itself and deliberately does not touch render surfaces.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":214,"title":"Should `spt daemon status` surface the inbound-blocked warning that subnet status already shows?"},{"body":"Surfaced by the releases#196 census (todlando, doyle filing the follow-up to me). Not PORTER scope.\n\n**There is no operator-facing verb that closes an endpoint's posture on its own.** Censused at `b88fab2a`: `set_endpoint_mode` / `set_endpoint_surface_mode` have no CLI arm — every production caller is internal (`redeemop`, the daemon's own paths) or a test. The node tier has its verbs (`spt api access-node-mode`, `access-node-surface-mode`) and they are the engine room's seat. For an endpoint, the ONLY lever is `AccessStore::restrict_if_unset`, reached as a **side effect** of the positional `spt endpoint access allow <endpoint> <node-hex>`.\n\nSo an operator who wants \"close this endpoint, I will grant access separately\" cannot say that. They must admit a machine in order to close, which conflates two decisions — and the close only happens `iff unset`, so the verb silently does nothing on an endpoint that already names any posture.\n\nThis became visible because releases#196 ruled (HORN B) that the precise/flag spelling is a RULE verb and leaves posture alone. That ruling is right on structure, and it is what makes the missing verb load-bearing: the #196 notice, written to tell an operator their rule changes no verdict, has to name the positional spelling as the lever — the only one that exists:\n\n```\nACCESS_GRANT_CHANGES_NOTHING:open-ep — the rule is written and stands, but it changes no\nverdict today: … To make admission mean something here, close the posture first —\n`spt endpoint access allow open-ep <node-hex>` (the positional spelling, which restricts\nthe endpoint as well as admitting that machine), or deny by name whoever should be refused.\n```\n\nThat sentence is honest and it is awkward, most of all for a **sender-endpoint** subject: the operator ruled about one sender, and the advice back is \"now go admit some whole machine so the close happens\".\n\n## Suggested shape (not binding)\n\nAn explicit endpoint-tier posture verb — `spt endpoint access close <endpoint>` (and per-surface, mirroring `access-node-surface-mode`), with `spt endpoint access open <endpoint>` already existing as its widening opposite. Points worth ruling before anyone builds it:\n\n- **Authority.** `open` is available to the endpoint's own seat today; a close narrows, so it is the safer direction, but it should still answer to the same classification the mutation seam uses.\n- **`iff unset` or unconditional?** `restrict_if_unset` deliberately refuses to overwrite a configured posture. A verb the operator typed *means* it, so an explicit close should probably be unconditional — which makes it a genuinely different body from `restrict_if_unset`, not a wrapper.\n- **The default-on carve-out (releases#180) still applies:** a blanket close does not withhold `DISCOVER`. The verb must say so, the way the positional arm's `ACCESS_DISCOVER_UNCHANGED` line already does, or it will read as \"I went dark\" to someone who did not.\n- **Then #196's notice should name THIS verb** instead of the positional spelling, which is the real reason this is worth doing rather than merely tidy.\n\n---\nRequester: todlando\n","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":207,"title":"add: no operator verb closes an endpoint's posture — the only close is a side effect of the positional allow, which conflates close-with-admit"},{"body":"Refusal rider from the v0.56.0 NAMEPLATE respin, recorded durable on the #181 triage record and filed here per the post-ship queue.\n\nTHE OBSERVATION (measured during the twohost-b W8 red triage): an endpoint-authored node-subject FORK grant is refused by the widening gate under closed posture (access.rs:1616-1624, REQ-ACL-GRANT-NODES-POLICY: \"closed => engine-room only\") even when that grant is semantically subsumed by an existing allow row — FORK is a subset of FORK+DISCOVER on the same node subject. A no-op-in-effect grant is refused because the gate compares tuple shape, not effect.\n\nNOT A DEFECT: product behaves exactly per the documented contract; the refusal string and posture rule verified at the emit site during the same triage. This files as a design question, not a bug.\n\nTHE QUESTION FOR THE OPERATOR: should a grant already subsumed by an existing allow row pass the widening gate as a no-op (subsumption-awareness enters the gate), or does the shape-keyed refusal stand as contract? Either answer is coherent; the current behavior surprises a caller who reads grants as effects rather than rows.\n\nORIGIN: #181 record (W8-r2 triage riders, twohost_cli.rs gated_cli_role_b arm); the companion rider from the same triage (rung-text split) already shipped as test-side work in v0.56.0.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":195,"title":"Widening gate refuses semantically subsumed node grants — keys on tuple shape, not subsumption"},{"body":"Measured on run 32200175631 (#181 diag ladder, instrument pre-registered at #181 comment 5335832570): a livehost spt process and the home's daemon each ran a full net-consumer set and double-served the same streams — 147 streams across six families (Sync/Notif/Registry/Update/Attach/Redeem) taken twice, silently everywhere the store is not exactly-once. The redeem family made it visible as #193 (reply race, fixed narrowly there).\n\nTwo structural facts, both measured: (1) the single-dispatcher gate in brainproc is per-PROCESS and cannot see a sibling process's consumer set; (2) finished_row_is_terminal retires finished rows on-sight for Attach alone, so every other family re-serves finished rows from seq 0 to whichever dispatcher picks them up.\n\nThe architecture's invariant is one dispatcher set per node (one-supervisor model, broker as state anchor), and the condition is abnormal-but-reachable: attested field windows include autostart inheriting a job-escaped daemon, update resume-steal, and boot races. Design question for triage: does exclusion become broker-side (cross-process claim), or does the supervisor enforce single-set at spawn — and should non-Attach families retire finished rows? Deliberately NOT attached to the v0.56.0 milestone: expanding #193 would re-price the operator's branch-1 choice. Full mechanism record: BigscreenVR/spt-bs-releases#181 (instrument verdict comment).\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":194,"title":"Cross-process dispatcher exclusion: two dispatcher processes on one home each serve the same streams"},{"body":"Found during the NAMEPLATE twohost RCA (releases#188 chain). Every product spawn site for daemon-shaped children nulls stderr (shellhost.rs:494-650, shellwake.rs:283-285, daemon.rs:869-871, service.rs:213-214), and the brain child redirects to $SPT_HOME/logs before any code runs. Consequence, MEASURED: livehost.rs:821's CONTROL_REAP_NO_SESSION print - a deliberately loud, ruled diagnostic - counted ZERO in a job log on the very run the site provably fired (naming run 32122237934, cross-process file-sink conviction). Three separate refutations in the RCA were overturned solely because a zero over the test process's stderr was read wider than its channel. Question for eval: route child diagnostics somewhere durable by default (the brain child's stderrlog pattern generalized: $SPT_HOME/logs per child), so a ruled print is never structurally invisible. Not asking for stderr inheritance (the null is deliberate for detach correctness) - asking for a sink.\n\nRequester: doyle (gate), from the NAMEPLATE v0.56.0 RCA.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":192,"title":"daemon-spawned children are unobservable: every ruled loud print dies in Stdio::null()"},{"body":"Found during the NAMEPLATE twohost RCA (releases#188 chain, naming run 32122237934). A CLI invocation against a home whose daemon runs IN ANOTHER PROCESS (in the rig: the test process's in-process daemon) autostarts a SECOND full daemon (daemon.rs:861/871 site) against the same home root. Each daemon then evaluates the ruled no-session control reap (livehost.rs:821, ADR-0041 decision 4) against ITS OWN broker's session table - so each reaps control stamps belonging to sessions live on the OTHER daemon. Measured: the second daemon (proc_pid 1114877, exe=spt) cleared controlled=true on a perch it did not own, 5/5 reproductions. In production this shape needs a boot-race window or a broker-discovery miss, but the reap fires from boot tick 1, so the window is real. Question for eval: should home binding be exclusive (daemon singleton per home root, refuse-or-adopt on second bind) rather than relying on boot-race self-heal? Evidence: releases#188 comments 5325861353, 5326279408, doyle countersign 5326598499.\n\nRequester: doyle (gate), from the NAMEPLATE v0.56.0 RCA.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":191,"title":"daemon autostart binds a home already hosted by a live daemon - split-brain control reap across the two"},{"body":"Golden twohost runs 32093894524 (@f967208) and 32097943571 (@a8c3227): role B pump drops its established conn to role A with PUMP_PEER_FAIL \"peer reply-read: no progress within budget - dropping peer (brain IPC read deadline elapsed)\", then every re-dial fails for the rest of the run (\"closed by peer: 0\" / \"no such conn N\" - 164 attempts over 15 min in run 2). 2/2 occurrences, both fired inside the advert-barrier phase (drop 04:40:39.48 vs adverts crossing 04:40:39.62 in run 2; 03:29:48 vs 03:29:49-52 in run 1). With role A pump also wedged (releases#188), the dropped conn is the only B->A path, so the ER-conjunction rung (first to need post-barrier B->A replication) times out at 900s both runs - the NAMEPLATE #163/#169 int cells cannot green until this heals. Two product questions: (1) the reply-read IPC budget starving under advert-round load; (2) re-dial never re-establishing - closed by peer on every attempt. Distinct from #188 (A-side cold-start dial escaping the 10s bound); the two compound. Seam pre-existing: pump/nethost product code zero-delta across 27d40b9..a8c3227 (registry.rs milestone delta is test-only). Detail comment with per-run line evidence follows.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":189,"title":"twohost rig: B-side pump drops its only peer conn (brain IPC reply-read starve) and re-dials never heal"},{"body":"Field-measured HFENDULEAM 2026-08-06 -> 08-08 (sequestration incident, companion filings #172/#173). Onset: Ethernet profile flap 17:33:03-17:34:31 on 08-06 (Private->None->Public->None->Public->Private, profile events lag real link loss so this is a ceiling); from the 17:29 all-fail transition onward EVERY pump dial to all 6 targets timed out at stage quic-connect (\"submit-dial exceeded the 10s bound\") on ALL paths - relay, Tailscale, direct LAN - for ~41h, while ICMP to a LAN peer and TCP 443 to the relay stayed healthy throughout. Binder pid 6336 (bound 00:48 same day) survived the flap; the 18:21 brain restart did not touch its sockets and did not heal it. Discriminant measured 2026-08-08: 11:03 daemon restart on the SAME binary (v0.55.0, mtime 08-05, no update) - dials recovered within ~5 minutes (5/7 connected, inbound verdict ok, registry updates flowing); subsequent 11:18 full reboot stayed healthy. ENLYZEAM (same 192.168.1.x LAN, same router bounce) showed the same 0/6 through the same window with no peer-side story. Fix shape (ruled): the daemon must detect interface/profile change - or sustained all-peer all-path dial failure - and rebind/recreate the iroh QUIC endpoint instead of wedging until a manual restart. Detail comment follows.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":174,"title":"QUIC endpoint does not recover from a NIC/interface bounce; all peer dials wedge at quic-connect until binder restart"},{"body":"`spt endpoint resume <id> [session]`: an optional positional session id resumes THAT session from the endpoint's ledger; omitted keeps today's latest-only behavior unchanged. Unknown/foreign session id refuses naming the ledger (never a silent fallback to latest). Fills the refusal slot the #5 verb surface deliberately reserved — cli.rs pins `resume <id> <session>` as a refusal today, so this is ADDITIVE: no verb-table change, no `endpoint run` resurrection, picker untouched. Operator-ruled 2026-08-05 after the v0.54.0 release-notes narrowing review: the picker's Resume-from-history carries any-session resume, but the scripted/CLI form is first-class SPT capability and returns. Unscheduled — rolls into a future milestone at intake.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":162,"title":"add: session argument on `endpoint resume` — specific-session resume returns to the CLI"},{"body":"Follow-on staged out of #109 (doyle ruling 2026-08-04, todlando build). #109 ships the predicate (a perch dir is RESIDUE iff no endpoint record resolves on any read — recordless AND spool-less AND non-empty reaps; spool-carriers and empties are reported loudly, never deleted, per the 3.4 extension), an operator-fired `spt endpoint gc` (report-only default, `--reap` explicit), and the classification report. THIS request is the automation half of the original ask: a daemon-fired periodic/boot sweep of the same ruled population. Deliberately staged second — a deletion loop nobody typed is a different risk class from a deletion the operator asked for. Trigger: the report layer has run loud on real boxes with zero misclassifications of OCCUPIED dirs; the field data earns the loop. Link: staged out of #109.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":158,"title":"Perch-GC automation: daemon-fired sweep of ruled residue population"},{"body":"Two published-prose defects produced confident wrong beliefs fleet-wide in one evening (#154 whitelist semantics from CLI help; #155 version-scope claim from a runtime banner) — both internally coherent, neither catchable by careful reading alone. Ruled response (doyle 2026-08-04): a SCOPED audit, not point fixes alone. Scope: the access/knock family CLI help + runtime notices/banners + docs-site access pages, audited against the resolution-chain code. Method: blind-consumer read — a source-blind reader states the model each line implies (flynn qualifies by construction), a source reader falsifies each implied model against the chain. Special attention: VERSION-SCOPE CLAIMS (any \"X was inert/absent/enforced before version N\" prose) — a class only source can settle and invisible to a clean-room sanity check; the audit inventories every instance, and whether that class earns a mechanical tag-verified gate is decided FROM that inventory, not tonight. Sizing note: runtime STRINGS are published surface for clean-room consumers — the audit population includes them, not just docs pages.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":156,"title":"Access-subsystem published surface: blind-consumer audit against the chain code"},{"body":"Split from #6 recon (todlando, 2026-08-04; doyle ruled re-home). Mechanically the stop half of relink force — non-ephemeral close_shell and nothing else — but NOT free as a surface. Two semantics decisions the #6 Request never states, to be ruled before build:\n\n1. Ephemeral arm: unlink on an ephemeral instance is a teardown wearing a gentler word (close_shell diverges ephemeral => TornDown: perch + spool history erased, mint slot freed), and unlike relink force there is no restart afterwards to make that intent obvious. Refuse-loud vs alias-to-teardown vs allow needs an explicit ruling.\n2. Already-offline arm: no-op-ok or refuse? relink force never meets this arm; unlink meets it immediately.\n\nInherits #6 finding 1 whole. The close_shell survivor semantics (#6 finding 2) apply to any stop verb: a SHELL_CLOSE_SURVIVOR outcome must not report clean stop.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":152,"title":"spt shell unlink — explicit stop-half surface for shell links"},{"body":"# EVAL request — wait_bounded should tree-kill on timeout (spt-runtime)\n\n**Type:** BUGFIX (product). **State:** EVAL. **Origin:** hertz item-1 analysis during USHER #150 triage (2026-08-04); #131-adjacent but a distinct product surface.\n\n**Problem:** when `wait_bounded` (spt-runtime) expires its bound, the awaited child process tree is left running — the bound bounds the WAIT, not the process. Test-side sleeper fixtures that outlive their bound are hertz's lane (test-only), but the PROD gap is real: any runtime caller that gives up on a child after a timeout strands the child's whole tree (grandchildren included), which on Windows is the same orphan-window / zombie-process family the USHER triage catalogued (IR-35 kin, resident_service :664 leaked-pid sighting).\n\n**Ask:** on bound expiry, wait_bounded (or its caller contract) must kill the tree it was waiting on — job-object / kill_tree semantics, pinned-identity kill (pid+started_at, per pid-reuse hazard), not bare-pid. Scope ruling needed: whether the kill lives inside wait_bounded or is a documented caller obligation with a helper.\n\n**Relation to #131:** #131 owns spawn-flag hygiene (DETACHED_PROCESS / CREATE_NO_WINDOW interaction). This request owns termination-on-timeout. Same family, separate surfaces; todlando's lane if greenlit.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":151,"title":"wait_bounded leaves the awaited process tree running on bound expiry (needs tree-kill-on-timeout)"},{"body":"tested with lia@HFENDULEAM (who minted the code) and ball-b@ENLYZEAM.\n- when ball-b redeemed the code, lia did not receive the designed-for redeem notification.\n- a message attempt to lia shows `NO_PERCH` and fails\n- `spt endpoint list` shows lia as \"known but nodeless\"\n\nlog:\n```\nKnown to this node, not listed in a shared subnet\n  lia                      UNLISTED  invited-outbound  node unknown       not asked  we knocked them; not answered yet\n  evidence is what this node recorded; the presence word is their own node's answer, asked just now\n  not asked — no node is recorded for that row, so there was nobody to ask\n```\n\ntangential: those bottom two lines \"evidence is ...\" and \"not asked ...\" should be wholly excluded. they are confusing and not helpful.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":149,"title":"diagnose and triage: knock code redemption issues"},{"body":"have each endpoint spool its outgoing messages strictly for historical context\n\nsimilar spool format to the perch spool?\n\nCLI to view \"last N messages\" as ledger stubs, i.e. `spt endpoint ledger [<endpoint-id>] --count <n>[,<outbound-n>]` with optional `--outbound-only` and `--inbound-only` flags. the optional extra count digit sets separate counts for both inbound and outbound messages\n\nworks in tandem with the \"message short IDs\" system #147 for the ledger line item stubs + IDs/links to view whole messages\n\nalso shows message timestamps both as `HH:MM[AM|PM] MM-DD` and i.e. `1d 2h 12m ago`. this way agents and users can easily gauge relative time.\n\n## tangential add: CLI to resend a given message\nin case the receiver didn't get it somehow. helps prevent unnecessary token spend\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":148,"title":"idea: track endpoint outgoing messages"},{"body":"# Arm (c) — behavioural statement, for minting the request\n\nperri → doyle, 2026-08-03. Stated against the PUBLISHED contract and against what is\nobservable at the adapter boundary. It deliberately does NOT propose a core design:\nwhat core changes is core's call ([[report-measurement-never-issue-direction]]).\n\n## What happens today, at the boundary\n\nAn inbound delivery to a Claude Code session rides the harness's `additionalContext`\nchannel. That channel has a hard size limit, and content over it is truncated by the\nharness **silently** — no error, no signal, the tail simply is not there.\n\nThe adapter therefore pre-empts it: it caps its own emission below the harness limit, and\nwhen a delivery exceeds that cap it writes the FULL content to a file on disk\n(`~/.claude/sptc-drain-<session>-<millis>-<pid>.txt`) and inlines a pointer instructing the\nagent to read that file. The agent then spends a tool call reading its own message.\n\nThis is the adapter choosing a visible cost over an invisible one. Losing the tail of a\npeer's message with no signal is the worse failure, so the spill stays until the size\npressure itself is addressed.\n\n## Measured, this node, 2026-08-03\n\n- **1969** spill files present, totalling **11,878,123 bytes**; mean **6032.6 B**,\n  min 1697 B, max 203,873 B.\n- **208** written today. **8** in a single working session (this one).\n- Arm (a) re-derived today against its locked cutoff (≤2026-08-01T00:36:37Z):\n  **COUNT 1161, MEAN 6341.9** — reproduces the locked values EXACTLY, so the instrument\n  has not moved and a later delta will be interpretable.\n- Arm (b), locked 2026-08-01T02:51:59Z: COUNT 1234, MEAN 6250.4, SUM 7,712,988.\n\nStanding caveats, restated because they bound every number above: zero monics held; this\nnode is an **upper-bound** instrument, not fleet-representative; and the post-bounce\nevery-message repetition is EXPECTED shipped-bug state in another agent's lane — it must\nnot be re-filed as a fresh defect.\n\n## Why it is a defect and not merely a cost\n\n1. **The agent pays a tool call to read a message that was already delivered to it.** The\n   content reached the node; the only thing that failed is fitting it through the channel.\n2. **It accumulates without bound.** Nothing prunes the spill directory. 1969 files is the\n   count on a node nobody has cleaned.\n3. **It degrades the thing it protects.** A spill pointer consumes context too, and when\n   several arrive in one turn the pointers themselves approach the cap.\n4. **Its failure mode is silent for the reader.** An agent that does not read the file\n   simply never sees the message, and nothing distinguishes that from never being sent.\n\n## What \"fixed\" would look like, as a MEASUREMENT\n\nNot a prescription — the observable that would settle it:\n\n> After the change, the same workload on the same node produces a materially lower spill\n> COUNT and SUM, re-derived with the identical glob and the identical statistic, with arm\n> (a)'s cutoff still reproducing 1161 / 6341.9 as the anchor proving the instrument did not\n> move.\n\nIf arm (a) ever fails to reproduce, the honest report is **\"the instrument moved\"**, not\n\"the code improved\" — and the comparison is void until that is explained.\n\n## What I do NOT hold\n\nThe specific core-side change this waits on. My record carries it as prose — \"the core-side\ndrain-spill fix\" — with no id, no scope, and no author. That gap is exactly why this\nstatement exists: so the request is minted from an observable rather than from my memory of\na conversation.\n\n---\nFiled by doyle from perri's behavioural statement (above, verbatim). The adapter-side spill is the\nWORKAROUND, deliberately chosen (visible cost over silent truncation) and staying until this lands.\nThe ask is core-side: address the size pressure at the delivery seam so oversized inbound deliveries\nstop requiring a disk spill + pointer + extra tool call at the adapter boundary. Design is core's\ncall; the acceptance measurement is stated in the statement's own terms (spill COUNT and SUM\nmaterially lower under the identical glob and statistic, arm (a) anchor still reproducing\n1161/6341.9).\nRequester: perri (adapter DRI), via doyle.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":146,"title":"change: oversized inbound deliveries force an adapter-side disk spill — address the size pressure at the delivery seam"},{"body":"Production liveness decisions ask a BARE pid, so a recycled pid reads as the recorded process. Nine sites; two activated hazard REQs read covered while the arm they name is undefended.\n\n**Subject sha for every claim: `b7b00c3`** (origin/golden/locksmith, v0.53.0 chain). Re-derive before acting — every claim below carries the command that produced it.\n\nFiled by doyle from a stage-2 caller classification by hertz; the load-bearing claims were re-derived independently before acceptance. This is the SITE half (production code). The ENFORCEMENT half — a lint that flags `is_process_alive` at a production decision site — is infra debt and is filed to `docs/INFRA-REGISTER.md`, not here.\n\n## The defect\n\n`proc::is_process_alive(pid)` answers \"some process holds this pid\", never \"the process I recorded holds this pid\". Production code treats the first answer as the second at 24 of 27 call sites. Pid recycle is not theoretical here: a same-boot recycle was MEASURED on this fleet in 30 seconds, both processes user-owned.\n\nThe paired, sound predicate is already shipped and already used elsewhere in the very files that probe bare:\n\n```\nspt_store::liveness::relay_liveness(pid, recorded_birth) -> Held | Gone | Unproven\n```\n\n## Two activated hazard REQs read COVERED with the discriminating arm undefended\n\n**`REQ-HAZARD-WINDOWS-PID-RECYCLE`** — `required_stages = [\"impl\",\"unit\"]` (traceable-reqs.toml:956-958). Spans two crates: impl at `startup.rs:138` (`bind_from_seed`) and `spt-msg/src/deliver.rs:95` (`deliver_tcp`); unit at `startup.rs:1827`, `startup.rs:1885`, `deliver.rs:344`, `proc.rs:573`.\n\nThe alive-arm tests are real and they pass. The precise gap: **every alive-arm test presents a pid that is alive AND genuinely the recorded process** — `std::process::id()`, or the runner's own parent. Not one constructs the discriminating condition the hazard is NAMED for: a pid that is alive but worn by a DIFFERENT process than the one recorded. There is no identity mismatch anywhere in this REQ's unit evidence.\n\nDo not restate this as \"it only covers the dead arm\" — that is false and one grep from refutation.\n\nSharpest specimen: `deliver.rs:344` is named `recycled_pid_address_does_not_misdeliver` and comments \"(e.g. recycled to this test process)\", but the fixture writes the row with `std::process::id()` and the probe reads that same live process back. Nothing is recycled. What it actually proves is that a dead ADDRESS spools. The uncovered arm reads as covered to a human not because the traceability gate was fooled, but because the test NAME asserts a property the FIXTURE NEVER CREATES.\n\nThe doc at `startup.rs:126-136` argues a SPEND defense — a dead-anchor seed stays taken so a recycled pid cannot re-take it under the victim's session id. That defense is sound for the branch it is on, and that branch is never taken: it engages only when `!is_process_alive(seed.parent_pid)`. The recycle vector runs the other way — harness dies, pid recycled by an unrelated process, bare probe reads ALIVE, the seed is never classified stale, `bind_taken_seed` BINDS. This is an auth-adjacent bind path.\n\n**`REQ-HAZARD-LISTEN-ORPHAN`** — same hole, second REQ. `startup.rs:843` `parent_is_gone` is `[impl->REQ-HAZARD-LISTEN-ORPHAN]`, and its doc says: \"Pure over `proc::is_process_alive` so the exit trigger is unit-testable without a real host fork.\" The purity is real and the unit test is real, but it can only ever exercise the PURE WRAPPER. The probe is the untestable part, and the probe is where the recycle lives. A recycled anchor reads alive, `parent_is_gone` returns false, the listener never exits, and the perch stays false-ONLINE — precisely what this REQ exists to prevent.\n\nSweep every hazard REQ whose evidence bottoms out in `is_process_alive` before assuming the breach stops at these two.\n\n## The nine sites, split by whether in-tree data can fix them\n\n### (a) Remediable with in-tree data — no schema change, the birth stamp is already on the record (4)\n\n- `shellhost.rs:324` `live_launch_winner` — alive means stand down, do not relaunch. A recycled pid makes a dead shell permanently unrelaunchable. `shell_pid_provably_dead` (shellinfo.rs:198) exists and is NOT called here.\n- `shellwake.rs:414` `resolve_wake` — same failure on the wake path, and the sharpest of the four: `read_waker_launch` already returns `(pid, birth)`, and the same file pairs correctly at line 701.\n- `livehost.rs:868` — reads the info.json pid bare, while `livehost.rs:760` in the SAME file calls `relay_liveness(pid, info.pid_started_at)` on the same record.\n- `liveness.rs:143` — already parses the raw record that carries `pid_started_at`.\n\n### (b) NOT remediable without a new stamp — these anchor on a PARENT pid, and no parent birth stamp exists (5, all HIGH)\n\n- `startup.rs:430` `bind_taken_seed` — carries the `REQ-HAZARD-WINDOWS-PID-RECYCLE` breach above.\n- `startup.rs:487` `bind_from_session_id`.\n- `startup.rs:843` `parent_is_gone` — carries the `REQ-HAZARD-LISTEN-ORPHAN` breach above.\n- `lifecycle.rs:1792` `harness_owner_gone`.\n- `lifecycle.rs:1822` `run_orphan_watch` poll.\n\nMeasured: `git grep -nE \"parent_pid_started_at|parent_started_at|parent_birth\" b7b00c3 -- crates docs` returns ZERO. `Seed` carries parent_pid, session_id, cwd, created — no birth stamp. So (b) has a hard prerequisite: **stamp the parent.**\n\n### Already resolved, recorded so they are not re-chased\n\n- FIXED at this sha, custody-first: `auth.rs:162`, `startup.rs:615`.\n- SOUND by positive identity, leave alone: `livehost.rs:1040` (exe basename + cmdline match) — the only kill-direction site that is sound.\n\n## Four comments assert a pid-recycle defense the code does not implement\n\nCorrect these by REPLACEMENT, not by annotating a caveat onto a claim that is simply false:\n\n- `startup.rs:427` — labels ITSELF \"Pid-recycle defense (5.1): anchor liveness on the stable parent pid.\" The defense is the bare probe.\n- `startup.rs:471-472` — doc on `bind_from_session_id`: \"the parent-pid anchor must be ALIVE (5.1 pid-recycle defense)\". Same claim, same bare probe at line 487.\n- `seed.rs:35` — calls `session_id` \"the pid-recycle discriminator (5.1)\". At startup.rs:430 the liveness gate runs BEFORE and independently of any session comparison, and the guard there is `seed.session_id.is_empty()` — an emptiness check that compares nothing. It discriminates nothing.\n- `lifecycle.rs:1781-1787` — claims anchoring on the stable `parent_pid` defends against recycling. Anchoring changes WHICH pid is probed; it does not make that pid non-recyclable. A stable anchor is not a recycling defense.\n\n## BINDING CONSTRAINT for whoever takes this — read before writing a test\n\n**The missing unit test CANNOT be honestly written at `startup.rs:430` today.** Constructing \"alive but not the recorded process\" requires a RECORDED IDENTITY to mismatch against, and no parent-side birth stamp exists on `Seed` or in `info.json`.\n\nIf the site work is done without stamping the parent first, the natural test to reach for is another own-pid test — and the REQ reads covered a SECOND time, with the same arm still undefended. The test debt and the site debt are ONE debt with ONE prerequisite. Stamp the parent, or the tag is a lie either way.\n\nSuggested order: (1) add the parent-side birth stamp to the seed/info record; (2) repair the five (b) sites against it and write the mismatch test that then becomes constructible; (3) repair the four (a) sites via `relay_liveness` / `shell_pid_provably_dead`, which need nothing new; (4) replace the four false comments.\n\n(3) is independently landable today and does not wait on (1).\n\n## Out of scope for this request\n\n- The enforcement lint: infra register, hertz's lane.\n- The 34 in-src `#[cfg(test)]` bare-pid call sites (9 files, plus 3 `use` imports): UNTRIAGED, stated explicitly so the absence is not read as \"there were none\". A test probing a bare pid fabricates a red rather than shipping a wrong decision, so it is a different polarity and a different lane (IR-15's class).\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":143,"title":"Bare-pid liveness probes: 9 production sites unsound to pid recycle, and two activated hazard REQs read covered with the named arm undefended"},{"body":"A soundness premise the codebase states about ITSELF has been falsified by measurement. `spt_store::shellinfo::shell_pid_provably_dead`'s docstring buys its known miss with **\"rare during steady-state operation\"** — i.e. it concedes that a recycled pid defeats the probe, and licenses the miss on the grounds that recycling effectively requires a reboot.\n\nThat scoping is false on this fleet's own hardware.\n\n## Measured (HFENDULEAM, 2026-08-03)\n\nWhile sampling process CWDs during an unrelated sweep, **pid 41356 was observed as two different processes about thirty seconds apart**:\n\n- first sample: an `spt_daemon-<hash>` test harness\n- ~30s later: a `PING` process **22 seconds old**\n\n**Same boot. No restart anywhere in the scenario.** The box was running a daemon test suite, which churns processes hard — an entirely ordinary state for a CI runner and gate box, not a contrived one.\n\n## Why the scoping is the load-bearing part\n\nThe write-up this premise supports told readers to demand a pid **plus a start-time** *when a restart is in the scenario*. Under that rule, a reader with no restart in view was licensed to accept a bare-pid probe. The measurement removes the licence: pid reuse is reachable inside seconds of ordinary operation on a process-churning box.\n\nSo this is worse than \"the probe is theoretically weak.\" A weak probe with an honest caveat is a known risk. A probe whose caveat tells you **when not to worry**, incorrectly, is a risk that has been actively hidden.\n\n## The near-miss that looks like evidence the probe works\n\nA prior incident (2026-08-01, on `PACER-0`) derived \"offline\" **correctly** through this class — and it did so **by luck**. The pid's new occupant was a SYSTEM-owned process, so the query returned `ACCESS_DENIED`, and access-denied reads as dead. The right answer arrived through an accident of ownership.\n\nIn the case measured here **both occupants were user-owned**, so that accident would not have applied. Anyone reading the 2026-08-01 record as corroboration that the probe is sound is reading a lucky outcome as a working mechanism.\n\n## What this request is asking for\n\nNot a fix to a named call site — releases#134 already fixed one (the bind conflict check, which paired the recorded birth). This asks for the **premise sweep**:\n\n1. Enumerate every shipping probe that decides liveness, death, or ownership from a **bare pid**, and every comment or doc that justifies one on steady-state/reboot-rarity grounds.\n2. For each, state whether it pairs a birth stamp (`relay_liveness`-style), and if not, what a wrong answer costs there — the consequence asymmetry differs per site and decides the correct unknown-default.\n3. Correct the falsified justifications **by replacement**, not annotation, so the retraction reaches every place the claim was made.\n\nRelated but distinct: **releases#134** (one call site, fixed by pairing the birth), **releases#138** (session-id rotation edges), **releases#139** (whether a Binder-role pid's liveness is evidence at all). This item is the premise underneath all three.\n\n## Provenance\n\npid-recycle observation by doyle during a `.worktrees` reconciliation; premise falsification, the 2026-08-01 ownership-luck analysis, and the corrected write-up by **todlando**, who refused to draw the register/board consequence and referred it. Filed by doyle.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":140,"title":"bare-pid liveness probes rest on a \"rare during steady-state\" premise measured false: pid reused in ~30s, same boot"},{"body":"The bind conflict check consults a pid whose liveness cannot answer the question it is asked, on the fleet's own dominant topology.\n\n## The mechanism\n\n`establish_perch`'s conflict check refuses a bind when the recorded owner pid is alive and the recorded session id differs. What that pid MEANS is recorded beside it: `pid_role_for` maps `HostingAuthority::ListenerOnly -> Relay` and `BrokerPty | NonAgent -> Binder`, and its doc states the distinction in the codebase's own words — *\"a listen path leaves a process holding the endpoint, every bind path leaves an ANNOUNCER THAT EXITS.\"*\n\n`prior_relay_died` already acts on that distinction: it returns early for a non-Relay record with the comment *\"binder or legacy: no knowledge of a holder's death.\"* The conflict check does not.\n\nSo for a **Binder** record — every spt-hosted endpoint, including the `hertz` specimen in #134 (`pid_role: \"binder\"`, `adapter: claude-spt:ccs`) — the check probes a process that has, by design, already exited.\n\n## Why that is more than imprecision\n\nA `true` from that probe on a Binder record can only mean one of two things:\n\n1. a RECYCLED pid (the #134 defect, now fixed by pairing the recorded birth), or\n2. a bind still in flight.\n\n**It cannot mean \"another session holds this endpoint\"**, because the process it asked about was never the holder.\n\nWhich raises the question #134 deliberately did not answer: what, if anything, is protecting an spt-hosted endpoint from a second session binding over it?\n\n## Why the obvious edit is not safe\n\nAdding `pid_role == Relay` to the check would make it honest — it would stop refusing on evidence it cannot read. It was deliberately kept OUT of #134 because it is not a safe drop-in: it changes behaviour on `Held` Binder records, i.e. on in-flight binds, which is a far wider blast radius than the recycled-pid arm, and it would REMOVE the only refusal an spt-hosted perch currently has without putting anything in its place.\n\n## The honest shape: two questions, not one edit\n\n- **(a)** Is a Binder-role pid's liveness ever legitimate evidence at this check?\n- **(b)** If it is not, what is the real squat guard for an spt-hosted perch — a broker-held session query, the `controllable`/status pair, or an explicit statement that bind-over is permitted for this topology and the protection lives elsewhere?\n\n## Stated as open, NOT as findings\n\nTwo claims in this issue are deliberately marked rather than asserted, because a filed question that quietly reads as a finding is how the next person inherits a guess:\n\n- **\"The real holder is the broker\" is an UNVERIFIED INFERENCE**, drawn from `pid_role_for`'s own doc plus the `BrokerPty` variant's name — not from reading the broker's session ownership. Making it load-bearing requires its own read.\n- **How often a Binder-role conflict refusal fires in the field HAS NOT BEEN MEASURED.** The field datum is one specimen. It is worth measuring before either question is answered: if the answer is \"only ever on the #134 bug\", then the check has been protecting nothing on that topology for as long as it has existed.\n\n## Kin\n\n- **#134** — the recycled-pid arm at this same check, fixed.\n- **#138** — the two other session-id rotation mechanisms.\n\nFound by **todlando** while reconning #134, and correctly kept out of it. Filed by doyle.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":139,"title":"bind conflict check probes a Binder pid that has already exited — what guards an spt-hosted perch from bind-over?"},{"body":"Two further mechanisms rotate a bound perch's `session_id` and leave the prior session's empowerment record standing, exactly as the boundary edge did before releases#117 fixed it. **releases#117 does NOT close these** — it closes the boundary edge only, and its hazard entry says so.\n\n## The two mechanisms (swept from every writer of `info.session_id`)\n\n| | site | what it is |\n|---|---|---|\n| (a) | `crates/spt/src/api/reporting.rs:77` | `cmd_boundary` — **fixed by releases#117** |\n| (b) | `crates/spt/src/api/auth.rs:149` | dead-owner re-pin: `info::mutate_info(\\|r\\| r.session_id = sid)` after the alive / owns-another / custody guards, with a loud `SESSION_REPIN` line at :151-155 |\n| (c) | `crates/spt/src/api/startup.rs:475+` | `establish_perch` re-bind: a fresh bind presenting a new sid over an existing perch whose owner is not alive |\n\nAn engine-room empowerment is keyed on the session id alone (`crates/spt-store/src/empower.rs`, `empowerments_file(session_id)`). After (b) or (c), the prior sid's record is unreachable by the seat and unswept by anything — and re-acquirable by rotating back onto that sid, which is the mechanism `REQ-HAZARD-EMPOWER-SESSION-RESURRECT` names.\n\n## Why this is a DROP and not a carry — the reason it is a separate request\n\nreleases#117 ruled that a boundary CARRIES the empowerment, because a boundary is **one session lineage continuing**: the actor on the far side of the rotation is the actor that proved the admin code, and dropping there would silently revoke a human's TOTP-proved grant every time an agent self-clears.\n\n(b) and (c) have the opposite polarity. Both are a **NEW session taking over a perch whose prior owner is gone** — the session that proved the admin code no longer exists. Authority must not follow that transition; it must drop.\n\nSame hazard class, same file family, opposite direction, different argument. Folding it into releases#117 would have smuggled a second ruling into a lane scoped to one, which is why it is filed rather than absorbed.\n\n## Suggested shape (not ruled)\n\nA drop at both seams, most likely reusing `drop_authority_at_edge`'s unconditional-call no-op shape (`crates/spt-store/src/engineroom.rs:428-431`) so the seat edges can call it without knowing whether the endpoint is the engine room.\n\nOpen question worth answering before building: whether the drop belongs at the two call sites or inside the sid-rotation primitive they share, so a fourth rotation mechanism added later inherits it rather than repeating this filing.\n\n## Lane note\n\n(c) is `establish_perch` — the same function carrying **releases#134** (the bind-conflict bare-PID ABA). These two want the same lane; that is a dispatch decision, not a scope decision.\n\n## Provenance\n\nSwept and correctly refused-in-lane by **todlando** during the releases#117 recon, who brought the polarity argument rather than folding the sites in. Filed by doyle.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":138,"title":"dead-owner re-pin and establish_perch re-bind leave the prior session empowerment standing (releases#117 closes only the boundary edge)"},{"body":"`endpoint list --json` emits `psyche_host_error` unconditionally while its two sibling fault annotations skip when absent. The inconsistency is real and shipped; this request is about whether the SHAPE should change, not about the doc — the doc drift it exposed is being fixed separately as a documentation defect.\n\n## Measured (worktree `.worktrees/locksmith-t1` @ `de168dd`, which matches main for these lines)\n\n`crates/spt/src/cli.rs`, the `SelfPinJson` struct:\n\n```rust\npsyche_host_error: Option<String>,                      // 4566 — NO serde attribute\n\n#[serde(default, skip_serializing_if = \"Option::is_none\")]\ntranslation_fault: Option<String>,                      // 4571-4573\n\n#[serde(default, skip_serializing_if = \"Option::is_none\")]\nhost_error: Option<String>,                             // 4579-4581\n```\n\nSo a perch with no psyche-host fault emits `\"psyche_host_error\": null`, while the same perch omits `translation_fault` and `host_error` entirely. The two siblings document their own reasoning in-place — \"Additive, `skip_serializing_if` keeps the JSON byte-identical when absent (N-1 safe)\" — which `psyche_host_error` predates.\n\nThe code comment at `cli.rs:23552` states the current behaviour deliberately (\"always serialized (no skip-if-none)\").\n\n## The question\n\nShould `psyche_host_error` gain `#[serde(default, skip_serializing_if = \"Option::is_none\")]` to match its siblings?\n\n**For:** the three fields are one render pass, described together in the harness contract, and consumed together by adapter authors. One of the three behaving differently is a trap that costs an adapter author a wrong presence check. It is also what the public doc already (wrongly) promises, so changing the shape would make the doc true rather than requiring the doc to explain an exception.\n\n**Against:** it is a change to a SHIPPED public wire shape on the harness-contract surface. Any adapter that currently keys on the KEY being present — which today is always true — would start seeing it absent. That is exactly the N-1 direction the siblings' comments were written to protect, pointing the other way.\n\nNot ruled by me: a shipped public wire shape is operator triage, not a gater call, and it is not urgent — the doc correction removes the active harm (an adapter author trusting the prose and keying on presence reads a clean perch as faulted).\n\n## Related\n\n- The doc defect this surfaced (`docs-site/src/harness-contract/integration-checklist.md:303` claims `psyche_host_error` is omitted when absent, contradicted by its own example at :266) is being corrected separately as a doc-only fix. That correction states the CURRENT behaviour. If this request is later accepted, the doc changes again.\n- Found by **todlando** during the releases#115 reader sweep, correctly filed rather than fixed in-lane — it is outside that lane's scope and the reading was genuinely ambiguous.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":136,"title":"endpoint list --json: psyche_host_error never skips while its two sibling fault fields do"},{"body":"primarily as an event for shells to observe. but also possibly something to notify agents of so they aren't overly verbose while the user isn't watching?\n\nthe \"defocus\" edge should auto-coincide with the \"detach\" edge created by `spt rc`/the remote client\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":135,"title":"idea: window-focus-edge surfacing"},{"body":"> ### ⚠️ CORRECTED 2026-08-03 (hertz — original filer and original diagnostician)\n>\n> **The mechanism this issue was filed on is FALSIFIED AT SOURCE.** Both rungs of\n> `detached_no_inherit_env` ALREADY set `CREATE_NO_WINDOW`. The original title asserted\n> otherwise and the `MECHANISM` and `FIX` sections below still state it; they are retained\n> for the record and marked, not deleted.\n>\n> **Do NOT land a `CREATE_NO_WINDOW` edit under this number.** The emitted flag word would be\n> bit-for-bit identical before and after — a no-op that would close this issue while the real\n> symptom kept happening, with the board reading as though it had been addressed.\n>\n> **The symptom is REAL** (operator-reported, 21 husk windows) and this issue stays OPEN. It is\n> a correctly-open issue whose first diagnosis was wrong, not a CUT.\n\n**WHAT IS ACTUALLY TRUE (source-verified, line-cited):** there is exactly ONE `CreateProcessW`\ncall in `spt-daemon/src/daemon.rs` — at `:1187` — and it passes\n`BASE_FLAGS | extra_flags | env_flag | ex_flag`. `BASE_FLAGS` is defined at `:1105`:\n\n```rust\nconst BASE_FLAGS: u32 = 0x0000_0008 | 0x0000_0200 | 0x0800_0000;\n// DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW\n```\n\n`0x0800_0000` IS `CREATE_NO_WINDOW`. Both rungs reach that single call:\n\n- rung 1 — `detached_no_inherit_env` (`:1495`) → `create_process_detached_keep_handle` directly;\n- rung 2 — `detached_no_inherit` (`:1300`) → `create_process_detached` (`:902`), whose entire body\n  delegates to `create_process_detached_keep_handle`.\n\n`extra_flags` is OR'd ON TOP of `BASE_FLAGS`, so the ACCESS_DENIED fallback drops\n`CREATE_BREAKAWAY_FROM_JOB`, never the base. There is no run in which the proposed edit changes\nbehavior.\n\n**CANDIDATE DIRECTION — offered as direction, NOT as a diagnosis** (the symptom has not been\nreproduced and no cause is claimed): `DETACHED_PROCESS` gives the service NO console. A console\nchild spawned BY that service with no creation flags of its own therefore gets a NEW console\nallocated — a visible window. The service's own GRANDCHILDREN are the candidate. If that is it, the\ndefect is in what the SERVICE spawns, not in how the daemon spawns the service, and no flag on\nthese two rungs can reach it.\n\n**NEXT STEP, observation-first:** start from an actually-observed window → enumerate to its owning\npid → walk its parent chain. Do not start from a code reading again; that is how this issue got its\nfirst, wrong answer.\n\n---\n\n*Original filing below, retained unedited except for the FALSIFIED markers.*\n\nOperator-reported 2026-08-02: 21 lingering Windows Terminal windows on hfenduleam titled ping -n 120 127.0.0.1 showing error 0x800700e8 (ERROR_PIPE_NOT_CONNECTED). Diagnosed by hertz; windows were husks from his sanctioned A/B experiment (80 runs of the tree-teardown test), all closed, zero live processes behind them.\n\n**MECHANISM — ❌ FALSIFIED, retained for the record (see CORRECTED note above):** detached_no_inherit_env (spt-daemon/src/daemon.rs:1495) spawns with CREATE_BREAKAWAY_FROM_JOB | CREATE_SUSPENDED (fallback rung: bare CREATE_SUSPENDED). Neither rung sets CREATE_NO_WINDOW or DETACHED_PROCESS, so the child allocates a console and Windows default-terminal turns it into a window; a LAUNCH FAILURE window is held open regardless of closeOnExit. Every OTHER spawn path in the tree sets the flag (cli.rs:7913, brainproc.rs:1171, daemon.rs:1103, daemon.rs:2414 with the explicit no-console comment) — this helper is the odd one out, and its name misleads: detached means breakaway-from-job here, not DETACHED_PROCESS.\n\n*(The final clause about the NAME is the one part of that paragraph that survives: the helper's name does mislead — \"detached\" means breakaway-from-job, not `DETACHED_PROCESS`. A rename is recorded as a candidate rider on IR-16's product lane, where that file is already open.)*\n\nPRODUCT SURFACE: 8 callers; 7 are tests, but servicehost.rs:770 is the REAL supervised [service] spawn — on Windows every supervised resident service pops a visible terminal window in shipped behavior.\n\n**FIX — ❌ FALSIFIED, DO NOT APPLY (see CORRECTED note above):** ~~add CREATE_NO_WINDOW to both rungs. Handle inheritance, capture file, breakaway/job semantics, parentage all unchanged — only window visibility moves.~~ DETACHED_PROCESS would still be WRONG for this helper (one caller captures stdout to a file; the helper's contract is jobs, not consoles).\n\nGATE CONSTRAINT: servicehost's spawn path is the same path resident_service_e2e exercises, and that test burned a bring-up deadline on this box tonight (specimen 30782259675, cause unidentified) — NO claimed connection, but any eventual fix must be gated WITH resident_service_e2e rather than assumed inert. Own thin lane.\n\nRequester: doyle; diagnosis + fix proposal: hertz; sighting: operator. Falsification of that diagnosis: hertz, 2026-08-03, during the IR-18 lane that was to have carried the rider.\n\n---\nRequester: doyle\n","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":131,"title":"Windows supervised services leave visible console husks — mechanism UNKNOWN, first diagnosis falsified"},{"body":"Filed from the BAROMETER golden window (doyle, 2026-08-02). Run 30755949373 (head 2138b16, Windows/hfenduleam, Phase A): resume_no_control_steal_e2e::brain_respawn_keeps_every_session_controller_and_still_promotes failed once — session 0 of 3 received ZERO new output frames in the post-resume window (froze at tick 7) while sessions 1–2 gained 13 and promotion succeeded; the rig names this its Failure-A signature (resume re-attach displacing the local controller). FIRST SIGHTING: no FLAKE-LEDGER row, no HEAVY grouping, no prior recorded flake history; the same test passed 2605/2605 on head 3 (a0b8d5f) on the same box, and the head delta is provably innocent (xtask-only, product crates byte-identical).\n\nSo either (a) a real low-probability race on the REQ-BRAIN-RESUME-NO-CONTROL-STEAL surface — one session's controller genuinely stealable/starvable across brain respawn under load — or (b) a rig race manufacturing the frozen-tick read. Both are worth the hunt: (a) is the v0.13 rc-attach-wedge lesson (a 'flake' that was a REAL throughput bug), (b) is a golden-window red generator. Deliverable: an RCA that names the mechanism, plus a FLAKE-LEDGER row keyed by test name (backfill discipline: state what evidence survives — run id 30755949373, job 91518552081, the gate line with ticks_before/after arrays is in the job log).\n\nOutcome of the ruled same-sha rerun (whatever it says) should be appended here as a second data point.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2j-w","name":"state: WIP","description":"Handed to an agent / in flight","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":123,"title":"resume_no_control_steal_e2e: one session's controller froze post-resume at golden scale — first-sighting race, hunt it"},{"body":"Filed from the BAROMETER kill-auth close (todlando's recommendation, doyle's ruling 2026-08-02: hardening on a closing milestone files past — the #118/#119 shelf).\n\nThe v0.52.0 kill gate fires only on relay_liveness == Held (pid + birth-stamp pair). hertz measured the pair test's Linux imprecision: /proc stat field 22 is CLK_TCK=100 jiffies, so two processes starting in the same 10ms tick are indistinguishable — and the tick collision is hit at ORDINARY rates (4/15 idle, 7/15 loaded on kitsubito, in the drive_e2e fixture shape). The shipped gate therefore NARROWS the recycled-pid mis-fire to the same-tick window on Linux (Windows FILETIME closes it outright) — stated as a narrowing in the shipped docs.\n\nProposed hardening: before firing on Linux, corroborate the Held pair with the target's IMAGE PATH — a stranger inside a 10ms tick is overwhelmingly a different binary. This is exactly the rig-side technique KNOWN-HAZARDS 7.58 already prescribes for test rigs, so it unifies the two populations (rig + product) on one rule instead of two.\n\nScope note: the residual window's precondition (our process dies AND the OS recycles its pid into the same tick) is its own partial mitigation; this filing is about closing it properly, not about urgency.\n\n---\nRequester: doyle (todlando's recommendation)","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":120,"title":"harden the authenticated kill: corroborate the pair test with the target's image path (unifies KH 7.58's rig rule with the product gate)"},{"body":"Golden run 30720655534 (2026-08-01, sha 13e94d5, Windows hfenduleam): poll_envelope_e2e api_poll_emits_whole_self_delimiting_events failed — `spt api --adapter spt poll doyle` exited 1 with EMPTY stdout and stderr carrying ONLY the two autostart lines (DAEMON_AUTOSTART + \"ELEVATED_DAEMON: no unelevated identity to drop to — daemon inherits the elevated token\"). Single sample; file untouched by DOORBELL (last touch ac6c802, on main).\n\nRCA so far (doyle):\n1. The box's real daemon (pid 15788, unelevated, started 01:10 local) was ALIVE continuously through the failure instant — verified by process creation time. So `ensure_running`'s is_running() pre-check returned FALSE for a live daemon: a transient probe failure (pipe connect timeout/refusal) under full-parallel Phase-A load, with TWO golden runs queued plus live agents on the box. Every api invocation runs ensure_daemon() (REQ-DAEMON-3), so the universal anchor converts one missed probe into an autostart storm arm.\n2. The autostart then spawned a daemon from the runner-SERVICE context: elevated, no unelevated identity to drop to (daemon.rs:814 arm). ELEVATED_DAEMON appears in NO green run log (HANDRAIL golden 30694163123: zero occurrences) — first CI sighting. The stray elevated daemon is gone from the box (lost the pipe race and exited); no cleanup was needed.\n3. UNEXPLAINED: the poll's exit 1. Every refusal arm in api/mod.rs + delivery.rs prints to stderr before returning EXIT_REFUSED=1, and cmd_poll returns 0 unconditionally; nothing printed. A silent exit 1 with empty stdout is BOTH the open RCA question and a defect in its own right (CLI honesty: an exit-1 arm that says nothing).\n\nSCOPE:\na. Find and fix the silent exit-1 arm on the api poll path (repro: elevated context + no reachable daemon at probe time is the observed precondition).\nb. Harden is_running() against transient probe failure converting into autostart beside a live daemon (retry-with-deadline before declaring absent, or a busy-vs-absent distinction on the probe).\nc. Test-side hermeticity: the poll drain needs no daemon; evaluate suppressing the universal autostart in this test's isolated home (standing stop marker in setup) so the test measures the envelope contract, not the box's daemon weather.\nd. FLAKE-LEDGER.md row (first sighting) in the same change.\n\nA second occurrence on the independent same-sha run 30720656689 (in flight) upgrades this from observed to urgent; its result will be recorded here.\n\nRequester: doyle (RCA of golden red at 13e94d5).\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":94,"title":"api poll exits 1 silently when a transient daemon-probe miss triggers autostart under an elevated context"},{"body":"TEST DEFECT (not product): servicehost_supervision_e2e bits_swap_under_the_hold_and_the_new_ones_come_up_on_release asserts new-process identity by PID INEQUALITY (`assert_ne!(second, Some(first))`, servicehost_supervision_e2e.rs:475). Windows recycles pids aggressively under suite churn; golden run 30720655534 (2026-08-01, sha 13e94d5) failed it with left/right both Some(47100) while the log SELF-PROVES the swap happened: SERVICE_STARTED pid 47100 → SERVICE_QUIESCED cooperative exit under hold → SERVICE_STARTED pid 47100 (recycled), and the immediately-preceding assertions passed — ServiceOutcome::Started on release AND `back` (the swapped-in binary's beacon), which would have failed had the old binary still been running. Functional swap proven; the pid assert is a false-proxy discriminator.\n\nThis is the documented pid-reuse class (KNOWN-HAZARDS pid_started_at precedent: pid-only identity is unsound past any exit on Windows). File untouched by DOORBELL (last touch 1488e39, already on main) — pre-existing surface.\n\nFIX: replace the pid-inequality assert with the (pid, process-start-time) pair — birth-stamp comparison per the pid_started_at precedent — or drop it as redundant (beacon + Started outcome already discriminate a missed swap). Add the FLAKE-LEDGER.md row (first sighting 2026-08-01 run 30720655534) in the same change; evaluate a flake-registry.json entry per its criteria.\n\nRouted to hertz per the dispatch split (test-only rework). Rides the next head, not v0.51.0.\n\nRequester: doyle (RCA of golden red at 13e94d5).\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2j-w","name":"state: WIP","description":"Handed to an agent / in flight","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":93,"title":"servicehost swap test asserts process identity by pid inequality — unsound under Windows pid reuse"},{"body":"Upstream half of spt-progress-tool#52 (flynn, observed live 2026-07-31 on alchemy-testbed#43; ruled upstream-accepted by doyle 2026-08-01). A single `spt shell send <ref> <text> --file <path>` is ONE intent — the text consumes the staged file — but the frames drain text-first, so the create mints with no attachment and the file strands in staging for whatever write comes next. Content lost in silence at the moment of capture; the one-command form is the intuitive one. Independently reproduced by doyle the same night filing releases#78 (used the two-command workaround by accident).\n\nRULED FIX, upstream: within ONE send invocation, the file frame spools/delivers BEFORE the text frame. Emission-order change only — no wire-format change, no new field, no N-1 concern (file-first is byte-identical to the already-proven two-command pattern). The frame contract gains one sentence: within a single send, file frames precede the text frame — an ordering promise scoped to same-invocation only, no global cross-send claims. The correlation-key alternative (xfer-id on the text frame) was considered and refused as a heavier contract change solving the same case.\n\nAlchemy's side has a shipped retro-apply mitigation (converges like every other repair) — it stays as belt-and-braces and can retire on its own schedule after this lands.\n\nNext-batch register. Requester: doyle (upstream ruling on flynn's spt-progress-tool#52).\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":81,"title":"one shell send carrying text + --file delivers the text frame first, stranding the file"},{"body":"Observer: lia (discovery by comparison — a healthy node has NO identity/release-keys.json; the genuine anchor is compiled in and the file only overrides it). Relayed by perri (claude-spt F-029 @1a03b9a); filed by doyle.\n\nTHE INCIDENT SHAPE: a box carrying debug-rollout residue (release-keys.json with an expired debug key + fabricated version floor 9001) silently narrowed its trust anchor — rejected every genuine release as a rollback while reporting healthy version status. Nothing on any CLI surface distinguishes that box from a clean one; the state is discoverable only by an action that fails, or by comparing against a known-good node.\n\nSCOPE RULING (doyle): the public adapter surface does NOT need the debug mechanism documented — DEBUG-ROLLOUT.md owns it and it is maintainer-facing by design. The durable fix for discovery-by-comparison is a STATUS SIGNAL: spt update status (and/or the doctor surface) states loudly when the trust anchor is overridden by identity/release-keys.json, e.g. 'trust anchor OVERRIDDEN (identity/release-keys.json, key <id>, channel <ch>)'. An override in effect must never be silent; cleanup guidance (delete the file to restore the builtin anchor) rides the message.\n\n---\nRequester: lia (via perri F-029; filed by doyle)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":64,"title":"change: surface an active release-keys.json trust-anchor override in status output"},{"body":"Finding by lia (Athenaeum, 2026-07-31/08-01), flagged via perri, filed by doyle so it is not lost. Context: claude-spt shipped its Linux binaries mode 644 (exec bit lost in a Windows-built archive — fixed adapter-side @claude-spt 2aa9768 + REQ-HAZARD-ADAPTER-EXEC-BIT). spt-core extracted faithfully and was NOT at fault; the node was still bricked for that adapter (no hooks, no endpoint hosting) until manual chmod.\n\nQUESTION for the design record: should spt-core's extractor treat an adapter's DECLARED entry binary that arrives non-executable as (a) force exec-bit as defense in depth, (b) force + warn loudly, (c) refuse to install with a diagnostic naming the file and mode, or (d) extract faithfully as today (adapter packer owns correctness)?\n\nTENSION to grill, not pre-decided: forcing silently masks the adapter's packaging defect class that was just caught by red-proven packer validation; extracting faithfully bricks the node for that adapter until a human intervenes. A slip in ANY adapter reproduces this — the question is which side of the seam owns the last line of defense, and whether the failure is loud or silent either way.\n\n---\nRequester: lia (via perri; filed by doyle)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":62,"title":"change: should the extractor force (or loudly refuse) a non-executable declared entry binary?"},{"body":"Evidence and design from hertz's #42 evaluation (2026-07-31), filed by doyle so diagnosis does not smuggle production code.\n\nTHE GAP (verified at pinned iroh =0.98.2): spt-net's connect_with_alpn is the whole dial seam and it maps iroh's structured connect error to a string — every path detail is discarded at that line. #41's observability gives address-RESOLUTION attribution (RouteLeg tokens, peer_health, advertised relay URLs) but nothing distinguishes a dial that went over relay from one that went direct, nor records whether the relay path was attempted. Result: any 'died at quic-connect' report — including releases#42 fact 2 — is unfalsifiable in both directions.\n\nTHE INSTRUMENT EXISTS in the pinned version: Endpoint::remote_info(endpoint_id) -> Option<RemoteInfo>, addrs are TransportAddrInfo { addr, usage: Active|Inactive }, and TransportAddr::is_relay() in iroh-base 0.98.0 — per-address relay-vs-direct, active-vs-known.\n\nASKED: at the dial seam, on connect failure (a) stop flattening the iroh error to a string, (b) record the relay/direct split of the addr dialled plus remote_info's active set. Product change — todlando's lane per the dispatch split; hertz consumes the output for #42.\n\n---\nRequester: hertz (via doyle; #42 evaluation finding)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"}],"number":60,"title":"add: dial-path attribution at the connect seam (relay-vs-direct, un-flattened errors)"},{"body":"#43 found (and fixed for the firewall verify path) the read-side generalization of KNOWN-HAZARDS 7.58: daemon.pid is written BEFORE the seed-socket bind arbitrates single-daemon-per-home, so a losing starter overwrites the winner on exit — the file can name a dead pid while the real daemon serves (measured on HFENDULEAM: breadcrumb 40332 dead-since-startup, serving daemon 23416).\n\nThe firewall verify path now re-derives validity from the process table + image path with the trigger at the post-bind site. Remaining readers of daemon.pid (cli.rs ~4908 / ~5043 at the time of finding, plus any others a sweep finds) are unaudited against this class: any feature-gating or identity decision keyed on the raw breadcrumb inherits the same defect. Sweep authoritatively (grep-census, cfg(test)-excluded), classify each reader (display-only vs decision input), fix decision inputs to the process-table pattern.\n\nOrigin: doyle ruling on #43 limit 2, 2026-07-31.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":55,"title":"Audit remaining daemon.pid readers — breadcrumb is not an identity oracle (7.58 read-side)"},{"body":"Deferred from #43 (doyle ruling 2026-07-31, option L3): #43 ships the Linux leg as verify-only (L2 — detect active firewall ufw/nft/firewalld, verify inbound UDP against the currently bound port, render the exact command, zero writes) because production BindScope::All binds an ephemeral UDP port — a durable firewall rule needs a pinned port, and minting a stable-port knob is a transport-config + security-posture change with pairing/ticket/two-host ripple that requires its own wave and gate.\n\nScope when activated: (1) stable-port knob (config/env), default off; (2) install/repair writes the port rule keyed to the resident daemon binary path (hazard 7.61 discipline — green must assert the rule matches the binding binary, never the invoking CLI argv[0]); (3) pairing/ticket/two-host ripple gated; (4) security-posture ruling on pinned-port exposure rides the wave (operator-visible).\n\nRelocation record: this is the repair half of #43's Linux leg — relocated here, not dropped (intake stipulation: dropped scope never dangles).\n\nAttachments:\n- [alchemy-l1-seed.txt](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/shx-1785483753362080800-alchemy-l1-seed.txt)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":54,"title":"Linux stable-port knob + firewall rule write (L1 half of #43, deferred by ruling)"},{"body":"Split out of WAN-truth #40 lane 1 (doyle-ruled 2026-07-31: right scope cut, file so it does not evaporate).\n\n**What #40 already fixed:** `EpochSource` now writes durably and `atomic.rs` no longer names epoch counters as safe-for-non-durable RECONSTRUCTIBLE state. That sentence had been a documented-false invariant — the counter is not reconstructible (nothing regenerates it past its historical maximum), and the NUL-husk-to-0 degrade froze every node's advertised roster row fleet-wide (KNOWN-HAZARDS 7.60).\n\n**What this request covers:** the rest of that doc list, audited rather than assumed. `atomic_write_bytes`' doc still names registry snapshots, peer caches and the release cache as safe for the non-durable path on the same reasoning that turned out to be false for the epoch counter. The reasoning is only sound where a post-crash NUL husk genuinely parse-fails to *absent* AND absent is genuinely recoverable — the epoch counter satisfied the first half and failed the second, silently, for weeks.\n\n**Shape of the work:**\n1. Census every `atomic_write_string` / `atomic_write_bytes` caller (~26 per the doc's own count) and classify each record: is a husk distinguishable from absent, and is absent actually recoverable to the same value or a safe successor?\n2. For any record where absent is NOT recoverable, either move it to the durable sibling or state explicitly what regenerates it. The epoch case shows the failure mode is not \"we forgot to fsync\" — it is a *classification* claim in a doc comment that nothing tests.\n3. Update the `atomic.rs` doc list to whatever the census actually supports, and consider whether the classification deserves a per-caller assertion rather than one prose list far from the call sites.\n\n**Why not urgent:** #40's fast-forward self-heal makes the epoch counter's durability optional (the node repairs itself on boot), and no other record on the list has a known field incident. This is the audit that finds the next one before it costs a fleet outage, not a response to a live failure.\n\nKin: KNOWN-HAZARDS 7.60, `REQ-ROSTER-SELF-LEASE-HEAL`, `REQ-HAZARD-PERCH-RECORD-POWER-LOSS` (the durable-scope ruling this would revisit).\n","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":52,"title":"Audit atomic.rs's RECONSTRUCTIBLE-state doc list — the epoch counter was on it and was not reconstructible"},{"body":"currently, the only way `shell cmd` commands communicate to agents is (seemingly) via `spt send`. is that right? if so, we should update it so shells can also simply pass back stdout-->it is mirrored to `shell cmd`'s own stdout for the agent to perceive. saves time and tokens.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":51,"title":"add: shell cmd to support piping stdout from shell binary"},{"body":"Operator-filed 2026-07-31 (via doyle).\n\nEvery active `spt rc` connection freezes whenever the daemon brain restarts under it: `spt daemon refresh` reproduces it directly, and `spt update` with a staged spt-core update (any equivalent brain-swap action) reproduces it the same way.\n\nThis is a LONG-STANDING bug with a failed-fix history — it has been attemptedly fixed before, more than once, and none of the attempts held. Treat every prior \"fixed\" claim in the history as refuted by field evidence; the RCA must explain why the prior attempts failed, not just propose another patch.\n\nContext the RCA should weigh (non-binding): the broker/brain split exists precisely to keep endpoints (including rc viewports) alive across a brain swap (seamless self-update architecture); rc reconnect obligations and no-endpoint-terminates-during-update obligations both exist in the registry and have shipped evidence, yet the field behavior persists — so either the contract is satisfied in test but unsound in the field path, or a different layer (viewport pump, attach lease, broker handoff) is the real owner.\n\nOperator sequencing ruling (2026-07-31): this Request is NOT in the current greenlit batch. It goes to a joint RCA-first lane alongside #42 (relay path RCA) AFTER the current EVAL batch (#40 #41 #43 #48) ships; fixes for both ship together from that RCA. RCA-first discipline applies (agreement-never-promotes-to-proven).\n\nAttachments:\n- [mint-rc-freeze.txt](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/shx-1785475938589153900-mint-rc-freeze.txt)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":49,"title":"all spt rc connections freeze across `spt daemon refresh` / staged self-update restart (long-standing; prior fixes unsuccessful)"},{"body":"Two specimens, consecutive main thin runs, both at shas whose golden passed the full nextest battery on the same box:\n- run 30602845316 @00f3f92: psyrelay::tests::notify_reaches_own_user_only — notif_id \"cafe:2\" vs expected \"cafe:1\" (722/723 pass). The id mints from EpochSource under ambient SPT_HOME; the assertion encodes a fresh-counter-per-process assumption.\n- run 30540268719 @d26a2b2: daemon::tests::a_captured_spawn_inherits_only_the_handle_in_its_allowlist — different subsystem, same lane.\n\nStructural divergence: ci.yml unit job runs cargo test --workspace --lib --bins (all tests of a binary threaded in ONE process, env shared); golden runs nextest process-per-test. with_home serializes env-mutating tests on a binary-local mutex, but the class evidently leaks around it (exact interleaving = the RCA).\n\nScope: RCA the interference (both specimens), fix the isolation defect(s), and rule whether the thin unit lane converts to nextest to match golden's process model. Release impact: none — v0.47.0 ruled PROCEED on this evidence (doyle, 2026-07-30); this is lane hygiene, but every thin-lane red at a green sha burns a deployah referral, so it is not cosmetic.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2j-w","name":"state: WIP","description":"Handed to an agent / in flight","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":47,"title":"thin-lane unit(Windows) red at golden-green shas: in-process test-isolation class under cargo test threading"},{"body":"Follow-on to #32 (doyle-dispatched, hertz lane). The #32 RCA established the defect family: test reapers that (a) taskkill breadcrumb pids without identity checks can kill pid-reuse strangers, and (b) string-compare image paths break under slash-spelled CARGO_TARGET_DIR (refuse-then-panic-and-leak, defect found in shipped 0443613 guard, fixed in the #32 lane via canonicalized shared reap::same_image).\n\nScope: the 12 flow-confirmed daemon.pid taskkill /F sites (no /T) enumerated in the #32 lane's dbccbb3 commit body — census re-asserted fresh at d26a2b2, zero drift, /T=0 set == exactly those 12 files. Mechanical port of the authenticated reap helper (identity+image checks) to each.\n\nLane: fix/reaper-port-12sites, STACKED on fix/authenticated-test-reapers (imports tests/common/reap.rs, not on main yet); merges with/after the #32 lane in the next thin-lane batch. Filed by doyle on hertz's behalf (alchemy-0 unreachable from hertz's perch — NO_PERCH; deferred-not-filed guard honored).\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2j-w","name":"state: WIP","description":"Handed to an agent / in flight","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":46,"title":"tree-kill/pid-reuse unsound reapers: port authenticated-reap to the 12 remaining taskkill /F sites"},{"body":"Split from the cross-site stranding RCA (hertz F6). Two unexplained facts:\n\n- Every fleet node homes on iroh-CANARY relays (usw1-1/use1-1.relay.n0.iroh-canary.iroh.link) while daemon.json says relay=n0/N0Default.\n- Relay HTTPS is reachable (200 in 240ms) yet dials with relay-bearing EndpointAddrs still die at quic-connect — the relay path is not producing connections at all. Candidates: iroh =0.98.2 dial semantics with stale direct addrs + relay present, or relay attach never actually established.\n\nA working relay path would have masked the entire stranding defect class; conversely the stranding fixes are only fully effective WAN-wide if relay fallback also works when UDP inbound is filtered (gravity firewall, DO droplet UDP allowlist). Needs instrumentation first (own-EndpointAddr/home-relay surfacing from the observability request).\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":42,"title":"relay path produces no connections: canary-vs-config mismatch + dial-via-relay ineffective (RCA lane)"},{"body":"need to `wayfinder` or `grill-with-docs`:\n- analyze the project history across multiple historical records (commits, milestones, roadmap, plans) to identify where the submodule seams should be\n- each submodule is independent of spt-core or its other submodules:\n  - builds separately, compiles a library\n  - has its own unique CI flow and int tests\n- as such, spt-core is alleviated from the bulk of today's CI tests, and must mostly run the tests which cross the submodule boundaries\n\ngoal is to make CI faster and more compartmentalized, potentially allowing for parallelized per-submodule CI, and fewer CI tests run per milestone.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":34,"title":"idea: split spt-core into submodules"},{"body":"\n# `worker_lifecycle_e2e` Windows Phase A — intermittent, mechanism WEAKENED, guard UNEXERCISED\n\n**Status: neither a proven flake nor a proven defect.** Deliberately NOT in the flake registry — the admission gate says a red a named mechanism can explain is a defect wearing a flake label, and the breadcrumb tree-kill mechanism is now a *weakened* candidate rather than a proven one. Registering it would be laundering.\n\n## The two step-level readings\n\nRead from the GitHub jobs API at step level, never from the run conclusion and never from the CI informant ping (which named only `test(failure)` and did not mention the two-host jobs at all).\n\n| candidate | job | step 13 `Test — Phase A` | step 14 Phase B |\n|---|---|---|---|\n| `ce4386e` | 90742055246 | **completed/failure** | skipped |\n| `8f3e10b` | 90749868137 | **completed/success** | ran |\n\nFailing test: `spt::worker_lifecycle_e2e worker_start_mints_on_stdout_and_stop_authenticates_by_parent_sid`.\nCI output shape: `running 1 test` then a bare `(test failed with exit code 1)`, **no panic text**.\n\n⚖ **Exit 1 is NOT a Rust assertion failure — libtest exits 101 on a failed assertion.** That single number falsified the original fail-closed/ADR-0053 hypothesis: every failure path in that test is an `assert!` with an interpolated message, so no assertion ever fired. The process was **terminated**.\n\n`worker_lifecycle_e2e` appears in NEITHER golden.yml Phase A nor Phase B binary list, so it runs in **Phase A** (`cargo nextest run --workspace` minus the heavy class, `NEXTEST_PROFILE=ci-windows`, `test-threads = 8`). Established from the extracted filterset, not assumed.\n\n## Intermittency rate — measured, not suspected\n\n| tree | observation | source |\n|---|---|---|\n| `ce4386e` (unrepaired) | **RED** | CI Phase A, job 90742055246 |\n| `ce4386e` (unrepaired) | **GREEN** | local rig, CI's extracted Phase A filterset, 2170 tests across 108 binaries, 220s, `2170 passed (8 leaky)`, target PASS at 4.966s |\n| `8f3e10b` (guard applied) | **GREEN** | CI Phase A, job 90749868137 |\n\n⚠ **DO NOT INFER A STABLE RATE FROM THREE OBSERVATIONS.** An earlier draft of this issue — and the ruling behind it — said \"roughly 1-in-2\". That phrasing is withdrawn: three observations do not establish a rate, and a reader who treats 1-in-2 as a probability will size a reproduction budget off it and be wrong. What the table supports is only this: **the failure is intermittent, it has been observed once, and a green is not evidence of its absence.**\n\n⭐⭐ **Consequence: a green Phase A is a reading the UNREPAIRED tree also produces.** A pass that also happened while the defect was live cannot distinguish repaired from lucky, so the `8f3e10b` green is **zero information** about the guard — not weak evidence. Zero.\n\n## Breadcrumb census — enumerated, with its predicate\n\n⚠ Predicate stated because a count without its tool and scope is not reproducible evidence. **Scan root `crates/`, `grep (GNU grep) 3.0`, fixed-string (`grep -rlF`), measured at `8f3e10b`.** These are *containment* intersections, not proven data-flow; the flow-confirmed subset is called out below.\n\n> ⭐ An earlier revision of this section said \"GNU grep 4.9\". That was **wrong** — 4.9 is this box's `sed`; `grep` is 3.0. The error was caught by a self-labelling census harness that emits `grep --version` itself rather than trusting a hand-typed label. Recorded because it is the thirteenth instance of this class in one day, it occurred *inside the document describing the class*, and **a generated label caught what a written rule had failed to prevent twice.**\n\n| set | predicate | count |\n|---|---|---|\n| contains literal `daemon.pid` | `grep -rlF 'daemon.pid' crates/` | 19 |\n| contains literal `brain.ready` | `grep -rlF 'brain.ready' crates/` | 34 |\n| contains literal `taskkill` | `grep -rlF 'taskkill' crates/` | 57 |\n| `daemon.pid` ∩ `taskkill` | intersection | **18** |\n| └ of those, tree-kill (`\"/T\"` present) | `grep -qF '\"/T\"'` | **6** |\n| └ of those, `/F` alone (no `/T`) | complement | **12** |\n| `brain.ready` ∩ `taskkill` | intersection | **28** |\n\nThe 6 tree-killers, enumerated (an enumerated list is falsifiable file by file; a bare count is not):\n\n```\ncrates/spt/tests/activity_link_push_e2e.rs\ncrates/spt/tests/contract_e2e.rs\ncrates/spt/tests/job_escape_e2e.rs\ncrates/spt/tests/ready_resume_ledger_e2e.rs\ncrates/spt/tests/worker_lifecycle_e2e.rs\ncrates/spt/tests/worker_visibility_e2e.rs\n```\n\n⚖ **`/T` grades BLAST RADIUS; it is not the defect. The defect is TERMINATING ON A PID YOU DID NOT AUTHENTICATE.**\n\n### ⭐⭐ The stable number — and why the others are noise\n\n**The 6-file `daemon.pid` `/F /T` tier reproduces across all three independent measurements, with different predicates, different roots and different trees.** That is the actionable figure; an investigator acts on those six files.\n\nA SECOND, EARLIER census exists (different agent, taken before this tree): 42 files with `taskkill` + literal `/T` over the non-recursive root `crates/*/tests/*.rs`; 30 also joining a literal `*.pid`/`*.ready`; 26 referencing `brain.ready`; **6 `daemon.pid` tree-killers; 12 `/F`-only.**\n\n⚠ **The two censuses are NOT in conflict — they differ by ROOT, PREDICATE and VINTAGE, not by correctness.** Recursive containment-intersection at `8f3e10b` versus a non-recursive flow-narrowed read at an earlier tree. Both are recorded with their predicates precisely so a future reader does not see `42` beside `57`, or `26` beside `28`, and conclude somebody was wrong. **That false-discrepancy trap was paid for three times the night this was filed; it is not being baked into the issue that documents it.** The containment totals are scope-sensitive scaffolding. The `6` is the invariant.\n\n**Scope bound on the failing test specifically:** `worker_lifecycle_e2e.rs` reads **only** `daemon.pid` — `reap_daemon` at **`ce4386e`:L61-68**, single call site at **`ce4386e`:L118** — and **never** `brain.ready`. So any finding here speaks for the `daemon.pid` `/F /T` tier and says nothing about the `brain.ready` population.\n\n> ⚠ Those line numbers are bound to **`ce4386e`, the tree that FAILED — they are pre-guard positions and are NOT valid at `8f3e10b`**, where the guard rewrote the file (+172/-38). Stated explicitly because the surrounding census is measured at `8f3e10b`, and a line reference silently inheriting the wrong tree is the wrong-subject class this issue exists to document.\n\n**Flow-confirmation status OUTSIDE the 6-file tier: UNDETERMINED at this tree.**\n\n⚠ An earlier draft carried a \"23 confirmed / 7 unconfirmed\" flow split from the second census. **Its author has RETRACTED that split.** This issue therefore records no unconfirmed enumeration at all, rather than deriving a replacement set from a withdrawn one — subtracting one file from a retracted 7 to publish a tidy 6 would launder the retraction into a fresh figure that no measurement supports. **Re-measuring flow confirmation across the `taskkill` population is investigation work, not a number this issue may assert.**\n\n⚠ **`ready_resume_ledger_e2e.rs` was listed in BOTH the confirmed tree-killers and the flow-unconfirmed set. It cannot be both, and the contradiction is resolved by reading the flow rather than by picking a side (line refs at `8f3e10b`):**\n\n```\nL47   fn kill_pid(pid: u32) {\nL49       let _ = Command::new(\"taskkill\")\nL51           .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\nL58   fn reap_daemon(home: &Path) {\nL59       if let Ok(p) = std::fs::read_to_string(home.join(\"daemon.pid\")) {\nL61           kill_pid(p);\nL168  reap_daemon(home.path());          // the breadcrumb call site\nL165  kill_pid(listener.id());           // an OWNED handle — authenticated, NOT this class\n```\n\nThe breadcrumb value reaches `taskkill /F /T` directly, so **it is flow-CONFIRMED and belongs in the 6-file tree-kill tier.**\n\n⚠ **And it cannot be a member of a `brain.ready`-unconfirmed set, because `grep -cF 'brain.ready'` on this file returns `0` — the file does not mention that breadcrumb at all.** A reconciliation was proposed that the two lists were \"about different breadcrumbs\"; it was plausible and it was **false**, and the source read is what settled it. **A plausible reconciliation is not a resolution.**\n\n⭐ **The seventh member of the withdrawn unconfirmed set is UNIDENTIFIED and was NOT invented to preserve the arithmetic.** Decrementing 7 to 6 would have restored a tidy `23+7=30` total while hiding an unknown inside it — **an arithmetic identity is not evidence that its terms are correct.** Hence the whole decomposition is retracted above rather than repaired.\n\n*(Both line reads reported during review were correct and did not conflict: L165 and L168 are different call sites in the same file.)*\n\n## Guard status: UNEXERCISED\n\n**Identity by BLOB, not by commit id** — a rebase minted the shipping sha, so the blob is the honest identity:\n\n| | |\n|---|---|\n| source commit | `b3a545c2872c41224390fc60c10332065177b1fb` |\n| shipped as | `0443613` (rebased onto the repair tip) |\n| file blob, both | `4ee6d7a3492507ad4cb65927e6f41ac2b645d3c9` — `crates/spt/tests/worker_lifecycle_e2e.rs` |\n\nAsserting `is-ancestor b3a545c <tip>` would FAIL on a correct tree; byte equality of the blob is the invariant that actually holds.\n\nThe guard records `daemon.pid` plus process creation time after first worker-start; at reap it keeps self/ancestor and liveness guards, re-reads the breadcrumb and refuses change, re-reads creation time and refuses mismatch, and requires **exact spt-executable equality** (Windows case-insensitive) rather than target-prefix membership.\n\n⭐ **Why exact equality and not a prefix — measured, not argued.**\n\n**Provenance of the transcript below:** emitted by an instrumented copy of `worker_lifecycle_e2e.rs` in a throwaway git worktree detached at **`ce4386e`** (never the candidate tree), run under `cargo test -p spt --test worker_lifecycle_e2e` on hfenduleam, 2026-07-30 ~00:50Z, on an idle box. The probe was injected immediately above the `kill_pid` body and resolved the pid via `Get-CimInstance Win32_Process -Filter 'ProcessId=<pid>'`, walking `ParentProcessId` up to 8 levels. Both the worktree and its target have since been disposed, so **this transcript is the only surviving artifact and is not independently re-derivable without re-running the rig.**\n\n```\nREPRO about-to-kill pid=11920 ALIVE name=spt.exe path=<target>\\debug\\spt.exe chain=spt.exe(11920)\nREPRO self_pid=40032 label=about-to-kill\n```\n\nThe probe fired exactly once, consistent with the single `reap_daemon` call site. `chain=` shows no ancestor above the daemon — it is already detached, so an ancestor test process is not reachable through it.\n\n- true daemon → `<target>\\debug\\spt.exe`\n- sibling nextest binary → `<target>\\debug\\deps\\<name>-<hash>.exe`\n\n**Both satisfy `starts_with(<target>/debug)`; only the first satisfies exact equality.** The prefix form is holed by `deps/` siblings, and a reused pid is ALIVE, so a liveness check does not close it either.\n\n### ⭐ What the guard DOES ship, unconditionally: the next occurrence will be diagnosable\n\nSeparate from the identity checks — which are unexercised — the shipped guard makes the **failure mode that produced this issue observable**. Verified from source at `8f3e10b`:\n\n```\nL48-49    /// Render every child outcome before a destructive cleanup boundary and in every\n          /// assertion failure. A hard-killed harness cannot unwind and print its panic.\nL216-217  // Run every real-binary call FIRST, then print their complete outcomes BEFORE\n          // the destructive reaper. Even a hard-killed harness leaves a diagnosable log.\nL244      eprintln!(\"{diagnostic}\");        // all four child outcomes\nL246      reap_daemon(home.path(), &spt_bin, observed_daemon);\nL75       eprintln!(\"WORKER_E2E_OBSERVE: pid={pid} started_at={started_at}\");\nL95/119/125/140  WORKER_E2E_REAP / REAP_SKIPPED markers\nL169      eprintln!(\"{}\", output_diagnostic(\"WORKER_E2E_REAP_RESULT\", &reaped));\n```\n\n**All four child outcomes are emitted before the destructive reaper runs and before every assertion.** This directly answers the original evidence gap: the `ce4386e` failure produced `running 1 test` and a bare `(test failed with exit code 1)` with **no panic text**, because a hard-killed process cannot unwind to print one. A recurrence at this tree leaves the observed pid, its creation time, the expected executable, and all four child outcomes in the log *before* the kill boundary.\n\n⚠ **This is a DIAGNOSTIC capability, not a fix, and it is not evidence the identity checks work.** It changes the next occurrence from uninterpretable to interpretable. That is why the acceptance criteria below can demand an exit code plus complete child status/stdout/stderr — the shipped tree can now supply them.\n\n⚖ **RULED, verbatim, for the release record: the suite passed; the defect did not appear; the guard is unexercised.** Neither \"fixed\" nor \"validated\" may appear near `0443613`/`b3a545c`. A validating leg was deliberately **not run**, because a green against a green baseline validates nothing.\n\n## The axis that CLOSED — and made the red less explained\n\nThe leading mechanism was pid **reuse**: the daemon exits, the OS reassigns its pid, and `taskkill /F /T` then takes whatever now holds it — under nextest, the runner or a sibling test process, killing the target as a tree casualty with exit 1 and no unwind. That shape matches the observed output exactly.\n\nThe best remaining hiding place for it was the run-scoped temp root: golden.yml creates a run-scoped `TMP`/`TEMP` sandbox on Windows (step 11), which moves where `tempfile::tempdir()` — and therefore `daemon.pid` — lives, and the local rig did not reproduce that.\n\n⚠ **Job 90749868137 ran exactly that shape** — step 11 run-scoped temp sandbox `success`, step 13 Phase A after `n1-gate` on a warm box — **and greened.** That closes the axis in the direction of \"no defect there tonight\" and **removes the leading candidate for where the pid-reuse story lived.**\n\n**The red is LESS explained now than when it was first classified, not more.**\n\n## Corroborating observation\n\nA path-scoped sweep of the local rig's own throwaway target, run after suite completion, **killed 5 survivors** — an independent reproduction of the leaked-child shape `REQ-CI-LOCAL-GATE-DISPOSAL` was registered for (its seed cites six Phase-B daemons outliving completion). Upgrades that registration from a remembered incident to a reproduced one.\n\n## Acceptance for investigation\n\n- Reproduce a termination while preserving evidence that identifies the killer or the target identity transition.\n- Discriminate external termination from assertion/content using the actual exit code and complete child status/stdout/stderr.\n- Test breadcrumb pid, creation-time, and executable identity as separate facts; uncertainty must refuse termination, never become permission.\n- Preserve the stated scan root, lexical predicate, manually confirmed data-flow subset, full file list, and unmeasured populations for every census.\n- Do not admit a flake-registry entry without a proven named mechanism and admission evidence.\n- Re-run the flow census with a **GENERATED** predicate label — emitted by the same code that executes the command — so a description cannot drift from what was measured.\n\n## References\n\n- ADR-0050 **Face 5** (exact image + creation-time identity) and **ruling 8** (verify the subject before trusting its evidence)\n- KNOWN-HAZARDS **7.58**\n- `REQ-HAZARD-TEST-PID-TREE-KILL-IDENTITY` — **inactive**\n- `REQ-CI-LOCAL-GATE-DISPOSAL` — registered `required_stages = []`, inactive; the killed=5 sweep above upgrades its evidence from remembered to reproduced\n- `activity_link_push` flake-registry entry — stays **UNDER REVIEW** on the same reasoning that keeps this issue out of the registry\n\n## Request metadata\n\n- **Title:** Investigate intermittent `worker_lifecycle_e2e` external termination\n- **Type:** `type: BUGFIX`\n- **Initial state:** `state: BACKLOG`\n\n---\n\nAttachments:\n- [alchemy-payload.txt](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/shx-1785374058864596800-alchemy-payload.txt)\n\n---\nRequester: doyle\n\n","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2j-w","name":"state: WIP","description":"Handed to an agent / in flight","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":32,"title":"worker_lifecycle_e2e Windows Phase A — intermittent, mechanism WEAKENED, guard UNEXERCISED"},{"body":"Distinct from #26 (stream-open / stale op_id, 5 peers, from the 02:25 broker restart) and #25 (session bringup wedge). This is a different stage (quic-connect), a different error, 7 peers, and a later onset (~07:40) - but the evidence below also CORRECTS #26's framing, so read them together.\n\nSYMPTOM AS REPORTED: operator cannot start new sessions nor RC-attach to existing ones. spt daemon status on HFENDULEAM has read \"peer reachability: DEGRADED - all 7/7 peers failing (stage: quic-connect)\" for ~6.9h.\n\nTHE PEERS ARE NOT THE LOCUS. The pump reports 7 independent peers, across two subnets, each independently exceeding a 10s dial bound ON THE IDENTICAL MILLISECOND:\n  wall_ms=1785360690444 peers_failing=1\n  wall_ms=1785360690445 peers_failing=4\n  wall_ms=1785361001608 peers_failing=5\n762 failures, 7 distinct peer keys, batches sharing one wall_ms. Seven unrelated hosts cannot each independently time out on the same millisecond. They were submitted together and released together by ONE SHARED LOCAL GATE. The failing thing is the local submit path, not the peers. (This is why #26's expectation - that cross-node streams to \"those peers\" stay down - points a fixer at the wrong end; the peer set is a symptom of a shared local release, not a set of unreachable hosts.)\n\nCORROBORATION THAT THE NETWORK IS FINE: last admitted registry update 2468s ago (traffic lands); PAIR_MEET_UP beacons continue every 30s slot; locally, shell spawn bound online, \"rc chert --view\" attached and rendered, messaging flows. ONLY the cross-node path is dead - which is exactly the operator's mobile-gateway vantage, and why remote session-start and remote RC attach fail while the same operations succeed locally. Anyone testing locally will not reproduce it.\n\nWHERE IT LIVES: the failing pump runs in pid 21352 = \"spt daemon brain --generation 1 --start-reason update\", a child of daemon pid 8820 (\"daemon run --detached\"). Two distinct mono_ms baselines in the shared daemon.stderr.log separate the writers cleanly - 8820 started 02:25:36 (uptime 12.1h, matches CONN_LIFECYCLE mono_ms 43.7M); 21352 started 03:58:46 (uptime 10.5h, matches PUMP_PEER_FAIL mono_ms 37.9M). The brain generation was spawned BY AN UPDATE, 1.5h after the broker restart #25/#26 describe. The coordinator owns every socket (QUIC UDP, mDNS 5353, docs 5474); the brain owns none, consistent with it submitting dials through the coordinator. That submit path is the shared gate the simultaneity points at.\n\nUNEXPLAINED: the brain started 03:58:46 but reachability did not collapse until ~07:40 - a 3.7h healthy window, so the spawn itself is not the trigger. A fleet-process poll ran on this box 07:24-07:39, immediately before onset; correlation only, not a claim. Once wedged it never self-heals - 6.9h and counting, the 10s bound re-expiring every ~55s.\n\nSECOND DEFECT, THE OBSERVABILITY HID IT:\n1. \"(peer unresponsive)\" is a misattribution. The bound that expired is on submit-dial, which is local. The string names the remote peer as the faulty party and sends an operator hunting the network across seven peers and two subnets. The same-millisecond simultaneity that disproves it is only visible if you group the raw log by wall_ms.\n2. spt daemon status reports \"peer pump: live (last tick 0s ago)\" AND \"peer reachability: DEGRADED - all 7/7 failing\" in the SAME view. The pump is ticking and every dial it makes fails, so \"live\" is true and useless. No single observable says the pump is wedged.\n\nNOT DONE HERE: diagnosis only, per operator instruction - no fix attempted, nothing restarted. \"spt daemon refresh\" is the documented recovery verb for a stuck coordinator and was deliberately NOT run, so the wedged state is STILL LIVE on HFENDULEAM for whoever takes this. That state is the reproduction; it is lost on the next daemon restart or update.\n\nEVIDENCE: %LOCALAPPDATA%\\spt-core\\logs\\daemon.stderr.log (grep PUMP_PEER_FAIL, group by wall_ms); logs\\obs\\rc-establish.log. Full writeup in the attached file.\n\nFiled by deployah.\n\nAttachments:\n- [alchemy-request-pump-wedge.md](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/shx-1785361239803559500-alchemy-request-pump-wedge.md)\n\n---\nRequester: deployah","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":30,"title":"peer pump dials wedge at quic-connect and misreport a LOCAL submit stall as \"peer unresponsive\""},{"body":"it should exclude and/or dim options and information that won't work or display on/for a given endpoint\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":28,"title":"change: make the SPT picker GUI access-rules-aware"},{"body":"After the 2026-07-29 02:25 broker cold restart on HFENDULEAM, the daemon log fills with an unbounded retry loop for 5 distinct peers:\n\nPUMP_PEER_FAIL:<peer>:stream-open op already applied but its stream is no longer held (broker restarted); retry with a fresh op_id\n\nThe error text itself names the fix (\"retry with a fresh op_id\") but the pump retries with the SAME op_id indefinitely — hours of identical failures for the same 5 peer hashes, no backoff escape, no op_id regeneration. Cross-node streams to those peers presumably stay down until manual intervention.\n\nExpected: on this error class the pump mints a fresh op_id and re-opens; the op-journal dedup is there to catch replays, not to permanently brick recovery after a broker generation bump.\nRelated: filed alongside the new-session bringup wedge from the same restart window — likely same root (broker restart leaves op-journal state that post-restart paths cannot get past), but distinct code path and fix.\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":26,"title":"peer pump stale-op_id stream-open retry loop never self-heals after broker restart"},{"body":"Observed on HFENDULEAM 2026-07-29 after the 02:25 daemon+brain cold restart (generation 0): every NEW spt-hosted session failed bringup while all pre-existing live agents kept working and harness-hosted sessions started fine.\n\nEvidence (daemon.stderr.log):\n- New-session controller attaches die instantly: controller-attach -> write-start -> writer-exit reason=channel-closed -> transport-close within ~100ms (chert sessions 10/11, slate session 12).\n- Anonymous role=brain connections (no endpoint/session attribution) opening on a ~5s supervisor cadence and closing within 0-6ms of write-start, dozens over minutes (conn 1175..1199+) — bringup retry loop dying before identification.\n- Roster/daemon state divergence in the same window: subnet roster showed chert ONLINE while daemon status said ready=false alive=false; daemon listed an endpoint the roster did not.\n- HOSTING_AUTHORITY_DEMOTED:chert: no broker session, but a relay holds the endpoint.\n\nConfounder to exclude in RCA: a Claude session limit was ALSO active in the window (limit banner verbatim in log, exit 1) and explains some early chert attempts — but a later launch via an unlimited profile still failed bringup, so the wedge is real and broker-side. Fleet is on v0.45.0.\nOperator impact: cannot grow the fleet until daemon bounce; existing agents ride pre-established hosting and mask the defect.\n\nAttachments:\n- [alchemy-bug1.txt](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/shx-1785322455005645000-alchemy-bug1.txt)\n- [alchemy-bug2.txt](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/shx-1785322455096380400-alchemy-bug2.txt)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2lGQ","name":"type: BUGFIX","description":"Something existing is broken","color":"7057ff"}],"number":25,"title":"new spt-hosted session bringup wedged after daemon/broker cold restart (harness-hosted unaffected)"},{"body":"> *relies on: now-signal (#11)*\n\nDeferred out of now-signal v1 by design ruling (grill 2026-07-29): the PROJECTS category needs project-index cross-node semantics before it can ship.\n\nScope when picked up:\n- previous projects + activity dates for the endpoint\n- per-project \"how-to-fetch\" guidance for that project's `project-context`\n- surfaces as a `<PROJECTS>` category tag under `<SPT-NOW-SIGNAL>`, delta discipline like every category (emit only new-since-last-emit)\n\nMinted so the v1 lean-set ruling doesn't orphan it.\n\n---\nRequester: doyle (grill ruling, operator-directed).","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2mUw","name":"type: IDEA","description":"An idea to explore — every mint is flagged Needs Operator","color":"7057ff"}],"number":16,"title":"now-signal category: PROJECTS (previous projects + activity dates + project-context fetch guidance)"},{"body":"largely docs with some API helpers\n\nstrongly encourage adapter devs to build their apps with seamless live updates as a first-class affordance. should be supported through the manifest-->a number of adapter-provisioned commands for initiating and completing a seamless update with minimal observed interruption to the agents using them\n\nshould also provision for in-place updates of any adapter-owned ResidentServices.\n\n---\nRequester: discord:reavo.","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jJA","name":"state: BACKLOG","description":"Recorded, not yet worked","color":"86bc90"},{"id":"LA_kwDOTY3w7c8AAAACte2l9w","name":"type: ADDITION","description":"New capability inside existing feature surface","color":"7057ff"},{"id":"LA_kwDOTY3w7c8AAAACte2miA","name":"flag: NEEDS-OPERATOR","description":"Blocked on an operator decision","color":"fbca04"}],"number":4,"title":"add: \"seamless update contract\" for adapters"},{"body":"Watch registry for daemon node `HFENDULEAM` (ADR-0009).\n\nEvery comment below is one machine-parseable Watch — registered by an alchemy shell, fired and deleted (or advanced) by the Hub Daemon. Do not delete this issue or edit the comments by hand: a lost comment is a silently lost Watch.","labels":[{"id":"LA_kwDOTY3w7c8AAAACtlzAuA","name":"kind: SPT-TRACKING (DO NOT DELETE)","description":"Alchemy Watch registry — one machine-parseable comment per Watch (ADR-0009)","color":"b60205"}],"number":3,"title":"HFENDULEAM"},{"body":"Routed from spt-progress-tool#23 (flynn hand-off; Operator ruled it out of alchemy's next milestone — the constraint lives in spt-core's install path, so the Request mints here).\n\nToday deploying a new release of a service exe (field case: alchemy) requires EVERY instance on the node to be down simultaneously: all instances execute the same installed exe and Windows refuses to overwrite a running one. A routine upgrade therefore needs cross-owner coordination, a window where the service is absent from the node entirely, and — because the only clean way down is `spt shell teardown` — each instance returns having lost its perch: repo binding gone (re-run bind-repo), tag cursor re-baselined at the digest tip so tags written during the gap are never scanned, and a new canonical id.\n\nOperator ruling on record: the brief outage itself is acceptable; the design requirement is that an upgrade must not need the synchronized stand-down at all.\n\nThree sketched shapes, none decided (design ruling owed by doyle):\n1. Versioned install dirs — install per-version, point registration at the new dir; running exes keep their own file open, next spawn picks up new bits. Costs disk plus a reaping story.\n2. Rename-then-replace — Windows permits renaming a running exe: move the live binary aside, write the new one in its place, delete the orphan on next boot. Cheap; leaves running instances executing an unnamed file.\n3. Upgrade-on-relaunch handshake — instances stage the new binary and swap as each relaunches; the node converges with no synchronized window.\n\nCost coupling noted in the hand-off: the teardown-loses-the-perch penalty above is the same cost that makes the STALE-ONLINE liveness fix worth landing.\n\nProvenance: https://github.com/BigscreenVR/spt-progress-tool/issues/23 — flynn Watches from that side and closes #23 as routed once this ref exists.\n\nAttachments:\n- [req-shared-exe-upgrade.txt](https://github.com/BigscreenVR/spt-bs-releases/releases/download/untagged-3ecc0debcb4b3bffe480/shx-1785204617552120000-req-shared-exe-upgrade.txt)\n\n---\nRequester: doyle","labels":[{"id":"LA_kwDOTY3w7c8AAAACte2jaQ","name":"state: EVAL","description":"Being shaped into a greenlightable Request","color":"73d686"},{"id":"LA_kwDOTY3w7c8AAAACte2lqw","name":"type: CHANGE","description":"Something existing should behave differently","color":"7057ff"}],"number":2,"title":"Upgrading a shared-exe service must not require a node-wide stand-down of every instance"}]
