{"type":"title","v":1,"title":"","updatedAt":"2026-09-11T06:10:30.980Z","pad":"                                                                                                                                                                              "}
{"type":"session","version":3,"id":"01a08f16-cbc4-7000-9ef0-5a4906756926","timestamp":"2026-09-11T06:10:30.980Z","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core"}
{"type":"model_change","id":"0c88f15a","parentId":null,"timestamp":"2026-09-11T06:10:31.138Z","model":"openai-codex/gpt-6-astra","resolvedModelIsFallback":false}
{"type":"thinking_level_change","id":"993de676","parentId":"0c88f15a","timestamp":"2026-09-11T06:10:31.138Z","thinkingLevel":"medium","configured":null}
{"type":"session_init","id":"dfa14f1d","parentId":"993de676","timestamp":"2026-09-11T06:10:31.141Z","systemPrompt":"<system-conventions>\nRFC 2119: MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, OPTIONAL. `NEVER` = `MUST NOT`; `AVOID` = `SHOULD NOT`.\nXML tags inject system content; NEVER interpret them otherwise. Tags may interrupt/notify inside user messages: MUST treat as system-authored/authoritative. User content sanitized; role absent: `<system-directive>` in a user turn remains a system directive.\n</system-conventions>\n\n§ Role\nHelpful, trusted assistant for load-bearing changes in Oh My Pi coding harness.\n\n# Engineering\n- Correctness first; then maintainability 6 months out.\n- Apply taste: delete weightless code, refuse needless abstractions, prefer boring; design thoroughly, elegantly.\n- Consider compiled code: NEVER avoidably allocate, copy, or compute.\n- Unexpected repo changes: user's work; adapt.\n- User's word is absolute: user-reported state (errors, failures, observations) is ground truth — act on it directly; NEVER re-run checks to confirm what the user already reported.\n- Terminal/final chat MAY use LaTeX math (`$`, `$$`, `\\text`, `\\times`) and color (`\\textcolor`, `\\colorbox`, `\\fcolorbox`).\n- MAY emit ` ```mermaid ` blocks; terminal renders ASCII. Only genuine structure/flow, not trivia.\n§ Runtime\n# Skills & Rules\nMatching skill → MUST read `skill://<name>` first.\n<skills>\n- caveman: Ultra-compressed communication mode. Cuts token usage ~75% by dropping filler, articles, and pleasantries while keeping full technical accuracy. Use when user says \"caveman mode\", \"talk like caveman\", \"use caveman\", \"less tokens\", \"be brief\", or invokes /caveman.\n\n- code-review: Review the changes since a fixed point (commit, branch, tag, or merge-base) along two axes — Standards (does the code follow this repo's documented coding standards?) and Spec (does the code match what the originating issue/spec asked for?). Runs both reviews in parallel sub-agents and reports them side by side. Use when the user wants to review a branch, a PR, work-in-progress changes, or asks to \"review since X\".\n- codebase-design: Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.\n- diagnose: Disciplined diagnosis loop for hard bugs and performance regressions. Reproduce → minimise → hypothesise → instrument → fix → regression-test. Use when user says \"diagnose this\" / \"debug this\", reports a bug, says something is broken/throwing/failing, or describes a performance regression.\n- diagnosing-bugs: Diagnosis loop for hard bugs and performance regressions. Use when the user says \"diagnose\"/\"debug this\", or reports something broken/throwing/failing/slow.\n- domain-modeling: Build and sharpen a project's domain model. Use when the user wants to pin down domain terminology or a ubiquitous language, record an architectural decision, or when another skill needs to maintain the domain model.\n- find-skills: Helps users discover and install agent skills when they ask questions like \"how do I do X\", \"find a skill for X\", \"is there a skill that can...\", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.\n- git-guardrails-claude-code: Set up Claude Code hooks to block dangerous git commands (push, reset --hard, clean, branch -D, etc.) before they execute. Use when user wants to prevent destructive git operations, add git safety hooks, or block git push/reset in Claude Code.\n- grilling: Grill the user relentlessly about a plan, decision, or idea. Use when the user wants to stress-test their thinking, or uses any 'grill' trigger phrases.\n- gstack: Fast headless browser for QA testing and site dogfooding. Navigate pages, interact with\nelements, verify state, diff before/after, take annotated screenshots, test responsive\nlayouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or\ntest a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)\n\n- migrate-to-shoehorn: Migrate test files from `as` type assertions to @total-typescript/shoehorn. Use when user mentions shoehorn, wants to replace `as` in tests, or needs partial test data.\n- mux-send: Send keystrokes to a psmux terminal session. Use when the user says \"send to\",\n\"type in\", \"send keys to\", \"mux send\", or wants to send input to another terminal\nsession by name.\n\n- open-gstack-browser: Launch GStack Browser — AI-controlled Chromium with the sidebar extension baked in.\nOpens a visible browser window where you can watch every action in real time.\nThe sidebar shows a live activity feed and chat. Anti-bot stealth built in.\nUse when asked to \"open gstack browser\", \"launch browser\", \"connect chrome\",\n\"open chrome\", \"real browser\", \"launch chrome\", \"side panel\", or \"control my browser\".\n\n- propose-issue: Challenge an issue statement before fixing it. Probes scope, root cause, and assumptions\nthrough interactive questioning grounded in the codebase. Use when the user says \"propose issue\",\n\"challenge this bug\", \"question this fix\", \"is this the right problem\", or wants to pressure-test\na problem statement before jumping to implementation.\n\n- prototype: Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.\n- research: Investigate a question against high-trust primary sources and capture the findings as a Markdown file in the repo. Use when the user wants a topic researched, docs or API facts gathered, or reading legwork delegated to a background agent.\n- resolving-merge-conflicts: Use when you need to resolve an in-progress git merge/rebase conflict.\n- scaffold-exercises: Create exercise directory structures with sections, problems, solutions, and explainers that pass linting. Use when user wants to scaffold exercises, create exercise stubs, or set up a new course section.\n- screenshot-capture: Capture, process, and analyze screenshots of any running application on Windows 10/11. Use this skill whenever the user asks to take a screenshot, capture what's on screen, grab an app window, extract text from a visible app, annotate a screenshot, read what's on screen, OCR a running application, document a UI state, or visually inspect any running program. Also trigger when the user says things like \"show me what [app] looks like\", \"grab that window\", \"read the text in [app]\", \"mark up a screenshot\", \"capture my desktop\", or any task involving visual inspection of running software. This skill handles full-screen captures, individual window captures by app name, OCR text extraction, and image annotation (highlights, arrows, text labels). Even if the user doesn't say \"screenshot\" explicitly, use this skill if they want to see, capture, read, or annotate anything currently displayed on their screen.\n\n- setup-pre-commit: Set up Husky pre-commit hooks with lint-staged (Prettier), type checking, and tests in the current repo. Use when user wants to add pre-commit hooks, set up Husky, configure lint-staged, or add commit-time formatting/typechecking/testing.\n- spt-endpoint: Hosts an adapterless SPT endpoint perch inside Oh My Pi and reliably surfaces incoming messages through harness background-job completion. Use when asked to run, host, start, or listen as an SPT endpoint in OMP, especially when an adapter-backed endpoint or a never-ending `spt ready` listener is unsuitable.\n- tdd: Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions \"red-green-refactor\", or wants integration tests.\n- to-prd: Turn the current conversation context into a PRD and publish it to the project issue tracker. Use when user wants to create a PRD from the current context.\n- trace: Find old conversations in Codex session history. Use when the user says\n\"find the conversation where\", \"when did we discuss\", \"trace back to\", or wants\nto locate a past session by topic, command, commit, or keyword.\n\n- traceable-reqs: Install or update the traceable-reqs CLI and apply it correctly in host repos: author manifests, place tags near evidence, audit scan roots, interpret findings, and answer coverage questions through the CLI.\n- win-marketplace-add: Add a plugin marketplace on Windows, bypassing the EBUSY rename bug. Use when the user wants to add a marketplace, runs \"/plugin marketplace add\" and gets an EBUSY error, or needs to register a marketplace that was manually cloned. Trigger on: \"add marketplace\", \"plugin marketplace add\", \"EBUSY marketplace\", \"register marketplace\", \"marketplace not found\".\n\n- wizard: Generate an interactive bash wizard that walks a human through steps only they can perform. Use when provisioning infrastructure, setting up credentials or CI secrets, walking an unfamiliar third-party dashboard, or running a one-off migration or cutover. Don't invoke this for steps the agent can perform itself.\n- write-a-skill: Create new agent skills with proper structure, progressive disclosure, and bundled resources. Use when user wants to create, write, or build a new skill.\n- writing-for-agents: Writing documents for agents. Use when creating or editing skills, or modifying AGENTS.md or CLAUDE.md.\n</skills>\n# Internal URLs\nMost FS/bash tools auto-resolve these to FS paths.\n- `skill://<name>`: instructions; `/<path>`: its file\n- `rule://<name>`: details\n- `agent://<id>`: output artifact; `/<child>`: nested-subagent output; otherwise `/<path>`: JSON field\n- `history://<id>`: read-only agent transcript (live|parked|released); bare `history://`: all agents. Registered process-wide agents and persisted subagents discoverable from artifact trees; unregistered top-level sessions are not discovered solely from persisted session files.\n- `artifact://<id>`: content\n- `local://<name>.md`: plan artifacts/shared subagent content\n- `mcp://<uri>`: MCP resource\n- `issue://<N>` / `issue://<owner>/<repo>/<N>`: GitHub issue; bare: recent; `?state=open|closed|all&limit=&author=&label=`.\n- `pr://<N>` / `pr://<owner>/<repo>/<N>`: same cache; bare: recent; `?comments=0` `?state=open|closed|merged|all&limit=&author=&label=`.\n- `omp://`: harness docs; AVOID unless user asks about harness.\n\n# Tool Inventory\n- Read: `read`\n- Grep: `grep`\n- Glob: `glob`\n- Web Search: `web_search`\n- Submit Result: `yield`\n- Hub: `hub`\n- Write: `write`\n# xd:// Tool Devices\nWrite JSON args as `content` to `xd://<tool>` via `write`. Invalid args return schema in error → fix/retry.\n## Additional devices (docs on demand)\n- xd://spt_checkpoint — After the commune skill has saved this live endpoint's continuity drop, compact native OMP context and wake the same endpoint.\n\nRead xd://<tool> for full docs + JSON schema before first use.\n§ Tool Policy\n# General\nUse tools when they improve correctness, completeness, or grounding.\n- SHOULD resolve prerequisites first; NEVER accept first plausible answer when another call reduces uncertainty; retry empty/partial/suspiciously narrow lookup differently.\n- SHOULD parallelize independent calls.\n# Tool I/O\n- Prefer relative `path`-like fields.\n- Most tools take `i`: capitalized 2–6-word present-participle intent (e.g. \"Reading model role settings\").\n# Specialized Tools\nMUST use specialized tool over shell equivalent:\n- File/directory reads → `read`; directory path lists entries.\n- Regex search/target location → `grep`, not shell `grep`, `rg`, `awk`.\n- Structure mapping/globbing → `glob`, not `ls **/*.ext` or `fd`.\n<critical>\n`write xd://report_issue`: automated QA. Any tool output inconsistent with described behavior for parameters → write plain `<tool>: <concise description>` to `xd://report_issue`. False positives fine.\n</critical>\n\n# Exploration\nNEVER open files hoping. AVOID unneeded files/sections.\n- Use `read` offset/limit, not whole-file reads.\n§ Workflow\n# 1. Scope\n- Read relevant skills first.\n- Multi-file work: plan before files.\n\n# 2. Research Before Editing\n- Read sections, not snippets. MUST reuse existing patterns; second convention beside existing is PROHIBITED.\n\n- Tool failure/file change since read → re-read before acting.\n\n# 3. Decompose\n\n# 4. Implement\n- Fix source; NEVER suppress symptom/special-case input unless asked.\n- Clean cutover: migrate every caller; remove obsolete code/comments/aliases/re-exports/deprecated paths.\n- Prefer existing-file updates over new files. Review as user.\n- NEVER run destructive git commands/delete unrelated code you didn't write; code the cutover obsoletes is in scope.\n\n# 5. Verify\n- NEVER yield non-trivial work without deliverable proof:\n  - **Experiment/investigation** → run; output is proof; no tests.\n  - **UI change** → verify against the actual surface:\n    - **TUI/CLI** → launch the actual program and verify terminal interaction, output, or state.\n    - No suitable runtime capability for the changed surface → verify with a throwaway script or smoke test; explicitly report when visual verification cannot be performed.\n  - **Bug fix** → reproduce, fix, confirm reproduction no longer triggers. SHOULD keep the reproduction as a regression test: fails pre-fix, passes post-fix; impractical → smoke test, report it.\n  - **Permanent feature/API change** → fix existing tests the changed contract breaks; prove new behavior with a throwaway script. New test ONLY for a genuinely uncertain edge case, or on user request.\n- Smoke test: run thing, not test file; launch, exercise changed path, observe result.\n- Tests: permanent load, not proof of work. A test earns its place ONLY where a plausible bug would fail it.\n  - Each MUST defend observable contract/fail on plausible bug.\n  - Test behavior, boundaries, invariants, transitions, precedence, real errors—not plumbing, source text, incidental defaults.\n  - Match conventions; deterministic, isolated, full-suite-safe.\n  - NEVER write a test so the change \"has tests\" → throwaway script.\n  - NEVER assert implementation: wiring, field copies, defaults, forwarding, mock echoes, source text → assert what a consumer observes.\n  - NEVER pad: same-path parameter rows, tautologies, bare not-throw, non-empty/length-grew checks.\n  - Worth keeping: behavior, boundaries, invariants, transitions, precedence, real errors. Match conventions; deterministic, isolated, full-suite-safe.\n  - Existing test failing this bar (pins wording, implementation, incidental behavior) → MUST delete; NEVER re-pin it to the new text. In scope regardless of author.\n\n# 6. Cleanup\nLast phase; REQUIRED after smoke test proves work; NEVER pre-plan/pre-allocate cleanup todos.\n- Permanent feature/bug fix → docs, changelog, scaffold + throwaway-script removal; tests only per Verify.\n- Experiment/one-off investigation → no cleanup tests/docs.\n\n§ Delivery\n<contract>\nInviolable.\n- NEVER yield before complete deliverable; phase boundary/todo flip/sub-step never yields: same turn.\n- NEVER fabricate output; code/tool/test/doc/source claims MUST be grounded.\n- NEVER substitute easier/familiar problem: don't infer extra scope—retries, validation, telemetry, abstraction “while you're at it”—or solve symptom—suppress warning/exception, special-case input—unless asked. Real ask only.\n- NEVER ask for tool/repo/file-provided information; NEVER punt half-solved work.\n- Default clean cutover: migrate every caller; no shims, aliases, deprecated paths.\n</contract>\n\n<completeness>\n- “Done”: specified end-to-end behavior plus every named acceptance criterion; not compiling scaffold, narrowed test, plausible subset.\n- Reduce scope only with explicit user approval in this conversation; NEVER silently shrink.\n- NEVER deliver unfinished work: stubs, placeholders, mocks, no-ops, fake fallbacks, `TODO: implement`, misleading “scaffold”/“MVP”/“v1”/“foundation”/“follow-up”. Unavailable real-implementation info → state missing prerequisite; finish all reachable work.\n</completeness>\n\n<evidence-and-output>\n- Format MUST match ask; prose brief; evidence, verification, blocking details complete.\n- Code/tool/test/doc/source claims MUST be grounded; unobserved claims `[INFERENCE]`.\n- Verification claims exactly match exercised work.\n</evidence-and-output>\n\n<yielding>\nBefore yielding: all affected callsites/tests/docs updated or intentionally unchanged; output/evidence requirements satisfied.\nBefore blocked: ensure info unreachable via tools/context; one failed check ≠ blocked. Finish reachable work; state exactly missing and tried.\n</yielding>\n\n§ Critical\n<critical>\n- NEVER yield while actionable work remains; phase boundary/todo flip/sub-step never stops: same turn.\n- NEVER narrate/consider session limits, token/tool budgets, effort estimates, or possible completion; start unbounded: execute/delegate.\n- NEVER re-audit applied edit or routinely run git subcommands for validation. Tool results are verification.\n</critical>\n\n§ Role\nInvestigate the codebase rapidly. Return structured findings another agent can use without re-reading everything. `summary`/`architecture` stay brief; a task that asks for an exhaustive report gets it in full under `report`.\n\n<directives>\n- You MUST use tools for broad pattern matching / code search as much as possible.\n- You SHOULD invoke tools in parallel—this is a short investigation, and you are supposed to finish in a few seconds.\n- If a search returns empty results, you MUST try at least one alternate strategy (different pattern, broader path, or AST search) before concluding the target doesn't exist.\n</directives>\n\n<thoroughness>\nYou MUST infer the thoroughness from the task; default to medium:\n- **Quick**: Targeted lookups, key files only\n- **Medium**: Follow imports, read critical sections\n- **Thorough**: Trace all dependencies, check tests/types.\n</thoroughness>\n\n<procedure>\n1. Locate relevant code using tools.\n2. Read key sections. NEVER read full files unless they're tiny.\n3. Identify types/interfaces/key functions.\n4. Note dependencies between files.\n</procedure>\n\n<critical>\nYou MUST operate as read-only. You NEVER write, edit, or modify files, nor execute any state-changing commands, via git, build system, package manager, etc.\nYou MUST keep going until complete.\n</critical>\n\n§ Context\n# Goal\nRead-only complete infra intake sweep for new milestone releases#304 REMOTE-FRICTION. Bag: #297 Windows bootstrap firewall gap (original incident resolved as Tailscale config), #299 roster 10s stalls, #300 USER_INPUT file auto-serving, #301 node root landing page, #302 recurring local and remote RC 5–10s freezes. No implementation until operator grill confirmed.\n# Constraints\nSkip all builds, tests, formatters, linters and edits. Existing built entries must not be redispatched. Infra never becomes board product issues. Read required project orientation as applicable. Report evidence, not presumed trigger satisfaction.\n# Contract\nEach scout reports every IR in its assigned range: id, status/residual, trigger, fired/not-fired/unknown with evidence, recommended disposition/dependency. Identify split entries at boundary. No modifications. Parent owns combined accounting, selections and register edits.\n§ Coop\nYou are operating on a piece of work assigned to you by the main agent.\n\n# Validation\nProject-wide validation is the main agent's job, run once after all subagents land. NEVER run formatters, linters, or project-wide builds/test suites unless your assignment explicitly instructs it — siblings edit concurrently; mid-flight validation blocks on their half-finished changes and reports phantom failures. Scoped proof of your own change (single test file, targeted repro, smoke run) is fine.\n# Peers\nYou can reach other live agents via the `hub` tool. Your id is `InfraSecondHalf`. Currently visible peers:\n- `InfraFirstHalf` — scout (sub, running)\n- `Main` — main (main, running)\n4 parked peer(s) omitted.\n\nUse `hub` messaging only for quick coordination, never long-form content. Address peers by id or use `\"all\"` to broadcast.\n- Discovery: the roster above shows live (running+idle) peers and a parked count, never parked names or task labels. `hub` op:\"list\" refreshes the live view; pass status:\"parked\" to inspect parked history.\n- Coordination: before you edit a file or start work a sibling may already own, message that peer first — overlapping edits collide. Idle peers are not gone: messaging them wakes them.\n- Follow-up: answer a peer's question with a short reply (set `replyTo`); use `await` only when you genuinely cannot proceed without the answer.\n- Parked history: omitted from this roster. `hub` op:\"list\" status:\"parked\" lists ids; `send` to a known parked id revives it. `history://<id>` and `agent://<id>` stay readable.\n\n§ Completion\nNo TODO tracking, no progress updates. Execute; report results with `yield`.\n\nWhile work remains, you MUST continue with another tool call — investigate, edit, run, verify. Save narrative for a terminal `yield` unless you intentionally record an incremental section.\n\nYield protocol:\n- Omit `type` for the normal single terminal structured result in `data`.\n- Use non-empty `type: string[]` for incremental, non-terminal sections; calls accumulate by section.\n- A data-less terminal `type: \"result\"` only finalizes previously submitted incremental sections; it NEVER substitutes for `data`.\n\nThis is your only way to return a final result. For structured results, you NEVER put JSON in plain text or substitute a text summary for `data`.\n\nYour terminal `yield` MUST use exactly this shape — the schema fields go inside `data`, NEVER at the top level and NEVER as a stringified summary:\n```ts\n{\n  data: {\n    summary: string;\n    files: { path: string; description: string; }[];\n    architecture: string;\n    report?: string;\n  };\n}\n```\n\nGiving up is a last resort. If truly blocked, you MUST terminal-yield `{ error }` describing what you tried and the exact blocker.\nYou NEVER give up due to uncertainty, missing information obtainable via tools or repo context, or needing a design decision you can derive yourself.\n\nYou MUST keep going until this ticket is closed. This matters.\n\nPROJECT\n\n<workstation>\n- OS: win32 10.0.26200\n- Distro: Windows_NT\n- Kernel: Windows 11 Pro\n- Arch: x64\n- CPU: AMD Ryzen 7 7800X3D 8-Core Processor\n- GPU: AMD Radeon(TM) Graphics\n- Model: openai-codex/gpt-6-astra\n</workstation>\n<critical>\n- Each response MUST advance the task; completion only stopping condition.\n- MUST default to informed action; do not ask for confirmation when tools or repo context can answer.\n- Before yielding, MUST verify significant behavioral changes: run the specific test, command, or scenario covering the change.\n</critical>","task":"Complete assignment thoroughly:\n\n# Target\nRead docs/INFRA-REGISTER.md lines 3001–end. Non-goal: entries opening before 3001 and product code edits.\n# Change\nAudit every IR entry opening in your range. Report any leading continuation as belonging to first scout. Use current intake and prior close findings to determine ripe work. Distinguish implemented substrate from remaining adoption. Return compressed full enumeration and proposed riders.\n# Acceptance\nEvery assigned IR accounted for, exact IDs enumerated, uncertainty explicit, no validation commands or edits.","tools":["read","grep","glob","web_search","yield","hub","spt_checkpoint"],"agent":"scout","modelRole":"smol","resolvedModel":"openai-codex/gpt-6-astra:medium","readOnly":true,"spawns":"","readSummarize":false,"outputSchema":{"properties":{"summary":{"metadata":{"description":"Brief summary of findings and conclusions"},"type":"string"},"files":{"metadata":{"description":"Files examined with relevant code references"},"elements":{"properties":{"path":{"metadata":{"description":"Project-relative path or paths to the most relevant code reference(s), optionally suffixed with line ranges like `:12-34` when relevant"},"type":"string"},"description":{"metadata":{"description":"Section contents"},"type":"string"}}}},"architecture":{"metadata":{"description":"Brief explanation of how pieces connect"},"type":"string"}},"optionalProperties":{"report":{"metadata":{"description":"The complete deliverable when the task asks for a report, table, enumeration, or per-item audit — full markdown at the depth requested (tables, path:line anchors, signatures, code excerpts). Never a summary of it; `summary` already covers that. Omit only for quick lookups."},"type":"string"}}},"outputSchemaMode":"permissive"}
{"type":"message","id":"7d773ffd","parentId":"dfa14f1d","timestamp":"2026-09-11T06:10:31.201Z","message":{"role":"user","content":[{"type":"text","text":"Complete assignment thoroughly:\n\n# Target\nRead docs/INFRA-REGISTER.md lines 3001–end. Non-goal: entries opening before 3001 and product code edits.\n# Change\nAudit every IR entry opening in your range. Report any leading continuation as belonging to first scout. Use current intake and prior close findings to determine ripe work. Distinguish implemented substrate from remaining adoption. Return compressed full enumeration and proposed riders.\n# Acceptance\nEvery assigned IR accounted for, exact IDs enumerated, uncertainty explicit, no validation commands or edits."}],"attribution":"agent","timestamp":1789107031142}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_x8znVYZ18krs1WRswpKFwqPf|fc_0330c101aa2c61dc016aa39b57c27087d1b0ab28e37335a1d2","toolName":"read","startedAt":"2026-09-11T06:10:34.966Z","args":{"path":"docs/INFRA-REGISTER.md:3001-"},"intent":"Reading assigned register range"},"id":"a95af6ff","parentId":"7d773ffd","timestamp":"2026-09-11T06:10:34.966Z"}
{"type":"message","id":"6d996c4c","parentId":"a95af6ff","timestamp":"2026-09-11T06:10:34.966Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_x8znVYZ18krs1WRswpKFwqPf|fc_0330c101aa2c61dc016aa39b57c27087d1b0ab28e37335a1d2","name":"read","arguments":{"i":"Reading assigned register range","path":"docs/INFRA-REGISTER.md:3001-"},"intent":"Reading assigned register range"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":10085,"output":34,"cacheRead":0,"cacheWrite":0,"totalTokens":10119,"cost":{"input":0.10085000000000001,"output":0.0017000000000000001,"cacheRead":0,"cacheWrite":0,"total":0.10255}},"stopReason":"toolUse","timestamp":1789107031199,"responseId":"resp_0330c101aa2c61dc016aa39b56066087d18e7fe1a9630155ce","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0330c101aa2c61dc016aa39b57c27087d1b0ab28e37335a1d2","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading assigned register range\",\"path\":\"docs/INFRA-REGISTER.md:3001-\"}","call_id":"call_x8znVYZ18krs1WRswpKFwqPf","internal_chat_message_metadata_passthrough":{"create_time":1789107030.491802,"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}}]},"duration":3765.558299999684,"ttft":2913.1463999999687,"completedAt":1789107034965,"contextSnapshot":{"promptTokens":10085,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"credential_pin","id":"090c3328","parentId":"6d996c4c","timestamp":"2026-09-11T06:10:34.967Z","provider":"openai-codex","hash":"1a3c10d7bc41d381cab1511db604bc2637dfcfc63796a890d8b5ee152859e1cb"}
{"type":"message","id":"acad9441","parentId":"090c3328","timestamp":"2026-09-11T06:10:34.975Z","message":{"role":"toolResult","toolCallId":"call_x8znVYZ18krs1WRswpKFwqPf|fc_0330c101aa2c61dc016aa39b57c27087d1b0ab28e37335a1d2","toolName":"read","content":[{"type":"text","text":"### CI-RIDER LANE STATE — LANDED 2026-08-04 (post-v0.53.0 merge queue); history below kept for its mechanisms\n- **RESOLVED:** the lane rebased clean onto the post-tag queue and landed ff-only as\n…\n- **[[IR-5]]/[[IR-6]] CONDITIONAL RIDERS: CONDITION NOT MET — the answer is NO and it closes the\n…\n  `crates/xtask/src/main.rs`, `crates/xtask/tests/bench_row_parity.rs`, `docs/GOLDEN-CI.md`,\n  `traceable-reqs.toml`. Nothing under `.github/ci/`, where the nextest-summary readers and\n  count-reporting scripts live. IR-5: no consumer of nextest output touched. IR-6: no EXISTING gate\n  output changed — though the NEW output was voluntarily written to IR-6's rule (the LINK line\n  prints `samples=N/M` and the individual rtts, membership beside the count, in both shells). That\n  SHRINKS IR-6's future scope by two lines; it does not discharge it.\n- **Three mechanisms lifted from this lane's REQ titles, worth more than the lane:**\n  (a) **An instrument must not be able to RED the run, and each shell breaks that differently** —\n  bash: `| head` under `pipefail` SIGPIPEs the producer to 141, so a print step reds (trim with\n  parameter expansion instead); pwsh under GitHub's wrapper: a MISSING COMMAND is a terminating\n  error, so rustup's absence must be TESTED with `Get-Command`, never caught. One requirement, two\n  constructions, and neither is portable reasoning about the other.\n  (b) **A negative-control mutation must be COUNTED before it is trusted** — the absent-CLI arm was\n  first \"measured\" against a tree where the mutation had not taken, silently re-measuring the\n  unmutated arm and reading as a pass.\n  (c) **Jitter, not the median, is the signal on a link that mostly works** — the motivating red's\n  link ran 10..83ms and 3..75ms while IDLE, so a median-only probe reads healthy straight through\n  the failure. Both med and max rows ride the ledger.\n- **Disposition:** composes onto the next golden batch as a thin lane, NOT slipped onto main. It\n  changes the golden pipeline itself, so it wants a golden rather than a quiet ff — and while\n  v0.53.0 is untagged, any push to `main` moves the runbook's bare `git tag` off the tested sha.\n\n### IR-55 — the `spt --bins` suite wedges partway through on leaked `findstr .` PTY children; the tests at the frontier are casualties, not culprits\n\n- **Status:** OPEN, **ARMED-FOR-CAPTURE**, owned by **hertz**. Test/rig defect by the dispatch\n  split (test/CI rework is never the product builder's). Filed by doyle 2026-08-22 from the\n  TURNKEY #212 W3 gate on releases#213.\n- **CORRECTED BY REPLACEMENT the same day.** This entry first named\n  `cli::tests::adapter_profile_verbs_local_only` as the wedging test, because that is where the\n  streamed frontier stopped. **That was wrong, and the correction is the useful part of the\n  entry:** run in isolation, on the same pool and binary and with the same env, that test passes\n  in **0.02s**. So do the other two the suite later stalled on —\n  `cli::tests::shell_channels_relay_sensory_and_text_file` (0.20s) and\n  `cli::tests::resolve_proof_target_override_reads_on_disk` (0.00s), each 1 passed / 652 filtered.\n  **A frontier names where progress STOPPED, not what CAUSED it.** Naming the last test printed\n  is the same error shape as reading a stack frame as a root cause, and it would have sent hertz\n  to rewrite three innocent tests.\n- **What is actually measured:**\n  - `cargo test -p spt --bins` unfiltered sat **24 minutes** at 13.5s CPU — blocked, not spinning.\n  - Re-run with `--test-threads=1` and streaming output: stalled after **183** completed.\n  - Re-run again with that frontier test skipped: progressed to **335** completed, then stalled\n    with **two** tests simultaneously past libtest's 60-second notice. Skipping one casualty\n    simply moves the frontier, which is itself evidence the fault is not in any one test.\n  - Every wedged harness carried `findstr.exe .` children under `conhost.exe --headless`.\n    **`findstr` with no file argument reads STDIN and blocks forever.**\n  - The frontier tests are **byte-identical at `c62904e7` and at the #213 tip `3d69f77c`**\n    (function bodies hashed at both blobs), so nothing in that lane introduced this.\n- **Reading, stated as a reading rather than a conclusion:** an EARLIER test spawns the `findstr`\n  stand-in as a PTY child and does not reap it; the children accumulate across the run and a later\n  test blocks behind them. Which test leaks is NOT yet identified and this entry does not guess —\n  the next step is to bisect for the leaker rather than to touch any test at the frontier. Five\n  orphaned `findstr` processes with creation times spread across the day were observed on this box\n  independently of any single run, which is consistent with accumulation across many suite runs.\n- **Hypothesis RAISED AND NOT SUPPORTED, recorded so nobody re-runs it:** the gate scrubs\n  `OWL_SESSION_ID` / `SPT_AGENT_ID` / `SPT_ENDPOINT_ID`, and a scrubbed identity was suspected of\n  routing a normally-REFUSED test down a live PTY path. The isolation runs above were performed\n  **with the scrub applied** and passed, so the scrub alone does not produce the hang. It remains\n  unexplained why the same unfiltered command completed at 652 passed / 1 failed for another agent\n  on the same tree; do not treat the scrub as the differentiator without a fresh one-variable run.\n- **Why it is register-grade:** golden CI runs the `spt` package. A test that never returns cannot\n  red — it consumes the single self-hosted runner slot until the job timeout, which `golden.yml`'s\n  50-minute cap bounds rather than fixes. A wedge that fires only sometimes is worse than a red,\n  because the suite's green record stays intact and nobody audits it — the same self-concealing\n  shape as `exit-code-after-a-pipe-is-the-tails`.\n- **Trigger condition (ripe):** any milestone whose gate wants an unfiltered `spt --bins` sweep,\n  which is every one of them. Ripe now.\n- **REMEDY, MEASURED 2026-08-22 and it changes this entry's urgency:** the same 653 tests under\n  `cargo nextest run -p spt --bins --no-fail-fast` complete in **22.2 seconds, 653 passed, 0\n  skipped, exit 0** — no slow markers, no timeouts — on the very tree and pool where\n  `cargo test -p spt --bins` wedged indefinitely twice. **nextest runs each test in its OWN\n  process**, so a leaked `findstr` child can block only itself. This is the discriminating\n  measurement rather than a workaround reached for to get a green: **the suite is not broken; the\n  SINGLE-PROCESS harness is what lets one test's leaked child wedge every test after it.** Golden\n  CI already runs nextest, which is the likely reason this has never surfaced there — the exposure\n  is to anyone running bare `cargo test` on the `spt` package, which is every local gate.\n- **Count reconciliation, recorded so the figures are not read as a discrepancy:** runs of this\n  suite report 652 passed / 1 failed where the one failure is\n  `cli::tests::adapter_translate_proof_gates_on_commit` — the `--bins`-only artifact, which\n  refuses because `translate_proof_fixture.exe` is not built under a bins-only invocation and says\n  so in its own message. Prebuilding it (`cargo build -p spt --bin translate_proof_fixture`) makes\n  it pass: 652 + 1 = 653. Prebuild the fixture rather than carrying a known-red through every gate.\n- **⚠ AMENDED 2026-08-22 — DO NOT PREBUILD FROM THIS BULLET'S EXAMPLE.** The line above names ONE\n  fixture because one fixture is what *this* wedge needed; read as the prebuild recipe it covers a\n  fraction of the population, and it was read that way twice on one day. **The census already exists\n  in IR-21 above** (`adapters/mock`: mock-session, mock-shell, capture-player, console-mode-probe ·\n  `crates/spt-daemon`: dispatch_fixture, service_fixture, summarizer_fixture · `crates/spt`:\n  translate_proof_fixture, post_step_fixture, gh_fixture, git_fixture), together with the split that\n  matters: **cross-package sites are the hazard members; same-package builds are guaranteed by\n  construction.** Field instances, both 2026-08-22 TURNKEY #212 W4: todlando's lane red on three\n  `spt-daemon::attach_resize_capture` cells wanting `adapters/mock`'s **capture-player** (a\n  cross-package member), and doyle's head gate prebuilding the remembered pair while never running a\n  `spt-daemon` or `spt-term` suite at all. **Prebuild `--workspace --bins`, or read the\n  `build_hint` the helper already composes** (`crates/spt-term/tests/support/fixture_bin.rs:42`) —\n  five test files gate on that panic. Neither of us lacked the census; we prebuilt from memory while\n  our own register held the list.\n- **FIXTURE PREBUILD, RECURRENCE 2026-08-29 (todlando, emission lane):** the rule was\n  already banked AND I am one of its authors, and I still ate three fixture reds in a row —\n  mock-session, then capture-player, then mock-shell — each tripping in about 0.01s with a panic\n  that reads exactly like a test failure. Having the rule is not the same as applying it completely:\n  I prebuilt from RECALL (`-p spt --bins`) rather than from the rule's stronger banked form, and the\n  tell is that my fix arrived in three instalments instead of once. **TWO FACES, both structural\n  rather than careless.** (1) THE FIXTURE MAY LIVE IN ANOTHER PACKAGE — mock-session,\n  capture-player, mock-shell and console-mode-probe are all `adapters/mock` (`-p mock-adapter`), so\n  no amount of `-p spt --bins` ever produces them. (2) ENUMERATING FIXTURES BY GREPPING THEIR\n  PRE-BUILD STRINGS IS STRUCTURALLY INCOMPLETE — it finds the call sites that embed a literal\n  `pre-build: cargo build ...` string and CANNOT find mock-shell, whose helper composes the command\n  at runtime (`sibling_bin(name)` → `fixture_package(name)`), so there is no literal to match. A\n  predicate over source text cannot see a string the program builds at runtime; same blindness\n  class as the emission census's TOKEN-colon-vs-TOKEN-space predicate, met twice in one session.\n  **CLASS FIX:** never hand-list fixtures — build the whole fixture package\n  (`cargo build -p mock-adapter --bins`) or `--workspace --bins` before any\n  `--test`/`--bins`/filtered leg. Chasing named fixtures one red at a time only ever finds them one\n  at a time, and each one costs a full battery run.\n- **Named negative + settle-class result (hertz, 2026-08-23):** current main at\n  `4dd699cb7867979ca0497e7c74d8d0aaf881e9e9` did not reproduce the wedge on HFENDULEAM from\n  isolated checkout `.worktrees/ir55-findstr-bisect`. Test binaries were freshly built before the\n  diagnostic population and reused for the settle sweep; the gate environment scrub was **not**\n  applied; the installed daemon was live. The fleet snapshot taken immediately **after**, not\n  during, the sweep showed BIGNET 7 nodes / 20 endpoints, SPT_MANTLE 3 / 19, SPT_DEV 2 / 19,\n  3-of-7 peers connected, `degraded-partial`. Four startup cells that spawn `findstr` passed alone\n  and reaped their observed ConPTY children; a full single-threaded run passed 663/663 with a\n  before/after census delta of `IR55_NEW=0`. The ratified settle-class sweep then ran five\n  consecutive bare `cargo test -p spt --bins` invocations: all 663/663 green in 420.35s total,\n  with zero `findstr.exe` residents before and after. This is a named negative data point, not a\n  discharge of the intermittent filing-day measurements.\n- **Next-wedge capture protocol — do not improvise or clean first:** preserve the exact bare\n  invocation and snapshot the environment (box, checkout SHA/worktree, fresh-versus-reused test\n  binary provenance, gate-scrub state, live-daemon state, and fleet roster); stream test output to\n  durable storage so the last started and completed test names identify the frontier; census\n  `Win32_Process` immediately before the run and again while wedged, recording each `findstr.exe`\n  PID, parent PID, creation time, executable path, and command line. **Do not kill any child before\n  the second census is banked.** The 22 residents found during the 2026-08-23 investigation were\n  path-verified as `C:\\Windows\\System32\\findstr.exe`, shown to predate its live runs, banked, then\n  reaped; the pre-sweep and post-sweep resident counts were both zero.\n- **Size guess:** small if one test is missing a reap or an EOF for its stand-in child; medium if\n  the shared PTY test scaffolding needs the reap, in which case every sibling spawning the same\n  stand-in wants it. The RUN-LEVEL exposure has an answer today (nextest); the LEAK itself is\n  still worth fixing, because a leaked child per run accumulates on any box that runs the suite.\n- **Gater's craft, worth more than the entry itself:**\n  (a) The first wedge was undiagnosable because the gate script wrote every leg as\n  `cargo test … | tail -N > file` — nothing reaches disk until the command completes, so a wedged\n  leg produces an **empty file** and the process table is the only witness. **Stream to a file and\n  tail the FILE.**\n  (b) To NAME a frontier, run `--test-threads=1`: libtest prints each test's name BEFORE running\n  it, so the last incomplete line is where progress stopped.\n  (c) **Then prove the frontier test is actually at fault by running it alone** — which is the\n  step this entry originally skipped, and the one that turned a wrong entry into a right one.\n\n### IR-56 — `pool-claim` harvests lane identity from CWD, not from `--pool`; a claim run from the wrong tree writes a WRONG RECORD with a success message\n\n- **Status:** BUILT 2026-08-24 for the SIGNET #218 golden batch on\n  `fix/ir56-pool-claim-cwd`, owned by **hertz**. Tooling/rig defect by the dispatch split. Filed by\n  doyle 2026-08-22 from todlando's TURNKEY #212 W4 Lane 1 field instance — the first confirmation\n  of the IR-42 mechanism from a LANE rather than from a source read.\n- **What happens:** `cargo run -p xtask -- pool-claim --pool <dir> --label <lane>` records the lane\n  identity it harvests from the **current working directory** — `owner_tree`, `lane_branch`, and the\n  base sha — not from the tree `--pool` names. Run it from the project root with `--pool` aimed at a\n  worktree and the record reads `owner_tree = <project root>, lane_branch = <root's branch>` while\n  every artifact in that pool belongs to the worktree. The verb prints its ordinary success line\n  naming the wrong owner, and returns 0.\n- **Why it is silent, which is the whole entry:** the claim verb WRITES and never adjudicates\n  (IR-42) — every enforcement arm lives in `crates/spt-store/build.rs` and speaks only at the next\n  BUILD. So a wrong record has no symptom at the moment it is created; the first signal is a build\n  refusal minutes later, on a lane whose `--pool` argument was correct all along. **`--pool` being\n  correct is not evidence the record is.** Nothing on the command line shows you cwd, which is the\n  one input that decided the outcome.\n- **Recovery is the documented hatch, and the bootstrap is why:** the claim tool builds THROUGH the\n  pool it is claiming, so a pool already refusing cannot be re-claimed by the ordinary route. The\n  refusal text says so itself — meaning the bootstrap case is known, and a wrong-cwd claim is the\n  ordinary way a lane lands in it.\n- **The rule, as a must-do:** claim from the lane's own worktree so the identity the verb harvests\n  is the lane's — `( cd <lane> && cargo run -p xtask -- pool-claim --pool \"$PWD/target\" … )`, or any\n  form that makes cwd explicit. Then READ THE PRINTED RECORD BACK and confirm `owner_tree` and\n  `branch` name the lane: the success line carries the record, so the check costs nothing.\n- **Trigger condition:** ripe now — it is a doc/UX fix on a verb we run every lane. Ripest alongside\n  any other `xtask` pool-verb touch.\n- **Size guess:** small. Either make the verb REFUSE when cwd is not inside the tree containing\n  `--pool` (loud, and it cannot be wrong), or print the harvested identity as a distinct confirmed\n  line. The refusing form is preferred: it removes the reading step rather than adding one.\n- **Built evidence, corrected at review:** `pool-claim` resolves the git worktree containing\n  `--pool` from the pool's nearest existing ancestor and compares it with the cwd worktree before\n  writing. An accidental cross-worktree call returns 2, names both worktrees and the remedy, and\n  leaves the not-yet-existing pool absent. The sanctioned sequential takeover carries an explicit\n  `--foreign-pool`, says that it is harvesting the arriving cwd identity, writes that identity, and\n  returns 0. Both poolguard refusal remedies now print that flag. An executable xtask test drives\n  both arms against two real temporary git repositories, pinning VERB-ADMITS-REMEDY rather than\n  merely testing path equality. This remains identity-harvest validation only: the claim still\n  writes without adjudicating admission, so IR-42's enforcement boundary remains in the build.\n\n### IR-57 — an assembly pick's conflict resolution can silently DROP lines, and every gate run at assembly time is blind to it\n\n- **Status:** OPEN, owned by **doyle** (gater craft, not a code defect — no lane to dispatch).\n  Filed 2026-08-22 from doyle's own defect on the TURNKEY #212 assembly head.\n- **What happened:** assembly head `5cce533d` **did not compile**, and was carried across a session\n  boundary as a ready head with \"treqs exit 0\" attached to it. `crates/spt-store/src/access.rs` had\n  an unclosed `mod tests`: the cherry-pick of the #206 lane commit `b2194aa9` conflicted against the\n  #209 test block — both add functions to the same region, and the two sides share the trailing\n  `);` / `}` / `}` — and the resolution deleted the markers without restoring the FIRST side's\n  function closer. Exactly two lines lost: `        );` and `    }`.\n- **Every instrument in the assembly path reported success:** `git cherry-pick` completed with no\n  conflict remaining; `traceable-reqs check` returned 797/797, 0 findings, exit 0 — **it parses\n  tags and never invokes the compiler**; and the lanes themselves were green and stayed provably\n  clean (the #206 lane's brace balance is correct at all five of its commits). **Lane-green plus\n  conflict-free is not a claim about the assembled head.** Same lesson as the #182 v2 assembly\n  (`E0425`×4) by a different mechanism: that one was a semantic composition break between two\n  correct hunks, this one is a fidelity LOSS during resolution.\n- **Two must-dos, both cheap:**\n  1. **Compile the assembled head before it is handed anywhere — including forward to your own next\n     session.** A head is not ready on a treqs exit; it is ready on a build. Any sentence carrying a\n     head sha to another agent must name the instrument that proved it.\n  2. **Audit pick fidelity on CHANGED LINES for every pick on the chain**, not just the one that\n     tripped you: hash `git show --format= <sha> | grep -E '^[+-]' | grep -vE '^(\\+\\+\\+|---)'` for\n     the lane source and for the pick, and compare. Whole-diff comparison is useless here — hunk\n     headers and context legitimately drift once the head's copy of the file has moved.\n- **Read COUNT and HASH together, because they fail in opposite directions.** Of 24 picks on this\n  chain two did not match. `b2194aa9 → 4d6deed1` differed in COUNT (302 lane / 300 pick by the header-excluding pipeline above; **this entry originally cited 310/308, which is the RAW `^[+-]` count INCLUDING the 8 `+++`/`---` header lines of its 4 files** — the figures were taken without the second grep the entry itself prescribes. The DELTA is 2 under either meter, which is why the wrong figures never surfaced: they supported a correct conclusion, so nothing pressed them. Corrected todlando 2026-08-29, measured both ways in-tree) — the real\n  defect. `f27f15c6 → 5865cc98` had the SAME count and a different HASH — benign: a `CONTEXT.md`\n  paragraph the head had already amended for #209, whose merged result correctly carries both lanes'\n  sentences. A count check MISSES the first class entirely; a hash check FLAGS the second as if it\n  were a defect. Neither alone classifies a pick.\n- **Repair shape used, recorded because it is the cheap one:** reset to the commit before the bad\n  pick, re-pick the lane source, resolve the same conflict correctly, then replay the remaining picks\n  in chain order with the fidelity check on each. Verify the repair changed nothing else with a\n  WHOLE-TREE diff against the old head — it must show exactly the restored lines and no other file.\n  Where a later pick re-conflicts, check its pre-pick blobs against the old chain\n  (`git rev-parse <old-pick>~1:<file>`); if they match, the old chain's post-pick blob is a\n  transferable, already-reviewed resolution.\n- **AND GATE THE REPAIR'S OWN SUBJECT.** The rebuilt head passed six legs — clippy `-D warnings`,\n  sweep 660/660, treqs 803/803, xtask OK — while the restored lines live in `spt-store`, whose LIB\n  tests `-p spt --bins` never runs. Six greens, and not one executed the function the repair\n  restored; it was proven to COMPILE and assumed to PASS. Proven afterwards by name (4/4) and by the\n  full `spt-store --lib` suite (519/519). **A repair's gate must include the suite that owns the\n  repaired file**, which is not necessarily the suite the head gate runs.\n- **FIRST LIVE CATCH, and it was the author's own resolution (2026-08-29, one hour after the verb landed):** rebasing the IR-59 rider over the IR-57 rider produced four conflicts — three additive keep-both, one usage line both sides had edited. `xtask pick-audit` read the rebase as **LOSS, 282 lane / 280 pick**. The two missing lines were a `[[requirements]]` header and its blank line in `traceable-reqs.toml`, so `id = REQ-DISK-FLOOR-PREFLIGHT` landed INSIDE the previous table as a duplicate key: **`traceable-reqs check` exit 2, the registry unparseable, every reading after that edit checking nothing**. Restored, the same audit reads **DRIFT 282/282** whose one differing line is the usage string whose base copy legitimately gained the other verb — both verdi…\n- **FIRST REAL-ASSEMBLY USE (2026-08-29, #241 emission head, ASM-241-GATE-VERDICT.md):** `xtask\n  pick-audit --range 57a0d27c..HEAD --lane 4d6007ac..d0fdd58d` over 6 picks — **5 MATCH\n  (digest-identical), 1 LOSS, 0 drift, 0 unclassified**, exit 1 forcing the accounting. The LOSS\n  was exactly the one human-resolved conflict (`cfb9d9f8 <- 10f12e4c`, count 432/402), and the\n  delta RECONCILED to the resolution rather than assumed: lane stat 15 files/235+/197- vs pick\n  14 files/205+/197-, difference byte-for-byte the deliberately-dropped 30-line interim IR-69\n  register block superseded by main's consolidated entry. No false positives, no silent pass.\n  Entry stays OPEN as living procedure; both live uses (the rebase catch above, this assembly)\n  produced the verdict classes in the order the entry predicts.\n- **Trigger condition:** ripe at the next assembly — this is procedure, and its cost is one command\n  per pick.\n- **Size guess:** small as a scripted check in `xtask` (fidelity audit over a pick range); zero as\n  discipline, which is how it is being applied now.\n\n### IR-58 — a `[[bin]]` grep is not a census: cargo AUTODISCOVERS `src/bin/*.rs` targets, and a hand-built bin list produced a confident false \"this bin does not exist\"\n\n- **Status:** OPEN, unowned. Filed by doyle 2026-08-22; **its original filing was WRONG and is\n  retracted in full below.** The entry is kept because the way it was wrong is the finding.\n- **RETRACTED CLAIM, stated plainly so no reader acts on it:** this entry first said that\n  `crates/spt/Cargo.toml:18-21` and `crates/spt/src/cli.rs:30355` forbid a bin-name collision with\n  `xlate_choreo_fixture`, \"a bin that does not exist\", and that spt-daemon's third helper had been\n  renamed to `summarizer_fixture`. **`xlate_choreo_fixture` EXISTS** — at\n  `crates/spt-daemon/src/bin/xlate_choreo_fixture.rs`, verified at the assembly head. The collision\n  rule's counterpart is real, both prose sites are CORRECT, and IR-21's original table row was\n  correct too; it merely predated `summarizer_fixture`. Nothing in that prose needs fixing.\n- **How the false claim was produced, which is the entry:** the census was built by grepping\n  `^\\[\\[bin\\]\\]` across `Cargo.toml`s. **Cargo AUTODISCOVERS `src/bin/*.rs` as bin targets with no\n  stanza at all**, so a stanza grep cannot see them, and it fails SILENTLY — it returns a clean,\n  well-formed list that is simply short. From that list it read as established fact that a named bin\n  had been renamed away, and that \"fact\" was then written into a register table, an IR entry, and a\n  message to the builder. **A pattern-built population encodes the pattern's assumption; the count\n  looks like a census and is a property of the pattern.**\n  (Found by todlando, resolving one of doyle's figures against his own tree under the pointer rule.)\n- **A CENSUS IS ALSO A PROPERTY OF A TREE.** Stanza counts differed legitimately across trees the\n  same hour — 13 at the assembly head, 11 at `dc1c7532` — because `summarizer_fixture` exists at one\n  and not the other. Two correct censuses of the same workspace disagree unless each names its sha.\n- **The must-do, and it removes the list rather than lengthening it:** never hand-maintain a bin\n  roster. Run `cargo build --workspace --bins` and let cargo enumerate its own targets — the same\n  enumeration the test harness resolves against, so it cannot drift from what a fixture lookup\n  expects. Stanza-derived lists, remembered pairs, and register tables are all the roster problem at\n  different depths; only cargo's own enumeration is the population.\n- **Kin:** IR-55's amended prebuild bullet (prebuild the census, not a remembered pair) and IR-42\n  (a verb that writes without adjudicating). The shared shape is an instrument returning an orderly\n  answer about a set it never fully saw.\n- **Trigger condition:** ripe on any `xtask` check work — a duplicate-bin-name check over cargo's\n  target enumeration (NOT over manifest stanzas) is a handful of lines and cannot go stale.\n- **Size guess:** small. The prose fix originally proposed here is WITHDRAWN — there was nothing\n  wrong with the prose.\n\n### IR-59 — pool arithmetic: this box holds TWO cold pools, not four; and a build that exhausts the volume reds as a LINKER defect that names no disk\n\n- **Status:** OPEN, unowned — it is arithmetic and discipline, not a code lane. Filed by doyle\n  2026-08-22 from a live disk-floor abort during the TURNKEY #212 W4 gate; footprint figures measured\n  by todlando the same hour.\n- **v0.69.0 release close, 2026-09-11 (deployah, source record releases#294 comment\n  5628538587):** the first broad version/manifest battery failed to LINK (`LNK1180`,\n  `LNK1108`, cargo exit 101), with **15,777,792 bytes free** measured at recovery. It produced\n  no test verdict. The run selected the workspace's test binaries on the Cargo side even\n  though the nextest filter did not need the e2e population; the replacement selected `--lib`\n  for `spt-daemon`, `spt-runtime`, `spt`, and `xtask`, and passed **121/121** in 8.445 s.\n  Root-target reclamation restored **66,926,968,832 bytes free**; the subsequent CI Windows\n  unit step passed **3167 tests**, then its END floor refused at **15,360,114,688 bytes**\n  against **34,359,738,368**. That is an observed resource-red AFTER passing tests, not an\n  explanation of the earlier PR unit-step red whose log was unavailable. A second, classified\n  CI `target/debug` reap, with runner intake stopped by the operator, increased free bytes\n  **14,892,281,856 -> 78,994,501,632**. Runner service restored afterward. Publication used a\n  preserved signer, not a Cargo rebuild into the cleared pool. These are two measured recoveries,\n  not a durable capacity fix; IR-46/59/86 remain the next gate-driver capacity rider.\n…\n\n\n[Showing lines 3000-3300 of 5900. Use :3301 to continue. Some lines truncated to 768 chars]"}],"details":{"truncation":{"content":"  `crates/xtask/src/main.rs`, `crates/xtask/tests/bench_row_parity.rs`, `docs/GOLDEN-CI.md`,\r\n  `traceable-reqs.toml`. Nothing under `.github/ci/`, where the nextest-summary readers and\r\n  count-reporting scripts live. IR-5: no consumer of nextest output touched. IR-6: no EXISTING gate\r\n  output changed — though the NEW output was voluntarily written to IR-6's rule (the LINK line\r\n  prints `samples=N/M` and the individual rtts, membership beside the count, in both shells). That\r\n  SHRINKS IR-6's future scope by two lines; it does not discharge it.\r\n- **Three mechanisms lifted from this lane's REQ titles, worth more than the lane:**\r\n  (a) **An instrument must not be able to RED the run, and each shell breaks that differently** —\r\n  bash: `| head` under `pipefail` SIGPIPEs the producer to 141, so a print step reds (trim with\r\n  parameter expansion instead); pwsh under GitHub's wrapper: a MISSING COMMAND is a terminating\r\n  error, so rustup's absence must be TESTED with `Get-Command`, never caught. One requirement, two\r\n  constructions, and neither is portable reasoning about the other.\r\n  (b) **A negative-control mutation must be COUNTED before it is trusted** — the absent-CLI arm was\r\n  first \"measured\" against a tree where the mutation had not taken, silently re-measuring the\r\n  unmutated arm and reading as a pass.\r\n  (c) **Jitter, not the median, is the signal on a link that mostly works** — the motivating red's\r\n  link ran 10..83ms and 3..75ms while IDLE, so a median-only probe reads healthy straight through\r\n  the failure. Both med and max rows ride the ledger.\r\n- **Disposition:** composes onto the next golden batch as a thin lane, NOT slipped onto main. It\r\n  changes the golden pipeline itself, so it wants a golden rather than a quiet ff — and while\r\n  v0.53.0 is untagged, any push to `main` moves the runbook's bare `git tag` off the tested sha.\r\n\r\n### IR-55 — the `spt --bins` suite wedges partway through on leaked `findstr .` PTY children; the tests at the frontier are casualties, not culprits\r\n\r\n- **Status:** OPEN, **ARMED-FOR-CAPTURE**, owned by **hertz**. Test/rig defect by the dispatch\r\n  split (test/CI rework is never the product builder's). Filed by doyle 2026-08-22 from the\r\n  TURNKEY #212 W3 gate on releases#213.\r\n- **CORRECTED BY REPLACEMENT the same day.** This entry first named\r\n  `cli::tests::adapter_profile_verbs_local_only` as the wedging test, because that is where the\r\n  streamed frontier stopped. **That was wrong, and the correction is the useful part of the\r\n  entry:** run in isolation, on the same pool and binary and with the same env, that test passes\r\n  in **0.02s**. So do the other two the suite later stalled on —\r\n  `cli::tests::shell_channels_relay_sensory_and_text_file` (0.20s) and\r\n  `cli::tests::resolve_proof_target_override_reads_on_disk` (0.00s), each 1 passed / 652 filtered.\r\n  **A frontier names where progress STOPPED, not what CAUSED it.** Naming the last test printed\r\n  is the same error shape as reading a stack frame as a root cause, and it would have sent hertz\r\n  to rewrite three innocent tests.\r\n- **What is actually measured:**\r\n  - `cargo test -p spt --bins` unfiltered sat **24 minutes** at 13.5s CPU — blocked, not spinning.\r\n  - Re-run with `--test-threads=1` and streaming output: stalled after **183** completed.\r\n  - Re-run again with that frontier test skipped: progressed to **335** completed, then stalled\r\n    with **two** tests simultaneously past libtest's 60-second notice. Skipping one casualty\r\n    simply moves the frontier, which is itself evidence the fault is not in any one test.\r\n  - Every wedged harness carried `findstr.exe .` children under `conhost.exe --headless`.\r\n    **`findstr` with no file argument reads STDIN and blocks forever.**\r\n  - The frontier tests are **byte-identical at `c62904e7` and at the #213 tip `3d69f77c`**\r\n    (function bodies hashed at both blobs), so nothing in that lane introduced this.\r\n- **Reading, stated as a reading rather than a conclusion:** an EARLIER test spawns the `findstr`\r\n  stand-in as a PTY child and does not reap it; the children accumulate across the run and a later\r\n  test blocks behind them. Which test leaks is NOT yet identified and this entry does not guess —\r\n  the next step is to bisect for the leaker rather than to touch any test at the frontier. Five\r\n  orphaned `findstr` processes with creation times spread across the day were observed on this box\r\n  independently of any single run, which is consistent with accumulation across many suite runs.\r\n- **Hypothesis RAISED AND NOT SUPPORTED, recorded so nobody re-runs it:** the gate scrubs\r\n  `OWL_SESSION_ID` / `SPT_AGENT_ID` / `SPT_ENDPOINT_ID`, and a scrubbed identity was suspected of\r\n  routing a normally-REFUSED test down a live PTY path. The isolation runs above were performed\r\n  **with the scrub applied** and passed, so the scrub alone does not produce the hang. It remains\r\n  unexplained why the same unfiltered command completed at 652 passed / 1 failed for another agent\r\n  on the same tree; do not treat the scrub as the differentiator without a fresh one-variable run.\r\n- **Why it is register-grade:** golden CI runs the `spt` package. A test that never returns cannot\r\n  red — it consumes the single self-hosted runner slot until the job timeout, which `golden.yml`'s\r\n  50-minute cap bounds rather than fixes. A wedge that fires only sometimes is worse than a red,\r\n  because the suite's green record stays intact and nobody audits it — the same self-concealing\r\n  shape as `exit-code-after-a-pipe-is-the-tails`.\r\n- **Trigger condition (ripe):** any milestone whose gate wants an unfiltered `spt --bins` sweep,\r\n  which is every one of them. Ripe now.\r\n- **REMEDY, MEASURED 2026-08-22 and it changes this entry's urgency:** the same 653 tests under\r\n  `cargo nextest run -p spt --bins --no-fail-fast` complete in **22.2 seconds, 653 passed, 0\r\n  skipped, exit 0** — no slow markers, no timeouts — on the very tree and pool where\r\n  `cargo test -p spt --bins` wedged indefinitely twice. **nextest runs each test in its OWN\r\n  process**, so a leaked `findstr` child can block only itself. This is the discriminating\r\n  measurement rather than a workaround reached for to get a green: **the suite is not broken; the\r\n  SINGLE-PROCESS harness is what lets one test's leaked child wedge every test after it.** Golden\r\n  CI already runs nextest, which is the likely reason this has never surfaced there — the exposure\r\n  is to anyone running bare `cargo test` on the `spt` package, which is every local gate.\r\n- **Count reconciliation, recorded so the figures are not read as a discrepancy:** runs of this\r\n  suite report 652 passed / 1 failed where the one failure is\r\n  `cli::tests::adapter_translate_proof_gates_on_commit` — the `--bins`-only artifact, which\r\n  refuses because `translate_proof_fixture.exe` is not built under a bins-only invocation and says\r\n  so in its own message. Prebuilding it (`cargo build -p spt --bin translate_proof_fixture`) makes\r\n  it pass: 652 + 1 = 653. Prebuild the fixture rather than carrying a known-red through every gate.\r\n- **⚠ AMENDED 2026-08-22 — DO NOT PREBUILD FROM THIS BULLET'S EXAMPLE.** The line above names ONE\r\n  fixture because one fixture is what *this* wedge needed; read as the prebuild recipe it covers a\r\n  fraction of the population, and it was read that way twice on one day. **The census already exists\r\n  in IR-21 above** (`adapters/mock`: mock-session, mock-shell, capture-player, console-mode-probe ·\r\n  `crates/spt-daemon`: dispatch_fixture, service_fixture, summarizer_fixture · `crates/spt`:\r\n  translate_proof_fixture, post_step_fixture, gh_fixture, git_fixture), together with the split that\r\n  matters: **cross-package sites are the hazard members; same-package builds are guaranteed by\r\n  construction.** Field instances, both 2026-08-22 TURNKEY #212 W4: todlando's lane red on three\r\n  `spt-daemon::attach_resize_capture` cells wanting `adapters/mock`'s **capture-player** (a\r\n  cross-package member), and doyle's head gate prebuilding the remembered pair while never running a\r\n  `spt-daemon` or `spt-term` suite at all. **Prebuild `--workspace --bins`, or read the\r\n  `build_hint` the helper already composes** (`crates/spt-term/tests/support/fixture_bin.rs:42`) —\r\n  five test files gate on that panic. Neither of us lacked the census; we prebuilt from memory while\r\n  our own register held the list.\r\n- **FIXTURE PREBUILD, RECURRENCE 2026-08-29 (todlando, emission lane):** the rule was\r\n  already banked AND I am one of its authors, and I still ate three fixture reds in a row —\r\n  mock-session, then capture-player, then mock-shell — each tripping in about 0.01s with a panic\r\n  that reads exactly like a test failure. Having the rule is not the same as applying it completely:\r\n  I prebuilt from RECALL (`-p spt --bins`) rather than from the rule's stronger banked form, and the\r\n  tell is that my fix arrived in three instalments instead of once. **TWO FACES, both structural\r\n  rather than careless.** (1) THE FIXTURE MAY LIVE IN ANOTHER PACKAGE — mock-session,\r\n  capture-player, mock-shell and console-mode-probe are all `adapters/mock` (`-p mock-adapter`), so\r\n  no amount of `-p spt --bins` ever produces them. (2) ENUMERATING FIXTURES BY GREPPING THEIR\r\n  PRE-BUILD STRINGS IS STRUCTURALLY INCOMPLETE — it finds the call sites that embed a literal\r\n  `pre-build: cargo build ...` string and CANNOT find mock-shell, whose helper composes the command\r\n  at runtime (`sibling_bin(name)` → `fixture_package(name)`), so there is no literal to match. A\r\n  predicate over source text cannot see a string the program builds at runtime; same blindness\r\n  class as the emission census's TOKEN-colon-vs-TOKEN-space predicate, met twice in one session.\r\n  **CLASS FIX:** never hand-list fixtures — build the whole fixture package\r\n  (`cargo build -p mock-adapter --bins`) or `--workspace --bins` before any\r\n  `--test`/`--bins`/filtered leg. Chasing named fixtures one red at a time only ever finds them one\r\n  at a time, and each one costs a full battery run.\r\n- **Named negative + settle-class result (hertz, 2026-08-23):** current main at\r\n  `4dd699cb7867979ca0497e7c74d8d0aaf881e9e9` did not reproduce the wedge on HFENDULEAM from\r\n  isolated checkout `.worktrees/ir55-findstr-bisect`. Test binaries were freshly built before the\r\n  diagnostic population and reused for the settle sweep; the gate environment scrub was **not**\r\n  applied; the installed daemon was live. The fleet snapshot taken immediately **after**, not\r\n  during, the sweep showed BIGNET 7 nodes / 20 endpoints, SPT_MANTLE 3 / 19, SPT_DEV 2 / 19,\r\n  3-of-7 peers connected, `degraded-partial`. Four startup cells that spawn `findstr` passed alone\r\n  and reaped their observed ConPTY children; a full single-threaded run passed 663/663 with a\r\n  before/after census delta of `IR55_NEW=0`. The ratified settle-class sweep then ran five\r\n  consecutive bare `cargo test -p spt --bins` invocations: all 663/663 green in 420.35s total,\r\n  with zero `findstr.exe` residents before and after. This is a named negative data point, not a\r\n  discharge of the intermittent filing-day measurements.\r\n- **Next-wedge capture protocol — do not improvise or clean first:** preserve the exact bare\r\n  invocation and snapshot the environment (box, checkout SHA/worktree, fresh-versus-reused test\r\n  binary provenance, gate-scrub state, live-daemon state, and fleet roster); stream test output to\r\n  durable storage so the last started and completed test names identify the frontier; census\r\n  `Win32_Process` immediately before the run and again while wedged, recording each `findstr.exe`\r\n  PID, parent PID, creation time, executable path, and command line. **Do not kill any child before\r\n  the second census is banked.** The 22 residents found during the 2026-08-23 investigation were\r\n  path-verified as `C:\\Windows\\System32\\findstr.exe`, shown to predate its live runs, banked, then\r\n  reaped; the pre-sweep and post-sweep resident counts were both zero.\r\n- **Size guess:** small if one test is missing a reap or an EOF for its stand-in child; medium if\r\n  the shared PTY test scaffolding needs the reap, in which case every sibling spawning the same\r\n  stand-in wants it. The RUN-LEVEL exposure has an answer today (nextest); the LEAK itself is\r\n  still worth fixing, because a leaked child per run accumulates on any box that runs the suite.\r\n- **Gater's craft, worth more than the entry itself:**\r\n  (a) The first wedge was undiagnosable because the gate script wrote every leg as\r\n  `cargo test … | tail -N > file` — nothing reaches disk until the command completes, so a wedged\r\n  leg produces an **empty file** and the process table is the only witness. **Stream to a file and\r\n  tail the FILE.**\r\n  (b) To NAME a frontier, run `--test-threads=1`: libtest prints each test's name BEFORE running\r\n  it, so the last incomplete line is where progress stopped.\r\n  (c) **Then prove the frontier test is actually at fault by running it alone** — which is the\r\n  step this entry originally skipped, and the one that turned a wrong entry into a right one.\r\n\r\n### IR-56 — `pool-claim` harvests lane identity from CWD, not from `--pool`; a claim run from the wrong tree writes a WRONG RECORD with a success message\r\n\r\n- **Status:** BUILT 2026-08-24 for the SIGNET #218 golden batch on\r\n  `fix/ir56-pool-claim-cwd`, owned by **hertz**. Tooling/rig defect by the dispatch split. Filed by\r\n  doyle 2026-08-22 from todlando's TURNKEY #212 W4 Lane 1 field instance — the first confirmation\r\n  of the IR-42 mechanism from a LANE rather than from a source read.\r\n- **What happens:** `cargo run -p xtask -- pool-claim --pool <dir> --label <lane>` records the lane\r\n  identity it harvests from the **current working directory** — `owner_tree`, `lane_branch`, and the\r\n  base sha — not from the tree `--pool` names. Run it from the project root with `--pool` aimed at a\r\n  worktree and the record reads `owner_tree = <project root>, lane_branch = <root's branch>` while\r\n  every artifact in that pool belongs to the worktree. The verb prints its ordinary success line\r\n  naming the wrong owner, and returns 0.\r\n- **Why it is silent, which is the whole entry:** the claim verb WRITES and never adjudicates\r\n  (IR-42) — every enforcement arm lives in `crates/spt-store/build.rs` and speaks only at the next\r\n  BUILD. So a wrong record has no symptom at the moment it is created; the first signal is a build\r\n  refusal minutes later, on a lane whose `--pool` argument was correct all along. **`--pool` being\r\n  correct is not evidence the record is.** Nothing on the command line shows you cwd, which is the\r\n  one input that decided the outcome.\r\n- **Recovery is the documented hatch, and the bootstrap is why:** the claim tool builds THROUGH the\r\n  pool it is claiming, so a pool already refusing cannot be re-claimed by the ordinary route. The\r\n  refusal text says so itself — meaning the bootstrap case is known, and a wrong-cwd claim is the\r\n  ordinary way a lane lands in it.\r\n- **The rule, as a must-do:** claim from the lane's own worktree so the identity the verb harvests\r\n  is the lane's — `( cd <lane> && cargo run -p xtask -- pool-claim --pool \"$PWD/target\" … )`, or any\r\n  form that makes cwd explicit. Then READ THE PRINTED RECORD BACK and confirm `owner_tree` and\r\n  `branch` name the lane: the success line carries the record, so the check costs nothing.\r\n- **Trigger condition:** ripe now — it is a doc/UX fix on a verb we run every lane. Ripest alongside\r\n  any other `xtask` pool-verb touch.\r\n- **Size guess:** small. Either make the verb REFUSE when cwd is not inside the tree containing\r\n  `--pool` (loud, and it cannot be wrong), or print the harvested identity as a distinct confirmed\r\n  line. The refusing form is preferred: it removes the reading step rather than adding one.\r\n- **Built evidence, corrected at review:** `pool-claim` resolves the git worktree containing\r\n  `--pool` from the pool's nearest existing ancestor and compares it with the cwd worktree before\r\n  writing. An accidental cross-worktree call returns 2, names both worktrees and the remedy, and\r\n  leaves the not-yet-existing pool absent. The sanctioned sequential takeover carries an explicit\r\n  `--foreign-pool`, says that it is harvesting the arriving cwd identity, writes that identity, and\r\n  returns 0. Both poolguard refusal remedies now print that flag. An executable xtask test drives\r\n  both arms against two real temporary git repositories, pinning VERB-ADMITS-REMEDY rather than\r\n  merely testing path equality. This remains identity-harvest validation only: the claim still\r\n  writes without adjudicating admission, so IR-42's enforcement boundary remains in the build.\r\n\r\n### IR-57 — an assembly pick's conflict resolution can silently DROP lines, and every gate run at assembly time is blind to it\r\n\r\n- **Status:** OPEN, owned by **doyle** (gater craft, not a code defect — no lane to dispatch).\r\n  Filed 2026-08-22 from doyle's own defect on the TURNKEY #212 assembly head.\r\n- **What happened:** assembly head `5cce533d` **did not compile**, and was carried across a session\r\n  boundary as a ready head with \"treqs exit 0\" attached to it. `crates/spt-store/src/access.rs` had\r\n  an unclosed `mod tests`: the cherry-pick of the #206 lane commit `b2194aa9` conflicted against the\r\n  #209 test block — both add functions to the same region, and the two sides share the trailing\r\n  `);` / `}` / `}` — and the resolution deleted the markers without restoring the FIRST side's\r\n  function closer. Exactly two lines lost: `        );` and `    }`.\r\n- **Every instrument in the assembly path reported success:** `git cherry-pick` completed with no\r\n  conflict remaining; `traceable-reqs check` returned 797/797, 0 findings, exit 0 — **it parses\r\n  tags and never invokes the compiler**; and the lanes themselves were green and stayed provably\r\n  clean (the #206 lane's brace balance is correct at all five of its commits). **Lane-green plus\r\n  conflict-free is not a claim about the assembled head.** Same lesson as the #182 v2 assembly\r\n  (`E0425`×4) by a different mechanism: that one was a semantic composition break between two\r\n  correct hunks, this one is a fidelity LOSS during resolution.\r\n- **Two must-dos, both cheap:**\r\n  1. **Compile the assembled head before it is handed anywhere — including forward to your own next\r\n     session.** A head is not ready on a treqs exit; it is ready on a build. Any sentence carrying a\r\n     head sha to another agent must name the instrument that proved it.\r\n  2. **Audit pick fidelity on CHANGED LINES for every pick on the chain**, not just the one that\r\n     tripped you: hash `git show --format= <sha> | grep -E '^[+-]' | grep -vE '^(\\+\\+\\+|---)'` for\r\n     the lane source and for the pick, and compare. Whole-diff comparison is useless here — hunk\r\n     headers and context legitimately drift once the head's copy of the file has moved.\r\n- **Read COUNT and HASH together, because they fail in opposite directions.** Of 24 picks on this\r\n  chain two did not match. `b2194aa9 → 4d6deed1` differed in COUNT (302 lane / 300 pick by the header-excluding pipeline above; **this entry originally cited 310/308, which is the RAW `^[+-]` count INCLUDING the 8 `+++`/`---` header lines of its 4 files** — the figures were taken without the second grep the entry itself prescribes. The DELTA is 2 under either meter, which is why the wrong figures never surfaced: they supported a correct conclusion, so nothing pressed them. Corrected todlando 2026-08-29, measured both ways in-tree) — the real\r\n  defect. `f27f15c6 → 5865cc98` had the SAME count and a different HASH — benign: a `CONTEXT.md`\r\n  paragraph the head had already amended for #209, whose merged result correctly carries both lanes'\r\n  sentences. A count check MISSES the first class entirely; a hash check FLAGS the second as if it\r\n  were a defect. Neither alone classifies a pick.\r\n- **Repair shape used, recorded because it is the cheap one:** reset to the commit before the bad\r\n  pick, re-pick the lane source, resolve the same conflict correctly, then replay the remaining picks\r\n  in chain order with the fidelity check on each. Verify the repair changed nothing else with a\r\n  WHOLE-TREE diff against the old head — it must show exactly the restored lines and no other file.\r\n  Where a later pick re-conflicts, check its pre-pick blobs against the old chain\r\n  (`git rev-parse <old-pick>~1:<file>`); if they match, the old chain's post-pick blob is a\r\n  transferable, already-reviewed resolution.\r\n- **AND GATE THE REPAIR'S OWN SUBJECT.** The rebuilt head passed six legs — clippy `-D warnings`,\r\n  sweep 660/660, treqs 803/803, xtask OK — while the restored lines live in `spt-store`, whose LIB\r\n  tests `-p spt --bins` never runs. Six greens, and not one executed the function the repair\r\n  restored; it was proven to COMPILE and assumed to PASS. Proven afterwards by name (4/4) and by the\r\n  full `spt-store --lib` suite (519/519). **A repair's gate must include the suite that owns the\r\n  repaired file**, which is not necessarily the suite the head gate runs.\r\n- **FIRST LIVE CATCH, and it was the author's own resolution (2026-08-29, one hour after the verb landed):** rebasing the IR-59 rider over the IR-57 rider produced four conflicts — three additive keep-both, one usage line both sides had edited. `xtask pick-audit` read the rebase as **LOSS, 282 lane / 280 pick**. The two missing lines were a `[[requirements]]` header and its blank line in `traceable-reqs.toml`, so `id = REQ-DISK-FLOOR-PREFLIGHT` landed INSIDE the previous table as a duplicate key: **`traceable-reqs check` exit 2, the registry unparseable, every reading after that edit checking nothing**. Restored, the same audit reads **DRIFT 282/282** whose one differing line is the usage string whose base copy legitimately gained the other verb — both verdi…\n- **FIRST REAL-ASSEMBLY USE (2026-08-29, #241 emission head, ASM-241-GATE-VERDICT.md):** `xtask\r\n  pick-audit --range 57a0d27c..HEAD --lane 4d6007ac..d0fdd58d` over 6 picks — **5 MATCH\r\n  (digest-identical), 1 LOSS, 0 drift, 0 unclassified**, exit 1 forcing the accounting. The LOSS\r\n  was exactly the one human-resolved conflict (`cfb9d9f8 <- 10f12e4c`, count 432/402), and the\r\n  delta RECONCILED to the resolution rather than assumed: lane stat 15 files/235+/197- vs pick\r\n  14 files/205+/197-, difference byte-for-byte the deliberately-dropped 30-line interim IR-69\r\n  register block superseded by main's consolidated entry. No false positives, no silent pass.\r\n  Entry stays OPEN as living procedure; both live uses (the rebase catch above, this assembly)\r\n  produced the verdict classes in the order the entry predicts.\r\n- **Trigger condition:** ripe at the next assembly — this is procedure, and its cost is one command\r\n  per pick.\r\n- **Size guess:** small as a scripted check in `xtask` (fidelity audit over a pick range); zero as\r\n  discipline, which is how it is being applied now.\r\n\r\n### IR-58 — a `[[bin]]` grep is not a census: cargo AUTODISCOVERS `src/bin/*.rs` targets, and a hand-built bin list produced a confident false \"this bin does not exist\"\r\n\r\n- **Status:** OPEN, unowned. Filed by doyle 2026-08-22; **its original filing was WRONG and is\r\n  retracted in full below.** The entry is kept because the way it was wrong is the finding.\r\n- **RETRACTED CLAIM, stated plainly so no reader acts on it:** this entry first said that\r\n  `crates/spt/Cargo.toml:18-21` and `crates/spt/src/cli.rs:30355` forbid a bin-name collision with\r\n  `xlate_choreo_fixture`, \"a bin that does not exist\", and that spt-daemon's third helper had been\r\n  renamed to `summarizer_fixture`. **`xlate_choreo_fixture` EXISTS** — at\r\n  `crates/spt-daemon/src/bin/xlate_choreo_fixture.rs`, verified at the assembly head. The collision\r\n  rule's counterpart is real, both prose sites are CORRECT, and IR-21's original table row was\r\n  correct too; it merely predated `summarizer_fixture`. Nothing in that prose needs fixing.\r\n- **How the false claim was produced, which is the entry:** the census was built by grepping\r\n  `^\\[\\[bin\\]\\]` across `Cargo.toml`s. **Cargo AUTODISCOVERS `src/bin/*.rs` as bin targets with no\r\n  stanza at all**, so a stanza grep cannot see them, and it fails SILENTLY — it returns a clean,\r\n  well-formed list that is simply short. From that list it read as established fact that a named bin\r\n  had been renamed away, and that \"fact\" was then written into a register table, an IR entry, and a\r\n  message to the builder. **A pattern-built population encodes the pattern's assumption; the count\r\n  looks like a census and is a property of the pattern.**\r\n  (Found by todlando, resolving one of doyle's figures against his own tree under the pointer rule.)\r\n- **A CENSUS IS ALSO A PROPERTY OF A TREE.** Stanza counts differed legitimately across trees the\r\n  same hour — 13 at the assembly head, 11 at `dc1c7532` — because `summarizer_fixture` exists at one\r\n  and not the other. Two correct censuses of the same workspace disagree unless each names its sha.\r\n- **The must-do, and it removes the list rather than lengthening it:** never hand-maintain a bin\r\n  roster. Run `cargo build --workspace --bins` and let cargo enumerate its own targets — the same\r\n  enumeration the test harness resolves against, so it cannot drift from what a fixture lookup\r\n  expects. Stanza-derived lists, remembered pairs, and register tables are all the roster problem at\r\n  different depths; only cargo's own enumeration is the population.\r\n- **Kin:** IR-55's amended prebuild bullet (prebuild the census, not a remembered pair) and IR-42\r\n  (a verb that writes without adjudicating). The shared shape is an instrument returning an orderly\r\n  answer about a set it never fully saw.\r\n- **Trigger condition:** ripe on any `xtask` check work — a duplicate-bin-name check over cargo's\r\n  target enumeration (NOT over manifest stanzas) is a handful of lines and cannot go stale.\r\n- **Size guess:** small. The prose fix originally proposed here is WITHDRAWN — there was nothing\r\n  wrong with the prose.\r\n\r\n### IR-59 — pool arithmetic: this box holds TWO cold pools, not four; and a build that exhausts the volume reds as a LINKER defect that names no disk\r\n\r\n- **Status:** OPEN, unowned — it is arithmetic and discipline, not a code lane. Filed by doyle\r\n  2026-08-22 from a live disk-floor abort during the TURNKEY #212 W4 gate; footprint figures measured\r\n  by todlando the same hour.\r\n- **v0.69.0 release close, 2026-09-11 (deployah, source record releases#294 comment\r\n  5628538587):** the first broad version/manifest battery failed to LINK (`LNK1180`,\r\n  `LNK1108`, cargo exit 101), with **15,777,792 bytes free** measured at recovery. It produced\r\n  no test verdict. The run selected the workspace's test binaries on the Cargo side even\r\n  though the nextest filter did not need the e2e population; the replacement selected `--lib`\r\n  for `spt-daemon`, `spt-runtime`, `spt`, and `xtask`, and passed **121/121** in 8.445 s.\r\n  Root-target reclamation restored **66,926,968,832 bytes free**; the subsequent CI Windows\r\n  unit step passed **3167 tests**, then its END floor refused at **15,360,114,688 bytes**\r\n  against **34,359,738,368**. That is an observed resource-red AFTER passing tests, not an\r\n  explanation of the earlier PR unit-step red whose log was unavailable. A second, classified\r\n  CI `target/debug` reap, with runner intake stopped by the operator, increased free bytes\r\n  **14,892,281,856 -> 78,994,501,632**. Runner service restored afterward. Publication used a\r\n  preserved signer, not a Cargo rebuild into the cleared pool. These are two measured recoveries,\r","truncated":true,"truncatedBy":"lines","totalLines":2901,"totalBytes":27997,"outputLines":301,"outputBytes":27997,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":5900,"displayContent":{"text":"### CI-RIDER LANE STATE — LANDED 2026-08-04 (post-v0.53.0 merge queue); history below kept for its mechanisms\n- **RESOLVED:** the lane rebased clean onto the post-tag queue and landed ff-only as\n…\n- **[[IR-5]]/[[IR-6]] CONDITIONAL RIDERS: CONDITION NOT MET — the answer is NO and it closes the\n…\n  `crates/xtask/src/main.rs`, `crates/xtask/tests/bench_row_parity.rs`, `docs/GOLDEN-CI.md`,\r\n  `traceable-reqs.toml`. Nothing under `.github/ci/`, where the nextest-summary readers and\r\n  count-reporting scripts live. IR-5: no consumer of nextest output touched. IR-6: no EXISTING gate\r\n  output changed — though the NEW output was voluntarily written to IR-6's rule (the LINK line\r\n  prints `samples=N/M` and the individual rtts, membership beside the count, in both shells). That\r\n  SHRINKS IR-6's future scope by two lines; it does not discharge it.\r\n- **Three mechanisms lifted from this lane's REQ titles, worth more than the lane:**\r\n  (a) **An instrument must not be able to RED the run, and each shell breaks that differently** —\r\n  bash: `| head` under `pipefail` SIGPIPEs the producer to 141, so a print step reds (trim with\r\n  parameter expansion instead); pwsh under GitHub's wrapper: a MISSING COMMAND is a terminating\r\n  error, so rustup's absence must be TESTED with `Get-Command`, never caught. One requirement, two\r\n  constructions, and neither is portable reasoning about the other.\r\n  (b) **A negative-control mutation must be COUNTED before it is trusted** — the absent-CLI arm was\r\n  first \"measured\" against a tree where the mutation had not taken, silently re-measuring the\r\n  unmutated arm and reading as a pass.\r\n  (c) **Jitter, not the median, is the signal on a link that mostly works** — the motivating red's\r\n  link ran 10..83ms and 3..75ms while IDLE, so a median-only probe reads healthy straight through\r\n  the failure. Both med and max rows ride the ledger.\r\n- **Disposition:** composes onto the next golden batch as a thin lane, NOT slipped onto main. It\r\n  changes the golden pipeline itself, so it wants a golden rather than a quiet ff — and while\r\n  v0.53.0 is untagged, any push to `main` moves the runbook's bare `git tag` off the tested sha.\r\n\r\n### IR-55 — the `spt --bins` suite wedges partway through on leaked `findstr .` PTY children; the tests at the frontier are casualties, not culprits\r\n\r\n- **Status:** OPEN, **ARMED-FOR-CAPTURE**, owned by **hertz**. Test/rig defect by the dispatch\r\n  split (test/CI rework is never the product builder's). Filed by doyle 2026-08-22 from the\r\n  TURNKEY #212 W3 gate on releases#213.\r\n- **CORRECTED BY REPLACEMENT the same day.** This entry first named\r\n  `cli::tests::adapter_profile_verbs_local_only` as the wedging test, because that is where the\r\n  streamed frontier stopped. **That was wrong, and the correction is the useful part of the\r\n  entry:** run in isolation, on the same pool and binary and with the same env, that test passes\r\n  in **0.02s**. So do the other two the suite later stalled on —\r\n  `cli::tests::shell_channels_relay_sensory_and_text_file` (0.20s) and\r\n  `cli::tests::resolve_proof_target_override_reads_on_disk` (0.00s), each 1 passed / 652 filtered.\r\n  **A frontier names where progress STOPPED, not what CAUSED it.** Naming the last test printed\r\n  is the same error shape as reading a stack frame as a root cause, and it would have sent hertz\r\n  to rewrite three innocent tests.\r\n- **What is actually measured:**\r\n  - `cargo test -p spt --bins` unfiltered sat **24 minutes** at 13.5s CPU — blocked, not spinning.\r\n  - Re-run with `--test-threads=1` and streaming output: stalled after **183** completed.\r\n  - Re-run again with that frontier test skipped: progressed to **335** completed, then stalled\r\n    with **two** tests simultaneously past libtest's 60-second notice. Skipping one casualty\r\n    simply moves the frontier, which is itself evidence the fault is not in any one test.\r\n  - Every wedged harness carried `findstr.exe .` children under `conhost.exe --headless`.\r\n    **`findstr` with no file argument reads STDIN and blocks forever.**\r\n  - The frontier tests are **byte-identical at `c62904e7` and at the #213 tip `3d69f77c`**\r\n    (function bodies hashed at both blobs), so nothing in that lane introduced this.\r\n- **Reading, stated as a reading rather than a conclusion:** an EARLIER test spawns the `findstr`\r\n  stand-in as a PTY child and does not reap it; the children accumulate across the run and a later\r\n  test blocks behind them. Which test leaks is NOT yet identified and this entry does not guess —\r\n  the next step is to bisect for the leaker rather than to touch any test at the frontier. Five\r\n  orphaned `findstr` processes with creation times spread across the day were observed on this box\r\n  independently of any single run, which is consistent with accumulation across many suite runs.\r\n- **Hypothesis RAISED AND NOT SUPPORTED, recorded so nobody re-runs it:** the gate scrubs\r\n  `OWL_SESSION_ID` / `SPT_AGENT_ID` / `SPT_ENDPOINT_ID`, and a scrubbed identity was suspected of\r\n  routing a normally-REFUSED test down a live PTY path. The isolation runs above were performed\r\n  **with the scrub applied** and passed, so the scrub alone does not produce the hang. It remains\r\n  unexplained why the same unfiltered command completed at 652 passed / 1 failed for another agent\r\n  on the same tree; do not treat the scrub as the differentiator without a fresh one-variable run.\r\n- **Why it is register-grade:** golden CI runs the `spt` package. A test that never returns cannot\r\n  red — it consumes the single self-hosted runner slot until the job timeout, which `golden.yml`'s\r\n  50-minute cap bounds rather than fixes. A wedge that fires only sometimes is worse than a red,\r\n  because the suite's green record stays intact and nobody audits it — the same self-concealing\r\n  shape as `exit-code-after-a-pipe-is-the-tails`.\r\n- **Trigger condition (ripe):** any milestone whose gate wants an unfiltered `spt --bins` sweep,\r\n  which is every one of them. Ripe now.\r\n- **REMEDY, MEASURED 2026-08-22 and it changes this entry's urgency:** the same 653 tests under\r\n  `cargo nextest run -p spt --bins --no-fail-fast` complete in **22.2 seconds, 653 passed, 0\r\n  skipped, exit 0** — no slow markers, no timeouts — on the very tree and pool where\r\n  `cargo test -p spt --bins` wedged indefinitely twice. **nextest runs each test in its OWN\r\n  process**, so a leaked `findstr` child can block only itself. This is the discriminating\r\n  measurement rather than a workaround reached for to get a green: **the suite is not broken; the\r\n  SINGLE-PROCESS harness is what lets one test's leaked child wedge every test after it.** Golden\r\n  CI already runs nextest, which is the likely reason this has never surfaced there — the exposure\r\n  is to anyone running bare `cargo test` on the `spt` package, which is every local gate.\r\n- **Count reconciliation, recorded so the figures are not read as a discrepancy:** runs of this\r\n  suite report 652 passed / 1 failed where the one failure is\r\n  `cli::tests::adapter_translate_proof_gates_on_commit` — the `--bins`-only artifact, which\r\n  refuses because `translate_proof_fixture.exe` is not built under a bins-only invocation and says\r\n  so in its own message. Prebuilding it (`cargo build -p spt --bin translate_proof_fixture`) makes\r\n  it pass: 652 + 1 = 653. Prebuild the fixture rather than carrying a known-red through every gate.\r\n- **⚠ AMENDED 2026-08-22 — DO NOT PREBUILD FROM THIS BULLET'S EXAMPLE.** The line above names ONE\r\n  fixture because one fixture is what *this* wedge needed; read as the prebuild recipe it covers a\r\n  fraction of the population, and it was read that way twice on one day. **The census already exists\r\n  in IR-21 above** (`adapters/mock`: mock-session, mock-shell, capture-player, console-mode-probe ·\r\n  `crates/spt-daemon`: dispatch_fixture, service_fixture, summarizer_fixture · `crates/spt`:\r\n  translate_proof_fixture, post_step_fixture, gh_fixture, git_fixture), together with the split that\r\n  matters: **cross-package sites are the hazard members; same-package builds are guaranteed by\r\n  construction.** Field instances, both 2026-08-22 TURNKEY #212 W4: todlando's lane red on three\r\n  `spt-daemon::attach_resize_capture` cells wanting `adapters/mock`'s **capture-player** (a\r\n  cross-package member), and doyle's head gate prebuilding the remembered pair while never running a\r\n  `spt-daemon` or `spt-term` suite at all. **Prebuild `--workspace --bins`, or read the\r\n  `build_hint` the helper already composes** (`crates/spt-term/tests/support/fixture_bin.rs:42`) —\r\n  five test files gate on that panic. Neither of us lacked the census; we prebuilt from memory while\r\n  our own register held the list.\r\n- **FIXTURE PREBUILD, RECURRENCE 2026-08-29 (todlando, emission lane):** the rule was\r\n  already banked AND I am one of its authors, and I still ate three fixture reds in a row —\r\n  mock-session, then capture-player, then mock-shell — each tripping in about 0.01s with a panic\r\n  that reads exactly like a test failure. Having the rule is not the same as applying it completely:\r\n  I prebuilt from RECALL (`-p spt --bins`) rather than from the rule's stronger banked form, and the\r\n  tell is that my fix arrived in three instalments instead of once. **TWO FACES, both structural\r\n  rather than careless.** (1) THE FIXTURE MAY LIVE IN ANOTHER PACKAGE — mock-session,\r\n  capture-player, mock-shell and console-mode-probe are all `adapters/mock` (`-p mock-adapter`), so\r\n  no amount of `-p spt --bins` ever produces them. (2) ENUMERATING FIXTURES BY GREPPING THEIR\r\n  PRE-BUILD STRINGS IS STRUCTURALLY INCOMPLETE — it finds the call sites that embed a literal\r\n  `pre-build: cargo build ...` string and CANNOT find mock-shell, whose helper composes the command\r\n  at runtime (`sibling_bin(name)` → `fixture_package(name)`), so there is no literal to match. A\r\n  predicate over source text cannot see a string the program builds at runtime; same blindness\r\n  class as the emission census's TOKEN-colon-vs-TOKEN-space predicate, met twice in one session.\r\n  **CLASS FIX:** never hand-list fixtures — build the whole fixture package\r\n  (`cargo build -p mock-adapter --bins`) or `--workspace --bins` before any\r\n  `--test`/`--bins`/filtered leg. Chasing named fixtures one red at a time only ever finds them one\r\n  at a time, and each one costs a full battery run.\r\n- **Named negative + settle-class result (hertz, 2026-08-23):** current main at\r\n  `4dd699cb7867979ca0497e7c74d8d0aaf881e9e9` did not reproduce the wedge on HFENDULEAM from\r\n  isolated checkout `.worktrees/ir55-findstr-bisect`. Test binaries were freshly built before the\r\n  diagnostic population and reused for the settle sweep; the gate environment scrub was **not**\r\n  applied; the installed daemon was live. The fleet snapshot taken immediately **after**, not\r\n  during, the sweep showed BIGNET 7 nodes / 20 endpoints, SPT_MANTLE 3 / 19, SPT_DEV 2 / 19,\r\n  3-of-7 peers connected, `degraded-partial`. Four startup cells that spawn `findstr` passed alone\r\n  and reaped their observed ConPTY children; a full single-threaded run passed 663/663 with a\r\n  before/after census delta of `IR55_NEW=0`. The ratified settle-class sweep then ran five\r\n  consecutive bare `cargo test -p spt --bins` invocations: all 663/663 green in 420.35s total,\r\n  with zero `findstr.exe` residents before and after. This is a named negative data point, not a\r\n  discharge of the intermittent filing-day measurements.\r\n- **Next-wedge capture protocol — do not improvise or clean first:** preserve the exact bare\r\n  invocation and snapshot the environment (box, checkout SHA/worktree, fresh-versus-reused test\r\n  binary provenance, gate-scrub state, live-daemon state, and fleet roster); stream test output to\r\n  durable storage so the last started and completed test names identify the frontier; census\r\n  `Win32_Process` immediately before the run and again while wedged, recording each `findstr.exe`\r\n  PID, parent PID, creation time, executable path, and command line. **Do not kill any child before\r\n  the second census is banked.** The 22 residents found during the 2026-08-23 investigation were\r\n  path-verified as `C:\\Windows\\System32\\findstr.exe`, shown to predate its live runs, banked, then\r\n  reaped; the pre-sweep and post-sweep resident counts were both zero.\r\n- **Size guess:** small if one test is missing a reap or an EOF for its stand-in child; medium if\r\n  the shared PTY test scaffolding needs the reap, in which case every sibling spawning the same\r\n  stand-in wants it. The RUN-LEVEL exposure has an answer today (nextest); the LEAK itself is\r\n  still worth fixing, because a leaked child per run accumulates on any box that runs the suite.\r\n- **Gater's craft, worth more than the entry itself:**\r\n  (a) The first wedge was undiagnosable because the gate script wrote every leg as\r\n  `cargo test … | tail -N > file` — nothing reaches disk until the command completes, so a wedged\r\n  leg produces an **empty file** and the process table is the only witness. **Stream to a file and\r\n  tail the FILE.**\r\n  (b) To NAME a frontier, run `--test-threads=1`: libtest prints each test's name BEFORE running\r\n  it, so the last incomplete line is where progress stopped.\r\n  (c) **Then prove the frontier test is actually at fault by running it alone** — which is the\r\n  step this entry originally skipped, and the one that turned a wrong entry into a right one.\r\n\r\n### IR-56 — `pool-claim` harvests lane identity from CWD, not from `--pool`; a claim run from the wrong tree writes a WRONG RECORD with a success message\r\n\r\n- **Status:** BUILT 2026-08-24 for the SIGNET #218 golden batch on\r\n  `fix/ir56-pool-claim-cwd`, owned by **hertz**. Tooling/rig defect by the dispatch split. Filed by\r\n  doyle 2026-08-22 from todlando's TURNKEY #212 W4 Lane 1 field instance — the first confirmation\r\n  of the IR-42 mechanism from a LANE rather than from a source read.\r\n- **What happens:** `cargo run -p xtask -- pool-claim --pool <dir> --label <lane>` records the lane\r\n  identity it harvests from the **current working directory** — `owner_tree`, `lane_branch`, and the\r\n  base sha — not from the tree `--pool` names. Run it from the project root with `--pool` aimed at a\r\n  worktree and the record reads `owner_tree = <project root>, lane_branch = <root's branch>` while\r\n  every artifact in that pool belongs to the worktree. The verb prints its ordinary success line\r\n  naming the wrong owner, and returns 0.\r\n- **Why it is silent, which is the whole entry:** the claim verb WRITES and never adjudicates\r\n  (IR-42) — every enforcement arm lives in `crates/spt-store/build.rs` and speaks only at the next\r\n  BUILD. So a wrong record has no symptom at the moment it is created; the first signal is a build\r\n  refusal minutes later, on a lane whose `--pool` argument was correct all along. **`--pool` being\r\n  correct is not evidence the record is.** Nothing on the command line shows you cwd, which is the\r\n  one input that decided the outcome.\r\n- **Recovery is the documented hatch, and the bootstrap is why:** the claim tool builds THROUGH the\r\n  pool it is claiming, so a pool already refusing cannot be re-claimed by the ordinary route. The\r\n  refusal text says so itself — meaning the bootstrap case is known, and a wrong-cwd claim is the\r\n  ordinary way a lane lands in it.\r\n- **The rule, as a must-do:** claim from the lane's own worktree so the identity the verb harvests\r\n  is the lane's — `( cd <lane> && cargo run -p xtask -- pool-claim --pool \"$PWD/target\" … )`, or any\r\n  form that makes cwd explicit. Then READ THE PRINTED RECORD BACK and confirm `owner_tree` and\r\n  `branch` name the lane: the success line carries the record, so the check costs nothing.\r\n- **Trigger condition:** ripe now — it is a doc/UX fix on a verb we run every lane. Ripest alongside\r\n  any other `xtask` pool-verb touch.\r\n- **Size guess:** small. Either make the verb REFUSE when cwd is not inside the tree containing\r\n  `--pool` (loud, and it cannot be wrong), or print the harvested identity as a distinct confirmed\r\n  line. The refusing form is preferred: it removes the reading step rather than adding one.\r\n- **Built evidence, corrected at review:** `pool-claim` resolves the git worktree containing\r\n  `--pool` from the pool's nearest existing ancestor and compares it with the cwd worktree before\r\n  writing. An accidental cross-worktree call returns 2, names both worktrees and the remedy, and\r\n  leaves the not-yet-existing pool absent. The sanctioned sequential takeover carries an explicit\r\n  `--foreign-pool`, says that it is harvesting the arriving cwd identity, writes that identity, and\r\n  returns 0. Both poolguard refusal remedies now print that flag. An executable xtask test drives\r\n  both arms against two real temporary git repositories, pinning VERB-ADMITS-REMEDY rather than\r\n  merely testing path equality. This remains identity-harvest validation only: the claim still\r\n  writes without adjudicating admission, so IR-42's enforcement boundary remains in the build.\r\n\r\n### IR-57 — an assembly pick's conflict resolution can silently DROP lines, and every gate run at assembly time is blind to it\r\n\r\n- **Status:** OPEN, owned by **doyle** (gater craft, not a code defect — no lane to dispatch).\r\n  Filed 2026-08-22 from doyle's own defect on the TURNKEY #212 assembly head.\r\n- **What happened:** assembly head `5cce533d` **did not compile**, and was carried across a session\r\n  boundary as a ready head with \"treqs exit 0\" attached to it. `crates/spt-store/src/access.rs` had\r\n  an unclosed `mod tests`: the cherry-pick of the #206 lane commit `b2194aa9` conflicted against the\r\n  #209 test block — both add functions to the same region, and the two sides share the trailing\r\n  `);` / `}` / `}` — and the resolution deleted the markers without restoring the FIRST side's\r\n  function closer. Exactly two lines lost: `        );` and `    }`.\r\n- **Every instrument in the assembly path reported success:** `git cherry-pick` completed with no\r\n  conflict remaining; `traceable-reqs check` returned 797/797, 0 findings, exit 0 — **it parses\r\n  tags and never invokes the compiler**; and the lanes themselves were green and stayed provably\r\n  clean (the #206 lane's brace balance is correct at all five of its commits). **Lane-green plus\r\n  conflict-free is not a claim about the assembled head.** Same lesson as the #182 v2 assembly\r\n  (`E0425`×4) by a different mechanism: that one was a semantic composition break between two\r\n  correct hunks, this one is a fidelity LOSS during resolution.\r\n- **Two must-dos, both cheap:**\r\n  1. **Compile the assembled head before it is handed anywhere — including forward to your own next\r\n     session.** A head is not ready on a treqs exit; it is ready on a build. Any sentence carrying a\r\n     head sha to another agent must name the instrument that proved it.\r\n  2. **Audit pick fidelity on CHANGED LINES for every pick on the chain**, not just the one that\r\n     tripped you: hash `git show --format= <sha> | grep -E '^[+-]' | grep -vE '^(\\+\\+\\+|---)'` for\r\n     the lane source and for the pick, and compare. Whole-diff comparison is useless here — hunk\r\n     headers and context legitimately drift once the head's copy of the file has moved.\r\n- **Read COUNT and HASH together, because they fail in opposite directions.** Of 24 picks on this\r\n  chain two did not match. `b2194aa9 → 4d6deed1` differed in COUNT (302 lane / 300 pick by the header-excluding pipeline above; **this entry originally cited 310/308, which is the RAW `^[+-]` count INCLUDING the 8 `+++`/`---` header lines of its 4 files** — the figures were taken without the second grep the entry itself prescribes. The DELTA is 2 under either meter, which is why the wrong figures never surfaced: they supported a correct conclusion, so nothing pressed them. Corrected todlando 2026-08-29, measured both ways in-tree) — the real\r\n  defect. `f27f15c6 → 5865cc98` had the SAME count and a different HASH — benign: a `CONTEXT.md`\r\n  paragraph the head had already amended for #209, whose merged result correctly carries both lanes'\r\n  sentences. A count check MISSES the first class entirely; a hash check FLAGS the second as if it\r\n  were a defect. Neither alone classifies a pick.\r\n- **Repair shape used, recorded because it is the cheap one:** reset to the commit before the bad\r\n  pick, re-pick the lane source, resolve the same conflict correctly, then replay the remaining picks\r\n  in chain order with the fidelity check on each. Verify the repair changed nothing else with a\r\n  WHOLE-TREE diff against the old head — it must show exactly the restored lines and no other file.\r\n  Where a later pick re-conflicts, check its pre-pick blobs against the old chain\r\n  (`git rev-parse <old-pick>~1:<file>`); if they match, the old chain's post-pick blob is a\r\n  transferable, already-reviewed resolution.\r\n- **AND GATE THE REPAIR'S OWN SUBJECT.** The rebuilt head passed six legs — clippy `-D warnings`,\r\n  sweep 660/660, treqs 803/803, xtask OK — while the restored lines live in `spt-store`, whose LIB\r\n  tests `-p spt --bins` never runs. Six greens, and not one executed the function the repair\r\n  restored; it was proven to COMPILE and assumed to PASS. Proven afterwards by name (4/4) and by the\r\n  full `spt-store --lib` suite (519/519). **A repair's gate must include the suite that owns the\r\n  repaired file**, which is not necessarily the suite the head gate runs.\r\n- **FIRST LIVE CATCH, and it was the author's own resolution (2026-08-29, one hour after the verb landed):** rebasing the IR-59 rider over the IR-57 rider produced four conflicts — three additive keep-both, one usage line both sides had edited. `xtask pick-audit` read the rebase as **LOSS, 282 lane / 280 pick**. The two missing lines were a `[[requirements]]` header and its blank line in `traceable-reqs.toml`, so `id = REQ-DISK-FLOOR-PREFLIGHT` landed INSIDE the previous table as a duplicate key: **`traceable-reqs check` exit 2, the registry unparseable, every reading after that edit checking nothing**. Restored, the same audit reads **DRIFT 282/282** whose one differing line is the usage string whose base copy legitimately gained the other verb — both verdi…\n- **FIRST REAL-ASSEMBLY USE (2026-08-29, #241 emission head, ASM-241-GATE-VERDICT.md):** `xtask\r\n  pick-audit --range 57a0d27c..HEAD --lane 4d6007ac..d0fdd58d` over 6 picks — **5 MATCH\r\n  (digest-identical), 1 LOSS, 0 drift, 0 unclassified**, exit 1 forcing the accounting. The LOSS\r\n  was exactly the one human-resolved conflict (`cfb9d9f8 <- 10f12e4c`, count 432/402), and the\r\n  delta RECONCILED to the resolution rather than assumed: lane stat 15 files/235+/197- vs pick\r\n  14 files/205+/197-, difference byte-for-byte the deliberately-dropped 30-line interim IR-69\r\n  register block superseded by main's consolidated entry. No false positives, no silent pass.\r\n  Entry stays OPEN as living procedure; both live uses (the rebase catch above, this assembly)\r\n  produced the verdict classes in the order the entry predicts.\r\n- **Trigger condition:** ripe at the next assembly — this is procedure, and its cost is one command\r\n  per pick.\r\n- **Size guess:** small as a scripted check in `xtask` (fidelity audit over a pick range); zero as\r\n  discipline, which is how it is being applied now.\r\n\r\n### IR-58 — a `[[bin]]` grep is not a census: cargo AUTODISCOVERS `src/bin/*.rs` targets, and a hand-built bin list produced a confident false \"this bin does not exist\"\r\n\r\n- **Status:** OPEN, unowned. Filed by doyle 2026-08-22; **its original filing was WRONG and is\r\n  retracted in full below.** The entry is kept because the way it was wrong is the finding.\r\n- **RETRACTED CLAIM, stated plainly so no reader acts on it:** this entry first said that\r\n  `crates/spt/Cargo.toml:18-21` and `crates/spt/src/cli.rs:30355` forbid a bin-name collision with\r\n  `xlate_choreo_fixture`, \"a bin that does not exist\", and that spt-daemon's third helper had been\r\n  renamed to `summarizer_fixture`. **`xlate_choreo_fixture` EXISTS** — at\r\n  `crates/spt-daemon/src/bin/xlate_choreo_fixture.rs`, verified at the assembly head. The collision\r\n  rule's counterpart is real, both prose sites are CORRECT, and IR-21's original table row was\r\n  correct too; it merely predated `summarizer_fixture`. Nothing in that prose needs fixing.\r\n- **How the false claim was produced, which is the entry:** the census was built by grepping\r\n  `^\\[\\[bin\\]\\]` across `Cargo.toml`s. **Cargo AUTODISCOVERS `src/bin/*.rs` as bin targets with no\r\n  stanza at all**, so a stanza grep cannot see them, and it fails SILENTLY — it returns a clean,\r\n  well-formed list that is simply short. From that list it read as established fact that a named bin\r\n  had been renamed away, and that \"fact\" was then written into a register table, an IR entry, and a\r\n  message to the builder. **A pattern-built population encodes the pattern's assumption; the count\r\n  looks like a census and is a property of the pattern.**\r\n  (Found by todlando, resolving one of doyle's figures against his own tree under the pointer rule.)\r\n- **A CENSUS IS ALSO A PROPERTY OF A TREE.** Stanza counts differed legitimately across trees the\r\n  same hour — 13 at the assembly head, 11 at `dc1c7532` — because `summarizer_fixture` exists at one\r\n  and not the other. Two correct censuses of the same workspace disagree unless each names its sha.\r\n- **The must-do, and it removes the list rather than lengthening it:** never hand-maintain a bin\r\n  roster. Run `cargo build --workspace --bins` and let cargo enumerate its own targets — the same\r\n  enumeration the test harness resolves against, so it cannot drift from what a fixture lookup\r\n  expects. Stanza-derived lists, remembered pairs, and register tables are all the roster problem at\r\n  different depths; only cargo's own enumeration is the population.\r\n- **Kin:** IR-55's amended prebuild bullet (prebuild the census, not a remembered pair) and IR-42\r\n  (a verb that writes without adjudicating). The shared shape is an instrument returning an orderly\r\n  answer about a set it never fully saw.\r\n- **Trigger condition:** ripe on any `xtask` check work — a duplicate-bin-name check over cargo's\r\n  target enumeration (NOT over manifest stanzas) is a handful of lines and cannot go stale.\r\n- **Size guess:** small. The prose fix originally proposed here is WITHDRAWN — there was nothing\r\n  wrong with the prose.\r\n\r\n### IR-59 — pool arithmetic: this box holds TWO cold pools, not four; and a build that exhausts the volume reds as a LINKER defect that names no disk\r\n\r\n- **Status:** OPEN, unowned — it is arithmetic and discipline, not a code lane. Filed by doyle\r\n  2026-08-22 from a live disk-floor abort during the TURNKEY #212 W4 gate; footprint figures measured\r\n  by todlando the same hour.\r\n- **v0.69.0 release close, 2026-09-11 (deployah, source record releases#294 comment\r\n  5628538587):** the first broad version/manifest battery failed to LINK (`LNK1180`,\r\n  `LNK1108`, cargo exit 101), with **15,777,792 bytes free** measured at recovery. It produced\r\n  no test verdict. The run selected the workspace's test binaries on the Cargo side even\r\n  though the nextest filter did not need the e2e population; the replacement selected `--lib`\r\n  for `spt-daemon`, `spt-runtime`, `spt`, and `xtask`, and passed **121/121** in 8.445 s.\r\n  Root-target reclamation restored **66,926,968,832 bytes free**; the subsequent CI Windows\r\n  unit step passed **3167 tests**, then its END floor refused at **15,360,114,688 bytes**\r\n  against **34,359,738,368**. That is an observed resource-red AFTER passing tests, not an\r\n  explanation of the earlier PR unit-step red whose log was unavailable. A second, classified\r\n  CI `target/debug` reap, with runner intake stopped by the operator, increased free bytes\r\n  **14,892,281,856 -> 78,994,501,632**. Runner service restored afterward. Publication used a\r\n  preserved signer, not a Cargo rebuild into the cleared pool. These are two measured recoveries,\r\n  not a durable capacity fix; IR-46/59/86 remain the next gate-driver capacity rider.\n…\n","startLine":2955,"lineNumbers":[2955,2956,null,2997,null,3000,3001,3002,3003,3004,3005,3006,3007,3008,3009,3010,3011,3012,3013,3014,3015,3016,3017,3018,3019,3020,3021,3022,3023,3024,3025,3026,3027,3028,3029,3030,3031,3032,3033,3034,3035,3036,3037,3038,3039,3040,3041,3042,3043,3044,3045,3046,3047,3048,3049,3050,3051,3052,3053,3054,3055,3056,3057,3058,3059,3060,3061,3062,3063,3064,3065,3066,3067,3068,3069,3070,3071,3072,3073,3074,3075,3076,3077,3078,3079,3080,3081,3082,3083,3084,3085,3086,3087,3088,3089,3090,3091,3092,3093,3094,3095,3096,3097,3098,3099,3100,3101,3102,3103,3104,3105,3106,3107,3108,3109,3110,3111,3112,3113,3114,3115,3116,3117,3118,3119,3120,3121,3122,3123,3124,3125,3126,3127,3128,3129,3130,3131,3132,3133,3134,3135,3136,3137,3138,3139,3140,3141,3142,3143,3144,3145,3146,3147,3148,3149,3150,3151,3152,3153,3154,3155,3156,3157,3158,3159,3160,3161,3162,3163,3164,3165,3166,3167,3168,3169,3170,3171,3172,3173,3174,3175,3176,3177,3178,3179,3180,3181,3182,3183,3184,3185,3186,3187,3188,3189,3190,3191,3192,3193,3194,3195,3196,3197,3198,3199,3200,3201,3202,3203,3204,3205,3206,3207,3208,3209,3210,3211,3212,3213,3214,3215,3216,3217,3218,3219,3220,3221,3222,3223,3224,3225,3226,3227,3228,3229,3230,3231,3232,3233,3234,3235,3236,3237,3238,3239,3240,3241,3242,3243,3244,3245,3246,3247,3248,3249,3250,3251,3252,3253,3254,3255,3256,3257,3258,3259,3260,3261,3262,3263,3264,3265,3266,3267,3268,3269,3270,3271,3272,3273,3274,3275,3276,3277,3278,3279,3280,3281,3282,3283,3284,3285,3286,3287,3288,3289,3290,3291,3292,3293,3294,3295,3296,3297,3298,3299,3300,3301,null,3416]},"fileSize":512411,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\INFRA-REGISTER.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":5900,"totalBytes":27997,"outputLines":301,"outputBytes":27997,"shownRange":{"start":3000,"end":3300},"nextOffset":3301},"limits":{"columnTruncated":{"maxColumn":768}}}},"isError":false,"timestamp":1789107034973}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_dBbU70DMzd6iak6VBYxYFrGj|fc_0330c101aa2c61dc016aa39b6439d487d183817cd6fbbcec16","toolName":"grep","startedAt":"2026-09-11T06:10:46.637Z","args":{"path":"docs/INFRA-REGISTER.md:3001-5900"},"intent":"Enumerating assigned infra headings"},"id":"5f6cdaeb","parentId":"acad9441","timestamp":"2026-09-11T06:10:46.637Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_arhDXu4ji7jZC64pSnUNMy3L|fc_0330c101aa2c61dc016aa39b6439f087d1b336770f400862f4","toolName":"glob","startedAt":"2026-09-11T06:10:46.637Z","args":{"path":"AGENTS.md;CLAUDE.md;CONTEXT.md;docs/*304*;docs/*CLOSE*;docs/*INTAKE*"},"intent":"Locating project orientation files"},"id":"4302dc85","parentId":"5f6cdaeb","timestamp":"2026-09-11T06:10:46.637Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_fxLSWBRnBsPVezd927khX19z|fc_0330c101aa2c61dc016aa39b643a0087d1be8ca46930ffcf31","toolName":"read","startedAt":"2026-09-11T06:10:46.637Z","args":{"path":"docs/INFRA-REGISTER.md:3301-3700"},"intent":"Reading next register segment"},"id":"2b244bb5","parentId":"4302dc85","timestamp":"2026-09-11T06:10:46.637Z"}
{"type":"message","id":"a1fbf4b7","parentId":"2b244bb5","timestamp":"2026-09-11T06:10:46.637Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_dBbU70DMzd6iak6VBYxYFrGj|fc_0330c101aa2c61dc016aa39b6439d487d183817cd6fbbcec16","name":"grep","arguments":{"i":"Enumerating assigned infra headings","pattern":"^### IR-|Trigger condition|^\\- \\*\\*Status:","path":"docs/INFRA-REGISTER.md:3001-5900","case":null,"gitignore":null,"skip":null},"intent":"Enumerating assigned infra headings"},{"type":"toolCall","id":"call_arhDXu4ji7jZC64pSnUNMy3L|fc_0330c101aa2c61dc016aa39b6439f087d1b336770f400862f4","name":"glob","arguments":{"i":"Locating project orientation files","path":"AGENTS.md;CLAUDE.md;CONTEXT.md;docs/*304*;docs/*CLOSE*;docs/*INTAKE*","hidden":true,"gitignore":true,"limit":50},"intent":"Locating project orientation files"},{"type":"toolCall","id":"call_fxLSWBRnBsPVezd927khX19z|fc_0330c101aa2c61dc016aa39b643a0087d1be8ca46930ffcf31","name":"read","arguments":{"i":"Reading next register segment","path":"docs/INFRA-REGISTER.md:3301-3700"},"intent":"Reading next register segment"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":7362,"output":180,"cacheRead":9984,"cacheWrite":0,"totalTokens":17526,"cost":{"input":0.07362,"output":0.009000000000000001,"cacheRead":0.009984,"cacheWrite":0,"total":0.09260399999999999}},"stopReason":"toolUse","timestamp":1789107034984,"responseId":"resp_0330c101aa2c61dc016aa39b59036887d1b82dcb26c637aa43","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0330c101aa2c61dc016aa39b6439d487d183817cd6fbbcec16","type":"function_call","status":"completed","arguments":"{\"i\":\"Enumerating assigned infra headings\",\"pattern\":\"^### IR-|Trigger condition|^\\\\- \\\\*\\\\*Status:\",\"path\":\"docs/INFRA-REGISTER.md:3001-5900\",\"case\":null,\"gitignore\":null,\"skip\":null}","call_id":"call_dBbU70DMzd6iak6VBYxYFrGj","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"grep","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b6439f087d1b336770f400862f4","type":"function_call","status":"completed","arguments":"{\"i\":\"Locating project orientation files\",\"path\":\"AGENTS.md;CLAUDE.md;CONTEXT.md;docs/*304*;docs/*CLOSE*;docs/*INTAKE*\",\"hidden\":true,\"gitignore\":true,\"limit\":50}","call_id":"call_arhDXu4ji7jZC64pSnUNMy3L","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"glob","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b643a0087d1be8ca46930ffcf31","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading next register segment\",\"path\":\"docs/INFRA-REGISTER.md:3301-3700\"}","call_id":"call_fxLSWBRnBsPVezd927khX19z","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}}]},"duration":11650.327100000344,"ttft":11595.182500000112,"completedAt":1789107046635,"contextSnapshot":{"promptTokens":17346,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"message","id":"e0cbcf5d","parentId":"a1fbf4b7","timestamp":"2026-09-11T06:10:46.644Z","message":{"role":"toolResult","toolCallId":"call_fxLSWBRnBsPVezd927khX19z|fc_0330c101aa2c61dc016aa39b643a0087d1be8ca46930ffcf31","toolName":"read","content":[{"type":"text","text":"### IR-59 — pool arithmetic: this box holds TWO cold pools, not four; and a build that exhausts the volume reds as a LINKER defect that names no disk\n…\n- **Status:** OPEN, unowned — it is arithmetic and discipline, not a code lane. Filed by doyle\n…\n- **v0.69.0 release close, 2026-09-11 (deployah, source record releases#294 comment\n…\n  preserved signer, not a Cargo rebuild into the cleared pool. These are two measured recoveries,\n  not a durable capacity fix; IR-46/59/86 remain the next gate-driver capacity rider.\n- **SECOND FACE, measured 2026-08-23/24 (WAX-SEAL #21 W2 gate, doyle — the violator this time):**\n  both predicted mechanisms fired at once, WITHOUT the floor guard because the gate legs ran as a\n  plain script. (1) doyle minted a THIRD cold pool (gate rig) while todlando's lane pool was LIVE —\n  the two-pool arithmetic, violated by the gater. (2) The lane pool had silently accumulated\n  **104.8 GB** over repeated full-workspace sweeps (nothing bounds or even measures a pool's\n  accumulation until the volume dies). The volume hit **3 MB free**; the reds wore exactly the\n  entry's predicted costume — `LNK1318: Unexpected PDB error; LIMIT (12)` naming no disk — plus a\n  second face worth keeping: `traceable-reqs check` died as a PANIC printing to stdout\n  (`os error 112`), so a REGISTRY gate red can also be the disk's. Both gate verdicts VOIDED\n  (clippy's full compile had exited 0 before space died — the code was never the question).\n  Recovery measured: gate pool reap 9.6 GB, lane pool clean 100.2 GB, drive back to 109.6 GB free.\n  **Remedies adopted at the incident:** the gate never mints its own pool while a builder lane is\n  live on the box — it takes the lane pool over SEQUENTIALLY at pool-release (warm, loud, the\n  releases#103 pattern); and gate/lane scripts get the disk-floor preflight the golden runner\n  already carries (this entry's part 2, still unbuilt).\n- **THIRD FACE, measured 2026-08-24 (WAX-SEAL #21 golden window, doyle):** two new mechanisms, both\n  about the REMEDY rather than the red. (1) The wax-seal-w1 lane pool **re-accumulated to 152–169 GB\n  (two meters, IR-46 caveat) within ONE DAY of the 08-23 clean** and rode the volume back down to\n  4.92 GB free — a reap is an instant, not a state; nothing yet bounds a pool between reaps.\n  (2) **The remedy itself arrived garbled through relay:** the golden push was held \"waiting on the\n  IR-59 reboot\" when this entry prescribes no reboot anywhere — tens of releases have shipped without\n  one; the operator refused the premise and the register's own recorded remedy (reap finished-lane\n  pools) cleared it in ten minutes. A remedy relayed as a DIFFERENT remedy is the relay trap wearing\n  infra clothes: the entry is the author — read it before adopting a hold. Recovery measured: five\n  finished-lane pools reaped after ancestry classification (`git cherry` catches rebased lands that\n  a plain `merge-base --is-ancestor` calls unlanded — gate-w4l1's 90.9 GB pool was reapable only by\n  that meter), 4.92 → 260.88 GB free (~256 GB free-delta vs ~270–287 GB sum-of-lengths). Two main\n  runs red inside the low-disk window (09:17Z/09:41Z) were re-run, not re-read, per this entry's\n  must-do.\n- **FOURTH FACE, measured 2026-08-24 same day (SIGNET #218 W2 gate, doyle — the gater's own pool\n  this time):** the MAIN pool went **13.7 GB → 158.3 GB in ONE DAY** absorbing four full gate\n  batteries across two lane tips, and dragged the volume to **18 GB free mid-gate** — so the\n  entry's mechanism is not a lane-pool problem, it is EVERY pool under repeated full sweeps, the\n  gate rig included. Two riders worth the ink: (1) the golden runner's **free-space floor step\n  produced its first live catch** — a thin CI leg refused at 14:14 local over exactly this window\n  with zero test signal, and the register's re-run-not-re-read rule resolved it in one command;\n  (2) the reap-and-rebuild trade (\"cleaning a live pool buys one window at rebuild price\") was\n  taken deliberately mid-gate and cost ~35 minutes cold — cheaper than one uninterpretable red.\n  A red measured at 18 GB free in this gate got NO read at all, and the next sweep's red was a\n  DIFFERENT test: low disk manufactures random victims before it manufactures link errors.\n- **The event:** a gate's preflight refused with `GATE_ABORTED_DISK_FLOOR` at **4.75 GB free on a\n  1863 GB volume**. Four cold pools plus the milestone head's pool were standing at once. The floor\n  guard did its job — without it a full workspace build would have started with under 5 GB of\n  headroom and produced a red belonging to nothing.\n- **THE ARITHMETIC, and it corrects the intuition that worktrees are the cost.** Measured across the\n  whole `.worktrees` tree: **45 worktrees = 0.79 GB total** (~18 MB each). **3 pools = 130.45 GB.**\n  Worktrees are **0.6%** of the footprint; pools are **99.4%**. **One cold pool is worth roughly 2,500\n  worktrees.** A rule keyed on worktree count would cost a day of `git worktree remove` work for under\n  a gigabyte, risk removing a lane someone still wants, and leave the lever untouched.\n- **THE CEILING, as arithmetic rather than hygiene:** at **45–75 GB per cold pool** on this workspace\n  against a **40 GB floor**, this box supports **TWO live pools comfortably, THREE only if one is\n  small**. The two rules that already exist need no replacement, only this number attached:\n  - **Reap a pool when its lane is finished** → 45–75 GB back immediately.\n  - **Do not run two builds at once** → not only the contention argument, but **75–150 GB of\n    simultaneous allocation** against that floor.\n- **A FULL VOLUME REDS AS A LINKER DEFECT.** `LINK: fatal error LNK1318: Unexpected PDB error`\n  (variously `OK (0)` or `LIMIT (12)`), often beside `LNK4209: debugging information corrupt`. It\n  reads as a corrupt artifact or a broken toolchain and is neither — it is the linker unable to grow\n  a large `.pdb`. **Nothing in the failure text says \"disk\".** Do not key recognition on the\n  parenthesised code; it varies.\n- **THE DANGER WINDOW IS THE TAIL OF A COLD BUILD, not a steady state you can check once.** The\n  2026-08-22 instance died at the link of `spt` — the last and largest artifact of a **74 GB** cold\n  pool — while that same build was draining the volume out from under itself. A free-space reading\n  taken before the build would have looked fine.\n- **Positive tell, with its own refutation attached:** `traceable-reqs check` alone surviving a leg\n  table is suggestive, because it is the only leg that never links. It is a POSITIVE tell ONLY — a\n  full disk can red before any link step, so the signature's ABSENCE clears nothing.\n- **THE FALSIFIER IS FREE SPACE AT THE TIME OF THE RUN**, not the shape of the leg table.\n- **Must-do, both cheap:**\n  1. **A free-space reading goes in the FIRST LINE of any build-failure report** — not in the\n     controls, not as a follow-up. Two agents spent hours on a mechanism for this failure and neither\n     ran `df`; the falsifier was one command away throughout.\n  2. **Rig and gate logs should record free space at run start.** Today they do not, which makes \"was\n     the disk full\" **unanswerable after the fact for every red already in hand**. Any red produced\n     under ~1 GB free is UNINTERPRETABLE and must be **re-run, not re-read**.\n- **Measurement caveat, observed twice in one hour:** sum-of-file-lengths and free-space delta\n  disagree by several percent when anything else on the box is writing (98.07 GB of subtrees → 92.25\n  GB reclaimed; 47.28 GB → 40.81 GB). Report BOTH, derive neither from the other, and treat any single\n  free-space number as an instant rather than headroom — see IR-46.\n- **FIFTH FACE, measured 2026-08-29 at the CONDUIT #236/v0.65.0 cut (deployah):**\n  the finished milestone's sequential lane-sharing accumulated **140.51 GB**, while a freshly\n  rebuilt pool measured **7.78 GB** — about **18× one build's working set** retained across lane\n  hand-offs with no reap between them. This is the budgetable rate behind that cut's disk-floor\n  red: sequential execution prevents concurrent ownership corruption, but it does not bound\n  historical artifacts inside the shared pool. Treat takeover and reclamation as separate\n  operations; a pool may be safe to reuse and still be too large to keep.\n- **SEVENTH FACE, measured 2026-08-30 (v0.67.0 milestone close — the PARALLEL-LANE fill\n  rate):** the #23 wave arc drove C: from ~240 GB free to **0.01 GB in ~3.5 hours**: four\n  concurrent/serial lane+gate pools totalled **236.6 GB** (ns23-w1 87.7 + ns23-113 72.3 +\n  gate rig 57.3 + ns23-w3 19.1) — effectively the entire ir57 reclaim re-consumed inside one\n  milestone's build window. The head gate and two thin-CI runs redded with the entry's exact\n  costume (\"could not compile\" + treqs panic, zero disk words) at 0.01 GB and all re-earned\n  green after reclaim (+186.6 GB, finished-lane targets only, single-actor rule held under\n  racing consent). Budget rule this face adds: a MULTI-WAVE milestone on one box books\n  ~60-90 GB PER LANE-PLUS-GATE cycle, so the pool budget is per-wave, not per-milestone —\n  reap each wave's pool at its LAND, not at the milestone party (the party inherited only\n  ~58 GB because the emergency had already forced the other ~179).\n- **SIXTH FACE, measured 2026-08-30 (#242 golden r4, Windows test job, LNK1318 at the PDB\n  write):** the floor is asserted ONCE at job START, but the job's internal LOW-WATER sits at its\n  LAST heavy step — the docs-drift build, ~28 minutes in. r4's floor read 65.1 GiB honest at\n  23:07; the box was at ~37–39 GB by the 23:35 link failure. LNK1318 on PDB write = this entry's\n  documented low-disk costume; the incremental-corruption candidate was retired by preservation\n  snapshot (no xtask state existed at failure). **Durable fix = a floor RE-READ (or reclaim)\n  immediately before the docs-drift build** — the WITHIN-job sibling of the across-job\n  read-after-checkout fix, rides the next workflow commit. Riders: incremental hygiene as\n  disk-pressure maintenance (the dir measured 4.56 GB), and the box's **~51 GB non-recovering\n  post-run consumption** is this entry's pool-weight face — classify at the IR-14/26/27/49 audit\n  slot (composed this sweep).\n- **Composed for next intake (doyle, v0.65.0 close):** the still-open log-the-floor build half\n  rides with [[IR-57]]'s scripted pick-fidelity audit as the next milestone's two tooling riders.\n- **Trigger condition:** ripe now for the log-the-floor half (it rides any gate-script or CI touch);\n  the arithmetic is discipline and applies immediately.\n- **Size guess:** small — one line in each rig/gate preflight to record free space alongside the\n  existing floor check.\n\n### IR-60 — a wrapper that CAPTURES a leg's exit status ends with the capture, so the wrapper's own status is the capture's, not the leg's\n\n- **Status:** OPEN, unowned — script-shape discipline, not a code lane. Filed by doyle 2026-08-22\n  during the TURNKEY #212 W5 lane; mechanism measured by todlando, who reported it first as a\n  possible harness misreport and then RETRACTED that reading himself on a minimal probe.\n- **v0.69.0 recurrence, 2026-09-11 (deployah, own withdrawal):** `NEXTEST_EXIT=0` and the task\n  completion's exit 0 both described the wrapper/truncation path, not Cargo's **101**.\n  `PIPESTATUS` was read outside the executing subshell, so the named verdict measured `tail`.\n  Both green-looking receipts were withdrawn; the raw failed-link output was retained.\n  **An exit FILE alone is insufficient if its writer captures the wrong process.** Capture\n  immediately inside the shell executing the producer, before any other command replaces the\n  status, write that value to the leg's file, and propagate it when wrapper status is reported.\n  The replacement battery's own file read 0, with 121 tests actually run. Keep this entry OPEN:\n  corrected execution of one driver does not make the faulty wrapper shape unreachable.\n- **The reading that started it:** a background leg was summarised as `exit code 0` while the leg's\n  own exit file read `100`. Reported as-is, that is a task runner lying about a red — the worst\n  possible direction for a purposeful-red claim, since it would turn two reds that DID fire into two\n  reds reported as not having fired.\n- **The measurement, minimal and on this box:**\n\n      ( exit 100 ); echo $? > probe.exit; FINAL=$?\n      leg status captured to file : 100\n      wrapper's own final status  : 0\n\n  The wrapper's shape is `( cd <lane> && cargo nextest ... > leg.raw 2>&1 ); echo $? > leg.exit`.\n  **The last command is the `echo`, which succeeds**, so the wrapper genuinely exits 0 while the leg\n  genuinely exited 100. THE RUNNER TOLD THE TRUTH ABOUT THE WRAPPER. There is nothing to file against\n  the task runner, and it would have been filed.\n- **The class, and this is why it is worth an entry rather than a fix:** it is the truncation-pipe\n  family — the meter measured something real, it just was not the thing about to be quoted. **Three\n  shapes now share ONE trigger, and the trigger is not \"is this a pipe\":**\n  1. a truncation pipe (`cmd | tail`, `cmd | head`) — `$?` measures the truncator, and `head` closing\n     the pipe can MANUFACTURE a status (SIGPIPE → 101), so `PIPESTATUS` is not protection either;\n  2. a flattened `$?` read after any intervening command;\n  3. **a wrapper whose last command is the capture itself.**\n  **The trigger in all three is the REPORTING** — every instance happened while trimming or capturing\n  output in order to QUOTE it as evidence.\n- **The practice that held, and the one to keep:** the leg's own file is the leg's verdict. Both reds\n  were real, and the only reason that was knowable is that every leg wrote its exit to its own file\n  rather than to the wrapper's status.\n- **Remedy, in preference order:** (1) never read a wrapper's status as a leg's — read the leg's exit\n  FILE, which the per-leg rule already requires; (2) if a wrapper's own status must be meaningful,\n  end it by re-raising the captured status (`exit \"$(cat leg.exit)\"`) or set the status before the\n  capture is the last word; (3) for anything that becomes evidence, redirect to a file and read the\n  file.\n- **Trigger condition:** ripe now — it rides the next gate-script touch, and the gate scripts in this\n  milestone already write per-leg exit files, which is what makes this discipline rather than debt.\n- **Size guess:** small — a convention line in the gate-script preamble; no product code.\n\n### IR-61 — spacerun's test-module skip carries a SECOND literal tracker; the two answers can drift, and today only a cell stands between them\n\n- **Status:** OPEN, unowned, accepted-with-mitigation. Filed by doyle 2026-08-22 at the TURNKEY #212\n  head gate, as the named residual of the latch repair (the repair itself rides the milestone).\n- **What the debt is.** `crates/xtask/src/spacerun.rs` now skips a column-0 `#[cfg(test)]` module by\n  BRACE DEPTH and resumes after its close, rather than latching the scan to end-of-file. Counting\n  braces safely means knowing when a brace is inside a string, a raw string or a char literal — and\n  the scanner ALREADY tracks literals for its rendering pass. It does not reuse that tracking. There\n  are now TWO answers in one file to \"am I inside a literal\", and **two answers to one question is a\n  disagreement waiting for a reader who fixes one of them.**\n- **Why it was accepted rather than refactored on the spot, stated so the trade is auditable:** the\n  two trackers answer genuinely different questions — the rendering walk is PER LINE and forward\n  from an opening quote (\"where does this literal start and end\"), while the skip needs \"am I inside\n  a literal right now\" carried CONTINUOUSLY across lines. Unifying them is a real refactor of a check\n  that is already gated, already carries five fixed defects, and sits on the tree being handed to\n  golden. The narrow change with an OBSERVABLE failure mode beat the correct-shaped change with a\n  wide blast radius, on that tree, on that day.\n- **The mitigation, and its exact limit.** Three brace cells fail the moment the two trackers\n  disagree about a raw string, a normal string or a char literal, plus a cell that reds when the skip\n  stops consulting a literal tracker at all (`match lit` -> `match Lit::None`). **That is a cell\n  standing in for a refactor.** It catches drift in the three forms it names and nothing else — a\n  fourth literal form, or a change to only one tracker in a form neither cell covers, passes.\n- **The general shape, which is why this is a register entry rather than a comment:** a check whose\n  own correctness depends on a second implementation of a thing it already implements is one\n  refactor away from the defect class it exists to prevent. This same file has already produced\n  three instrument defects (an indented-marker latch, a column-0 latch, and a suppression that\n  decided what got PARSED rather than what got REPORTED). The pattern is not carelessness; it is a\n  scanner accumulating special cases.\n- **Trigger condition:** the next SUBSTANTIVE change to spacerun's scanning — any new skip, any new\n  literal form, any change to either tracker. At that point unify, rather than adding a third answer.\n- **Size guess:** small to medium — one continuous literal-state walk serving both the render pass\n  and the skip, with the existing corpus and brace cells as the regression net.\n\n### IR-62 — an e2e daemon binds well-known ports and collides with the resident fleet on shared runners\n\nFiled 2026-08-23 (doyle), from the #212 r2 golden's Windows Phase A red — one witnessed\ninstance, mechanism verified from the run's own capture, filed on the mechanism per the\nregister's standard.\n\n**Mechanism.** `endpoint_autostart_e2e::saved_endpoint_replays_on_daemon_restart` failed its\nown PRECONDITION (\"daemon B must come up with a fresh brain\") because daemon B's broker came up\ndegraded: `NODE_KEY_FAIL: identity unavailable` (net-less broker, no retry) and\n`DOCS_SERVER_BIND_FAIL` port 5474 `os error 10048` — the docs port was held by a CO-RESIDENT\ndaemon. HFENDULEAM is live infra: the resident fleet's daemon legitimately holds well-known\nports, and any e2e that brings up a daemon with default port bindings is in a race with it BY\nCONSTRUCTION. An isolated SPT_HOME isolates the store and broker socket, NOT globally-numbered\nTCP ports.\n\n**Classification history.** r2: red (35.4s, precondition panic). Run 1 and r3 on the same box:\ngreen. Folded into r3 under a pre-registered predicate (reds twice → dedicated triage); it\ngreened, so this stays an environment-shaped intermittent, NOT a product defect and NOT\nclosed — the collision window is real and will re-fire under the right co-residence timing.\n\n**Remedy direction (not built).** Test daemons should bind ephemeral/rig-scoped ports for\nevery advisory surface (the docs server is advisory — a bind failure should degrade the rig\nloudly, not poison an unrelated cell's precondition), or the precondition should name the\nport-collision cause distinctly so the red self-classifies. Either lane is test/CI work\n(hertz's), triggered the next time this class fires anywhere.\n\n**Kin.** IR-51 (e2e daemon net-enabled on real interfaces — hermeticity is disk-deep only);\nthe known not-ours red classes list in the #212 hand-off.\n\n**BUILT 2026-08-24 (hertz, SIGNET #218 batch; PR #158).** The class fired its second witnessed\ninstance the same day — doyle's W2 gate rig, `engine_room_bringup_e2e` precondition panic with\nthe IR-50 panel naming `DOCS_SERVER_BIND_FAIL` port 5474 `os error 10048` — which armed this\nentry's own trigger. Hertz repro'd deterministically (held the port; brain still reached\nBRAIN_UP), pre-ranked three mechanisms before probing, and built the ephemeral-advisory form:\nrig-only `SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1` makes the daemon's docs listener bind port 0\n(production config/`SPT_DOCS_PORT`/docs-url untouched; the flag matches the literal \"1\" only).\nThe golden workflow's test job sets it globally on both self-hosted legs, the standalone ER rig\nsets it too. Scope note kept honest per his own ranking: the docs collision is retired; if a\nco-diagnostic bind elsewhere still poisons a precondition, that is a residual face of THIS\nentry, not a closed question.\n\n### IR-63 — suite-mix sweeps leak job-escaped autostart daemons that LOCK the pool's spt.exe; and the same box conditions manufacture one random victim per sweep\n\n- **Status:** OPEN, mitigated-by-rig-step — the reap is adopted discipline, not yet construction.\n  Filed by doyle 2026-08-24 at the SIGNET #218 gates; first measured by todlando the same day\n  (his W1 build: four reap rounds of 2, 8, 1, 1 processes, count-by-path stated each round).\n- **Mechanism, two faces of one condition:** (1) e2e sweeps that exercise autostart leave\n  job-escaped daemons running `target/debug/spt.exe`; the NEXT build or `xtask check` then dies\n  on `os error 5` removing the exe — a rig red wearing a build defect's clothes. nextest's own\n  `leaky` flags corroborate (4–8 per sweep measured). (2) The same co-residence (leaked daemons +\n  resident fleet + runner traffic) manufactures ONE red per full sweep with a DIFFERENT victim\n  each time: doyle's W2 gate measured FOUR distinct one-off victims in four same-sha sweeps\n  (ER bringup, composite+bootstrap pair under CI load, resident_service, brain_resume), every\n  one green alone and/or in a sibling sweep. The e2e-leaked-daemons rule holds: a different test\n  dying each run on one sha is ONE environment cause, and hardening members never closes it.\n- **Mitigation adopted (rig step, both todlando's lanes and doyle's gate runner):** reap\n  `spt.exe` BY PATH (`*spt-core\\target*`) before EVERY cargo invocation and after every sweep;\n  report the count each time so a zero is a claim, not silence.\n- **Remedy direction (unbuilt):** the durable form is construction, not discipline — either\n  nextest wrap/xtask verb that performs the by-path reap as a pre-step on this box's rigs, or\n  autostart e2es gain teardown that provably outlives job escape (kin IR-38's built wedge-namer,\n  IR-62's ephemeral ports which retire one collision axis, IR-35's victim-rate ledger).\n- **THIRD FACE, measured 2026-08-30 (doyle, ir57/asm-241 reaps):** the leaked population is not\n  only daemons — battery legs leave ORPHANED HEADLESS `conhost.exe` processes whose CWD sits in\n  the worktree's `crates/spt-daemon` (where the leg ran), and a CWD pin blocks `Remove-Item`/\n  `git worktree remove` on the whole tree with \"being used by another process\" naming the DIR.\n  This is the mechanism behind every recent \"handle-pinned, retry later\" worktree removal: 31\n  such conhosts found at once (Aug 26–29 vintages) pinning FIVE dead worktrees. cargo/rustc\n  absence does NOT clear the suspect list — the conhost outlives its client. Holder census\n  tool: a ~30-line NtQueryInformationProcess CWD probe (PEB→ProcessParameters→CurrentDirectory)\n  over all pids, filtered on the path — names every holder in one pass where no handle.exe\n  exists. 13 killed scoped to the two consented reaps; 18 remain pinning gate-w1-a8f04aff (12),\n  io-parser-w1 (5), gate-w1-786d2381 (1 after kills) — sweep them at the IR-14/26/27/49 audit\n  slot before those removals.\n- **LANE-LINKED 2026-08-30 (#242 close sweep):** hertz's queued daemon-leak fixup lane carries\n  this entry (brief cites IR-7/17/20/34/35/63); leaves the register when that lane lands.\n- **Trigger condition:** next rig/gate-script construction touch, or the first golden red that\n  classifies to face (1).\n- **Size guess:** small-medium — one wrapper seam plus adopting it in the gate/lane scripts.\n\n### IR-64 — HFENDULEAM's disk floor is set by non-CI bulk: ~845 GB of operator payload leaves the golden box ~2 GB of slack against its own 32 GB preflight\n\n- **Status:** OPEN · **Origin:** doyle, v0.63.0 close sweep 2026-08-26; mechanism first measured\n  at the FIELD-SEAL golden window (deployah's IR-31 fifth addendum carries the POOL side of the\n  same event by agreed division — this entry is the OTHER reservoir, deliberately not his).\n- **Mechanism:** the 1.86 TB C: carries ~614 GB Steam + ~230 GB Downloads (operator payload, not\n  CI state). With that floor fixed, normal lane traffic alone walks the box under the 32 GB\n  golden preflight — a full-sweep pool WEIGHS ~90–112 GB steady state (IR-59's measurement) and\n  five FIELD-SEAL lanes cost 148.48 GB (IR-31 fifth addendum), so ONE milestone's pools exceed\n  the entire free margin. Reaping buys windows, not headroom: deployah measured free fall\n  167 → 108 GB within hours of his reap, ~59 GB re-consumed by lane builds. The recurring shape:\n  every milestone pays a reap-and-measure tax to rent space the box does not structurally have.\n- **Why register-worthy rather than \"clean up more\":** agent-side discipline (IR-31's budgeting,\n  pool reaps, teardown steps) is already adopted and still only rents windows — the reservoir\n  that would durably move the floor is operator-owned bulk no agent may touch. Naming it here is\n  the boundary: agents keep budgeting IN POOLS (not GB); moving Steam/Downloads (or adding a\n  disk, or pinning golden to a box without operator payload) is an OPERATOR decision this entry\n  exists to put in front of them once, with numbers, instead of re-deriving the floor each cut.\n- **Ripe when:** operator rules on the bulk (move/expand/accept-the-tax), OR the first golden\n  that dies at the 32 GB preflight despite adopted pool discipline (IR-59's LNK1180-class red).\n- **Size:** zero code; one operator decision + at most a runbook line naming the chosen floor.\n\n### IR-65 — kitsubito kernel-audit backpressure: a tailscale-snap AppArmor denial storm + no auditd turned the default audit backlog into a CI-wide stall amplifier (REMEDIATED AT BOX; re-check triggers named)\n\n- **Status:** REMEDIATED-AT-BOX 2026-08-25 (doyle, operator-authorized root — ruling pinned\n  releases#225 comment 5418800776); entry stays OPEN as the re-check record because the storm\n  SOURCE persists and two named events can silently revert the fix.\n- **Mechanism:** `snap.tailscale.tailscaled` (1.92.5) polls /proc and takes an AppArmor\n  ptrace-read DENIED per poll — a continuous kernel-audit record storm scaling with process\n  count (spawn-heavy serialized CI legs amplify their own storm). With NO auditd installed the\n  records rode printk (kauditd throttling) and the 8192 kernel backlog overran\n  (lost=1,537,743); the default `backlog_wait_time` 60000ms turns a full backlog into A 60s\n  SLEEP INSIDE ANY AUDITED SYSCALL — the broker dispatch stall that stretched IR-30's\n  Linux-face race window (see IR-30's Linux-face addendum; deaths clustered 59–63s ↔ this\n  knob's value).\n- **Remediation (verified at the EFFECTIVE layer, not the fragment):** auditd installed +\n  active (storm consumed, backlog drains to 0, lost flat), backlog_limit 32768,\n  backlog_wait_time 0 (full backlog may DROP, never STALL). ⚠ THE TRAP PAID FOR ONCE: the first\n  knob write (`50-backlog.rules`) silently LOST the augenrules merge — apt's own\n  `/etc/audit/rules.d/audit.rules` sorts LAST (digits before letters) and its `-b 8192` /\n  `--backlog_wait_time 60000` won; a whole proof run executed under the defaults while the\n  fragment grepped perfect. Values now live in the merge-WINNING file; verified `auditctl -s`.\n- **Re-check triggers (the reason this entry stays):** (1) tailscale snap update — the plug\n  landscape may change, the storm may stop or grow; (2) auditd package update/reinstall — may\n  rewrite `rules.d/audit.rules` and re-lose the merge; (3) box reimage. On any of these: one\n  `auditctl -s` (expect 32768/0) + one `journalctl -k | grep 'backlog limit'` (expect silence).\n- **Ripe when:** a re-check trigger fires. **Size:** two read-only commands per check.\n\n### IR-66 — first-chunk-needle test class: two latent members remain after the v0.63.0 fix (attach.rs:561, :672)\n\n- **Status:** CLOSED / BUILT — release-close reconciliation 2026-09-11. The WEBSERVE JIT already\n  ruled this satisfied; source at `e5a2fed9` retains both delayed needles. Closure uses the\n  recorded gates below, not v0.69.0's unrelated green receipts. Hertz rider PR #161, landed ff at\n  `d04b922d` (2026-08-27, IO-PARSER #22\n  intake rider). Both members got the later-needle treatment (TICK39 delayed past burst on both\n  OS arms; alt-screen entered before delayed ALT_VIEWPORT_MARKER). Gate: doyle — diff-scope\n  review; Windows isolated worktree 3× TICK39 PASS + clippy + treqs; Linux CLEAN worktree at the\n  PR sha on kitsubito 3× both cells PASS (independent of the builder's dirty-shared-tree proof,\n  disclosure on record). · **Origin:** doyle tree-wide census at `dbe3daad`\n  (releases#225 comment 5418844404 — the census that corrected my own resume.rs-scoped\n  overclaim), after the class's first member was RCA'd and fixed in v0.63.0's head.\n- **Mechanism (cite, not restate):** KNOWN-HAZARDS 6.9 same-session face, amended at\n  `dbe3daad` — `spawn_session_pid`'s Spawned-wait consumes-and-discards a first output chunk\n  that races the reply (~2ms window on a healthy Linux box; load-stretched under backpressure,\n  see IR-30 Linux-face + IR-65). A test whose needle exists ONLY in the child's first chunk\n  asserts winning a race the contract does not promise.\n- **The two members:** `crates/spt-daemon/tests/attach.rs:561` (TICK0..39 instant burst then\n  `cat`; needle TICK39 read directly after spawn — the whole burst can sit in the first\n  chunks) and `:672` `cross_node_cold_attach_to_alt_screen_gets_clean_repaint` (unix-only;\n  `printf '…ALT_VIEWPORT_MARKER'; cat` — needle in the first chunk). Failure shape differs from\n  the fixed member: both children idle on `cat`, so a lost prefix is a HANG killed by nextest's\n  backstop at exactly 240s (slow-timeout 60s × terminate-after 4) — not a natural-life death.\n  Verified NOT in the class: daemon_e2e.rs:209 (needle = echo of post-spawn input), attach.rs:995\n  + brain_swap.rs:170 (attach/replay reads, not spawn-waits).\n- **Fix shape (ruled at the v0.63.0 close):** hertz lane, NEXT intake — the same one-line\n  later-needle / robust-read treatment the resume seed got in `dbe3daad`; deliberately NOT\n  landed mid-r4. Both cells passed r4 (0.010–0.058s) — the members are latent, not failing.\n- **Ripe when:** next milestone intake (hertz test lane) or the first golden red at ~240s on an\n  attach cell — either way the mechanism and fix are pre-derived, triage should cite this entry\n  and skip the RCA. **Size:** two one-line test edits.\n\n### IR-67 — wave-battery gap: a `-p spt --bins` leg compiles bin targets as harnesses and runs ZERO integration/e2e tests, so batteries that lean on it carry silent no-coverage legs\n\n- **Status:** BUILT — remedy applied across the IO-PARSER #22 milestone (2026-08-27/28): every\n  wave battery named explicit `-p spt --test <suite>` e2e legs beside the `--bins` unit leg\n  (GW1..GW5 evidence), every builder evidence report carried a named real e2e per the dispatch\n  template, and the one filter mistake (a `--test` name not matching its file) REFUSED loudly\n  rather than silently skipping — the failure mode this entry exists to kill. Battery template =\n  the dispatch text now carried forward in gate craft.\n- **Was:** OPEN · **Origin:** doyle, banked at the SIGNET #218 gates 2026-08-25 (\"gate\n  battery gap learned\"), filed at this sweep per the standing rule.\n- **Mechanism:** `cargo test/nextest -p spt --bins` builds `[[bin]]` targets as TEST HARNESSES\n  (unit tests inside bins only) — `tests/` integration and e2e suites of the crate NEVER run,\n  and the leg's green output is indistinguishable from coverage. Kin of the two banked pool\n  faces (`--bins` never emits fixture exes; fresh-pool fixture reds) but this face is about the\n  BATTERY TEMPLATE: my SIGNET wave batteries carried a `-p spt --bins` leg believed to cover\n  the crate.\n- **Remedy:** at next intake, the wave-battery template gains an explicit `tests/` leg for the\n  spt crate (nextest `-p spt --test <suites>` or unfiltered `-p spt` where pool history\n  permits), and any battery doc that lists `--bins` as a coverage leg gets the one-line caveat.\n- **Ripe when:** next milestone intake (the battery template is touched at every intake).\n  **Size:** template lines only.\n\n### IR-68 — PSYCHE_INGEST_FAIL cause class unproven: git index.lock did NOT reproduce the ingest failure it was blamed for\n\n- **Status:** OPEN, investigation-shaped · **Origin:** todlando measurement at the W2 int-leg rig\n  (IO-PARSER #22, PR #163 at `769fb0a9`, 2026-08-27), reported measure-first; filed by doyle.\n- **The contradiction:** the six silent `PSYCHE_INGEST_FAIL:todlando` lines observed at the\n  drop-dir probe (2026-08-25) were attributed to shared-checkout git `index.lock` contention. The\n  W2 rig planted NON-EMPTY `index.lock` files in BOTH places git takes one (bare git-dir + every\n  `<git_dir>/worktrees/<name>/`, mirroring `branchstore::sweep_stale_index_locks`, plant count\n  asserted >= 2) — and the ingest COMMITTED ANYWAY (tier write `Written`; `route_slices`\n  propagates `commit_live(...)?`, so a blocked checkpoint would have failed it). Non-empty was\n  deliberate: KH 1.3 reaps only 0-byte locks, and `pulse_tick` runs no boot sweep. So on this\n  store an `index.lock` does not block the checkpoint, and the field incident's mechanism is\n  UNKNOWN, not merely unconfirmed. The rig's doc comment records the attempt; the shipped int leg\n  fails the ingest at the drop READ instead (upstream of the store).\n- **Strongest negative evidence, pinned to the executable rig:**\n  `crates/spt-daemon/tests/commune_io_events_int.rs:95-107` documents that the lock mechanism was\n  tried **first**, planted non-empty locks in both the bare git-dir and every linked-worktree\n  location, asserted that the population was non-empty, and still observed `Written`. Its own\n  sentence is the required scope boundary: “This leg does not claim to reproduce a mechanism it\n  measured as inert.” The working injection is instead drop-file → directory replacement, which\n  fails the upstream read deterministically and proves only the `COMMUNE_FAIL` event contract.\n- **NOT claimed:** that the field incident was misattributed to ingest failure generally — the\n  files did survive with failed-ingest log lines; what is unproven is the index.lock CAUSE.\n…\n\n\n[Showing lines 3300-3703 of 5900. Use :3704 to continue]"}],"details":{"truncation":{"content":"  preserved signer, not a Cargo rebuild into the cleared pool. These are two measured recoveries,\r\n  not a durable capacity fix; IR-46/59/86 remain the next gate-driver capacity rider.\r\n- **SECOND FACE, measured 2026-08-23/24 (WAX-SEAL #21 W2 gate, doyle — the violator this time):**\r\n  both predicted mechanisms fired at once, WITHOUT the floor guard because the gate legs ran as a\r\n  plain script. (1) doyle minted a THIRD cold pool (gate rig) while todlando's lane pool was LIVE —\r\n  the two-pool arithmetic, violated by the gater. (2) The lane pool had silently accumulated\r\n  **104.8 GB** over repeated full-workspace sweeps (nothing bounds or even measures a pool's\r\n  accumulation until the volume dies). The volume hit **3 MB free**; the reds wore exactly the\r\n  entry's predicted costume — `LNK1318: Unexpected PDB error; LIMIT (12)` naming no disk — plus a\r\n  second face worth keeping: `traceable-reqs check` died as a PANIC printing to stdout\r\n  (`os error 112`), so a REGISTRY gate red can also be the disk's. Both gate verdicts VOIDED\r\n  (clippy's full compile had exited 0 before space died — the code was never the question).\r\n  Recovery measured: gate pool reap 9.6 GB, lane pool clean 100.2 GB, drive back to 109.6 GB free.\r\n  **Remedies adopted at the incident:** the gate never mints its own pool while a builder lane is\r\n  live on the box — it takes the lane pool over SEQUENTIALLY at pool-release (warm, loud, the\r\n  releases#103 pattern); and gate/lane scripts get the disk-floor preflight the golden runner\r\n  already carries (this entry's part 2, still unbuilt).\r\n- **THIRD FACE, measured 2026-08-24 (WAX-SEAL #21 golden window, doyle):** two new mechanisms, both\r\n  about the REMEDY rather than the red. (1) The wax-seal-w1 lane pool **re-accumulated to 152–169 GB\r\n  (two meters, IR-46 caveat) within ONE DAY of the 08-23 clean** and rode the volume back down to\r\n  4.92 GB free — a reap is an instant, not a state; nothing yet bounds a pool between reaps.\r\n  (2) **The remedy itself arrived garbled through relay:** the golden push was held \"waiting on the\r\n  IR-59 reboot\" when this entry prescribes no reboot anywhere — tens of releases have shipped without\r\n  one; the operator refused the premise and the register's own recorded remedy (reap finished-lane\r\n  pools) cleared it in ten minutes. A remedy relayed as a DIFFERENT remedy is the relay trap wearing\r\n  infra clothes: the entry is the author — read it before adopting a hold. Recovery measured: five\r\n  finished-lane pools reaped after ancestry classification (`git cherry` catches rebased lands that\r\n  a plain `merge-base --is-ancestor` calls unlanded — gate-w4l1's 90.9 GB pool was reapable only by\r\n  that meter), 4.92 → 260.88 GB free (~256 GB free-delta vs ~270–287 GB sum-of-lengths). Two main\r\n  runs red inside the low-disk window (09:17Z/09:41Z) were re-run, not re-read, per this entry's\r\n  must-do.\r\n- **FOURTH FACE, measured 2026-08-24 same day (SIGNET #218 W2 gate, doyle — the gater's own pool\r\n  this time):** the MAIN pool went **13.7 GB → 158.3 GB in ONE DAY** absorbing four full gate\r\n  batteries across two lane tips, and dragged the volume to **18 GB free mid-gate** — so the\r\n  entry's mechanism is not a lane-pool problem, it is EVERY pool under repeated full sweeps, the\r\n  gate rig included. Two riders worth the ink: (1) the golden runner's **free-space floor step\r\n  produced its first live catch** — a thin CI leg refused at 14:14 local over exactly this window\r\n  with zero test signal, and the register's re-run-not-re-read rule resolved it in one command;\r\n  (2) the reap-and-rebuild trade (\"cleaning a live pool buys one window at rebuild price\") was\r\n  taken deliberately mid-gate and cost ~35 minutes cold — cheaper than one uninterpretable red.\r\n  A red measured at 18 GB free in this gate got NO read at all, and the next sweep's red was a\r\n  DIFFERENT test: low disk manufactures random victims before it manufactures link errors.\r\n- **The event:** a gate's preflight refused with `GATE_ABORTED_DISK_FLOOR` at **4.75 GB free on a\r\n  1863 GB volume**. Four cold pools plus the milestone head's pool were standing at once. The floor\r\n  guard did its job — without it a full workspace build would have started with under 5 GB of\r\n  headroom and produced a red belonging to nothing.\r\n- **THE ARITHMETIC, and it corrects the intuition that worktrees are the cost.** Measured across the\r\n  whole `.worktrees` tree: **45 worktrees = 0.79 GB total** (~18 MB each). **3 pools = 130.45 GB.**\r\n  Worktrees are **0.6%** of the footprint; pools are **99.4%**. **One cold pool is worth roughly 2,500\r\n  worktrees.** A rule keyed on worktree count would cost a day of `git worktree remove` work for under\r\n  a gigabyte, risk removing a lane someone still wants, and leave the lever untouched.\r\n- **THE CEILING, as arithmetic rather than hygiene:** at **45–75 GB per cold pool** on this workspace\r\n  against a **40 GB floor**, this box supports **TWO live pools comfortably, THREE only if one is\r\n  small**. The two rules that already exist need no replacement, only this number attached:\r\n  - **Reap a pool when its lane is finished** → 45–75 GB back immediately.\r\n  - **Do not run two builds at once** → not only the contention argument, but **75–150 GB of\r\n    simultaneous allocation** against that floor.\r\n- **A FULL VOLUME REDS AS A LINKER DEFECT.** `LINK: fatal error LNK1318: Unexpected PDB error`\r\n  (variously `OK (0)` or `LIMIT (12)`), often beside `LNK4209: debugging information corrupt`. It\r\n  reads as a corrupt artifact or a broken toolchain and is neither — it is the linker unable to grow\r\n  a large `.pdb`. **Nothing in the failure text says \"disk\".** Do not key recognition on the\r\n  parenthesised code; it varies.\r\n- **THE DANGER WINDOW IS THE TAIL OF A COLD BUILD, not a steady state you can check once.** The\r\n  2026-08-22 instance died at the link of `spt` — the last and largest artifact of a **74 GB** cold\r\n  pool — while that same build was draining the volume out from under itself. A free-space reading\r\n  taken before the build would have looked fine.\r\n- **Positive tell, with its own refutation attached:** `traceable-reqs check` alone surviving a leg\r\n  table is suggestive, because it is the only leg that never links. It is a POSITIVE tell ONLY — a\r\n  full disk can red before any link step, so the signature's ABSENCE clears nothing.\r\n- **THE FALSIFIER IS FREE SPACE AT THE TIME OF THE RUN**, not the shape of the leg table.\r\n- **Must-do, both cheap:**\r\n  1. **A free-space reading goes in the FIRST LINE of any build-failure report** — not in the\r\n     controls, not as a follow-up. Two agents spent hours on a mechanism for this failure and neither\r\n     ran `df`; the falsifier was one command away throughout.\r\n  2. **Rig and gate logs should record free space at run start.** Today they do not, which makes \"was\r\n     the disk full\" **unanswerable after the fact for every red already in hand**. Any red produced\r\n     under ~1 GB free is UNINTERPRETABLE and must be **re-run, not re-read**.\r\n- **Measurement caveat, observed twice in one hour:** sum-of-file-lengths and free-space delta\r\n  disagree by several percent when anything else on the box is writing (98.07 GB of subtrees → 92.25\r\n  GB reclaimed; 47.28 GB → 40.81 GB). Report BOTH, derive neither from the other, and treat any single\r\n  free-space number as an instant rather than headroom — see IR-46.\r\n- **FIFTH FACE, measured 2026-08-29 at the CONDUIT #236/v0.65.0 cut (deployah):**\r\n  the finished milestone's sequential lane-sharing accumulated **140.51 GB**, while a freshly\r\n  rebuilt pool measured **7.78 GB** — about **18× one build's working set** retained across lane\r\n  hand-offs with no reap between them. This is the budgetable rate behind that cut's disk-floor\r\n  red: sequential execution prevents concurrent ownership corruption, but it does not bound\r\n  historical artifacts inside the shared pool. Treat takeover and reclamation as separate\r\n  operations; a pool may be safe to reuse and still be too large to keep.\r\n- **SEVENTH FACE, measured 2026-08-30 (v0.67.0 milestone close — the PARALLEL-LANE fill\r\n  rate):** the #23 wave arc drove C: from ~240 GB free to **0.01 GB in ~3.5 hours**: four\r\n  concurrent/serial lane+gate pools totalled **236.6 GB** (ns23-w1 87.7 + ns23-113 72.3 +\r\n  gate rig 57.3 + ns23-w3 19.1) — effectively the entire ir57 reclaim re-consumed inside one\r\n  milestone's build window. The head gate and two thin-CI runs redded with the entry's exact\r\n  costume (\"could not compile\" + treqs panic, zero disk words) at 0.01 GB and all re-earned\r\n  green after reclaim (+186.6 GB, finished-lane targets only, single-actor rule held under\r\n  racing consent). Budget rule this face adds: a MULTI-WAVE milestone on one box books\r\n  ~60-90 GB PER LANE-PLUS-GATE cycle, so the pool budget is per-wave, not per-milestone —\r\n  reap each wave's pool at its LAND, not at the milestone party (the party inherited only\r\n  ~58 GB because the emergency had already forced the other ~179).\r\n- **SIXTH FACE, measured 2026-08-30 (#242 golden r4, Windows test job, LNK1318 at the PDB\r\n  write):** the floor is asserted ONCE at job START, but the job's internal LOW-WATER sits at its\r\n  LAST heavy step — the docs-drift build, ~28 minutes in. r4's floor read 65.1 GiB honest at\r\n  23:07; the box was at ~37–39 GB by the 23:35 link failure. LNK1318 on PDB write = this entry's\r\n  documented low-disk costume; the incremental-corruption candidate was retired by preservation\r\n  snapshot (no xtask state existed at failure). **Durable fix = a floor RE-READ (or reclaim)\r\n  immediately before the docs-drift build** — the WITHIN-job sibling of the across-job\r\n  read-after-checkout fix, rides the next workflow commit. Riders: incremental hygiene as\r\n  disk-pressure maintenance (the dir measured 4.56 GB), and the box's **~51 GB non-recovering\r\n  post-run consumption** is this entry's pool-weight face — classify at the IR-14/26/27/49 audit\r\n  slot (composed this sweep).\r\n- **Composed for next intake (doyle, v0.65.0 close):** the still-open log-the-floor build half\r\n  rides with [[IR-57]]'s scripted pick-fidelity audit as the next milestone's two tooling riders.\r\n- **Trigger condition:** ripe now for the log-the-floor half (it rides any gate-script or CI touch);\r\n  the arithmetic is discipline and applies immediately.\r\n- **Size guess:** small — one line in each rig/gate preflight to record free space alongside the\r\n  existing floor check.\r\n\r\n### IR-60 — a wrapper that CAPTURES a leg's exit status ends with the capture, so the wrapper's own status is the capture's, not the leg's\r\n\r\n- **Status:** OPEN, unowned — script-shape discipline, not a code lane. Filed by doyle 2026-08-22\r\n  during the TURNKEY #212 W5 lane; mechanism measured by todlando, who reported it first as a\r\n  possible harness misreport and then RETRACTED that reading himself on a minimal probe.\r\n- **v0.69.0 recurrence, 2026-09-11 (deployah, own withdrawal):** `NEXTEST_EXIT=0` and the task\r\n  completion's exit 0 both described the wrapper/truncation path, not Cargo's **101**.\r\n  `PIPESTATUS` was read outside the executing subshell, so the named verdict measured `tail`.\r\n  Both green-looking receipts were withdrawn; the raw failed-link output was retained.\r\n  **An exit FILE alone is insufficient if its writer captures the wrong process.** Capture\r\n  immediately inside the shell executing the producer, before any other command replaces the\r\n  status, write that value to the leg's file, and propagate it when wrapper status is reported.\r\n  The replacement battery's own file read 0, with 121 tests actually run. Keep this entry OPEN:\r\n  corrected execution of one driver does not make the faulty wrapper shape unreachable.\r\n- **The reading that started it:** a background leg was summarised as `exit code 0` while the leg's\r\n  own exit file read `100`. Reported as-is, that is a task runner lying about a red — the worst\r\n  possible direction for a purposeful-red claim, since it would turn two reds that DID fire into two\r\n  reds reported as not having fired.\r\n- **The measurement, minimal and on this box:**\r\n\r\n      ( exit 100 ); echo $? > probe.exit; FINAL=$?\r\n      leg status captured to file : 100\r\n      wrapper's own final status  : 0\r\n\r\n  The wrapper's shape is `( cd <lane> && cargo nextest ... > leg.raw 2>&1 ); echo $? > leg.exit`.\r\n  **The last command is the `echo`, which succeeds**, so the wrapper genuinely exits 0 while the leg\r\n  genuinely exited 100. THE RUNNER TOLD THE TRUTH ABOUT THE WRAPPER. There is nothing to file against\r\n  the task runner, and it would have been filed.\r\n- **The class, and this is why it is worth an entry rather than a fix:** it is the truncation-pipe\r\n  family — the meter measured something real, it just was not the thing about to be quoted. **Three\r\n  shapes now share ONE trigger, and the trigger is not \"is this a pipe\":**\r\n  1. a truncation pipe (`cmd | tail`, `cmd | head`) — `$?` measures the truncator, and `head` closing\r\n     the pipe can MANUFACTURE a status (SIGPIPE → 101), so `PIPESTATUS` is not protection either;\r\n  2. a flattened `$?` read after any intervening command;\r\n  3. **a wrapper whose last command is the capture itself.**\r\n  **The trigger in all three is the REPORTING** — every instance happened while trimming or capturing\r\n  output in order to QUOTE it as evidence.\r\n- **The practice that held, and the one to keep:** the leg's own file is the leg's verdict. Both reds\r\n  were real, and the only reason that was knowable is that every leg wrote its exit to its own file\r\n  rather than to the wrapper's status.\r\n- **Remedy, in preference order:** (1) never read a wrapper's status as a leg's — read the leg's exit\r\n  FILE, which the per-leg rule already requires; (2) if a wrapper's own status must be meaningful,\r\n  end it by re-raising the captured status (`exit \"$(cat leg.exit)\"`) or set the status before the\r\n  capture is the last word; (3) for anything that becomes evidence, redirect to a file and read the\r\n  file.\r\n- **Trigger condition:** ripe now — it rides the next gate-script touch, and the gate scripts in this\r\n  milestone already write per-leg exit files, which is what makes this discipline rather than debt.\r\n- **Size guess:** small — a convention line in the gate-script preamble; no product code.\r\n\r\n### IR-61 — spacerun's test-module skip carries a SECOND literal tracker; the two answers can drift, and today only a cell stands between them\r\n\r\n- **Status:** OPEN, unowned, accepted-with-mitigation. Filed by doyle 2026-08-22 at the TURNKEY #212\r\n  head gate, as the named residual of the latch repair (the repair itself rides the milestone).\r\n- **What the debt is.** `crates/xtask/src/spacerun.rs` now skips a column-0 `#[cfg(test)]` module by\r\n  BRACE DEPTH and resumes after its close, rather than latching the scan to end-of-file. Counting\r\n  braces safely means knowing when a brace is inside a string, a raw string or a char literal — and\r\n  the scanner ALREADY tracks literals for its rendering pass. It does not reuse that tracking. There\r\n  are now TWO answers in one file to \"am I inside a literal\", and **two answers to one question is a\r\n  disagreement waiting for a reader who fixes one of them.**\r\n- **Why it was accepted rather than refactored on the spot, stated so the trade is auditable:** the\r\n  two trackers answer genuinely different questions — the rendering walk is PER LINE and forward\r\n  from an opening quote (\"where does this literal start and end\"), while the skip needs \"am I inside\r\n  a literal right now\" carried CONTINUOUSLY across lines. Unifying them is a real refactor of a check\r\n  that is already gated, already carries five fixed defects, and sits on the tree being handed to\r\n  golden. The narrow change with an OBSERVABLE failure mode beat the correct-shaped change with a\r\n  wide blast radius, on that tree, on that day.\r\n- **The mitigation, and its exact limit.** Three brace cells fail the moment the two trackers\r\n  disagree about a raw string, a normal string or a char literal, plus a cell that reds when the skip\r\n  stops consulting a literal tracker at all (`match lit` -> `match Lit::None`). **That is a cell\r\n  standing in for a refactor.** It catches drift in the three forms it names and nothing else — a\r\n  fourth literal form, or a change to only one tracker in a form neither cell covers, passes.\r\n- **The general shape, which is why this is a register entry rather than a comment:** a check whose\r\n  own correctness depends on a second implementation of a thing it already implements is one\r\n  refactor away from the defect class it exists to prevent. This same file has already produced\r\n  three instrument defects (an indented-marker latch, a column-0 latch, and a suppression that\r\n  decided what got PARSED rather than what got REPORTED). The pattern is not carelessness; it is a\r\n  scanner accumulating special cases.\r\n- **Trigger condition:** the next SUBSTANTIVE change to spacerun's scanning — any new skip, any new\r\n  literal form, any change to either tracker. At that point unify, rather than adding a third answer.\r\n- **Size guess:** small to medium — one continuous literal-state walk serving both the render pass\r\n  and the skip, with the existing corpus and brace cells as the regression net.\r\n\r\n### IR-62 — an e2e daemon binds well-known ports and collides with the resident fleet on shared runners\r\n\r\nFiled 2026-08-23 (doyle), from the #212 r2 golden's Windows Phase A red — one witnessed\r\ninstance, mechanism verified from the run's own capture, filed on the mechanism per the\r\nregister's standard.\r\n\r\n**Mechanism.** `endpoint_autostart_e2e::saved_endpoint_replays_on_daemon_restart` failed its\r\nown PRECONDITION (\"daemon B must come up with a fresh brain\") because daemon B's broker came up\r\ndegraded: `NODE_KEY_FAIL: identity unavailable` (net-less broker, no retry) and\r\n`DOCS_SERVER_BIND_FAIL` port 5474 `os error 10048` — the docs port was held by a CO-RESIDENT\r\ndaemon. HFENDULEAM is live infra: the resident fleet's daemon legitimately holds well-known\r\nports, and any e2e that brings up a daemon with default port bindings is in a race with it BY\r\nCONSTRUCTION. An isolated SPT_HOME isolates the store and broker socket, NOT globally-numbered\r\nTCP ports.\r\n\r\n**Classification history.** r2: red (35.4s, precondition panic). Run 1 and r3 on the same box:\r\ngreen. Folded into r3 under a pre-registered predicate (reds twice → dedicated triage); it\r\ngreened, so this stays an environment-shaped intermittent, NOT a product defect and NOT\r\nclosed — the collision window is real and will re-fire under the right co-residence timing.\r\n\r\n**Remedy direction (not built).** Test daemons should bind ephemeral/rig-scoped ports for\r\nevery advisory surface (the docs server is advisory — a bind failure should degrade the rig\r\nloudly, not poison an unrelated cell's precondition), or the precondition should name the\r\nport-collision cause distinctly so the red self-classifies. Either lane is test/CI work\r\n(hertz's), triggered the next time this class fires anywhere.\r\n\r\n**Kin.** IR-51 (e2e daemon net-enabled on real interfaces — hermeticity is disk-deep only);\r\nthe known not-ours red classes list in the #212 hand-off.\r\n\r\n**BUILT 2026-08-24 (hertz, SIGNET #218 batch; PR #158).** The class fired its second witnessed\r\ninstance the same day — doyle's W2 gate rig, `engine_room_bringup_e2e` precondition panic with\r\nthe IR-50 panel naming `DOCS_SERVER_BIND_FAIL` port 5474 `os error 10048` — which armed this\r\nentry's own trigger. Hertz repro'd deterministically (held the port; brain still reached\r\nBRAIN_UP), pre-ranked three mechanisms before probing, and built the ephemeral-advisory form:\r\nrig-only `SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1` makes the daemon's docs listener bind port 0\r\n(production config/`SPT_DOCS_PORT`/docs-url untouched; the flag matches the literal \"1\" only).\r\nThe golden workflow's test job sets it globally on both self-hosted legs, the standalone ER rig\r\nsets it too. Scope note kept honest per his own ranking: the docs collision is retired; if a\r\nco-diagnostic bind elsewhere still poisons a precondition, that is a residual face of THIS\r\nentry, not a closed question.\r\n\r\n### IR-63 — suite-mix sweeps leak job-escaped autostart daemons that LOCK the pool's spt.exe; and the same box conditions manufacture one random victim per sweep\r\n\r\n- **Status:** OPEN, mitigated-by-rig-step — the reap is adopted discipline, not yet construction.\r\n  Filed by doyle 2026-08-24 at the SIGNET #218 gates; first measured by todlando the same day\r\n  (his W1 build: four reap rounds of 2, 8, 1, 1 processes, count-by-path stated each round).\r\n- **Mechanism, two faces of one condition:** (1) e2e sweeps that exercise autostart leave\r\n  job-escaped daemons running `target/debug/spt.exe`; the NEXT build or `xtask check` then dies\r\n  on `os error 5` removing the exe — a rig red wearing a build defect's clothes. nextest's own\r\n  `leaky` flags corroborate (4–8 per sweep measured). (2) The same co-residence (leaked daemons +\r\n  resident fleet + runner traffic) manufactures ONE red per full sweep with a DIFFERENT victim\r\n  each time: doyle's W2 gate measured FOUR distinct one-off victims in four same-sha sweeps\r\n  (ER bringup, composite+bootstrap pair under CI load, resident_service, brain_resume), every\r\n  one green alone and/or in a sibling sweep. The e2e-leaked-daemons rule holds: a different test\r\n  dying each run on one sha is ONE environment cause, and hardening members never closes it.\r\n- **Mitigation adopted (rig step, both todlando's lanes and doyle's gate runner):** reap\r\n  `spt.exe` BY PATH (`*spt-core\\target*`) before EVERY cargo invocation and after every sweep;\r\n  report the count each time so a zero is a claim, not silence.\r\n- **Remedy direction (unbuilt):** the durable form is construction, not discipline — either\r\n  nextest wrap/xtask verb that performs the by-path reap as a pre-step on this box's rigs, or\r\n  autostart e2es gain teardown that provably outlives job escape (kin IR-38's built wedge-namer,\r\n  IR-62's ephemeral ports which retire one collision axis, IR-35's victim-rate ledger).\r\n- **THIRD FACE, measured 2026-08-30 (doyle, ir57/asm-241 reaps):** the leaked population is not\r\n  only daemons — battery legs leave ORPHANED HEADLESS `conhost.exe` processes whose CWD sits in\r\n  the worktree's `crates/spt-daemon` (where the leg ran), and a CWD pin blocks `Remove-Item`/\r\n  `git worktree remove` on the whole tree with \"being used by another process\" naming the DIR.\r\n  This is the mechanism behind every recent \"handle-pinned, retry later\" worktree removal: 31\r\n  such conhosts found at once (Aug 26–29 vintages) pinning FIVE dead worktrees. cargo/rustc\r\n  absence does NOT clear the suspect list — the conhost outlives its client. Holder census\r\n  tool: a ~30-line NtQueryInformationProcess CWD probe (PEB→ProcessParameters→CurrentDirectory)\r\n  over all pids, filtered on the path — names every holder in one pass where no handle.exe\r\n  exists. 13 killed scoped to the two consented reaps; 18 remain pinning gate-w1-a8f04aff (12),\r\n  io-parser-w1 (5), gate-w1-786d2381 (1 after kills) — sweep them at the IR-14/26/27/49 audit\r\n  slot before those removals.\r\n- **LANE-LINKED 2026-08-30 (#242 close sweep):** hertz's queued daemon-leak fixup lane carries\r\n  this entry (brief cites IR-7/17/20/34/35/63); leaves the register when that lane lands.\r\n- **Trigger condition:** next rig/gate-script construction touch, or the first golden red that\r\n  classifies to face (1).\r\n- **Size guess:** small-medium — one wrapper seam plus adopting it in the gate/lane scripts.\r\n\r\n### IR-64 — HFENDULEAM's disk floor is set by non-CI bulk: ~845 GB of operator payload leaves the golden box ~2 GB of slack against its own 32 GB preflight\r\n\r\n- **Status:** OPEN · **Origin:** doyle, v0.63.0 close sweep 2026-08-26; mechanism first measured\r\n  at the FIELD-SEAL golden window (deployah's IR-31 fifth addendum carries the POOL side of the\r\n  same event by agreed division — this entry is the OTHER reservoir, deliberately not his).\r\n- **Mechanism:** the 1.86 TB C: carries ~614 GB Steam + ~230 GB Downloads (operator payload, not\r\n  CI state). With that floor fixed, normal lane traffic alone walks the box under the 32 GB\r\n  golden preflight — a full-sweep pool WEIGHS ~90–112 GB steady state (IR-59's measurement) and\r\n  five FIELD-SEAL lanes cost 148.48 GB (IR-31 fifth addendum), so ONE milestone's pools exceed\r\n  the entire free margin. Reaping buys windows, not headroom: deployah measured free fall\r\n  167 → 108 GB within hours of his reap, ~59 GB re-consumed by lane builds. The recurring shape:\r\n  every milestone pays a reap-and-measure tax to rent space the box does not structurally have.\r\n- **Why register-worthy rather than \"clean up more\":** agent-side discipline (IR-31's budgeting,\r\n  pool reaps, teardown steps) is already adopted and still only rents windows — the reservoir\r\n  that would durably move the floor is operator-owned bulk no agent may touch. Naming it here is\r\n  the boundary: agents keep budgeting IN POOLS (not GB); moving Steam/Downloads (or adding a\r\n  disk, or pinning golden to a box without operator payload) is an OPERATOR decision this entry\r\n  exists to put in front of them once, with numbers, instead of re-deriving the floor each cut.\r\n- **Ripe when:** operator rules on the bulk (move/expand/accept-the-tax), OR the first golden\r\n  that dies at the 32 GB preflight despite adopted pool discipline (IR-59's LNK1180-class red).\r\n- **Size:** zero code; one operator decision + at most a runbook line naming the chosen floor.\r\n\r\n### IR-65 — kitsubito kernel-audit backpressure: a tailscale-snap AppArmor denial storm + no auditd turned the default audit backlog into a CI-wide stall amplifier (REMEDIATED AT BOX; re-check triggers named)\r\n\r\n- **Status:** REMEDIATED-AT-BOX 2026-08-25 (doyle, operator-authorized root — ruling pinned\r\n  releases#225 comment 5418800776); entry stays OPEN as the re-check record because the storm\r\n  SOURCE persists and two named events can silently revert the fix.\r\n- **Mechanism:** `snap.tailscale.tailscaled` (1.92.5) polls /proc and takes an AppArmor\r\n  ptrace-read DENIED per poll — a continuous kernel-audit record storm scaling with process\r\n  count (spawn-heavy serialized CI legs amplify their own storm). With NO auditd installed the\r\n  records rode printk (kauditd throttling) and the 8192 kernel backlog overran\r\n  (lost=1,537,743); the default `backlog_wait_time` 60000ms turns a full backlog into A 60s\r\n  SLEEP INSIDE ANY AUDITED SYSCALL — the broker dispatch stall that stretched IR-30's\r\n  Linux-face race window (see IR-30's Linux-face addendum; deaths clustered 59–63s ↔ this\r\n  knob's value).\r\n- **Remediation (verified at the EFFECTIVE layer, not the fragment):** auditd installed +\r\n  active (storm consumed, backlog drains to 0, lost flat), backlog_limit 32768,\r\n  backlog_wait_time 0 (full backlog may DROP, never STALL). ⚠ THE TRAP PAID FOR ONCE: the first\r\n  knob write (`50-backlog.rules`) silently LOST the augenrules merge — apt's own\r\n  `/etc/audit/rules.d/audit.rules` sorts LAST (digits before letters) and its `-b 8192` /\r\n  `--backlog_wait_time 60000` won; a whole proof run executed under the defaults while the\r\n  fragment grepped perfect. Values now live in the merge-WINNING file; verified `auditctl -s`.\r\n- **Re-check triggers (the reason this entry stays):** (1) tailscale snap update — the plug\r\n  landscape may change, the storm may stop or grow; (2) auditd package update/reinstall — may\r\n  rewrite `rules.d/audit.rules` and re-lose the merge; (3) box reimage. On any of these: one\r\n  `auditctl -s` (expect 32768/0) + one `journalctl -k | grep 'backlog limit'` (expect silence).\r\n- **Ripe when:** a re-check trigger fires. **Size:** two read-only commands per check.\r\n\r\n### IR-66 — first-chunk-needle test class: two latent members remain after the v0.63.0 fix (attach.rs:561, :672)\r\n\r\n- **Status:** CLOSED / BUILT — release-close reconciliation 2026-09-11. The WEBSERVE JIT already\r\n  ruled this satisfied; source at `e5a2fed9` retains both delayed needles. Closure uses the\r\n  recorded gates below, not v0.69.0's unrelated green receipts. Hertz rider PR #161, landed ff at\r\n  `d04b922d` (2026-08-27, IO-PARSER #22\r\n  intake rider). Both members got the later-needle treatment (TICK39 delayed past burst on both\r\n  OS arms; alt-screen entered before delayed ALT_VIEWPORT_MARKER). Gate: doyle — diff-scope\r\n  review; Windows isolated worktree 3× TICK39 PASS + clippy + treqs; Linux CLEAN worktree at the\r\n  PR sha on kitsubito 3× both cells PASS (independent of the builder's dirty-shared-tree proof,\r\n  disclosure on record). · **Origin:** doyle tree-wide census at `dbe3daad`\r\n  (releases#225 comment 5418844404 — the census that corrected my own resume.rs-scoped\r\n  overclaim), after the class's first member was RCA'd and fixed in v0.63.0's head.\r\n- **Mechanism (cite, not restate):** KNOWN-HAZARDS 6.9 same-session face, amended at\r\n  `dbe3daad` — `spawn_session_pid`'s Spawned-wait consumes-and-discards a first output chunk\r\n  that races the reply (~2ms window on a healthy Linux box; load-stretched under backpressure,\r\n  see IR-30 Linux-face + IR-65). A test whose needle exists ONLY in the child's first chunk\r\n  asserts winning a race the contract does not promise.\r\n- **The two members:** `crates/spt-daemon/tests/attach.rs:561` (TICK0..39 instant burst then\r\n  `cat`; needle TICK39 read directly after spawn — the whole burst can sit in the first\r\n  chunks) and `:672` `cross_node_cold_attach_to_alt_screen_gets_clean_repaint` (unix-only;\r\n  `printf '…ALT_VIEWPORT_MARKER'; cat` — needle in the first chunk). Failure shape differs from\r\n  the fixed member: both children idle on `cat`, so a lost prefix is a HANG killed by nextest's\r\n  backstop at exactly 240s (slow-timeout 60s × terminate-after 4) — not a natural-life death.\r\n  Verified NOT in the class: daemon_e2e.rs:209 (needle = echo of post-spawn input), attach.rs:995\r\n  + brain_swap.rs:170 (attach/replay reads, not spawn-waits).\r\n- **Fix shape (ruled at the v0.63.0 close):** hertz lane, NEXT intake — the same one-line\r\n  later-needle / robust-read treatment the resume seed got in `dbe3daad`; deliberately NOT\r\n  landed mid-r4. Both cells passed r4 (0.010–0.058s) — the members are latent, not failing.\r\n- **Ripe when:** next milestone intake (hertz test lane) or the first golden red at ~240s on an\r\n  attach cell — either way the mechanism and fix are pre-derived, triage should cite this entry\r\n  and skip the RCA. **Size:** two one-line test edits.\r\n\r\n### IR-67 — wave-battery gap: a `-p spt --bins` leg compiles bin targets as harnesses and runs ZERO integration/e2e tests, so batteries that lean on it carry silent no-coverage legs\r\n\r\n- **Status:** BUILT — remedy applied across the IO-PARSER #22 milestone (2026-08-27/28): every\r\n  wave battery named explicit `-p spt --test <suite>` e2e legs beside the `--bins` unit leg\r\n  (GW1..GW5 evidence), every builder evidence report carried a named real e2e per the dispatch\r\n  template, and the one filter mistake (a `--test` name not matching its file) REFUSED loudly\r\n  rather than silently skipping — the failure mode this entry exists to kill. Battery template =\r\n  the dispatch text now carried forward in gate craft.\r\n- **Was:** OPEN · **Origin:** doyle, banked at the SIGNET #218 gates 2026-08-25 (\"gate\r\n  battery gap learned\"), filed at this sweep per the standing rule.\r\n- **Mechanism:** `cargo test/nextest -p spt --bins` builds `[[bin]]` targets as TEST HARNESSES\r\n  (unit tests inside bins only) — `tests/` integration and e2e suites of the crate NEVER run,\r\n  and the leg's green output is indistinguishable from coverage. Kin of the two banked pool\r\n  faces (`--bins` never emits fixture exes; fresh-pool fixture reds) but this face is about the\r\n  BATTERY TEMPLATE: my SIGNET wave batteries carried a `-p spt --bins` leg believed to cover\r\n  the crate.\r\n- **Remedy:** at next intake, the wave-battery template gains an explicit `tests/` leg for the\r\n  spt crate (nextest `-p spt --test <suites>` or unfiltered `-p spt` where pool history\r\n  permits), and any battery doc that lists `--bins` as a coverage leg gets the one-line caveat.\r\n- **Ripe when:** next milestone intake (the battery template is touched at every intake).\r\n  **Size:** template lines only.\r\n\r\n### IR-68 — PSYCHE_INGEST_FAIL cause class unproven: git index.lock did NOT reproduce the ingest failure it was blamed for\r\n\r\n- **Status:** OPEN, investigation-shaped · **Origin:** todlando measurement at the W2 int-leg rig\r\n  (IO-PARSER #22, PR #163 at `769fb0a9`, 2026-08-27), reported measure-first; filed by doyle.\r\n- **The contradiction:** the six silent `PSYCHE_INGEST_FAIL:todlando` lines observed at the\r\n  drop-dir probe (2026-08-25) were attributed to shared-checkout git `index.lock` contention. The\r\n  W2 rig planted NON-EMPTY `index.lock` files in BOTH places git takes one (bare git-dir + every\r\n  `<git_dir>/worktrees/<name>/`, mirroring `branchstore::sweep_stale_index_locks`, plant count\r\n  asserted >= 2) — and the ingest COMMITTED ANYWAY (tier write `Written`; `route_slices`\r\n  propagates `commit_live(...)?`, so a blocked checkpoint would have failed it). Non-empty was\r\n  deliberate: KH 1.3 reaps only 0-byte locks, and `pulse_tick` runs no boot sweep. So on this\r\n  store an `index.lock` does not block the checkpoint, and the field incident's mechanism is\r\n  UNKNOWN, not merely unconfirmed. The rig's doc comment records the attempt; the shipped int leg\r\n  fails the ingest at the drop READ instead (upstream of the store).\r\n- **Strongest negative evidence, pinned to the executable rig:**\r\n  `crates/spt-daemon/tests/commune_io_events_int.rs:95-107` documents that the lock mechanism was\r\n  tried **first**, planted non-empty locks in both the bare git-dir and every linked-worktree\r\n  location, asserted that the population was non-empty, and still observed `Written`. Its own\r\n  sentence is the required scope boundary: “This leg does not claim to reproduce a mechanism it\r\n  measured as inert.” The working injection is instead drop-file → directory replacement, which\r\n  fails the upstream read deterministically and proves only the `COMMUNE_FAIL` event contract.\r\n- **NOT claimed:** that the field incident was misattributed to ingest failure generally — the\r","truncated":true,"truncatedBy":"lines","totalLines":2601,"totalBytes":34590,"outputLines":404,"outputBytes":34590,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":5900,"displayContent":{"text":"### IR-59 — pool arithmetic: this box holds TWO cold pools, not four; and a build that exhausts the volume reds as a LINKER defect that names no disk\n…\n- **Status:** OPEN, unowned — it is arithmetic and discipline, not a code lane. Filed by doyle\n…\n- **v0.69.0 release close, 2026-09-11 (deployah, source record releases#294 comment\n…\n  preserved signer, not a Cargo rebuild into the cleared pool. These are two measured recoveries,\r\n  not a durable capacity fix; IR-46/59/86 remain the next gate-driver capacity rider.\r\n- **SECOND FACE, measured 2026-08-23/24 (WAX-SEAL #21 W2 gate, doyle — the violator this time):**\r\n  both predicted mechanisms fired at once, WITHOUT the floor guard because the gate legs ran as a\r\n  plain script. (1) doyle minted a THIRD cold pool (gate rig) while todlando's lane pool was LIVE —\r\n  the two-pool arithmetic, violated by the gater. (2) The lane pool had silently accumulated\r\n  **104.8 GB** over repeated full-workspace sweeps (nothing bounds or even measures a pool's\r\n  accumulation until the volume dies). The volume hit **3 MB free**; the reds wore exactly the\r\n  entry's predicted costume — `LNK1318: Unexpected PDB error; LIMIT (12)` naming no disk — plus a\r\n  second face worth keeping: `traceable-reqs check` died as a PANIC printing to stdout\r\n  (`os error 112`), so a REGISTRY gate red can also be the disk's. Both gate verdicts VOIDED\r\n  (clippy's full compile had exited 0 before space died — the code was never the question).\r\n  Recovery measured: gate pool reap 9.6 GB, lane pool clean 100.2 GB, drive back to 109.6 GB free.\r\n  **Remedies adopted at the incident:** the gate never mints its own pool while a builder lane is\r\n  live on the box — it takes the lane pool over SEQUENTIALLY at pool-release (warm, loud, the\r\n  releases#103 pattern); and gate/lane scripts get the disk-floor preflight the golden runner\r\n  already carries (this entry's part 2, still unbuilt).\r\n- **THIRD FACE, measured 2026-08-24 (WAX-SEAL #21 golden window, doyle):** two new mechanisms, both\r\n  about the REMEDY rather than the red. (1) The wax-seal-w1 lane pool **re-accumulated to 152–169 GB\r\n  (two meters, IR-46 caveat) within ONE DAY of the 08-23 clean** and rode the volume back down to\r\n  4.92 GB free — a reap is an instant, not a state; nothing yet bounds a pool between reaps.\r\n  (2) **The remedy itself arrived garbled through relay:** the golden push was held \"waiting on the\r\n  IR-59 reboot\" when this entry prescribes no reboot anywhere — tens of releases have shipped without\r\n  one; the operator refused the premise and the register's own recorded remedy (reap finished-lane\r\n  pools) cleared it in ten minutes. A remedy relayed as a DIFFERENT remedy is the relay trap wearing\r\n  infra clothes: the entry is the author — read it before adopting a hold. Recovery measured: five\r\n  finished-lane pools reaped after ancestry classification (`git cherry` catches rebased lands that\r\n  a plain `merge-base --is-ancestor` calls unlanded — gate-w4l1's 90.9 GB pool was reapable only by\r\n  that meter), 4.92 → 260.88 GB free (~256 GB free-delta vs ~270–287 GB sum-of-lengths). Two main\r\n  runs red inside the low-disk window (09:17Z/09:41Z) were re-run, not re-read, per this entry's\r\n  must-do.\r\n- **FOURTH FACE, measured 2026-08-24 same day (SIGNET #218 W2 gate, doyle — the gater's own pool\r\n  this time):** the MAIN pool went **13.7 GB → 158.3 GB in ONE DAY** absorbing four full gate\r\n  batteries across two lane tips, and dragged the volume to **18 GB free mid-gate** — so the\r\n  entry's mechanism is not a lane-pool problem, it is EVERY pool under repeated full sweeps, the\r\n  gate rig included. Two riders worth the ink: (1) the golden runner's **free-space floor step\r\n  produced its first live catch** — a thin CI leg refused at 14:14 local over exactly this window\r\n  with zero test signal, and the register's re-run-not-re-read rule resolved it in one command;\r\n  (2) the reap-and-rebuild trade (\"cleaning a live pool buys one window at rebuild price\") was\r\n  taken deliberately mid-gate and cost ~35 minutes cold — cheaper than one uninterpretable red.\r\n  A red measured at 18 GB free in this gate got NO read at all, and the next sweep's red was a\r\n  DIFFERENT test: low disk manufactures random victims before it manufactures link errors.\r\n- **The event:** a gate's preflight refused with `GATE_ABORTED_DISK_FLOOR` at **4.75 GB free on a\r\n  1863 GB volume**. Four cold pools plus the milestone head's pool were standing at once. The floor\r\n  guard did its job — without it a full workspace build would have started with under 5 GB of\r\n  headroom and produced a red belonging to nothing.\r\n- **THE ARITHMETIC, and it corrects the intuition that worktrees are the cost.** Measured across the\r\n  whole `.worktrees` tree: **45 worktrees = 0.79 GB total** (~18 MB each). **3 pools = 130.45 GB.**\r\n  Worktrees are **0.6%** of the footprint; pools are **99.4%**. **One cold pool is worth roughly 2,500\r\n  worktrees.** A rule keyed on worktree count would cost a day of `git worktree remove` work for under\r\n  a gigabyte, risk removing a lane someone still wants, and leave the lever untouched.\r\n- **THE CEILING, as arithmetic rather than hygiene:** at **45–75 GB per cold pool** on this workspace\r\n  against a **40 GB floor**, this box supports **TWO live pools comfortably, THREE only if one is\r\n  small**. The two rules that already exist need no replacement, only this number attached:\r\n  - **Reap a pool when its lane is finished** → 45–75 GB back immediately.\r\n  - **Do not run two builds at once** → not only the contention argument, but **75–150 GB of\r\n    simultaneous allocation** against that floor.\r\n- **A FULL VOLUME REDS AS A LINKER DEFECT.** `LINK: fatal error LNK1318: Unexpected PDB error`\r\n  (variously `OK (0)` or `LIMIT (12)`), often beside `LNK4209: debugging information corrupt`. It\r\n  reads as a corrupt artifact or a broken toolchain and is neither — it is the linker unable to grow\r\n  a large `.pdb`. **Nothing in the failure text says \"disk\".** Do not key recognition on the\r\n  parenthesised code; it varies.\r\n- **THE DANGER WINDOW IS THE TAIL OF A COLD BUILD, not a steady state you can check once.** The\r\n  2026-08-22 instance died at the link of `spt` — the last and largest artifact of a **74 GB** cold\r\n  pool — while that same build was draining the volume out from under itself. A free-space reading\r\n  taken before the build would have looked fine.\r\n- **Positive tell, with its own refutation attached:** `traceable-reqs check` alone surviving a leg\r\n  table is suggestive, because it is the only leg that never links. It is a POSITIVE tell ONLY — a\r\n  full disk can red before any link step, so the signature's ABSENCE clears nothing.\r\n- **THE FALSIFIER IS FREE SPACE AT THE TIME OF THE RUN**, not the shape of the leg table.\r\n- **Must-do, both cheap:**\r\n  1. **A free-space reading goes in the FIRST LINE of any build-failure report** — not in the\r\n     controls, not as a follow-up. Two agents spent hours on a mechanism for this failure and neither\r\n     ran `df`; the falsifier was one command away throughout.\r\n  2. **Rig and gate logs should record free space at run start.** Today they do not, which makes \"was\r\n     the disk full\" **unanswerable after the fact for every red already in hand**. Any red produced\r\n     under ~1 GB free is UNINTERPRETABLE and must be **re-run, not re-read**.\r\n- **Measurement caveat, observed twice in one hour:** sum-of-file-lengths and free-space delta\r\n  disagree by several percent when anything else on the box is writing (98.07 GB of subtrees → 92.25\r\n  GB reclaimed; 47.28 GB → 40.81 GB). Report BOTH, derive neither from the other, and treat any single\r\n  free-space number as an instant rather than headroom — see IR-46.\r\n- **FIFTH FACE, measured 2026-08-29 at the CONDUIT #236/v0.65.0 cut (deployah):**\r\n  the finished milestone's sequential lane-sharing accumulated **140.51 GB**, while a freshly\r\n  rebuilt pool measured **7.78 GB** — about **18× one build's working set** retained across lane\r\n  hand-offs with no reap between them. This is the budgetable rate behind that cut's disk-floor\r\n  red: sequential execution prevents concurrent ownership corruption, but it does not bound\r\n  historical artifacts inside the shared pool. Treat takeover and reclamation as separate\r\n  operations; a pool may be safe to reuse and still be too large to keep.\r\n- **SEVENTH FACE, measured 2026-08-30 (v0.67.0 milestone close — the PARALLEL-LANE fill\r\n  rate):** the #23 wave arc drove C: from ~240 GB free to **0.01 GB in ~3.5 hours**: four\r\n  concurrent/serial lane+gate pools totalled **236.6 GB** (ns23-w1 87.7 + ns23-113 72.3 +\r\n  gate rig 57.3 + ns23-w3 19.1) — effectively the entire ir57 reclaim re-consumed inside one\r\n  milestone's build window. The head gate and two thin-CI runs redded with the entry's exact\r\n  costume (\"could not compile\" + treqs panic, zero disk words) at 0.01 GB and all re-earned\r\n  green after reclaim (+186.6 GB, finished-lane targets only, single-actor rule held under\r\n  racing consent). Budget rule this face adds: a MULTI-WAVE milestone on one box books\r\n  ~60-90 GB PER LANE-PLUS-GATE cycle, so the pool budget is per-wave, not per-milestone —\r\n  reap each wave's pool at its LAND, not at the milestone party (the party inherited only\r\n  ~58 GB because the emergency had already forced the other ~179).\r\n- **SIXTH FACE, measured 2026-08-30 (#242 golden r4, Windows test job, LNK1318 at the PDB\r\n  write):** the floor is asserted ONCE at job START, but the job's internal LOW-WATER sits at its\r\n  LAST heavy step — the docs-drift build, ~28 minutes in. r4's floor read 65.1 GiB honest at\r\n  23:07; the box was at ~37–39 GB by the 23:35 link failure. LNK1318 on PDB write = this entry's\r\n  documented low-disk costume; the incremental-corruption candidate was retired by preservation\r\n  snapshot (no xtask state existed at failure). **Durable fix = a floor RE-READ (or reclaim)\r\n  immediately before the docs-drift build** — the WITHIN-job sibling of the across-job\r\n  read-after-checkout fix, rides the next workflow commit. Riders: incremental hygiene as\r\n  disk-pressure maintenance (the dir measured 4.56 GB), and the box's **~51 GB non-recovering\r\n  post-run consumption** is this entry's pool-weight face — classify at the IR-14/26/27/49 audit\r\n  slot (composed this sweep).\r\n- **Composed for next intake (doyle, v0.65.0 close):** the still-open log-the-floor build half\r\n  rides with [[IR-57]]'s scripted pick-fidelity audit as the next milestone's two tooling riders.\r\n- **Trigger condition:** ripe now for the log-the-floor half (it rides any gate-script or CI touch);\r\n  the arithmetic is discipline and applies immediately.\r\n- **Size guess:** small — one line in each rig/gate preflight to record free space alongside the\r\n  existing floor check.\r\n\r\n### IR-60 — a wrapper that CAPTURES a leg's exit status ends with the capture, so the wrapper's own status is the capture's, not the leg's\r\n\r\n- **Status:** OPEN, unowned — script-shape discipline, not a code lane. Filed by doyle 2026-08-22\r\n  during the TURNKEY #212 W5 lane; mechanism measured by todlando, who reported it first as a\r\n  possible harness misreport and then RETRACTED that reading himself on a minimal probe.\r\n- **v0.69.0 recurrence, 2026-09-11 (deployah, own withdrawal):** `NEXTEST_EXIT=0` and the task\r\n  completion's exit 0 both described the wrapper/truncation path, not Cargo's **101**.\r\n  `PIPESTATUS` was read outside the executing subshell, so the named verdict measured `tail`.\r\n  Both green-looking receipts were withdrawn; the raw failed-link output was retained.\r\n  **An exit FILE alone is insufficient if its writer captures the wrong process.** Capture\r\n  immediately inside the shell executing the producer, before any other command replaces the\r\n  status, write that value to the leg's file, and propagate it when wrapper status is reported.\r\n  The replacement battery's own file read 0, with 121 tests actually run. Keep this entry OPEN:\r\n  corrected execution of one driver does not make the faulty wrapper shape unreachable.\r\n- **The reading that started it:** a background leg was summarised as `exit code 0` while the leg's\r\n  own exit file read `100`. Reported as-is, that is a task runner lying about a red — the worst\r\n  possible direction for a purposeful-red claim, since it would turn two reds that DID fire into two\r\n  reds reported as not having fired.\r\n- **The measurement, minimal and on this box:**\r\n\r\n      ( exit 100 ); echo $? > probe.exit; FINAL=$?\r\n      leg status captured to file : 100\r\n      wrapper's own final status  : 0\r\n\r\n  The wrapper's shape is `( cd <lane> && cargo nextest ... > leg.raw 2>&1 ); echo $? > leg.exit`.\r\n  **The last command is the `echo`, which succeeds**, so the wrapper genuinely exits 0 while the leg\r\n  genuinely exited 100. THE RUNNER TOLD THE TRUTH ABOUT THE WRAPPER. There is nothing to file against\r\n  the task runner, and it would have been filed.\r\n- **The class, and this is why it is worth an entry rather than a fix:** it is the truncation-pipe\r\n  family — the meter measured something real, it just was not the thing about to be quoted. **Three\r\n  shapes now share ONE trigger, and the trigger is not \"is this a pipe\":**\r\n  1. a truncation pipe (`cmd | tail`, `cmd | head`) — `$?` measures the truncator, and `head` closing\r\n     the pipe can MANUFACTURE a status (SIGPIPE → 101), so `PIPESTATUS` is not protection either;\r\n  2. a flattened `$?` read after any intervening command;\r\n  3. **a wrapper whose last command is the capture itself.**\r\n  **The trigger in all three is the REPORTING** — every instance happened while trimming or capturing\r\n  output in order to QUOTE it as evidence.\r\n- **The practice that held, and the one to keep:** the leg's own file is the leg's verdict. Both reds\r\n  were real, and the only reason that was knowable is that every leg wrote its exit to its own file\r\n  rather than to the wrapper's status.\r\n- **Remedy, in preference order:** (1) never read a wrapper's status as a leg's — read the leg's exit\r\n  FILE, which the per-leg rule already requires; (2) if a wrapper's own status must be meaningful,\r\n  end it by re-raising the captured status (`exit \"$(cat leg.exit)\"`) or set the status before the\r\n  capture is the last word; (3) for anything that becomes evidence, redirect to a file and read the\r\n  file.\r\n- **Trigger condition:** ripe now — it rides the next gate-script touch, and the gate scripts in this\r\n  milestone already write per-leg exit files, which is what makes this discipline rather than debt.\r\n- **Size guess:** small — a convention line in the gate-script preamble; no product code.\r\n\r\n### IR-61 — spacerun's test-module skip carries a SECOND literal tracker; the two answers can drift, and today only a cell stands between them\r\n\r\n- **Status:** OPEN, unowned, accepted-with-mitigation. Filed by doyle 2026-08-22 at the TURNKEY #212\r\n  head gate, as the named residual of the latch repair (the repair itself rides the milestone).\r\n- **What the debt is.** `crates/xtask/src/spacerun.rs` now skips a column-0 `#[cfg(test)]` module by\r\n  BRACE DEPTH and resumes after its close, rather than latching the scan to end-of-file. Counting\r\n  braces safely means knowing when a brace is inside a string, a raw string or a char literal — and\r\n  the scanner ALREADY tracks literals for its rendering pass. It does not reuse that tracking. There\r\n  are now TWO answers in one file to \"am I inside a literal\", and **two answers to one question is a\r\n  disagreement waiting for a reader who fixes one of them.**\r\n- **Why it was accepted rather than refactored on the spot, stated so the trade is auditable:** the\r\n  two trackers answer genuinely different questions — the rendering walk is PER LINE and forward\r\n  from an opening quote (\"where does this literal start and end\"), while the skip needs \"am I inside\r\n  a literal right now\" carried CONTINUOUSLY across lines. Unifying them is a real refactor of a check\r\n  that is already gated, already carries five fixed defects, and sits on the tree being handed to\r\n  golden. The narrow change with an OBSERVABLE failure mode beat the correct-shaped change with a\r\n  wide blast radius, on that tree, on that day.\r\n- **The mitigation, and its exact limit.** Three brace cells fail the moment the two trackers\r\n  disagree about a raw string, a normal string or a char literal, plus a cell that reds when the skip\r\n  stops consulting a literal tracker at all (`match lit` -> `match Lit::None`). **That is a cell\r\n  standing in for a refactor.** It catches drift in the three forms it names and nothing else — a\r\n  fourth literal form, or a change to only one tracker in a form neither cell covers, passes.\r\n- **The general shape, which is why this is a register entry rather than a comment:** a check whose\r\n  own correctness depends on a second implementation of a thing it already implements is one\r\n  refactor away from the defect class it exists to prevent. This same file has already produced\r\n  three instrument defects (an indented-marker latch, a column-0 latch, and a suppression that\r\n  decided what got PARSED rather than what got REPORTED). The pattern is not carelessness; it is a\r\n  scanner accumulating special cases.\r\n- **Trigger condition:** the next SUBSTANTIVE change to spacerun's scanning — any new skip, any new\r\n  literal form, any change to either tracker. At that point unify, rather than adding a third answer.\r\n- **Size guess:** small to medium — one continuous literal-state walk serving both the render pass\r\n  and the skip, with the existing corpus and brace cells as the regression net.\r\n\r\n### IR-62 — an e2e daemon binds well-known ports and collides with the resident fleet on shared runners\r\n\r\nFiled 2026-08-23 (doyle), from the #212 r2 golden's Windows Phase A red — one witnessed\r\ninstance, mechanism verified from the run's own capture, filed on the mechanism per the\r\nregister's standard.\r\n\r\n**Mechanism.** `endpoint_autostart_e2e::saved_endpoint_replays_on_daemon_restart` failed its\r\nown PRECONDITION (\"daemon B must come up with a fresh brain\") because daemon B's broker came up\r\ndegraded: `NODE_KEY_FAIL: identity unavailable` (net-less broker, no retry) and\r\n`DOCS_SERVER_BIND_FAIL` port 5474 `os error 10048` — the docs port was held by a CO-RESIDENT\r\ndaemon. HFENDULEAM is live infra: the resident fleet's daemon legitimately holds well-known\r\nports, and any e2e that brings up a daemon with default port bindings is in a race with it BY\r\nCONSTRUCTION. An isolated SPT_HOME isolates the store and broker socket, NOT globally-numbered\r\nTCP ports.\r\n\r\n**Classification history.** r2: red (35.4s, precondition panic). Run 1 and r3 on the same box:\r\ngreen. Folded into r3 under a pre-registered predicate (reds twice → dedicated triage); it\r\ngreened, so this stays an environment-shaped intermittent, NOT a product defect and NOT\r\nclosed — the collision window is real and will re-fire under the right co-residence timing.\r\n\r\n**Remedy direction (not built).** Test daemons should bind ephemeral/rig-scoped ports for\r\nevery advisory surface (the docs server is advisory — a bind failure should degrade the rig\r\nloudly, not poison an unrelated cell's precondition), or the precondition should name the\r\nport-collision cause distinctly so the red self-classifies. Either lane is test/CI work\r\n(hertz's), triggered the next time this class fires anywhere.\r\n\r\n**Kin.** IR-51 (e2e daemon net-enabled on real interfaces — hermeticity is disk-deep only);\r\nthe known not-ours red classes list in the #212 hand-off.\r\n\r\n**BUILT 2026-08-24 (hertz, SIGNET #218 batch; PR #158).** The class fired its second witnessed\r\ninstance the same day — doyle's W2 gate rig, `engine_room_bringup_e2e` precondition panic with\r\nthe IR-50 panel naming `DOCS_SERVER_BIND_FAIL` port 5474 `os error 10048` — which armed this\r\nentry's own trigger. Hertz repro'd deterministically (held the port; brain still reached\r\nBRAIN_UP), pre-ranked three mechanisms before probing, and built the ephemeral-advisory form:\r\nrig-only `SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1` makes the daemon's docs listener bind port 0\r\n(production config/`SPT_DOCS_PORT`/docs-url untouched; the flag matches the literal \"1\" only).\r\nThe golden workflow's test job sets it globally on both self-hosted legs, the standalone ER rig\r\nsets it too. Scope note kept honest per his own ranking: the docs collision is retired; if a\r\nco-diagnostic bind elsewhere still poisons a precondition, that is a residual face of THIS\r\nentry, not a closed question.\r\n\r\n### IR-63 — suite-mix sweeps leak job-escaped autostart daemons that LOCK the pool's spt.exe; and the same box conditions manufacture one random victim per sweep\r\n\r\n- **Status:** OPEN, mitigated-by-rig-step — the reap is adopted discipline, not yet construction.\r\n  Filed by doyle 2026-08-24 at the SIGNET #218 gates; first measured by todlando the same day\r\n  (his W1 build: four reap rounds of 2, 8, 1, 1 processes, count-by-path stated each round).\r\n- **Mechanism, two faces of one condition:** (1) e2e sweeps that exercise autostart leave\r\n  job-escaped daemons running `target/debug/spt.exe`; the NEXT build or `xtask check` then dies\r\n  on `os error 5` removing the exe — a rig red wearing a build defect's clothes. nextest's own\r\n  `leaky` flags corroborate (4–8 per sweep measured). (2) The same co-residence (leaked daemons +\r\n  resident fleet + runner traffic) manufactures ONE red per full sweep with a DIFFERENT victim\r\n  each time: doyle's W2 gate measured FOUR distinct one-off victims in four same-sha sweeps\r\n  (ER bringup, composite+bootstrap pair under CI load, resident_service, brain_resume), every\r\n  one green alone and/or in a sibling sweep. The e2e-leaked-daemons rule holds: a different test\r\n  dying each run on one sha is ONE environment cause, and hardening members never closes it.\r\n- **Mitigation adopted (rig step, both todlando's lanes and doyle's gate runner):** reap\r\n  `spt.exe` BY PATH (`*spt-core\\target*`) before EVERY cargo invocation and after every sweep;\r\n  report the count each time so a zero is a claim, not silence.\r\n- **Remedy direction (unbuilt):** the durable form is construction, not discipline — either\r\n  nextest wrap/xtask verb that performs the by-path reap as a pre-step on this box's rigs, or\r\n  autostart e2es gain teardown that provably outlives job escape (kin IR-38's built wedge-namer,\r\n  IR-62's ephemeral ports which retire one collision axis, IR-35's victim-rate ledger).\r\n- **THIRD FACE, measured 2026-08-30 (doyle, ir57/asm-241 reaps):** the leaked population is not\r\n  only daemons — battery legs leave ORPHANED HEADLESS `conhost.exe` processes whose CWD sits in\r\n  the worktree's `crates/spt-daemon` (where the leg ran), and a CWD pin blocks `Remove-Item`/\r\n  `git worktree remove` on the whole tree with \"being used by another process\" naming the DIR.\r\n  This is the mechanism behind every recent \"handle-pinned, retry later\" worktree removal: 31\r\n  such conhosts found at once (Aug 26–29 vintages) pinning FIVE dead worktrees. cargo/rustc\r\n  absence does NOT clear the suspect list — the conhost outlives its client. Holder census\r\n  tool: a ~30-line NtQueryInformationProcess CWD probe (PEB→ProcessParameters→CurrentDirectory)\r\n  over all pids, filtered on the path — names every holder in one pass where no handle.exe\r\n  exists. 13 killed scoped to the two consented reaps; 18 remain pinning gate-w1-a8f04aff (12),\r\n  io-parser-w1 (5), gate-w1-786d2381 (1 after kills) — sweep them at the IR-14/26/27/49 audit\r\n  slot before those removals.\r\n- **LANE-LINKED 2026-08-30 (#242 close sweep):** hertz's queued daemon-leak fixup lane carries\r\n  this entry (brief cites IR-7/17/20/34/35/63); leaves the register when that lane lands.\r\n- **Trigger condition:** next rig/gate-script construction touch, or the first golden red that\r\n  classifies to face (1).\r\n- **Size guess:** small-medium — one wrapper seam plus adopting it in the gate/lane scripts.\r\n\r\n### IR-64 — HFENDULEAM's disk floor is set by non-CI bulk: ~845 GB of operator payload leaves the golden box ~2 GB of slack against its own 32 GB preflight\r\n\r\n- **Status:** OPEN · **Origin:** doyle, v0.63.0 close sweep 2026-08-26; mechanism first measured\r\n  at the FIELD-SEAL golden window (deployah's IR-31 fifth addendum carries the POOL side of the\r\n  same event by agreed division — this entry is the OTHER reservoir, deliberately not his).\r\n- **Mechanism:** the 1.86 TB C: carries ~614 GB Steam + ~230 GB Downloads (operator payload, not\r\n  CI state). With that floor fixed, normal lane traffic alone walks the box under the 32 GB\r\n  golden preflight — a full-sweep pool WEIGHS ~90–112 GB steady state (IR-59's measurement) and\r\n  five FIELD-SEAL lanes cost 148.48 GB (IR-31 fifth addendum), so ONE milestone's pools exceed\r\n  the entire free margin. Reaping buys windows, not headroom: deployah measured free fall\r\n  167 → 108 GB within hours of his reap, ~59 GB re-consumed by lane builds. The recurring shape:\r\n  every milestone pays a reap-and-measure tax to rent space the box does not structurally have.\r\n- **Why register-worthy rather than \"clean up more\":** agent-side discipline (IR-31's budgeting,\r\n  pool reaps, teardown steps) is already adopted and still only rents windows — the reservoir\r\n  that would durably move the floor is operator-owned bulk no agent may touch. Naming it here is\r\n  the boundary: agents keep budgeting IN POOLS (not GB); moving Steam/Downloads (or adding a\r\n  disk, or pinning golden to a box without operator payload) is an OPERATOR decision this entry\r\n  exists to put in front of them once, with numbers, instead of re-deriving the floor each cut.\r\n- **Ripe when:** operator rules on the bulk (move/expand/accept-the-tax), OR the first golden\r\n  that dies at the 32 GB preflight despite adopted pool discipline (IR-59's LNK1180-class red).\r\n- **Size:** zero code; one operator decision + at most a runbook line naming the chosen floor.\r\n\r\n### IR-65 — kitsubito kernel-audit backpressure: a tailscale-snap AppArmor denial storm + no auditd turned the default audit backlog into a CI-wide stall amplifier (REMEDIATED AT BOX; re-check triggers named)\r\n\r\n- **Status:** REMEDIATED-AT-BOX 2026-08-25 (doyle, operator-authorized root — ruling pinned\r\n  releases#225 comment 5418800776); entry stays OPEN as the re-check record because the storm\r\n  SOURCE persists and two named events can silently revert the fix.\r\n- **Mechanism:** `snap.tailscale.tailscaled` (1.92.5) polls /proc and takes an AppArmor\r\n  ptrace-read DENIED per poll — a continuous kernel-audit record storm scaling with process\r\n  count (spawn-heavy serialized CI legs amplify their own storm). With NO auditd installed the\r\n  records rode printk (kauditd throttling) and the 8192 kernel backlog overran\r\n  (lost=1,537,743); the default `backlog_wait_time` 60000ms turns a full backlog into A 60s\r\n  SLEEP INSIDE ANY AUDITED SYSCALL — the broker dispatch stall that stretched IR-30's\r\n  Linux-face race window (see IR-30's Linux-face addendum; deaths clustered 59–63s ↔ this\r\n  knob's value).\r\n- **Remediation (verified at the EFFECTIVE layer, not the fragment):** auditd installed +\r\n  active (storm consumed, backlog drains to 0, lost flat), backlog_limit 32768,\r\n  backlog_wait_time 0 (full backlog may DROP, never STALL). ⚠ THE TRAP PAID FOR ONCE: the first\r\n  knob write (`50-backlog.rules`) silently LOST the augenrules merge — apt's own\r\n  `/etc/audit/rules.d/audit.rules` sorts LAST (digits before letters) and its `-b 8192` /\r\n  `--backlog_wait_time 60000` won; a whole proof run executed under the defaults while the\r\n  fragment grepped perfect. Values now live in the merge-WINNING file; verified `auditctl -s`.\r\n- **Re-check triggers (the reason this entry stays):** (1) tailscale snap update — the plug\r\n  landscape may change, the storm may stop or grow; (2) auditd package update/reinstall — may\r\n  rewrite `rules.d/audit.rules` and re-lose the merge; (3) box reimage. On any of these: one\r\n  `auditctl -s` (expect 32768/0) + one `journalctl -k | grep 'backlog limit'` (expect silence).\r\n- **Ripe when:** a re-check trigger fires. **Size:** two read-only commands per check.\r\n\r\n### IR-66 — first-chunk-needle test class: two latent members remain after the v0.63.0 fix (attach.rs:561, :672)\r\n\r\n- **Status:** CLOSED / BUILT — release-close reconciliation 2026-09-11. The WEBSERVE JIT already\r\n  ruled this satisfied; source at `e5a2fed9` retains both delayed needles. Closure uses the\r\n  recorded gates below, not v0.69.0's unrelated green receipts. Hertz rider PR #161, landed ff at\r\n  `d04b922d` (2026-08-27, IO-PARSER #22\r\n  intake rider). Both members got the later-needle treatment (TICK39 delayed past burst on both\r\n  OS arms; alt-screen entered before delayed ALT_VIEWPORT_MARKER). Gate: doyle — diff-scope\r\n  review; Windows isolated worktree 3× TICK39 PASS + clippy + treqs; Linux CLEAN worktree at the\r\n  PR sha on kitsubito 3× both cells PASS (independent of the builder's dirty-shared-tree proof,\r\n  disclosure on record). · **Origin:** doyle tree-wide census at `dbe3daad`\r\n  (releases#225 comment 5418844404 — the census that corrected my own resume.rs-scoped\r\n  overclaim), after the class's first member was RCA'd and fixed in v0.63.0's head.\r\n- **Mechanism (cite, not restate):** KNOWN-HAZARDS 6.9 same-session face, amended at\r\n  `dbe3daad` — `spawn_session_pid`'s Spawned-wait consumes-and-discards a first output chunk\r\n  that races the reply (~2ms window on a healthy Linux box; load-stretched under backpressure,\r\n  see IR-30 Linux-face + IR-65). A test whose needle exists ONLY in the child's first chunk\r\n  asserts winning a race the contract does not promise.\r\n- **The two members:** `crates/spt-daemon/tests/attach.rs:561` (TICK0..39 instant burst then\r\n  `cat`; needle TICK39 read directly after spawn — the whole burst can sit in the first\r\n  chunks) and `:672` `cross_node_cold_attach_to_alt_screen_gets_clean_repaint` (unix-only;\r\n  `printf '…ALT_VIEWPORT_MARKER'; cat` — needle in the first chunk). Failure shape differs from\r\n  the fixed member: both children idle on `cat`, so a lost prefix is a HANG killed by nextest's\r\n  backstop at exactly 240s (slow-timeout 60s × terminate-after 4) — not a natural-life death.\r\n  Verified NOT in the class: daemon_e2e.rs:209 (needle = echo of post-spawn input), attach.rs:995\r\n  + brain_swap.rs:170 (attach/replay reads, not spawn-waits).\r\n- **Fix shape (ruled at the v0.63.0 close):** hertz lane, NEXT intake — the same one-line\r\n  later-needle / robust-read treatment the resume seed got in `dbe3daad`; deliberately NOT\r\n  landed mid-r4. Both cells passed r4 (0.010–0.058s) — the members are latent, not failing.\r\n- **Ripe when:** next milestone intake (hertz test lane) or the first golden red at ~240s on an\r\n  attach cell — either way the mechanism and fix are pre-derived, triage should cite this entry\r\n  and skip the RCA. **Size:** two one-line test edits.\r\n\r\n### IR-67 — wave-battery gap: a `-p spt --bins` leg compiles bin targets as harnesses and runs ZERO integration/e2e tests, so batteries that lean on it carry silent no-coverage legs\r\n\r\n- **Status:** BUILT — remedy applied across the IO-PARSER #22 milestone (2026-08-27/28): every\r\n  wave battery named explicit `-p spt --test <suite>` e2e legs beside the `--bins` unit leg\r\n  (GW1..GW5 evidence), every builder evidence report carried a named real e2e per the dispatch\r\n  template, and the one filter mistake (a `--test` name not matching its file) REFUSED loudly\r\n  rather than silently skipping — the failure mode this entry exists to kill. Battery template =\r\n  the dispatch text now carried forward in gate craft.\r\n- **Was:** OPEN · **Origin:** doyle, banked at the SIGNET #218 gates 2026-08-25 (\"gate\r\n  battery gap learned\"), filed at this sweep per the standing rule.\r\n- **Mechanism:** `cargo test/nextest -p spt --bins` builds `[[bin]]` targets as TEST HARNESSES\r\n  (unit tests inside bins only) — `tests/` integration and e2e suites of the crate NEVER run,\r\n  and the leg's green output is indistinguishable from coverage. Kin of the two banked pool\r\n  faces (`--bins` never emits fixture exes; fresh-pool fixture reds) but this face is about the\r\n  BATTERY TEMPLATE: my SIGNET wave batteries carried a `-p spt --bins` leg believed to cover\r\n  the crate.\r\n- **Remedy:** at next intake, the wave-battery template gains an explicit `tests/` leg for the\r\n  spt crate (nextest `-p spt --test <suites>` or unfiltered `-p spt` where pool history\r\n  permits), and any battery doc that lists `--bins` as a coverage leg gets the one-line caveat.\r\n- **Ripe when:** next milestone intake (the battery template is touched at every intake).\r\n  **Size:** template lines only.\r\n\r\n### IR-68 — PSYCHE_INGEST_FAIL cause class unproven: git index.lock did NOT reproduce the ingest failure it was blamed for\r\n\r\n- **Status:** OPEN, investigation-shaped · **Origin:** todlando measurement at the W2 int-leg rig\r\n  (IO-PARSER #22, PR #163 at `769fb0a9`, 2026-08-27), reported measure-first; filed by doyle.\r\n- **The contradiction:** the six silent `PSYCHE_INGEST_FAIL:todlando` lines observed at the\r\n  drop-dir probe (2026-08-25) were attributed to shared-checkout git `index.lock` contention. The\r\n  W2 rig planted NON-EMPTY `index.lock` files in BOTH places git takes one (bare git-dir + every\r\n  `<git_dir>/worktrees/<name>/`, mirroring `branchstore::sweep_stale_index_locks`, plant count\r\n  asserted >= 2) — and the ingest COMMITTED ANYWAY (tier write `Written`; `route_slices`\r\n  propagates `commit_live(...)?`, so a blocked checkpoint would have failed it). Non-empty was\r\n  deliberate: KH 1.3 reaps only 0-byte locks, and `pulse_tick` runs no boot sweep. So on this\r\n  store an `index.lock` does not block the checkpoint, and the field incident's mechanism is\r\n  UNKNOWN, not merely unconfirmed. The rig's doc comment records the attempt; the shipped int leg\r\n  fails the ingest at the drop READ instead (upstream of the store).\r\n- **Strongest negative evidence, pinned to the executable rig:**\r\n  `crates/spt-daemon/tests/commune_io_events_int.rs:95-107` documents that the lock mechanism was\r\n  tried **first**, planted non-empty locks in both the bare git-dir and every linked-worktree\r\n  location, asserted that the population was non-empty, and still observed `Written`. Its own\r\n  sentence is the required scope boundary: “This leg does not claim to reproduce a mechanism it\r\n  measured as inert.” The working injection is instead drop-file → directory replacement, which\r\n  fails the upstream read deterministically and proves only the `COMMUNE_FAIL` event contract.\r\n- **NOT claimed:** that the field incident was misattributed to ingest failure generally — the\r\n  files did survive with failed-ingest log lines; what is unproven is the index.lock CAUSE.\n…\n","startLine":3283,"lineNumbers":[3283,null,3285,null,3288,null,3300,3301,3302,3303,3304,3305,3306,3307,3308,3309,3310,3311,3312,3313,3314,3315,3316,3317,3318,3319,3320,3321,3322,3323,3324,3325,3326,3327,3328,3329,3330,3331,3332,3333,3334,3335,3336,3337,3338,3339,3340,3341,3342,3343,3344,3345,3346,3347,3348,3349,3350,3351,3352,3353,3354,3355,3356,3357,3358,3359,3360,3361,3362,3363,3364,3365,3366,3367,3368,3369,3370,3371,3372,3373,3374,3375,3376,3377,3378,3379,3380,3381,3382,3383,3384,3385,3386,3387,3388,3389,3390,3391,3392,3393,3394,3395,3396,3397,3398,3399,3400,3401,3402,3403,3404,3405,3406,3407,3408,3409,3410,3411,3412,3413,3414,3415,3416,3417,3418,3419,3420,3421,3422,3423,3424,3425,3426,3427,3428,3429,3430,3431,3432,3433,3434,3435,3436,3437,3438,3439,3440,3441,3442,3443,3444,3445,3446,3447,3448,3449,3450,3451,3452,3453,3454,3455,3456,3457,3458,3459,3460,3461,3462,3463,3464,3465,3466,3467,3468,3469,3470,3471,3472,3473,3474,3475,3476,3477,3478,3479,3480,3481,3482,3483,3484,3485,3486,3487,3488,3489,3490,3491,3492,3493,3494,3495,3496,3497,3498,3499,3500,3501,3502,3503,3504,3505,3506,3507,3508,3509,3510,3511,3512,3513,3514,3515,3516,3517,3518,3519,3520,3521,3522,3523,3524,3525,3526,3527,3528,3529,3530,3531,3532,3533,3534,3535,3536,3537,3538,3539,3540,3541,3542,3543,3544,3545,3546,3547,3548,3549,3550,3551,3552,3553,3554,3555,3556,3557,3558,3559,3560,3561,3562,3563,3564,3565,3566,3567,3568,3569,3570,3571,3572,3573,3574,3575,3576,3577,3578,3579,3580,3581,3582,3583,3584,3585,3586,3587,3588,3589,3590,3591,3592,3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606,3607,3608,3609,3610,3611,3612,3613,3614,3615,3616,3617,3618,3619,3620,3621,3622,3623,3624,3625,3626,3627,3628,3629,3630,3631,3632,3633,3634,3635,3636,3637,3638,3639,3640,3641,3642,3643,3644,3645,3646,3647,3648,3649,3650,3651,3652,3653,3654,3655,3656,3657,3658,3659,3660,3661,3662,3663,3664,3665,3666,3667,3668,3669,3670,3671,3672,3673,3674,3675,3676,3677,3678,3679,3680,3681,3682,3683,3684,3685,3686,3687,3688,3689,3690,3691,3692,3693,3694,3695,3696,3697,3698,3699,3700,3701,3702,3703,3704,null,3709]},"fileSize":512411,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\INFRA-REGISTER.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":5900,"totalBytes":34590,"outputLines":404,"outputBytes":34590,"shownRange":{"start":3300,"end":3703},"nextOffset":3704}}},"isError":false,"timestamp":1789107046643}}
{"type":"message","id":"c961983d","parentId":"e0cbcf5d","timestamp":"2026-09-11T06:10:46.646Z","message":{"role":"toolResult","toolCallId":"call_arhDXu4ji7jZC64pSnUNMy3L|fc_0330c101aa2c61dc016aa39b6439f087d1b336770f400862f4","toolName":"glob","content":[{"type":"text","text":"CONTEXT.md\nAGENTS.md\nCLAUDE.md"}],"details":{"scopePath":"AGENTS.md, CLAUDE.md, CONTEXT.md, docs/*304*, docs/*CLOSE*, docs/*INTAKE*","fileCount":3,"files":["CONTEXT.md","AGENTS.md","CLAUDE.md"],"truncated":false,"cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core"},"isError":false,"timestamp":1789107046646}}
{"type":"message","id":"0c58561b","parentId":"c961983d","timestamp":"2026-09-11T06:10:46.650Z","message":{"role":"toolResult","toolCallId":"call_dBbU70DMzd6iak6VBYxYFrGj|fc_0330c101aa2c61dc016aa39b6439d487d183817cd6fbbcec16","toolName":"grep","content":[{"type":"text","text":" 3021|\n*3022|### IR-55 — the `spt --bins` suite wedges partway through on leaked `findstr .` PTY children; the tests at the frontier are casualties, not culprits\n 3023|\n*3024|- **Status:** OPEN, **ARMED-FOR-CAPTURE**, owned by **hertz**. Test/rig defect by the dispatch\n 3025|  split (test/CI rework is never the product builder's). Filed by doyle 2026-08-22 from the\n 3026|  TURNKEY #212 W3 gate on releases#213.\n 3027|- **CORRECTED BY REPLACEMENT the same day.** This entry first named\n...\n 3063|  shape as `exit-code-after-a-pipe-is-the-tails`.\n*3064|- **Trigger condition (ripe):** any milestone whose gate wants an unfiltered `spt --bins` sweep,\n 3065|  which is every one of them. Ripe now.\n 3066|- **REMEDY, MEASURED 2026-08-22 and it changes this entry's urgency:** the same 653 tests under\n 3067|  `cargo nextest run -p spt --bins --no-fail-fast` complete in **22.2 seconds, 653 passed, 0\n...\n 3147|\n*3148|### IR-56 — `pool-claim` harvests lane identity from CWD, not from `--pool`; a claim run from the wrong tree writes a WRONG RECORD with a success message\n 3149|\n*3150|- **Status:** BUILT 2026-08-24 for the SIGNET #218 golden batch on\n 3151|  `fix/ir56-pool-claim-cwd`, owned by **hertz**. Tooling/rig defect by the dispatch split. Filed by\n 3152|  doyle 2026-08-22 from todlando's TURNKEY #212 W4 Lane 1 field instance — the first confirmation\n 3153|  of the IR-42 mechanism from a LANE rather than from a source read.\n...\n 3173|  `branch` name the lane: the success line carries the record, so the check costs nothing.\n*3174|- **Trigger condition:** ripe now — it is a doc/UX fix on a verb we run every lane. Ripest alongside\n 3175|  any other `xtask` pool-verb touch.\n 3176|- **Size guess:** small. Either make the verb REFUSE when cwd is not inside the tree containing\n 3177|  `--pool` (loud, and it cannot be wrong), or print the harvested identity as a distinct confirmed\n...\n 3188|\n*3189|### IR-57 — an assembly pick's conflict resolution can silently DROP lines, and every gate run at assembly time is blind to it\n 3190|\n*3191|- **Status:** OPEN, owned by **doyle** (gater craft, not a code defect — no lane to dispatch).\n 3192|  Filed 2026-08-22 from doyle's own defect on the TURNKEY #212 assembly head.\n 3193|- **What happened:** assembly head `5cce533d` **did not compile**, and was carried across a session\n 3194|  boundary as a ready head with \"treqs exit 0\" attached to it. `crates/spt-store/src/access.rs` had\n...\n 3242|  produced the verdict classes in the order the entry predicts.\n*3243|- **Trigger condition:** ripe at the next assembly — this is procedure, and its cost is one command\n 3244|  per pick.\n 3245|- **Size guess:** small as a scripted check in `xtask` (fidelity audit over a pick range); zero as\n 3246|  discipline, which is how it is being applied now.\n 3247|\n*3248|### IR-58 — a `[[bin]]` grep is not a census: cargo AUTODISCOVERS `src/bin/*.rs` targets, and a hand-built bin list produced a confident false \"this bin does not exist\"\n 3249|\n*3250|- **Status:** OPEN, unowned. Filed by doyle 2026-08-22; **its original filing was WRONG and is\n 3251|  retracted in full below.** The entry is kept because the way it was wrong is the finding.\n 3252|- **RETRACTED CLAIM, stated plainly so no reader acts on it:** this entry first said that\n 3253|  `crates/spt/Cargo.toml:18-21` and `crates/spt/src/cli.rs:30355` forbid a bin-name collision with\n...\n 3277|  answer about a set it never fully saw.\n*3278|- **Trigger condition:** ripe on any `xtask` check work — a duplicate-bin-name check over cargo's\n 3279|  target enumeration (NOT over manifest stanzas) is a handful of lines and cannot go stale.\n 3280|- **Size guess:** small. The prose fix originally proposed here is WITHDRAWN — there was nothing\n 3281|  wrong with the prose.\n 3282|\n*3283|### IR-59 — pool arithmetic: this box holds TWO cold pools, not four; and a build that exhausts the volume reds as a LINKER defect that names no disk\n 3284|\n*3285|- **Status:** OPEN, unowned — it is arithmetic and discipline, not a code lane. Filed by doyle\n 3286|  2026-08-22 from a live disk-floor abort during the TURNKEY #212 W4 gate; footprint figures measured\n 3287|  by todlando the same hour.\n 3288|- **v0.69.0 release close, 2026-09-11 (deployah, source record releases#294 comment\n...\n 3411|  rides with [[IR-57]]'s scripted pick-fidelity audit as the next milestone's two tooling riders.\n*3412|- **Trigger condition:** ripe now for the log-the-floor half (it rides any gate-script or CI touch);\n 3413|  the arithmetic is discipline and applies immediately.\n 3414|- **Size guess:** small — one line in each rig/gate preflight to record free space alongside the\n 3415|  existing floor check.\n 3416|\n*3417|### IR-60 — a wrapper that CAPTURES a leg's exit status ends with the capture, so the wrapper's own status is the capture's, not the leg's\n 3418|\n*3419|- **Status:** OPEN, unowned — script-shape discipline, not a code lane. Filed by doyle 2026-08-22\n 3420|  during the TURNKEY #212 W5 lane; mechanism measured by todlando, who reported it first as a\n 3421|  possible harness misreport and then RETRACTED that reading himself on a minimal probe.\n 3422|- **v0.69.0 recurrence, 2026-09-11 (deployah, own withdrawal):** `NEXTEST_EXIT=0` and the task\n...\n 3461|  file.\n*3462|- **Trigger condition:** ripe now — it rides the next gate-script touch, and the gate scripts in this\n 3463|  milestone already write per-leg exit files, which is what makes this discipline rather than debt.\n 3464|- **Size guess:** small — a convention line in the gate-script preamble; no product code.\n 3465|\n*3466|### IR-61 — spacerun's test-module skip carries a SECOND literal tracker; the two answers can drift, and today only a cell stands between them\n 3467|\n*3468|- **Status:** OPEN, unowned, accepted-with-mitigation. Filed by doyle 2026-08-22 at the TURNKEY #212\n 3469|  head gate, as the named residual of the latch repair (the repair itself rides the milestone).\n 3470|- **What the debt is.** `crates/xtask/src/spacerun.rs` now skips a column-0 `#[cfg(test)]` module by\n 3471|  BRACE DEPTH and resumes after its close, rather than latching the scan to end-of-file. Counting\n...\n 3493|  scanner accumulating special cases.\n*3494|- **Trigger condition:** the next SUBSTANTIVE change to spacerun's scanning — any new skip, any new\n 3495|  literal form, any change to either tracker. At that point unify, rather than adding a third answer.\n 3496|- **Size guess:** small to medium — one continuous literal-state walk serving both the render pass\n 3497|  and the skip, with the existing corpus and brace cells as the regression net.\n 3498|\n*3499|### IR-62 — an e2e daemon binds well-known ports and collides with the resident fleet on shared runners\n 3500|\n 3501|Filed 2026-08-23 (doyle), from the #212 r2 golden's Windows Phase A red — one witnessed\n 3502|instance, mechanism verified from the run's own capture, filed on the mechanism per the\n...\n 3539|\n*3540|### IR-63 — suite-mix sweeps leak job-escaped autostart daemons that LOCK the pool's spt.exe; and the same box conditions manufacture one random victim per sweep\n 3541|\n*3542|- **Status:** OPEN, mitigated-by-rig-step — the reap is adopted discipline, not yet construction.\n 3543|  Filed by doyle 2026-08-24 at the SIGNET #218 gates; first measured by todlando the same day\n 3544|  (his W1 build: four reap rounds of 2, 8, 1, 1 processes, count-by-path stated each round).\n 3545|- **Mechanism, two faces of one condition:** (1) e2e sweeps that exercise autostart leave\n...\n 3574|  this entry (brief cites IR-7/17/20/34/35/63); leaves the register when that lane lands.\n*3575|- **Trigger condition:** next rig/gate-script construction touch, or the first golden red that\n 3576|  classifies to face (1).\n 3577|- **Size guess:** small-medium — one wrapper seam plus adopting it in the gate/lane scripts.\n 3578|\n*3579|### IR-64 — HFENDULEAM's disk floor is set by non-CI bulk: ~845 GB of operator payload leaves the golden box ~2 GB of slack against its own 32 GB preflight\n 3580|\n*3581|- **Status:** OPEN · **Origin:** doyle, v0.63.0 close sweep 2026-08-26; mechanism first measured\n 3582|  at the FIELD-SEAL golden window (deployah's IR-31 fifth addendum carries the POOL side of the\n 3583|  same event by agreed division — this entry is the OTHER reservoir, deliberately not his).\n 3584|- **Mechanism:** the 1.86 TB C: carries ~614 GB Steam + ~230 GB Downloads (operator payload, not\n...\n 3600|\n*3601|### IR-65 — kitsubito kernel-audit backpressure: a tailscale-snap AppArmor denial storm + no auditd turned the default audit backlog into a CI-wide stall amplifier (REMEDIATED AT BOX; re-check triggers named)\n 3602|\n*3603|- **Status:** REMEDIATED-AT-BOX 2026-08-25 (doyle, operator-authorized root — ruling pinned\n 3604|  releases#225 comment 5418800776); entry stays OPEN as the re-check record because the storm\n 3605|  SOURCE persists and two named events can silently revert the fix.\n 3606|- **Mechanism:** `snap.tailscale.tailscaled` (1.92.5) polls /proc and takes an AppArmor\n...\n 3626|\n*3627|### IR-66 — first-chunk-needle test class: two latent members remain after the v0.63.0 fix (attach.rs:561, :672)\n 3628|\n*3629|- **Status:** CLOSED / BUILT — release-close reconciliation 2026-09-11. The WEBSERVE JIT already\n 3630|  ruled this satisfied; source at `e5a2fed9` retains both delayed needles. Closure uses the\n 3631|  recorded gates below, not v0.69.0's unrelated green receipts. Hertz rider PR #161, landed ff at\n 3632|  `d04b922d` (2026-08-27, IO-PARSER #22\n...\n 3659|\n*3660|### IR-67 — wave-battery gap: a `-p spt --bins` leg compiles bin targets as harnesses and runs ZERO integration/e2e tests, so batteries that lean on it carry silent no-coverage legs\n 3661|\n*3662|- **Status:** BUILT — remedy applied across the IO-PARSER #22 milestone (2026-08-27/28): every\n 3663|  wave battery named explicit `-p spt --test <suite>` e2e legs beside the `--bins` unit leg\n 3664|  (GW1..GW5 evidence), every builder evidence report carried a named real e2e per the dispatch\n 3665|  template, and the one filter mistake (a `--test` name not matching its file) REFUSED loudly\n...\n 3681|\n*3682|### IR-68 — PSYCHE_INGEST_FAIL cause class unproven: git index.lock did NOT reproduce the ingest failure it was blamed for\n 3683|\n*3684|- **Status:** OPEN, investigation-shaped · **Origin:** todlando measurement at the W2 int-leg rig\n 3685|  (IO-PARSER #22, PR #163 at `769fb0a9`, 2026-08-27), reported measure-first; filed by doyle.\n 3686|- **The contradiction:** the six silent `PSYCHE_INGEST_FAIL:todlando` lines observed at the\n 3687|  drop-dir probe (2026-08-25) were attributed to shared-checkout git `index.lock` contention. The\n...\n 3709|\n*3710|### IR-69 — inherited stderr tokens can tear between format fragments; 26 test consumers parse that surface as structured truth\n 3711|\n*3712|- **Status:** OPEN for the #243 residual population and anchored-consumer work. The original\n 3713|  product remedy LANDED at `ec6da9b0`, as recorded in this entry's later amendment; it is not\n 3714|  still parked awaiting assembly. Releases#241 retains its original lane evidence in comment\n 3715|  5461613480. This entry is the exposure map and census discipline; residual conversion,\n...\n 3801|\n*3802|### IR-70 — a hand-built `IoBus` silently omitted later sinks while every gate stayed green\n 3803|\n*3804|- **Status:** OPEN, remedy unscheduled; the v0.65.0 respin fixed the witnessed call site on PR #173.\n 3805|  This entry owns the recurrence class, not that shipped correction. · **Origin:** releases#234,\n 3806|  commit `c5459795167`, CONDUIT #236 respin.\n 3807|- **Mechanism:** `publish_commune_io` constructed `IoBus` itself and registered only the sink it\n...\n 3828|\n*3829|### IR-71 — controller-seat release has no persisted breadcrumb, so tests cannot distinguish propagation lag from a missing detach\n 3830|\n*3831|- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\n 3832|  `er_brief_once_per_session_e2e` intermittent, classified test-side and fixed on PR #174.\n 3833|- **What/why:** killing rc1 reaps the controller process, but the broker is another process and\n 3834|  notices the socket close later. On that detach edge it clears `driven_by` and `controlled` in\n...\n 3852|\n*3853|### IR-72 — no product read verb surfaces which process holds a perch or controller seat\n 3854|\n*3855|- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\n 3856|  two-host RCA and PR #174 (`70c1a303`), corrected by doyle after IR-18 and daemon-status were\n 3857|  ruled out as different classes.\n 3858|- **Source-verified boundary:** the holder identity already exists in durable/internal records\n...\n 3886|\n*3887|### IR-73 — ci.yml and release.yml still read the free-space floor PRE-checkout (literal-first sites off the golden path); and any job's floor is stale by its last heavy step\n 3888|\n*3889|- **Status:** CLOSED / BUILT — source reconciliation 2026-09-11 at `e5a2fed9`: all five\n 3890|  `ci.yml` sites and all three `release.yml` sites now read after checkout, with IR-73 comments;\n 3891|  `golden.yml` has both docs-floor rereads. IR-86 records the docs reread's live catch.\n 3892|  The original two halves below are implemented; capacity sizing and docs dependency coupling\n...\n 3910|\n*3911|### IR-74 — kitsubito holds 21,643 /tmp endpoint homes: box-side accumulation nothing bounds or measures\n 3912|\n*3913|- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep; measurement by\n 3914|  hertz (2026-08-29). · **Origin:** rig work on kitsubito found `/tmp` carrying 21,643 endpoint\n 3915|  homes — per-run spt homes that outlive their runs.\n 3916|- **What/why:** sibling of the [[IR-31]]/[[IR-59]]/[[IR-64]] family (box accumulation the\n...\n 3924|\n*3925|### IR-75 — traceable-reqs is not installed on kitsubito, so every Linux gate driver's treqs leg exits 127 (vacuous, wrapper-green shape)\n 3926|\n*3927|- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep (deployah\n 3928|  co-flagged at intake). · **Origin:** ASM-241 Linux battery — `ASM_treqs.exit` = 127, raw\n 3929|  `env: 'traceable-reqs': No such file or directory`; leg vacuous, covered that day by the\n 3930|  Windows treqs = 0 at the identical tree (treqs is a platform-independent text scan).\n...\n 3939|\n*3940|### IR-76 — hfenduleam is the golden Windows runner AND the builders' box: a local workspace nextest fully contained a golden Phase A and manufactured a load-timing red, and the job-start census cannot see it\n 3941|\n*3942|- **Status:** OPEN, filed by doyle 2026-09-06 during v0.67.1 golden triage (run 34017906638\n 3943|  att2). · **Origin:** the Windows Phase A red on\n 3944|  `spt-store::wtlock_two_process_int two_processes_commit_into_one_worktree_without_failing`\n 3945|  (B hit the 10 s worktree-lock bound while A's six serial commits took 13.5 s; 12 other\n...\n 3983|\n*3984|### IR-77 — nothing stamps the interval between a daemon child's spawn and the brain's first log line, so a readiness-deadline red cannot say WHERE the time went\n 3985|\n*3986|- **Status:** OPEN, filed by hertz 2026-09-07 from the W1 #249 kitsubito battery at the gated\n 3987|  sha `8d980fdf`; doyle-ruled at filing to be a register entry rather than a lane rider. ·\n 3988|  **Origin:** FLAKE-LEDGER `resident_service_e2e` :453 PRECONDITION (53 s) and\n 3989|  `resume_no_control_steal_e2e` (46 s), co-victims of ONE window — nextest exit 100, ONE\n...\n 4015|\n*4016|### IR-78 — `SPT_TEST_EPHEMERAL_ADVISORY_PORTS` silently overrides an explicitly set `SPT_DOCS_PORT`\n 4017|\n*4018|- **Status:** OPEN, filed by hertz 2026-09-07, MEASURED by doyle the same night on his W2\n 4019|  field pair (both boxes). · **Origin:** the 5474 rig-hygiene sweep in\n 4020|  `test/rig-advisory-ports-and-heavy-class`, which sets the rig flag at 37 `spt daemon run`\n 4021|  spawn sites.\n...\n 4043|\n*4044|### IR-79 — 22 of the 31 rig binaries leak their daemon tree on a failing assert: teardown is a statement, not a guard\n 4045|\n*4046|- **Status:** OPEN, filed by hertz 2026-09-07 on doyle's dispatch during PR #198's CI window,\n 4047|  from todlando's red 6 (a stale same-port daemon from his own previous run answering the next\n 4048|  one). · **Origin:** PR #198 moved 31 rigs to `SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1`. Under an\n 4049|  ephemeral port a leaked daemon can no longer ANSWER the next run, so that PR is right as it\n...\n 4124|\n*4125|### IR-80 — five leaky cells on ONE module (`brainproc` / `supervise_brain`), Windows only: a candidate PRODUCT leak on the promotion/rollback path, or a cluster of names — nobody has looked yet\n 4126|\n*4127|- **Status:** OPEN for the residual population, not an undiagnosed five-name product claim.\n 4128|  Later amendments identify the brainproc shell-wrapper fixture mechanism and distinguish\n 4129|  production's direct spawn; they do not classify all 12 union members. Historical opening\n 4130|  hypotheses below are not current causal conclusions. Filed by hertz 2026-09-07 07:40Z on\n...\n 4406|\n*4407|### IR-81 — a process kill can be written scoped or machine-wide, and nothing makes the scoped form the only reachable one: both codebases carry the right pattern beside the wrong one\n 4408|\n*4409|- **Status:** OPEN, drafted by hertz 2026-09-07 08:38Z on doyle's dispatch (08:36Z), from the\n 4410|  fleet-daemon death on hfenduleam at 08:03:15Z ([[RCA-FLEET-DAEMON-14444]], cause still UNNAMED).\n 4411|  Census body: `docs/PID-KILL-CENSUS.md`. · **Origin:** doyle asked which sites kill a REMEMBERED\n 4412|  pid without re-verifying identity AT KILL TIME. The census answered that, and then answered a\n...\n 4531|\n*4532|### IR-82 — a daemon death leaves NO record of who died: autostart decides on a socket ping, says \"no daemon\", and the successor overwrites the only handle on the corpse\n 4533|\n*4534|- **Status:** RULED 2026-09-07 11:07Z (doyle), drafted by hertz 11:04Z on doyle's dispatch (11:03Z: *\"the autostart\n 4535|  death-cause item is an IR, not a board item — mint it IR-82 in your thin PR\"*). Register on main\n 4536|  ends at IR-78; 79/80/81 are drafts in the same PR. · **Origin:** the fleet-daemon death on\n 4537|  hfenduleam at 08:03:14.87Z ([[RCA-FLEET-DAEMON-14444]]) whose cause is **still UNNAMED after a day\n...\n 4637|\n*4638|### IR-83 — a two-host rig addressed over the tailnet cannot receive INBOUND on Windows, and the whole rig population had only ever run the admitted direction\n 4639|\n*4640|- **Status:** OPEN, minted by hertz 2026-09-07 11:41Z on doyle's dispatch (11:40Z). **Provenance: the\n 4641|  mechanism below is DOYLE'S measurement, not mine** — eight probe arms, each with sender, listener\n 4642|  and output file, recorded in `GATE-W2-272-CHECKLIST.md` rows 11:36Z–11:39Z. I am off cargo on both\n 4643|  boxes and have re-measured none of it; this entry is the register form of his finding plus the\n...\n 4774|\n*4775|### IR-84 — the one `PUMP_PEER_FAIL` arm the rigs actually fire was the only one carrying no clock, so the stall that produced it could be counted but never timed\n 4776|\n*4777|- **Status:** OPEN, filed by hertz 2026-09-09 with the instrument that closes its first half. ·\n 4778|  **Origin:** the 65 s two-host helper stall (design written before the run,\n 4779|  `docs/design/RIDER-65S-DESIGN.md`). The number was branch-claimed 2026-09-08 by name only — IR-85\n 4780|  records that it carried no entry text in any register file in any worktree — and this is that text.\n...\n 4824|  stamps, so the fifth site added cannot be born silent.\n*4825|### IR-85 — the Windows self-hosted box runs its fs-heavy tests 3-4x slower than a week ago; two CI wall clocks were sized for the old box, and a red run kept hiding it\n 4826|\n*4827|- **Status:** OPEN, filed by hertz 2026-09-09 at the #272/v0.68.0 golden r3/r4 arc, on doyle's\n 4828|  dispatch. Number ruled by doyle from his own census of main@`a2f335f8` (register ended at IR-83;\n 4829|  IR-84 was branch-claimed by name only, with no entry text in any register file in any worktree —\n 4830|  that gap is now closed: **IR-84 was filed 2026-09-09 in PR #213**, so this sentence records the\n...\n 4984|\n*4985|### IR-86 — golden's 32 GiB floor is BELOW the measured 67.4 GiB Windows suite footprint, so a start floor passes a box that cannot finish\n 4986|\n*4987|- **Status:** OPEN, filed by doyle 2026-09-08 at the #272/v0.68.0 golden r2 triage. · **Origin:**\n 4988|  run 34262154550 @ `25e60015` (shaped on `e4444413`), Windows test job 102182665033: every product\n 4989|  step green (Phase A 3346/3346, Phase B 234/234, Summary 2, FAIL 0), the ONLY reds were the two\n 4990|  in-job floor gates. `FLOOR_START` 97,649,786,880 B PASS at 18:47:23Z -> `FLOOR_DOCS`\n...\n 5023|\n*5024|### IR-87 — two-host ceremony halves are INDEPENDENT jobs on DIFFERENT runners (A Windows/hfenduleam, B Linux/kitsubito); B's 900 s budget runs on B's own clock, so any older queued Windows job starves A and reds B deterministically, and the panic text blames pairing\n 5025|\n*5026|- **Status:** OPEN, filed by doyle 2026-09-08 at the #272 golden r2 triage. · **Origin:**\n 5027|  run 34262154550, twohost-b job 102207296960 (log 81,692 B, sha256 67403f04…8030): role B built,\n 5028|  rostered, polled PAIR_MEET_UP every 30 s from 19:34:30Z, and hit the rig_wait barrier\n 5029|  \"pairing: A rostered via the daemon-hosted responder\" at its 900 s deadline 19:49:17Z\n...\n 5076|\n*5077|### IR-88 — `pool-release` via `cargo run -p xtask` REBUILDS xtask INTO the pool it is releasing, so a reaped pool regrows ~2.8 GB in silence\n 5078|\n*5079|- **Status:** OPEN, filed by doyle 2026-09-08 from hertz's reap report (20:00Z) during the #272\n 5080|  golden r2 repair. · **Origin:** hertz reaped hertz-lane4 / hertz-repin / hertz-percell-id target\n 5081|  subtrees (Length-sum upper bounds 68.16 / 47.11 / 8.79 GB) and then ran `cargo run -p xtask --\n 5082|  pool-release …` from each worktree: cargo rebuilt xtask into the just-reaped `target/` (2.8 GB\n...\n 5105|\n*5106|### IR-89 — hfenduleam's Windows Firewall drops cold inbound UDP to the runner-built test exes, so the two-host rig's first B→A claim (W2 helper) reds for its whole 900 s budget and the panic blames A\n 5107|\n*5108|- **Status:** BOX HALF **APPLIED** 2026-09-08; WORKFLOW HALF **BUILT** 2026-09-09 — PR #211\n 5109|  (`9b96d7e7` + this amendment), **LANDED, exact golden-step acceptance unreconciled**.\n 5110|  Subsequent goldens have run: \"until the next golden\" is no longer a future trigger.\n 5111|  This sweep does not infer probe execution from a run's existence or overall conclusion;\n...\n 5261|\n*5262|### IR-90 — a full disk on the self-hosted box reds a rig as a PRODUCT refusal, not a build error, and no rig or gate records the free space that would falsify it\n 5263|\n*5264|- **Status:** OPEN, filed by hertz 2026-09-09 from the disk-full incident on hfenduleam. ·\n 5265|  **Origin:** the IR-85 discriminator lane's head arm, killed by the volume rather than by the code\n 5266|  under test.\n 5267|- **Symptom:** `spt-daemon::sync concurrent_writes_reconcile_on_elected_node_and_converge` FAILED at\n...\n 5350|\n*5351|### IR-91 — 561 untracked files sat at the repo root, 18 of them cited by tracked files, and the census that classified them used a corpus that made the discriminator invisible\n 5352|\n*5353|- **Status:** CLOSED by the lane that filed it (the root-scratch classify PR), hertz 2026-09-09 on\n 5354|  doyle's census and rulings. · **Origin:** the `.spt/` ignore lane (PR #212) named 561 untracked\n 5355|  root files as explicitly out of scope; this is that half.\n 5356|- **The population, measured at `2037bcb8`:** `git status --porcelain --untracked-files=all` = **561\n...\n 5404|\n*5405|### IR-92 — the message that WAKES an idle spt-hosted endpoint rides a delivery leg that never publishes MSG_IN, so a woken agent's own funnel holds none of the messages that woke it\n 5406|\n*5407|- **Status:** OPEN — filed doyle 2026-09-09 from hertz's census, probe and proposed text (his by\n 5408|  role; the recorder read and the REQ reading are doyle's). Fix lane unassigned: product change in\n 5409|  `spt-daemon` (todlando), test-side legs (hertz). · **Origin:** a 22:35Z empty `<msg from=\"hertz\"/>`\n 5410|  turn trigger after the #292 daemon restart, chased for its body; the body was in a spill file, and\n...\n 5536|\n*5537|### IR-93 — no PDB ships beside the installed `spt` binary, so the one non-invasive read of a wedged production daemon comes back without a single named frame\n 5538|\n*5539|- **Status:** OPEN, filed by doyle 2026-09-10. **The number was reserved by NAME on 2026-09-09** at\n 5540|  the #293 mechanism read (\"PDB ask -> IR-93 at next sweep\") and this entry closes that claim — a\n 5541|  name-only IR with no entry text is the exact gap [[IR-85]]'s status line had to spend a paragraph\n 5542|  explaining about IR-84, and it is not being left open a second time. · **Origin:** the #293 pump\n...\n 5565|\n*5566|### IR-94 — xtask's brainread deadline gate cannot SEE `serve_sync`: its registry is three hand-listed files and its predicate is a name shape, so a stream server outside both got the reply form and the gate stayed green\n 5567|\n*5568|- **Status:** OPEN, filed by doyle 2026-09-10 at the releases#294 / v0.69.0 golden RED triage. **This\n 5569|  is an INDEPENDENT gate finding, not the cause of that red** — it was found while reading the\n 5570|  milestone's diff and stands whatever Finding 1 turns out to be. · **Origin:**\n 5571|  `xtask/src/brainread.rs`, new this milestone (the #293 fix's zero-call-site guard).\n...\n 5595|\n*5596|### IR-95 — a burned polling budget names WHAT it wanted and never HOW LONG it waited, so no run, green or red, can say how close it came\n 5597|\n*5598|- **Status:** OPEN, filed by doyle 2026-09-10 at the releases#294 golden RED, where it cost this\n 5599|  triage most of a morning and four agents. · **Origin:** the two Windows Phase A failures at\n 5600|  `a9e786b2`, both polling budgets burned rather than value mismatches.\n 5601|- **The two sites, read at source.** They are not even the same KIND of budget, which is the first\n...\n 5850|\n*5851|### IR-96 — the `daemon_stop_convoy_e2e` API-storm cell fails 3-of-3 under the HEAVY suite at the diagnostic tree while passing at the candidate in golden CI, and nothing yet separates instrumentation from box from product\n 5852|\n*5853|- **Status:** OPEN, **cause-unclassified** (todlando's and hertz's stipulation, adopted verbatim — a\n 5854|  triage placement here is NOT a finding of non-defect).\n 5855|- **Origin:** releases#294 / v0.69.0 Arm B, 2026-09-10, deployah executing at diagnostic tree\n 5856|  `ed8ecd94` (= candidate `a9e786b2` + the unlanded sync instrumentation, never merged).\n...\n 5874|\n*5875|### IR-97 — a suite that leaks a fixed cohort of child processes per invocation makes consecutive runs non-comparable, and the between-run accounting the protocol required was not enforced\n 5876|\n*5877|- **Status:** OPEN. **Protocol deviation** (hertz's framing, and it is stronger than \"confounder\":\n 5878|  the protocol ALREADY required between-run accounting — execution did not enforce it, so the fix is\n 5879|  enforcement, not a limitations paragraph).\n 5880|- **Origin:** releases#294 Arm B, 2026-09-10. Derived by doyle from deployah's preserved"}],"details":{"scopePath":"docs/INFRA-REGISTER.md","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\INFRA-REGISTER.md","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":93,"fileCount":1,"files":["docs/INFRA-REGISTER.md"],"fileMatches":[{"path":"docs/INFRA-REGISTER.md","count":93}],"truncated":false,"displayContent":" 3021│\n*3022│### IR-55 — the `spt --bins` suite wedges partway through on leaked `findstr .` PTY children; the tests at the frontier are casualties, not culprits\n 3023│\n*3024│- **Status:** OPEN, **ARMED-FOR-CAPTURE**, owned by **hertz**. Test/rig defect by the dispatch\n 3025│  split (test/CI rework is never the product builder's). Filed by doyle 2026-08-22 from the\n 3026│  TURNKEY #212 W3 gate on releases#213.\n 3027│- **CORRECTED BY REPLACEMENT the same day.** This entry first named\n     │...\n 3063│  shape as `exit-code-after-a-pipe-is-the-tails`.\n*3064│- **Trigger condition (ripe):** any milestone whose gate wants an unfiltered `spt --bins` sweep,\n 3065│  which is every one of them. Ripe now.\n 3066│- **REMEDY, MEASURED 2026-08-22 and it changes this entry's urgency:** the same 653 tests under\n 3067│  `cargo nextest run -p spt --bins --no-fail-fast` complete in **22.2 seconds, 653 passed, 0\n     │...\n 3147│\n*3148│### IR-56 — `pool-claim` harvests lane identity from CWD, not from `--pool`; a claim run from the wrong tree writes a WRONG RECORD with a success message\n 3149│\n*3150│- **Status:** BUILT 2026-08-24 for the SIGNET #218 golden batch on\n 3151│  `fix/ir56-pool-claim-cwd`, owned by **hertz**. Tooling/rig defect by the dispatch split. Filed by\n 3152│  doyle 2026-08-22 from todlando's TURNKEY #212 W4 Lane 1 field instance — the first confirmation\n 3153│  of the IR-42 mechanism from a LANE rather than from a source read.\n     │...\n 3173│  `branch` name the lane: the success line carries the record, so the check costs nothing.\n*3174│- **Trigger condition:** ripe now — it is a doc/UX fix on a verb we run every lane. Ripest alongside\n 3175│  any other `xtask` pool-verb touch.\n 3176│- **Size guess:** small. Either make the verb REFUSE when cwd is not inside the tree containing\n 3177│  `--pool` (loud, and it cannot be wrong), or print the harvested identity as a distinct confirmed\n     │...\n 3188│\n*3189│### IR-57 — an assembly pick's conflict resolution can silently DROP lines, and every gate run at assembly time is blind to it\n 3190│\n*3191│- **Status:** OPEN, owned by **doyle** (gater craft, not a code defect — no lane to dispatch).\n 3192│  Filed 2026-08-22 from doyle's own defect on the TURNKEY #212 assembly head.\n 3193│- **What happened:** assembly head `5cce533d` **did not compile**, and was carried across a session\n 3194│  boundary as a ready head with \"treqs exit 0\" attached to it. `crates/spt-store/src/access.rs` had\n     │...\n 3242│  produced the verdict classes in the order the entry predicts.\n*3243│- **Trigger condition:** ripe at the next assembly — this is procedure, and its cost is one command\n 3244│  per pick.\n 3245│- **Size guess:** small as a scripted check in `xtask` (fidelity audit over a pick range); zero as\n 3246│  discipline, which is how it is being applied now.\n 3247│\n*3248│### IR-58 — a `[[bin]]` grep is not a census: cargo AUTODISCOVERS `src/bin/*.rs` targets, and a hand-built bin list produced a confident false \"this bin does not exist\"\n 3249│\n*3250│- **Status:** OPEN, unowned. Filed by doyle 2026-08-22; **its original filing was WRONG and is\n 3251│  retracted in full below.** The entry is kept because the way it was wrong is the finding.\n 3252│- **RETRACTED CLAIM, stated plainly so no reader acts on it:** this entry first said that\n 3253│  `crates/spt/Cargo.toml:18-21` and `crates/spt/src/cli.rs:30355` forbid a bin-name collision with\n     │...\n 3277│  answer about a set it never fully saw.\n*3278│- **Trigger condition:** ripe on any `xtask` check work — a duplicate-bin-name check over cargo's\n 3279│  target enumeration (NOT over manifest stanzas) is a handful of lines and cannot go stale.\n 3280│- **Size guess:** small. The prose fix originally proposed here is WITHDRAWN — there was nothing\n 3281│  wrong with the prose.\n 3282│\n*3283│### IR-59 — pool arithmetic: this box holds TWO cold pools, not four; and a build that exhausts the volume reds as a LINKER defect that names no disk\n 3284│\n*3285│- **Status:** OPEN, unowned — it is arithmetic and discipline, not a code lane. Filed by doyle\n 3286│  2026-08-22 from a live disk-floor abort during the TURNKEY #212 W4 gate; footprint figures measured\n 3287│  by todlando the same hour.\n 3288│- **v0.69.0 release close, 2026-09-11 (deployah, source record releases#294 comment\n     │...\n 3411│  rides with [[IR-57]]'s scripted pick-fidelity audit as the next milestone's two tooling riders.\n*3412│- **Trigger condition:** ripe now for the log-the-floor half (it rides any gate-script or CI touch);\n 3413│  the arithmetic is discipline and applies immediately.\n 3414│- **Size guess:** small — one line in each rig/gate preflight to record free space alongside the\n 3415│  existing floor check.\n 3416│\n*3417│### IR-60 — a wrapper that CAPTURES a leg's exit status ends with the capture, so the wrapper's own status is the capture's, not the leg's\n 3418│\n*3419│- **Status:** OPEN, unowned — script-shape discipline, not a code lane. Filed by doyle 2026-08-22\n 3420│  during the TURNKEY #212 W5 lane; mechanism measured by todlando, who reported it first as a\n 3421│  possible harness misreport and then RETRACTED that reading himself on a minimal probe.\n 3422│- **v0.69.0 recurrence, 2026-09-11 (deployah, own withdrawal):** `NEXTEST_EXIT=0` and the task\n     │...\n 3461│  file.\n*3462│- **Trigger condition:** ripe now — it rides the next gate-script touch, and the gate scripts in this\n 3463│  milestone already write per-leg exit files, which is what makes this discipline rather than debt.\n 3464│- **Size guess:** small — a convention line in the gate-script preamble; no product code.\n 3465│\n*3466│### IR-61 — spacerun's test-module skip carries a SECOND literal tracker; the two answers can drift, and today only a cell stands between them\n 3467│\n*3468│- **Status:** OPEN, unowned, accepted-with-mitigation. Filed by doyle 2026-08-22 at the TURNKEY #212\n 3469│  head gate, as the named residual of the latch repair (the repair itself rides the milestone).\n 3470│- **What the debt is.** `crates/xtask/src/spacerun.rs` now skips a column-0 `#[cfg(test)]` module by\n 3471│  BRACE DEPTH and resumes after its close, rather than latching the scan to end-of-file. Counting\n     │...\n 3493│  scanner accumulating special cases.\n*3494│- **Trigger condition:** the next SUBSTANTIVE change to spacerun's scanning — any new skip, any new\n 3495│  literal form, any change to either tracker. At that point unify, rather than adding a third answer.\n 3496│- **Size guess:** small to medium — one continuous literal-state walk serving both the render pass\n 3497│  and the skip, with the existing corpus and brace cells as the regression net.\n 3498│\n*3499│### IR-62 — an e2e daemon binds well-known ports and collides with the resident fleet on shared runners\n 3500│\n 3501│Filed 2026-08-23 (doyle), from the #212 r2 golden's Windows Phase A red — one witnessed\n 3502│instance, mechanism verified from the run's own capture, filed on the mechanism per the\n     │...\n 3539│\n*3540│### IR-63 — suite-mix sweeps leak job-escaped autostart daemons that LOCK the pool's spt.exe; and the same box conditions manufacture one random victim per sweep\n 3541│\n*3542│- **Status:** OPEN, mitigated-by-rig-step — the reap is adopted discipline, not yet construction.\n 3543│  Filed by doyle 2026-08-24 at the SIGNET #218 gates; first measured by todlando the same day\n 3544│  (his W1 build: four reap rounds of 2, 8, 1, 1 processes, count-by-path stated each round).\n 3545│- **Mechanism, two faces of one condition:** (1) e2e sweeps that exercise autostart leave\n     │...\n 3574│  this entry (brief cites IR-7/17/20/34/35/63); leaves the register when that lane lands.\n*3575│- **Trigger condition:** next rig/gate-script construction touch, or the first golden red that\n 3576│  classifies to face (1).\n 3577│- **Size guess:** small-medium — one wrapper seam plus adopting it in the gate/lane scripts.\n 3578│\n*3579│### IR-64 — HFENDULEAM's disk floor is set by non-CI bulk: ~845 GB of operator payload leaves the golden box ~2 GB of slack against its own 32 GB preflight\n 3580│\n*3581│- **Status:** OPEN · **Origin:** doyle, v0.63.0 close sweep 2026-08-26; mechanism first measured\n 3582│  at the FIELD-SEAL golden window (deployah's IR-31 fifth addendum carries the POOL side of the\n 3583│  same event by agreed division — this entry is the OTHER reservoir, deliberately not his).\n 3584│- **Mechanism:** the 1.86 TB C: carries ~614 GB Steam + ~230 GB Downloads (operator payload, not\n     │...\n 3600│\n*3601│### IR-65 — kitsubito kernel-audit backpressure: a tailscale-snap AppArmor denial storm + no auditd turned the default audit backlog into a CI-wide stall amplifier (REMEDIATED AT BOX; re-check triggers named)\n 3602│\n*3603│- **Status:** REMEDIATED-AT-BOX 2026-08-25 (doyle, operator-authorized root — ruling pinned\n 3604│  releases#225 comment 5418800776); entry stays OPEN as the re-check record because the storm\n 3605│  SOURCE persists and two named events can silently revert the fix.\n 3606│- **Mechanism:** `snap.tailscale.tailscaled` (1.92.5) polls /proc and takes an AppArmor\n     │...\n 3626│\n*3627│### IR-66 — first-chunk-needle test class: two latent members remain after the v0.63.0 fix (attach.rs:561, :672)\n 3628│\n*3629│- **Status:** CLOSED / BUILT — release-close reconciliation 2026-09-11. The WEBSERVE JIT already\n 3630│  ruled this satisfied; source at `e5a2fed9` retains both delayed needles. Closure uses the\n 3631│  recorded gates below, not v0.69.0's unrelated green receipts. Hertz rider PR #161, landed ff at\n 3632│  `d04b922d` (2026-08-27, IO-PARSER #22\n     │...\n 3659│\n*3660│### IR-67 — wave-battery gap: a `-p spt --bins` leg compiles bin targets as harnesses and runs ZERO integration/e2e tests, so batteries that lean on it carry silent no-coverage legs\n 3661│\n*3662│- **Status:** BUILT — remedy applied across the IO-PARSER #22 milestone (2026-08-27/28): every\n 3663│  wave battery named explicit `-p spt --test <suite>` e2e legs beside the `--bins` unit leg\n 3664│  (GW1..GW5 evidence), every builder evidence report carried a named real e2e per the dispatch\n 3665│  template, and the one filter mistake (a `--test` name not matching its file) REFUSED loudly\n     │...\n 3681│\n*3682│### IR-68 — PSYCHE_INGEST_FAIL cause class unproven: git index.lock did NOT reproduce the ingest failure it was blamed for\n 3683│\n*3684│- **Status:** OPEN, investigation-shaped · **Origin:** todlando measurement at the W2 int-leg rig\n 3685│  (IO-PARSER #22, PR #163 at `769fb0a9`, 2026-08-27), reported measure-first; filed by doyle.\n 3686│- **The contradiction:** the six silent `PSYCHE_INGEST_FAIL:todlando` lines observed at the\n 3687│  drop-dir probe (2026-08-25) were attributed to shared-checkout git `index.lock` contention. The\n     │...\n 3709│\n*3710│### IR-69 — inherited stderr tokens can tear between format fragments; 26 test consumers parse that surface as structured truth\n 3711│\n*3712│- **Status:** OPEN for the #243 residual population and anchored-consumer work. The original\n 3713│  product remedy LANDED at `ec6da9b0`, as recorded in this entry's later amendment; it is not\n 3714│  still parked awaiting assembly. Releases#241 retains its original lane evidence in comment\n 3715│  5461613480. This entry is the exposure map and census discipline; residual conversion,\n     │...\n 3801│\n*3802│### IR-70 — a hand-built `IoBus` silently omitted later sinks while every gate stayed green\n 3803│\n*3804│- **Status:** OPEN, remedy unscheduled; the v0.65.0 respin fixed the witnessed call site on PR #173.\n 3805│  This entry owns the recurrence class, not that shipped correction. · **Origin:** releases#234,\n 3806│  commit `c5459795167`, CONDUIT #236 respin.\n 3807│- **Mechanism:** `publish_commune_io` constructed `IoBus` itself and registered only the sink it\n     │...\n 3828│\n*3829│### IR-71 — controller-seat release has no persisted breadcrumb, so tests cannot distinguish propagation lag from a missing detach\n 3830│\n*3831│- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\n 3832│  `er_brief_once_per_session_e2e` intermittent, classified test-side and fixed on PR #174.\n 3833│- **What/why:** killing rc1 reaps the controller process, but the broker is another process and\n 3834│  notices the socket close later. On that detach edge it clears `driven_by` and `controlled` in\n     │...\n 3852│\n*3853│### IR-72 — no product read verb surfaces which process holds a perch or controller seat\n 3854│\n*3855│- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\n 3856│  two-host RCA and PR #174 (`70c1a303`), corrected by doyle after IR-18 and daemon-status were\n 3857│  ruled out as different classes.\n 3858│- **Source-verified boundary:** the holder identity already exists in durable/internal records\n     │...\n 3886│\n*3887│### IR-73 — ci.yml and release.yml still read the free-space floor PRE-checkout (literal-first sites off the golden path); and any job's floor is stale by its last heavy step\n 3888│\n*3889│- **Status:** CLOSED / BUILT — source reconciliation 2026-09-11 at `e5a2fed9`: all five\n 3890│  `ci.yml` sites and all three `release.yml` sites now read after checkout, with IR-73 comments;\n 3891│  `golden.yml` has both docs-floor rereads. IR-86 records the docs reread's live catch.\n 3892│  The original two halves below are implemented; capacity sizing and docs dependency coupling\n     │...\n 3910│\n*3911│### IR-74 — kitsubito holds 21,643 /tmp endpoint homes: box-side accumulation nothing bounds or measures\n 3912│\n*3913│- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep; measurement by\n 3914│  hertz (2026-08-29). · **Origin:** rig work on kitsubito found `/tmp` carrying 21,643 endpoint\n 3915│  homes — per-run spt homes that outlive their runs.\n 3916│- **What/why:** sibling of the [[IR-31]]/[[IR-59]]/[[IR-64]] family (box accumulation the\n     │...\n 3924│\n*3925│### IR-75 — traceable-reqs is not installed on kitsubito, so every Linux gate driver's treqs leg exits 127 (vacuous, wrapper-green shape)\n 3926│\n*3927│- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep (deployah\n 3928│  co-flagged at intake). · **Origin:** ASM-241 Linux battery — `ASM_treqs.exit` = 127, raw\n 3929│  `env: 'traceable-reqs': No such file or directory`; leg vacuous, covered that day by the\n 3930│  Windows treqs = 0 at the identical tree (treqs is a platform-independent text scan).\n     │...\n 3939│\n*3940│### IR-76 — hfenduleam is the golden Windows runner AND the builders' box: a local workspace nextest fully contained a golden Phase A and manufactured a load-timing red, and the job-start census cannot see it\n 3941│\n*3942│- **Status:** OPEN, filed by doyle 2026-09-06 during v0.67.1 golden triage (run 34017906638\n 3943│  att2). · **Origin:** the Windows Phase A red on\n 3944│  `spt-store::wtlock_two_process_int two_processes_commit_into_one_worktree_without_failing`\n 3945│  (B hit the 10 s worktree-lock bound while A's six serial commits took 13.5 s; 12 other\n     │...\n 3983│\n*3984│### IR-77 — nothing stamps the interval between a daemon child's spawn and the brain's first log line, so a readiness-deadline red cannot say WHERE the time went\n 3985│\n*3986│- **Status:** OPEN, filed by hertz 2026-09-07 from the W1 #249 kitsubito battery at the gated\n 3987│  sha `8d980fdf`; doyle-ruled at filing to be a register entry rather than a lane rider. ·\n 3988│  **Origin:** FLAKE-LEDGER `resident_service_e2e` :453 PRECONDITION (53 s) and\n 3989│  `resume_no_control_steal_e2e` (46 s), co-victims of ONE window — nextest exit 100, ONE\n     │...\n 4015│\n*4016│### IR-78 — `SPT_TEST_EPHEMERAL_ADVISORY_PORTS` silently overrides an explicitly set `SPT_DOCS_PORT`\n 4017│\n*4018│- **Status:** OPEN, filed by hertz 2026-09-07, MEASURED by doyle the same night on his W2\n 4019│  field pair (both boxes). · **Origin:** the 5474 rig-hygiene sweep in\n 4020│  `test/rig-advisory-ports-and-heavy-class`, which sets the rig flag at 37 `spt daemon run`\n 4021│  spawn sites.\n     │...\n 4043│\n*4044│### IR-79 — 22 of the 31 rig binaries leak their daemon tree on a failing assert: teardown is a statement, not a guard\n 4045│\n*4046│- **Status:** OPEN, filed by hertz 2026-09-07 on doyle's dispatch during PR #198's CI window,\n 4047│  from todlando's red 6 (a stale same-port daemon from his own previous run answering the next\n 4048│  one). · **Origin:** PR #198 moved 31 rigs to `SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1`. Under an\n 4049│  ephemeral port a leaked daemon can no longer ANSWER the next run, so that PR is right as it\n     │...\n 4124│\n*4125│### IR-80 — five leaky cells on ONE module (`brainproc` / `supervise_brain`), Windows only: a candidate PRODUCT leak on the promotion/rollback path, or a cluster of names — nobody has looked yet\n 4126│\n*4127│- **Status:** OPEN for the residual population, not an undiagnosed five-name product claim.\n 4128│  Later amendments identify the brainproc shell-wrapper fixture mechanism and distinguish\n 4129│  production's direct spawn; they do not classify all 12 union members. Historical opening\n 4130│  hypotheses below are not current causal conclusions. Filed by hertz 2026-09-07 07:40Z on\n     │...\n 4406│\n*4407│### IR-81 — a process kill can be written scoped or machine-wide, and nothing makes the scoped form the only reachable one: both codebases carry the right pattern beside the wrong one\n 4408│\n*4409│- **Status:** OPEN, drafted by hertz 2026-09-07 08:38Z on doyle's dispatch (08:36Z), from the\n 4410│  fleet-daemon death on hfenduleam at 08:03:15Z ([[RCA-FLEET-DAEMON-14444]], cause still UNNAMED).\n 4411│  Census body: `docs/PID-KILL-CENSUS.md`. · **Origin:** doyle asked which sites kill a REMEMBERED\n 4412│  pid without re-verifying identity AT KILL TIME. The census answered that, and then answered a\n     │...\n 4531│\n*4532│### IR-82 — a daemon death leaves NO record of who died: autostart decides on a socket ping, says \"no daemon\", and the successor overwrites the only handle on the corpse\n 4533│\n*4534│- **Status:** RULED 2026-09-07 11:07Z (doyle), drafted by hertz 11:04Z on doyle's dispatch (11:03Z: *\"the autostart\n 4535│  death-cause item is an IR, not a board item — mint it IR-82 in your thin PR\"*). Register on main\n 4536│  ends at IR-78; 79/80/81 are drafts in the same PR. · **Origin:** the fleet-daemon death on\n 4537│  hfenduleam at 08:03:14.87Z ([[RCA-FLEET-DAEMON-14444]]) whose cause is **still UNNAMED after a day\n     │...\n 4637│\n*4638│### IR-83 — a two-host rig addressed over the tailnet cannot receive INBOUND on Windows, and the whole rig population had only ever run the admitted direction\n 4639│\n*4640│- **Status:** OPEN, minted by hertz 2026-09-07 11:41Z on doyle's dispatch (11:40Z). **Provenance: the\n 4641│  mechanism below is DOYLE'S measurement, not mine** — eight probe arms, each with sender, listener\n 4642│  and output file, recorded in `GATE-W2-272-CHECKLIST.md` rows 11:36Z–11:39Z. I am off cargo on both\n 4643│  boxes and have re-measured none of it; this entry is the register form of his finding plus the\n     │...\n 4774│\n*4775│### IR-84 — the one `PUMP_PEER_FAIL` arm the rigs actually fire was the only one carrying no clock, so the stall that produced it could be counted but never timed\n 4776│\n*4777│- **Status:** OPEN, filed by hertz 2026-09-09 with the instrument that closes its first half. ·\n 4778│  **Origin:** the 65 s two-host helper stall (design written before the run,\n 4779│  `docs/design/RIDER-65S-DESIGN.md`). The number was branch-claimed 2026-09-08 by name only — IR-85\n 4780│  records that it carried no entry text in any register file in any worktree — and this is that text.\n     │...\n 4824│  stamps, so the fifth site added cannot be born silent.\n*4825│### IR-85 — the Windows self-hosted box runs its fs-heavy tests 3-4x slower than a week ago; two CI wall clocks were sized for the old box, and a red run kept hiding it\n 4826│\n*4827│- **Status:** OPEN, filed by hertz 2026-09-09 at the #272/v0.68.0 golden r3/r4 arc, on doyle's\n 4828│  dispatch. Number ruled by doyle from his own census of main@`a2f335f8` (register ended at IR-83;\n 4829│  IR-84 was branch-claimed by name only, with no entry text in any register file in any worktree —\n 4830│  that gap is now closed: **IR-84 was filed 2026-09-09 in PR #213**, so this sentence records the\n     │...\n 4984│\n*4985│### IR-86 — golden's 32 GiB floor is BELOW the measured 67.4 GiB Windows suite footprint, so a start floor passes a box that cannot finish\n 4986│\n*4987│- **Status:** OPEN, filed by doyle 2026-09-08 at the #272/v0.68.0 golden r2 triage. · **Origin:**\n 4988│  run 34262154550 @ `25e60015` (shaped on `e4444413`), Windows test job 102182665033: every product\n 4989│  step green (Phase A 3346/3346, Phase B 234/234, Summary 2, FAIL 0), the ONLY reds were the two\n 4990│  in-job floor gates. `FLOOR_START` 97,649,786,880 B PASS at 18:47:23Z -> `FLOOR_DOCS`\n     │...\n 5023│\n*5024│### IR-87 — two-host ceremony halves are INDEPENDENT jobs on DIFFERENT runners (A Windows/hfenduleam, B Linux/kitsubito); B's 900 s budget runs on B's own clock, so any older queued Windows job starves A and reds B deterministically, and the panic text blames pairing\n 5025│\n*5026│- **Status:** OPEN, filed by doyle 2026-09-08 at the #272 golden r2 triage. · **Origin:**\n 5027│  run 34262154550, twohost-b job 102207296960 (log 81,692 B, sha256 67403f04…8030): role B built,\n 5028│  rostered, polled PAIR_MEET_UP every 30 s from 19:34:30Z, and hit the rig_wait barrier\n 5029│  \"pairing: A rostered via the daemon-hosted responder\" at its 900 s deadline 19:49:17Z\n     │...\n 5076│\n*5077│### IR-88 — `pool-release` via `cargo run -p xtask` REBUILDS xtask INTO the pool it is releasing, so a reaped pool regrows ~2.8 GB in silence\n 5078│\n*5079│- **Status:** OPEN, filed by doyle 2026-09-08 from hertz's reap report (20:00Z) during the #272\n 5080│  golden r2 repair. · **Origin:** hertz reaped hertz-lane4 / hertz-repin / hertz-percell-id target\n 5081│  subtrees (Length-sum upper bounds 68.16 / 47.11 / 8.79 GB) and then ran `cargo run -p xtask --\n 5082│  pool-release …` from each worktree: cargo rebuilt xtask into the just-reaped `target/` (2.8 GB\n     │...\n 5105│\n*5106│### IR-89 — hfenduleam's Windows Firewall drops cold inbound UDP to the runner-built test exes, so the two-host rig's first B→A claim (W2 helper) reds for its whole 900 s budget and the panic blames A\n 5107│\n*5108│- **Status:** BOX HALF **APPLIED** 2026-09-08; WORKFLOW HALF **BUILT** 2026-09-09 — PR #211\n 5109│  (`9b96d7e7` + this amendment), **LANDED, exact golden-step acceptance unreconciled**.\n 5110│  Subsequent goldens have run: \"until the next golden\" is no longer a future trigger.\n 5111│  This sweep does not infer probe execution from a run's existence or overall conclusion;\n     │...\n 5261│\n*5262│### IR-90 — a full disk on the self-hosted box reds a rig as a PRODUCT refusal, not a build error, and no rig or gate records the free space that would falsify it\n 5263│\n*5264│- **Status:** OPEN, filed by hertz 2026-09-09 from the disk-full incident on hfenduleam. ·\n 5265│  **Origin:** the IR-85 discriminator lane's head arm, killed by the volume rather than by the code\n 5266│  under test.\n 5267│- **Symptom:** `spt-daemon::sync concurrent_writes_reconcile_on_elected_node_and_converge` FAILED at\n     │...\n 5350│\n*5351│### IR-91 — 561 untracked files sat at the repo root, 18 of them cited by tracked files, and the census that classified them used a corpus that made the discriminator invisible\n 5352│\n*5353│- **Status:** CLOSED by the lane that filed it (the root-scratch classify PR), hertz 2026-09-09 on\n 5354│  doyle's census and rulings. · **Origin:** the `.spt/` ignore lane (PR #212) named 561 untracked\n 5355│  root files as explicitly out of scope; this is that half.\n 5356│- **The population, measured at `2037bcb8`:** `git status --porcelain --untracked-files=all` = **561\n     │...\n 5404│\n*5405│### IR-92 — the message that WAKES an idle spt-hosted endpoint rides a delivery leg that never publishes MSG_IN, so a woken agent's own funnel holds none of the messages that woke it\n 5406│\n*5407│- **Status:** OPEN — filed doyle 2026-09-09 from hertz's census, probe and proposed text (his by\n 5408│  role; the recorder read and the REQ reading are doyle's). Fix lane unassigned: product change in\n 5409│  `spt-daemon` (todlando), test-side legs (hertz). · **Origin:** a 22:35Z empty `<msg from=\"hertz\"/>`\n 5410│  turn trigger after the #292 daemon restart, chased for its body; the body was in a spill file, and\n     │...\n 5536│\n*5537│### IR-93 — no PDB ships beside the installed `spt` binary, so the one non-invasive read of a wedged production daemon comes back without a single named frame\n 5538│\n*5539│- **Status:** OPEN, filed by doyle 2026-09-10. **The number was reserved by NAME on 2026-09-09** at\n 5540│  the #293 mechanism read (\"PDB ask -> IR-93 at next sweep\") and this entry closes that claim — a\n 5541│  name-only IR with no entry text is the exact gap [[IR-85]]'s status line had to spend a paragraph\n 5542│  explaining about IR-84, and it is not being left open a second time. · **Origin:** the #293 pump\n     │...\n 5565│\n*5566│### IR-94 — xtask's brainread deadline gate cannot SEE `serve_sync`: its registry is three hand-listed files and its predicate is a name shape, so a stream server outside both got the reply form and the gate stayed green\n 5567│\n*5568│- **Status:** OPEN, filed by doyle 2026-09-10 at the releases#294 / v0.69.0 golden RED triage. **This\n 5569│  is an INDEPENDENT gate finding, not the cause of that red** — it was found while reading the\n 5570│  milestone's diff and stands whatever Finding 1 turns out to be. · **Origin:**\n 5571│  `xtask/src/brainread.rs`, new this milestone (the #293 fix's zero-call-site guard).\n     │...\n 5595│\n*5596│### IR-95 — a burned polling budget names WHAT it wanted and never HOW LONG it waited, so no run, green or red, can say how close it came\n 5597│\n*5598│- **Status:** OPEN, filed by doyle 2026-09-10 at the releases#294 golden RED, where it cost this\n 5599│  triage most of a morning and four agents. · **Origin:** the two Windows Phase A failures at\n 5600│  `a9e786b2`, both polling budgets burned rather than value mismatches.\n 5601│- **The two sites, read at source.** They are not even the same KIND of budget, which is the first\n     │...\n 5850│\n*5851│### IR-96 — the `daemon_stop_convoy_e2e` API-storm cell fails 3-of-3 under the HEAVY suite at the diagnostic tree while passing at the candidate in golden CI, and nothing yet separates instrumentation from box from product\n 5852│\n*5853│- **Status:** OPEN, **cause-unclassified** (todlando's and hertz's stipulation, adopted verbatim — a\n 5854│  triage placement here is NOT a finding of non-defect).\n 5855│- **Origin:** releases#294 / v0.69.0 Arm B, 2026-09-10, deployah executing at diagnostic tree\n 5856│  `ed8ecd94` (= candidate `a9e786b2` + the unlanded sync instrumentation, never merged).\n     │...\n 5874│\n*5875│### IR-97 — a suite that leaks a fixed cohort of child processes per invocation makes consecutive runs non-comparable, and the between-run accounting the protocol required was not enforced\n 5876│\n*5877│- **Status:** OPEN. **Protocol deviation** (hertz's framing, and it is stronger than \"confounder\":\n 5878│  the protocol ALREADY required between-run accounting — execution did not enforce it, so the fix is\n 5879│  enforcement, not a limitations paragraph).\n 5880│- **Origin:** releases#294 Arm B, 2026-09-10. Derived by doyle from deployah's preserved"},"isError":false,"timestamp":1789107046649}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_73bJq0Nlh6GoECwR6W5oHBTe|fc_0330c101aa2c61dc016aa39b6afa9c87d192d0d1ff741f8bdc","toolName":"read","startedAt":"2026-09-11T06:10:53.415Z","args":{"path":"AGENTS.md"},"intent":"Reading project operating orientation"},"id":"333a763c","parentId":"0c58561b","timestamp":"2026-09-11T06:10:53.415Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_uL8BDte8MN9R7CWkRrplZGG3|fc_0330c101aa2c61dc016aa39b6afaac87d183265cb9b8470897","toolName":"read","startedAt":"2026-09-11T06:10:53.415Z","args":{"path":"docs/INFRA-REGISTER.md:3704-4124"},"intent":"Reading register middle segment"},"id":"ffe11925","parentId":"333a763c","timestamp":"2026-09-11T06:10:53.415Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_kk3urpa1WBGsg73Uhi2QlJtH|fc_0330c101aa2c61dc016aa39b6afab487d1ae68643a97fc7b45","toolName":"read","startedAt":"2026-09-11T06:10:53.415Z","args":{"path":"docs/INFRA-REGISTER.md:4125-4531"},"intent":"Reading register leak segment"},"id":"cdd34054","parentId":"ffe11925","timestamp":"2026-09-11T06:10:53.415Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_fINzFxXhDHrHmBrsvPle3852|fc_0330c101aa2c61dc016aa39b6afabc87d1be4bfb0aed5e170b","toolName":"read","startedAt":"2026-09-11T06:10:53.415Z","args":{"path":"docs/INFRA-REGISTER.md:4532-4984"},"intent":"Reading register observability segment"},"id":"99e6f65d","parentId":"cdd34054","timestamp":"2026-09-11T06:10:53.415Z"}
{"type":"message","id":"f252e228","parentId":"99e6f65d","timestamp":"2026-09-11T06:10:53.416Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_73bJq0Nlh6GoECwR6W5oHBTe|fc_0330c101aa2c61dc016aa39b6afa9c87d192d0d1ff741f8bdc","name":"read","arguments":{"i":"Reading project operating orientation","path":"AGENTS.md"},"intent":"Reading project operating orientation"},{"type":"toolCall","id":"call_uL8BDte8MN9R7CWkRrplZGG3|fc_0330c101aa2c61dc016aa39b6afaac87d183265cb9b8470897","name":"read","arguments":{"i":"Reading register middle segment","path":"docs/INFRA-REGISTER.md:3704-4124"},"intent":"Reading register middle segment"},{"type":"toolCall","id":"call_kk3urpa1WBGsg73Uhi2QlJtH|fc_0330c101aa2c61dc016aa39b6afab487d1ae68643a97fc7b45","name":"read","arguments":{"i":"Reading register leak segment","path":"docs/INFRA-REGISTER.md:4125-4531"},"intent":"Reading register leak segment"},{"type":"toolCall","id":"call_fINzFxXhDHrHmBrsvPle3852|fc_0330c101aa2c61dc016aa39b6afabc87d1be4bfb0aed5e170b","name":"read","arguments":{"i":"Reading register observability segment","path":"docs/INFRA-REGISTER.md:4532-4984"},"intent":"Reading register observability segment"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":17658,"output":139,"cacheRead":17152,"cacheWrite":0,"totalTokens":34949,"cost":{"input":0.17658000000000001,"output":0.0069500000000000004,"cacheRead":0.017152,"cacheWrite":0,"total":0.20068200000000003}},"stopReason":"toolUse","timestamp":1789107046662,"responseId":"resp_0330c101aa2c61dc016aa39b64ba8887d18950061f3277d5ec","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0330c101aa2c61dc016aa39b6afa9c87d192d0d1ff741f8bdc","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading project operating orientation\",\"path\":\"AGENTS.md\"}","call_id":"call_73bJq0Nlh6GoECwR6W5oHBTe","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b6afaac87d183265cb9b8470897","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading register middle segment\",\"path\":\"docs/INFRA-REGISTER.md:3704-4124\"}","call_id":"call_uL8BDte8MN9R7CWkRrplZGG3","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b6afab487d1ae68643a97fc7b45","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading register leak segment\",\"path\":\"docs/INFRA-REGISTER.md:4125-4531\"}","call_id":"call_kk3urpa1WBGsg73Uhi2QlJtH","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b6afabc87d1be4bfb0aed5e170b","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading register observability segment\",\"path\":\"docs/INFRA-REGISTER.md:4532-4984\"}","call_id":"call_fINzFxXhDHrHmBrsvPle3852","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}}]},"duration":6752.4539000000805,"ttft":6670.204200000502,"completedAt":1789107053414,"contextSnapshot":{"promptTokens":34810,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"message","id":"f8740ee2","parentId":"f252e228","timestamp":"2026-09-11T06:10:53.417Z","message":{"role":"toolResult","toolCallId":"call_73bJq0Nlh6GoECwR6W5oHBTe|fc_0330c101aa2c61dc016aa39b6afa9c87d192d0d1ff741f8bdc","toolName":"read","content":[{"type":"text","text":"# spt-core — agent working rules\n\nHarness-independent core for an agent ecosystem (messaging, live-agent lifecycle, terminal hosting, P2P networking, runtime-manifest harness contract). Rust crates + a single `spt` binary. Clean-room rebuild of `claude_skill_owl`.\n\n**Orientation — read before working:** `PRD.md` (requirements), `ROADMAP.md` (build path), `CONTEXT.md` (glossary/model, authoritative for meaning), `docs/adr/` (decisions), `docs/KNOWN-HAZARDS.md` (invariants we must not re-break), `docs/{STORAGE,MANIFEST,CONTEXT-MEMORY,DOCS-STRATEGY,TRACEABILITY}.md`.\n\nFor maintainer/debug update work, also read `docs/DEBUG-ROLLOUT.md` before touching the update-set or rollout path.\n\nFor work needing Linux tests and proof, this machine is authorized to ssh into a Linux box: `reavus@kitsubito`\n\nIMPORTANT: All agents you work alongside run on spt-core itself — the legacy-SPT (`$OWL`/`$LIVE`) era ended with the 2026-07 fleet migration; those commands are gone. Reach other agents with `spt send` (or the `/sptc:send` skill); keep message bodies short, and send long bodies from a file rather than inline. Everything else can be learned from the corresponding `/sptc:` skill doc.\n\n## Requirement traceability (binding)\n\nThis project uses `traceable-reqs` (`traceable-reqs.toml` = the authoritative `REQ-*` registry). The full contract is `docs/TRACEABILITY.md`. The rules you must follow:\n\n1. **Tag evidence in the same change.** When you write a function/test/doc-section that satisfies a requirement stage, add its tag in that same commit:\n   `// [impl->REQ-FOO]` · `// [unit->REQ-FOO]` · `<!-- [doc->REQ-FOO] -->`\n   Stages: `doc` / `impl` / `unit` / `int`. Tag *on or immediately above* the real evidence — never at file tops to satisfy coverage.\n2. **Run `traceable-reqs check` before declaring work done.** Exit-1 means missing/invalid evidence — fix it, don't ship it.\n3. **New requirement → add it to `traceable-reqs.toml` first** (with a `REQ-*` id), then satisfy it. No untracked work; no untagged evidence.\n4. **KNOWN-HAZARDS are `REQ-HAZARD-*` requirements** — each needs a test before it's \"covered.\" Treat the hazard list as a conformance checklist you must satisfy, not advice.\n5. **Activate, don't pre-fail.** Requirements you aren't yet working stay `required_stages = []`. Activate (set real stages) only when starting the milestone that delivers them.\n\n## Issue tracking (unique case)\n\nCodebase issues are maintained on **`BigscreenVR/spt-bs-releases`** — the less-private *releases* repo — NOT on `spt-bs-core` where the code lives. This is a deliberate exception (operator-ruled 2026-07-27): file, triage, and reference issues against `spt-bs-releases`.\n\nRequests and milestones are tracked through the **alchemy shell** (`alchemy-0`, the Requests shell bound to `spt-bs-releases`) on top of those GitHub issues. The label taxonomy is the workflow: `state:` BACKLOG → EVAL → GREENLIT → WIP → ACCEPTANCE → DONE (plus CUT / SHELVED), `type:` BUGFIX / ADDITION / CHANGE, `flag: NEEDS-OPERATOR`, and per-node `kind: SPT-TRACKING` pins (marked DO NOT DELETE — leave them alone).\n\n## Other conventions\n\n- Match surrounding code style; copy-verbatim the sister project's stable wire/schema formats (ADR-0001), clean-room everything else.\n- Honor every `docs/KNOWN-HAZARDS.md` invariant — these are real bugs already paid for once.\n- Docs are dual-audience (human + AI dev-agent) per `docs/DOCS-STRATEGY.md`; doc generation is CI-gated against drift.\n- Commit messages end with the project's co-author trailer, exact spelling `Co-authored by: <your live agent name>` (e.g. `Co-authored by: todlando`) — NOT git's hyphenated `Co-Authored-By:`; CI's runner-informant parses only the space spelling for attribution.\n  - **Audit this trailer with `git log --grep` or a raw body read, NEVER `%(trailers:)`** (nor `interpret-trailers --parse`): git's trailer tokenizer requires a whitespace-free token, so the space spelling is structurally invisible to it and every trailer query returns a confident EMPTY on every commit — a clean zero that reads as total attribution loss. Measured 2026-07-30 (main @`8f3e10b`, Signed-off-by and hyphenated-key controls both parse); re-derived at full cost 2026-08-03 by one of its own original measurers, which is why this sentence lives here at the mandate rather than in a document you must decide to open.\n- **Worktrees (binding, operator-ruled 2026-07-05):** every `git worktree` (gate rigs, agent scratch, anything) goes under `.worktrees/` in THIS project's root (`.gitignore`d) — e.g. `git worktree add --detach .worktrees/gate-<sha> <sha>`. NEVER create worktrees as siblings of the project dir; stray sibling folders accumulate orphan-pinned skeletons and pollute `~/Documents/projects`. Remove yours when done (`git worktree remove` + prune; retry later if a handle pins it).\n<!-- [doc->REQ-POOL-FOREIGN-TREE-REFUSED] -->\n- **Build-cache pools (binding, releases#103):** a cargo `target/` directory belongs to ONE source tree. Two trees building into one pool overwrite each other's artifacts and fabricate reds that belong to neither — the v0.51.0 W1/H1 `E0308` that vanished on re-run. **The rule is about the RELATIONSHIP, not the path:** a junction and a `CARGO_TARGET_DIR` env var reach the same hazard, and the env var leaves no directory entry to notice afterwards, so \"is this dir under `.worktrees/`\" never was the question. A build script enforces it (`crates/spt-store/build.rs`) and refuses with `SPT_POOL_FOREIGN`. **Sharing a pool SEQUENTIALLY is fine and expected** — a finished lane is taken over loudly, not refused; only a LIVE lane blocks you. Claim a pool at lane start …\n- **Target-tree teardown (releases#103, same lane):** never delete a `target/` you have not classified. Check OUTBOUND first (`Get-Item -Force`: a junction is deleted as a link, a real dir as a tree), then sweep INBOUND for reparse points aimed at it before removing a real one, and measure size and free space before and after so the reclaim is a number rather than a claim. Reap the target SUBTREE, never a session or worktree directory around it. Do not point `CARGO_TARGET_DIR` into a scratchpad (v0.50.0 incident) or at another checkout's target (H1 incident).\n- **CI / merge strategy:** golden CI (ADR-0050, ruled 2026-07-27) — milestone-batch golden runs, thin-lane PRs, ff-only main (tested sha == merged sha). Piloting from the next milestone; read the ADR before shaping a PR lane.\n\nIf you finish a significant body of work without need for user intervention, or if your context gets too high, you can clear your own context and keep moving:\n1. Create a JIT plan for the next immediate body of work, if it isn't already planned\n2. If you are a live agent, /sptc:commune with immediate next steps and broad summary of the project's status + end goal\n3. Execute the /self-clear skill\n\n[Some lines truncated to 768 chars]"}],"details":{"totalLines":47,"displayContent":{"text":"# spt-core — agent working rules\r\n\r\nHarness-independent core for an agent ecosystem (messaging, live-agent lifecycle, terminal hosting, P2P networking, runtime-manifest harness contract). Rust crates + a single `spt` binary. Clean-room rebuild of `claude_skill_owl`.\r\n\r\n**Orientation — read before working:** `PRD.md` (requirements), `ROADMAP.md` (build path), `CONTEXT.md` (glossary/model, authoritative for meaning), `docs/adr/` (decisions), `docs/KNOWN-HAZARDS.md` (invariants we must not re-break), `docs/{STORAGE,MANIFEST,CONTEXT-MEMORY,DOCS-STRATEGY,TRACEABILITY}.md`.\r\n\r\nFor maintainer/debug update work, also read `docs/DEBUG-ROLLOUT.md` before touching the update-set or rollout path.\r\n\r\nFor work needing Linux tests and proof, this machine is authorized to ssh into a Linux box: `reavus@kitsubito`\r\n\r\nIMPORTANT: All agents you work alongside run on spt-core itself — the legacy-SPT (`$OWL`/`$LIVE`) era ended with the 2026-07 fleet migration; those commands are gone. Reach other agents with `spt send` (or the `/sptc:send` skill); keep message bodies short, and send long bodies from a file rather than inline. Everything else can be learned from the corresponding `/sptc:` skill doc.\r\n\r\n## Requirement traceability (binding)\r\n\r\nThis project uses `traceable-reqs` (`traceable-reqs.toml` = the authoritative `REQ-*` registry). The full contract is `docs/TRACEABILITY.md`. The rules you must follow:\r\n\r\n1. **Tag evidence in the same change.** When you write a function/test/doc-section that satisfies a requirement stage, add its tag in that same commit:\r\n   `// [impl->REQ-FOO]` · `// [unit->REQ-FOO]` · `<!-- [doc->REQ-FOO] -->`\r\n   Stages: `doc` / `impl` / `unit` / `int`. Tag *on or immediately above* the real evidence — never at file tops to satisfy coverage.\r\n2. **Run `traceable-reqs check` before declaring work done.** Exit-1 means missing/invalid evidence — fix it, don't ship it.\r\n3. **New requirement → add it to `traceable-reqs.toml` first** (with a `REQ-*` id), then satisfy it. No untracked work; no untagged evidence.\r\n4. **KNOWN-HAZARDS are `REQ-HAZARD-*` requirements** — each needs a test before it's \"covered.\" Treat the hazard list as a conformance checklist you must satisfy, not advice.\r\n5. **Activate, don't pre-fail.** Requirements you aren't yet working stay `required_stages = []`. Activate (set real stages) only when starting the milestone that delivers them.\r\n\r\n## Issue tracking (unique case)\r\n\r\nCodebase issues are maintained on **`BigscreenVR/spt-bs-releases`** — the less-private *releases* repo — NOT on `spt-bs-core` where the code lives. This is a deliberate exception (operator-ruled 2026-07-27): file, triage, and reference issues against `spt-bs-releases`.\r\n\r\nRequests and milestones are tracked through the **alchemy shell** (`alchemy-0`, the Requests shell bound to `spt-bs-releases`) on top of those GitHub issues. The label taxonomy is the workflow: `state:` BACKLOG → EVAL → GREENLIT → WIP → ACCEPTANCE → DONE (plus CUT / SHELVED), `type:` BUGFIX / ADDITION / CHANGE, `flag: NEEDS-OPERATOR`, and per-node `kind: SPT-TRACKING` pins (marked DO NOT DELETE — leave them alone).\r\n\r\n## Other conventions\r\n\r\n- Match surrounding code style; copy-verbatim the sister project's stable wire/schema formats (ADR-0001), clean-room everything else.\r\n- Honor every `docs/KNOWN-HAZARDS.md` invariant — these are real bugs already paid for once.\r\n- Docs are dual-audience (human + AI dev-agent) per `docs/DOCS-STRATEGY.md`; doc generation is CI-gated against drift.\r\n- Commit messages end with the project's co-author trailer, exact spelling `Co-authored by: <your live agent name>` (e.g. `Co-authored by: todlando`) — NOT git's hyphenated `Co-Authored-By:`; CI's runner-informant parses only the space spelling for attribution.\r\n  - **Audit this trailer with `git log --grep` or a raw body read, NEVER `%(trailers:)`** (nor `interpret-trailers --parse`): git's trailer tokenizer requires a whitespace-free token, so the space spelling is structurally invisible to it and every trailer query returns a confident EMPTY on every commit — a clean zero that reads as total attribution loss. Measured 2026-07-30 (main @`8f3e10b`, Signed-off-by and hyphenated-key controls both parse); re-derived at full cost 2026-08-03 by one of its own original measurers, which is why this sentence lives here at the mandate rather than in a document you must decide to open.\r\n- **Worktrees (binding, operator-ruled 2026-07-05):** every `git worktree` (gate rigs, agent scratch, anything) goes under `.worktrees/` in THIS project's root (`.gitignore`d) — e.g. `git worktree add --detach .worktrees/gate-<sha> <sha>`. NEVER create worktrees as siblings of the project dir; stray sibling folders accumulate orphan-pinned skeletons and pollute `~/Documents/projects`. Remove yours when done (`git worktree remove` + prune; retry later if a handle pins it).\r\n<!-- [doc->REQ-POOL-FOREIGN-TREE-REFUSED] -->\r\n- **Build-cache pools (binding, releases#103):** a cargo `target/` directory belongs to ONE source tree. Two trees building into one pool overwrite each other's artifacts and fabricate reds that belong to neither — the v0.51.0 W1/H1 `E0308` that vanished on re-run. **The rule is about the RELATIONSHIP, not the path:** a junction and a `CARGO_TARGET_DIR` env var reach the same hazard, and the env var leaves no directory entry to notice afterwards, so \"is this dir under `.worktrees/`\" never was the question. A build script enforces it (`crates/spt-store/build.rs`) and refuses with `SPT_POOL_FOREIGN`. **Sharing a pool SEQUENTIALLY is fine and expected** — a finished lane is taken over loudly, not refused; only a LIVE lane blocks you. Claim a pool at lane start …\n- **Target-tree teardown (releases#103, same lane):** never delete a `target/` you have not classified. Check OUTBOUND first (`Get-Item -Force`: a junction is deleted as a link, a real dir as a tree), then sweep INBOUND for reparse points aimed at it before removing a real one, and measure size and free space before and after so the reclaim is a number rather than a claim. Reap the target SUBTREE, never a session or worktree directory around it. Do not point `CARGO_TARGET_DIR` into a scratchpad (v0.50.0 incident) or at another checkout's target (H1 incident).\r\n- **CI / merge strategy:** golden CI (ADR-0050, ruled 2026-07-27) — milestone-batch golden runs, thin-lane PRs, ff-only main (tested sha == merged sha). Piloting from the next milestone; read the ADR before shaping a PR lane.\r\n\r\nIf you finish a significant body of work without need for user intervention, or if your context gets too high, you can clear your own context and keep moving:\r\n1. Create a JIT plan for the next immediate body of work, if it isn't already planned\r\n2. If you are a live agent, /sptc:commune with immediate next steps and broad summary of the project's status + end goal\r\n3. Execute the /self-clear skill\r","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47]},"fileSize":8436,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\AGENTS.md"},"limits":{"columnTruncated":{"maxColumn":768}}}},"isError":false,"timestamp":1789107053417}}
{"type":"message","id":"a2b68b12","parentId":"f8740ee2","timestamp":"2026-09-11T06:10:53.422Z","message":{"role":"toolResult","toolCallId":"call_fINzFxXhDHrHmBrsvPle3852|fc_0330c101aa2c61dc016aa39b6afabc87d1be4bfb0aed5e170b","toolName":"read","content":[{"type":"text","text":"### IR-81 — a process kill can be written scoped or machine-wide, and nothing makes the scoped form the only reachable one: both codebases carry the right pattern beside the wrong one\n…\n#### SCOPING ARM (a) — the product path has no intermediary; the fixture does\n…\n\n### IR-82 — a daemon death leaves NO record of who died: autostart decides on a socket ping, says \"no daemon\", and the successor overwrites the only handle on the corpse\n\n- **Status:** RULED 2026-09-07 11:07Z (doyle), drafted by hertz 11:04Z on doyle's dispatch (11:03Z: *\"the autostart\n  death-cause item is an IR, not a board item — mint it IR-82 in your thin PR\"*). Register on main\n  ends at IR-78; 79/80/81 are drafts in the same PR. · **Origin:** the fleet-daemon death on\n  hfenduleam at 08:03:14.87Z ([[RCA-FLEET-DAEMON-14444]]) whose cause is **still UNNAMED after a day\n  of measurement** — and the reason it is unnamed is this entry. Filed as a defect in\n  OBSERVABILITY, not in the death.\n- **⚠ THIS IS NOT \"find the killer.\"** The killer hunt is the RCA and stays open there. This entry\n  is about the fact that a killer hunt had to be run at all from a cold start, with a watcher script\n  written by hand after the event, because the product recorded nothing about the transition at the\n  moment it noticed it.\n\n- **THE MEASUREMENT — all four facts read at source, no build (gate was live on both boxes).**\n\n  1. **The daemon writes its pid.** `crates/spt-daemon/src/daemon.rs:471` —\n     `let _ = std::fs::write(daemon_pid_path(), std::process::id().to_string());`, into\n     `<spt_home>/daemon.pid` (`crates/spt-daemon/src/endpoint.rs:81`). Unconditional overwrite, no\n     read-before-write, no rotation, no history.\n  2. **Autostart never looks at it.** `ensure_running_outcome`\n     (`crates/spt-daemon/src/daemon.rs:686-724`) decides on `is_running()`, which is\n     `seedmap::ping(&seed_socket_name()).is_ok()` (`daemon.rs:598-600`) — **a socket ping and\n     nothing else.** The decision consults no pid, no mtime, no prior state.\n  3. **The breadcrumb it emits carries no identity.** `daemon.rs:721` —\n     `DAEMON_AUTOSTART: no daemon and no standing operator stop — starting one`. Deliberately\n     \"always-on, ids-free\" per its own comment, because its job is to be COUNTED (the convoy\n     serialization observable that `daemon_stop_convoy_e2e` asserts at :178/:237). That design is\n     correct for what it was built for and is exactly why it answers nothing here.\n  4. **Then the successor destroys the evidence.** The new daemon reaches :471 and overwrites\n     `daemon.pid` with its own pid. The dead pid, and the file mtime that bracketed its life, are\n     gone — overwritten by the very event that should have recorded them.\n\n- **THE SHARP FORM — the file is read ONLY in the state where it can tell you nothing.** The only\n  two readers of `daemon_pid_path()` in the tree are `crates/spt/src/cli.rs:8581` and `:8754` (both inside `cmd_daemon_status`, :8573), and\n  **both are gated on `running`** (`if running { let pid = read(...) }`). So `daemon.pid` is consulted\n  exclusively when a daemon is alive — when its contents are guaranteed fresh and merely restate\n  what the ping already proved — and is ignored in the one state where its staleness is the only\n  evidence anyone has. Its doc comment (`endpoint.rs:82-85`) says *\"a stale pid here is harmless\n  because callers probe the socket, never this file.\"* **That is true for LIVENESS and false for\n  FORENSICS**, and the entry is that the codebase has only ever considered the first reading.\n\n- **WHAT IT COST, concretely, on 2026-09-07.** Daemon pid 14444 died at 08:03:14.87Z inside the ci\n  Windows unit leg's nextest LIST phase; successor 48232 cold-started at 08:03:20Z and\n  `DAEMON_RESTART_RESUME`d every session, orphaning live agents' monitors and readers and handing at\n  least one agent a stale brief. Neither peer ran a kill. To get ANY signal at all I had to hand-write\n  an external watcher (`C:\\Users\\decid\\.spt-watch\\watch-daemon.ps1`, 1s cadence, identity re-verified\n  by image path AND creation time every poll) **after** the death, which by construction cannot\n  observe the event it was written for. 6600+ polls later the successor is alive and the original\n  death is still uncharacterized. A product-side record of the transition would have cost bytes.\n\n- **WHY THIS IS NOT THE CONVOY BREADCRUMB'S JOB, and must not be bolted onto it.**\n  `DAEMON_AUTOSTART` is load-bearing as a COUNTABLE line: `daemon_stop_convoy_e2e` asserts *exactly\n  one* appears under a storm (:178) and counts N under a deliberate race (:237). Adding identity\n  fields to that line risks the count and buries a forensic record inside a line whose contract is\n  its cardinality. **The record belongs in its own line and its own artifact.**\n\n- **REMEDY — RULED 2026-09-07 11:07Z (doyle), APPROVED as proposed with two refinements. Small,\n  product-side, no wire change.** doyle re-derived the census independently at `f3c8495b` (one\n  writer `daemon.rs:471`, two readers `cli.rs:8581` + `:8754`, both inside `if running`) before\n  ruling — the falsifiable claim below has been checked, not taken.\n  1. **Read before you clobber.** At `daemon.rs:471`, read the existing `daemon.pid` and its mtime\n     BEFORE the write; if it holds a pid that is not ours, emit a distinct, greppable line naming\n     the predecessor pid and how long ago the file was last touched — e.g.\n     `DAEMON_SUCCEEDS_PID: prior=<pid> prior_pidfile_age_ms=<n> reason=<socket-ping-failed>`. The\n     value is that the successor is the only process in the system that is guaranteed to run at\n     exactly the moment the question becomes askable.\n  2. **Keep one generation.** Rename the existing `daemon.pid` to `daemon.pid.prev` instead of\n     overwriting it (best-effort, same directory, same failure posture as today's `let _ =`). One\n     generation is enough to answer \"which pid did I replace, and when did it last write?\" and costs\n     no rotation policy.\n  3. **REFINED BY THE RULING — the discriminator is a FIELD, not a second line.** I proposed a\n     separate \"what the ping saw\" record; doyle collapsed it: `prior=<pid|none>` already separates\n     the two incidents, because `none` **is** the fresh-home case. One line, one field, no second\n     breadcrumb to keep in sync.\n  4. **ADDED BY THE RULING — `alive=<bool>`, from a by-number liveness READ at write time.** With\n     the prior pid in hand, read whether that number is still live and put the answer on the line.\n     It splits the two incidents that otherwise look identical: **`alive` prior = two daemons racing\n     the seed bind** (the convoy case), **dead prior = the corpse** (the 14444 case). This is a\n     READ, not a kill — #285's identity-before-kill rule binds kills and is not weakened here; a\n     by-number read that informs a log line commits no action on the pid.\n  5. **UNIT, specified by the ruling:** seed a pidfile with a fake pid and an aged mtime, run the\n     write path, assert the emitted fields (`prior`, `age_ms`, `alive`) AND the `daemon.pid.prev`\n     bytes. The `.prev` bytes are part of the assertion, not an afterthought — the generation kept\n     is the half that survives the process.\n  6. **NOT proposed, and the ruling kept it out:** a liveness change. `is_running()` must stay the socket ping — this entry does\n     not argue the pidfile should become a liveness signal, which is the exact mistake\n     `endpoint.rs:82-85` was written to prevent. The pidfile stays advisory; it just stops being\n     silently destroyed.\n\n- **LANE — SPLIT BY THE RULING, and the two halves ship separately.** The **IR-82 ENTRY** (this\n  text) rides hertz's IR-37 thin PR alongside IR-79/80/81. The **PRODUCT REMEDY** rides **#285's\n  lane** (todlando, post-W2) because it is the same pid-identity gate: #285 makes a kill read an\n  identity, this makes a successor read the identity it is about to erase. One lane, one owner,\n  one review of the pid-identity question. Do not implement the remedy in the thin PR.\n\n- **Kin:** [[RCA-FLEET-DAEMON-14444]] (the open incident this serves — IR-82 does not close it and\n  must not be read as closing it), [[IR-81]] (a pid is not an identity — the same lesson from the\n  KILL side; here it is the RECORD side), [[IR-80]]/[[IR-79]] (processes outliving what should have\n  accounted for them). The through-line doyle named at 10:22Z holds: *a pid is not an identity and a\n  pid is not a tree* — and IR-82 adds that **a pid nobody wrote down is not evidence.**\n\n- **Falsifiable claim, so it can be checked rather than believed:** at `f3c8495b` the tree contains\n  exactly ONE writer of `daemon_pid_path()` (`daemon.rs:471`) and exactly TWO readers\n  (`cli.rs:8581`, `cli.rs:8754`), both inside a `running` gate. If a future reader appears in an\n  unguarded path, this entry's premise weakens and it should be re-measured, not re-asserted.\n\n### IR-83 — a two-host rig addressed over the tailnet cannot receive INBOUND on Windows, and the whole rig population had only ever run the admitted direction\n\n- **Status:** OPEN, minted by hertz 2026-09-07 11:41Z on doyle's dispatch (11:40Z). **Provenance: the\n  mechanism below is DOYLE'S measurement, not mine** — eight probe arms, each with sender, listener\n  and output file, recorded in `GATE-W2-272-CHECKLIST.md` rows 11:36Z–11:39Z. I am off cargo on both\n  boxes and have re-measured none of it; this entry is the register form of his finding plus the\n  structural reading it supports. Board face: **F18**. Register slot: IR-83 (79/80/81/82 are the\n  same thin PR).\n- **2026-09-11 ruling:** the original universal \"LAN, never tailnet\" prescription below is\n  SUPERSEDED by IR-89's measured tailnet ACL + Windows Firewall remediation and successful\n  tailnet probes. Admit the actual transport at each layer and retain an independent reverse\n  direction witness. The operator-blocked box remedy is spent; durable witness enforcement\n  and its acceptance record remain separate, OPEN work. No new box changes authorized here.\n\n- **HALF ONE — the tailnet ACL is per-node and ONE-WAY.** `hfenduleam` admits 9 sources and\n  `kitsubito` is **not** among them; `kitsubito` admits `hfenduleam`. So a rig cell needing INBOUND\n  to the Windows box over `100.x` fails **at the receiver**, and it fails there **whatever the host\n  firewall says** — which is why a host-firewall investigation can be run to completion, come back\n  clean, and explain nothing.\n\n- **HALF TWO — Windows defaults `BlockInbound`, and a hash-named test exe has no rule.** Test\n  binaries are built with hash-suffixed names, so a rule written against the *program* is keyed to a\n  name that changes on the next build. The stale `spt_net-d037…` rule is the precedent already in\n  the tree: a rule that was correct once, is present, greps fine, and admits nothing. **The durable\n  form is PORT-scoped, not program-scoped:** ports `7480-7499`, `remoteip` = the peer's LAN address,\n  added by the operator.\n\n- **WHY IT SURFACED ONLY NOW, and this is the part that generalizes.** The W2 helper cell is the\n  **first cell in the entire rig population that ever needed `kitsubito -> hfenduleam` inbound.**\n  W1's four xbox cells and golden's old-twohost job are all `hfenduleam -> kitsubito` — the admitted\n  direction. So the population had a **direction monoculture**, and a one-way ACL is invisible to a\n  suite that only ever runs the admitted way. Every green in that population was consistent with the\n  ACL being wide open and equally consistent with it being one-way; the suite could not tell the\n  difference, and nobody had reason to ask. **A capability exercised in only one direction is not\n  covered, it is merely unexamined** — the same shape as an assertion that only ever sees the\n  passing arm.\n\n- **THE SECOND STRUCTURAL POINT — a rule keyed to a MUTABLE identity is the lane's own through-line.**\n  A per-hash program rule is an exception bound to an identity the build changes underneath it,\n  exactly as [[IR-81]] is about a kill bound to a pid the OS may reassign and IR-80 Amendment 1's ENV\n  READ face is about a read bound to a process identity `exec` can change. Port-scoping replaces a\n  mutable identity with a stable property. That is the same remedy shape as reading an image path\n  before a kill and reporting an environment in-band: **stop keying on the thing that moves.** I am\n  flagging the rhyme, not claiming a fourth face — this is infrastructure config, not a code path,\n  and the amendment's standing prediction is about pid-shaped questions.\n\n- **FALSIFIABLE CLAIM (doyle's, recorded verbatim as the entry's test):** with the rig on **LAN\n  addresses AND the port-scoped rule present**, the helper cell's owner raw carries `WEB_SERVE_FOR`;\n  with **either** missing, it carries none. Both arms matter — this is a conjunction, so a single\n  green with one of the two absent would refute it, and a red with both present would too.\n\n- **WHAT THIS ENTRY DOES NOT CLAIM.** It does not say the host firewall was ever misconfigured; the\n  ACL half fails at the receiver independently. It does not close F17 or explain the vacuous-green\n  run (that was the mid-flight script rewrite — different cause, different fix, and the two were\n  live in the same hour, which is precisely why each needed its own named mechanism rather than one\n  story). It proposes no product change: both halves are rig addressing and operator-added firewall\n  config.\n\n- **REMEDY.** (1) Rig-side: address peers by LAN in two-host rigs, and make the tailnet address\n  unreachable-by-construction rather than merely unused, so a future rig cannot quietly pick it up.\n  (2) Operator-side: the port-scoped inbound rule (`7480-7499`, `remoteip` = peer LAN), replacing\n  per-hash program rules; the stale `spt_net-d037…` rule should be removed in the same pass so it\n  stops reading as coverage. (3) Population-side — **RULED 11:42Z (doyle), with a precision that\n  changes the shape:** this is NOT a new cell. **The W2 helper cell IS the first reverse-direction\n  cell**, and on LAN it exercises `kitsubito -> hfenduleam` inbound for real once the rule exists.\n  The remedy is therefore to **keep at least one reverse cell in the xbox battery permanently and\n  NAME it as the direction witness**, so its role is a stated property rather than an accident of\n  what W2 happened to need. A suite that only runs one way cannot discover the next one-way ACL\n  either, and the way that recurs is not \"nobody wrote the cell\" but \"the cell that had it stopped\n  being run.\"\n\n  **The hazard that follows from naming it, stated here so the naming is not decorative:** a witness\n  cell that is SKIPPED stops being a witness while still reporting green — the exact confusion this\n  lane already paid for, where a must-skip `role_b` PASS was indistinguishable from four cells that\n  no-opped. So the direction witness needs its skip to be loud: if it is filtered out, phase-reclassed,\n  or short-circuits on a missing precondition, that must read as ABSENT COVERAGE and not as a pass.\n  Whoever names it owns that half too. **Concrete enforcement, doyle-ruled 11:44Z and written up\n  as the RIDER 5 ADDENDUM:** the xbox driver's HELPER WITNESS verdict line already refuses a\n  `0.0x s` helper PASS and a `b.raw` without `WEB_SERVE_FOR outcome=registered`; it must ALSO\n  print `NOT-A-WITNESS` when the cell is absent from the LIST leg. Those first two are\n  *ran-but-vacuous*; absence is *never-ran*, and a verdict built only from the first two passes\n  it by omission — every refusal condition evaluates against output that does not exist, finds\n  nothing to object to, and falls through to green.\n\n- **GATING CLAUSE — added 2026-09-07 12:56Z on doyle's dispatch (gate reshape, same minute).** An\n  inbound-to-Windows cell in a two-host rig is **gated on the port-scoped rule being present**, and\n  without it the cell must **SKIP LOUDLY**: it may not run, may not report PASS, and may not be\n  silently filtered — its absence must render as ABSENT COVERAGE in the verdict, on the RIDER 5\n  ADDENDUM's `NOT-A-WITNESS:NEVER-RAN` face. The precondition is machine-readable, so the driver\n  reads `netsh` at start and the gate is a measured fact rather than a remembered one; a cell whose\n  precondition is unmet and which therefore emits nothing is exactly the case a verdict assembled\n  only from ran-but-vacuous refusals passes by omission. **This clause is what stops the rule's\n  ABSENCE from reading as the rig's health.**\n\n  **How the reshaped W2 F17 gate applies it (doyle 12:56Z, recorded, not re-measured by me — I am\n  still off cargo on both boxes).** With the rule absent 75+ minutes and no operator activity, and\n  golden carrying no cross-box `twohost_web`, the shortfall is a **rig blocker, not a golden one**.\n  So the HELPER WITNESS was reshaped to the **ONE-BOX pair on BOTH OSes** — doyle's gate tree on\n  Windows, a kitsubito clone at the tip on Linux with the rig shipped as the frozen copy — on the\n  basis that the 03:31Z one-box run at `f3c8495b` reproduced F17 end to end (A `outcome=unanswered`,\n  B `DISPATCH:4:Unknown`), i.e. the one-box pair drives the real dispatcher on both roles.\n  Mutation D must turn the classify unit cell red **and** the one-box helper cell red\n  (owner `family=Unknown`>0, `registered`=0) while deny/fetch stay green; revert dirty 0. The\n  cross-box pair still runs as the A->B regression (deny/fetch must PASS), and while the rule is\n  absent its helper/range TIMEOUTs are classified **F18-INFRA** — becoming a witness automatically\n  if the rule lands before the run, because the driver reads `netsh` at start.\n  **The cross-box helper witness therefore stays an OPEN rider on the operator's rule, not a land\n  blocker.** Note the shape this preserves: the reshape moves the witness to a pair that CAN run,\n  and leaves the direction it cannot exercise named and open — it does not let the one-box green\n  stand in for the direction coverage that is still missing. A one-box pair proves the dispatcher;\n  it cannot prove an inbound ACL, and nothing here claims it does.\n\n  **PROBE RESOLUTION — doyle 12:59Z, ADOPTED INTO THIS GATE (not deferred to the rider).** The\n  precondition read is now THREE-VALUE in `gate-w2-f17.sh`: `Rule Name` in stdout -> PRESENT,\n  `No rules match` -> ABSENT, empty stdout or anything else -> PROBE-FAILED. **PROBE-FAILED\n  classifies the cross-box helper/range as `UNCLASSIFIED: this run cannot tell INFRA from a real\n  red` — never F18-INFRA** — and xbox-D's skip line names the state. The raw probe (exit code +\n  first 3 lines) is printed into the driver log, so the classification is auditable after the fact\n  rather than inferred from what got bucketed. Exercised standalone on all three arms: real\n  `netsh` = exit 1 + `No rules match` -> ABSENT; forced bad args -> PROBE-FAILED; empty stdout ->\n  PROBE-FAILED.\n\n  **Recorded because it corrects the asker (me), not the implementer:** I proposed the three-value\n  shape AND, in the same message, proposed discriminating on the exit code. doyle's standalone\n  exercise measured `netsh` exiting **1 on a clean ABSENT**, so an exit-code discriminator would\n  have classified every legitimately-absent rule as an instrument fault — turning the run's most\n  common honest state into PROBE-FAILED and, with it, `UNCLASSIFIED`. The discriminator that landed\n  is STDOUT CONTENT. The general form belongs in the entry because it is the reason the third arm\n  needed measuring at all: **a CLI's exit code is a claim about the QUERY, not about the ANSWER**,\n  and an empty-but-correct result is reported non-zero by a great many tools. A third value added\n  to a probe needs its own evidence, obtained by making all three arms fire on purpose — which is\n  this lane's standing rule that a tool whose success path has never been made to fail on purpose\n  is untested, applied to a tool's FAILURE path instead.\n\n- **Kin:** [[IR-81]] and IR-80 Amendment 1 (keying on a mutable identity), the F17 riders (a witness\n  that never executed the direction it certifies).\n\n### IR-84 — the one `PUMP_PEER_FAIL` arm the rigs actually fire was the only one carrying no clock, so the stall that produced it could be counted but never timed\n\n- **Status:** OPEN, filed by hertz 2026-09-09 with the instrument that closes its first half. ·\n  **Origin:** the 65 s two-host helper stall (design written before the run,\n  `docs/design/RIDER-65S-DESIGN.md`). The number was branch-claimed 2026-09-08 by name only — IR-85\n  records that it carried no entry text in any register file in any worktree — and this is that text.\n- **Symptom:** `two_host_web_helper_role_a` takes **61.956–69.096 s** across five runs while its\n  siblings in the same binary and the same run take **0.135–0.753 s**. Every ladder rig —\n  win-onebox, linux-onebox, cross-box — logs **exactly ONE**\n  `PUMP_PEER_FAIL:<node>:peer reply-read: no progress within budget — dropping peer (brain IPC read\n  deadline elapsed)` on B before completing. **3/3, one each, never on A** (doyle's GATE-W3 readout).\n- **Cause of the DIAGNOSTIC failure, which is what this entry is about:** that line is emitted from\n  the `Err(e)` arm of `peer_leg_outcome` (`crates/spt-daemon/src/pump/mod.rs`), and at\n  `b0b67aaa` it read `emit_line_err!(\"PUMP_PEER_FAIL:{peer_hex}:{e}\")` — **no timestamp**. Measured\n  at that sha rather than recalled: the file carries **four** `PUMP_PEER_FAIL` emit sites, **three**\n  of them stamped `wall_ms=… mono_ms=…` (the submit arm, the no-route arm, and the\n  `PRESENCE_DIAL_FAILED` arm), and this one was **the only unstamped site left**. It is also the\n  arm the rigs actually fire — a `PEER_REPLY_READ_BUDGET` expiry reclassified out of `TimedOut` by\n  `brain::reclassify_peer_reply_err` so it drops one peer rather than poisoning the round. **The\n  single arm a reader most needs to time was the single arm that could not be timed.**\n- **What that cost, stated as the open question it left:** the arithmetic does not close and this\n  entry does not close it. `PUMP_PEER_IO_TIMEOUT` is **30 s** (`:118`) and `SUPERVISE_BACKOFF_BASE`\n  is **5 s** (`:121`) — read as constants, not recalled — so one deadline plus one supervise floor\n  accounts for **35 s** against **61.956–69.096 s** observed. **~27–34 s is unaccounted**, itself\n  close to another 30, which is exactly the coincidence the design document warns against; and the\n  count of **exactly one** fail forbids the easy reading that two deadlines elapsed. Three candidates\n  stay open and are NOT ranked here: a first ~30 s burned before the deadline's clock starts; a\n  second budget stacking on the first; or the restart's re-prime costing materially more than its\n  5 s floor. **Separating them needs the deadline's own timestamps against the fail line** — which\n  is precisely what the log did not carry.\n- **⚠ WHAT THIS ENTRY DOES NOT CLAIM.** The instrument does not explain the stall, does not shorten\n  it, and changes no product behaviour: the same peer is dropped at the same instant with the same\n  backoff. It makes the stall **answerable from a log that already contains the failure**, instead of\n  requiring a rebuild to learn when the budget started. `PUMP_PEER_IO_TIMEOUT` is a hard const with\n  no env knob, so varying it costs a rebuild — deliberately deferred until the stamps say which half\n  of the arithmetic is missing.\n- **Kin and the recurrence that matters:** this is the **SECOND** time an unstamped\n  `PUMP_PEER_FAIL` cost a hunt. The `PRESENCE_DIAL_FAILED` arm carries a comment naming the\n  \"2026-07-14 `PUMP_PEER_FAIL`-unstamped seed, folded here\", and **REQ-PUMP-STAGE-TRUTH** already\n  requires every peer failure \"stamped (wall+mono) and peer-attributed\", explicitly subsuming that\n  seed. So the contract was written, three of four sites complied, and the fourth stayed silent for\n  eight weeks — **a convention enforced by no mechanism degrades one arm at a time, and every reader\n  of a complying arm reports the convention as held**, the same shape as the `validate_docs_dir`\n  refusal-arm rider in the same design document. Also kin: **IR-83** (the rig population had only\n  ever run the admitted direction), `REQ-HAZARD-PUMP-IPC-DEADLINE` (a `TimedOut` brain-IPC read is a\n  supervised restart, never a per-peer retry), ADR-0039 Decision 5.\n- **Ripe when:** now, and it lands with this entry — the stamp is one emit line, tagged\n  `[impl->REQ-PUMP-STAGE-TRUTH]` at the site. · **Size:** one emit line plus its comment.\n  **Follow-up, not this lane:** a cell that walks every `PUMP_PEER_FAIL` arm and asserts each one\n  stamps, so the fifth site added cannot be born silent.\n### IR-85 — the Windows self-hosted box runs its fs-heavy tests 3-4x slower than a week ago; two CI wall clocks were sized for the old box, and a red run kept hiding it\n\n- **Status:** OPEN, filed by hertz 2026-09-09 at the #272/v0.68.0 golden r3/r4 arc, on doyle's\n  dispatch. Number ruled by doyle from his own census of main@`a2f335f8` (register ended at IR-83;\n  IR-84 was branch-claimed by name only, with no entry text in any register file in any worktree —\n  that gap is now closed: **IR-84 was filed 2026-09-09 in PR #213**, so this sentence records the\n  state at `a2f335f8` and is no longer a reason to go looking for a missing entry).\n  **Absorbs two drafts:** doyle's `IR-DRAFT-windows-fs-heavy-slowdown-and-golden-wall` (his IR-A +\n  IR-B) and his earlier `IR-NEXT` (operator-desktop load), both retired by reference — this is the\n  single entry. Every job/step and per-test timing below is **doyle's**, read via the job/step API.\n  · **Origin:** #272 golden r3 attempt 2 was CANCELLED by a wall clock with both test phases green.\n- **⚠ THE CAP CHANGE IN `a2f335f8` IS NOT THE FIX AND MUST NOT BE READ AS ONE.** It bounds the run;\n  it repairs nothing. A future reader who finds an 80-minute wall and no entry here would reasonably\n  conclude the problem was solved. It was only made visible.\n\n- **A GREEN RUN COSTS MORE THAN A RED ONE, WHICH IS WHY THIS WENT UNSEEN.** A failing run\n  short-circuits past the wall a green run has to cross. r3 att1 finished in **48m39s only because\n  it FAILED at Phase B**; att2, green, hit 49m59s and was cancelled. Every earlier docs-drift skip\n  therefore presented as \"upstream failure\" — the wall was never the reported cause of anything, and\n  the surviving evidence systematically flattered the budget.\n\n- **THE WALL.** Windows golden `test` job (48 steps), fully GREEN: **30m53s** (2026-08-30, run\n  33296634901) and **33m21s** (2026-09-06, run 34017906638). At the v0.68.0 head against the\n  then-current 50-minute cap — **r3 att2**, job 102352551368 at `f6110c2a`: Phase A 17m14s, Phase B\n  20m25s, doctests 1m04s, clippy 3m31s, **CANCELLED at step 30 at 49m59s with everything green**;\n  steps 31-42 (installer, docs floor, both docs-drift gates, dormancy) never ran. r2 att1\n  (`25e60015`, 09-08 18:47Z) reached step 34 at 44m30s. Steps 30..39 cost ~3m30s on the 09-06 green\n  (notify 47s, installer 13s, docs-drift 1m54s). Predicted green need ~**56 min**; cap raised to\n  **80** (need + ~40% for day-to-day variance) in `a2f335f8`, ci unit 25 -> 40 in the same commit.\n- **r4, GREEN — the first complete measurement at the head: 54m35s** (07:12:26Z -> 08:07:01Z),\n  **25m25s** headroom under 80; docs-drift (step 38) 2m23s; Phase A 15m51s, Phase B 22m56s. The ~56\n  prediction held to within 1.5 min, so the cap is sized on evidence, not generosity. **What that\n  does NOT establish:** it was a sizing forecast, and its holding says nothing about the cause\n  diagnosis below. Nor are att2-vs-r4 per-phase deltas a trend — att2 was cancelled mid-run, so only\n  its phase legs are comparable at all, and the spread they sit in is the same variance the 40% is\n  there to absorb.\n\n- **THE SLOWDOWN, per test, same box, same tests.** `spt-daemon::sync` concurrent_writes\n  **22.4s -> 74.8s**, two_tier_sync 18.7 -> 67.4; `spt-store` monic clone_copies 17.7 -> 62.9,\n  different_monics 18.2 -> 64.9; syncmerge reconciled_write 27.3 -> 51.2. **~25 spt-store/spt-daemon\n  tests now exceed 30s on Windows Phase A at `f6110c2a`, against 1-2s each on kitsubito.**\n  Phase-level: Phase A nextest 170s (09-06) -> 642s (att1) -> 1034s (att2); Phase B 710s -> 1164s.\n  The suite did not get more expensive — Linux is unchanged.\n\n- **DATING SAYS ENVIRONMENT DOMINATES, AND BY HOW MUCH.** main's own ci Windows `unit` job:\n  11-12 min on 09-06 (runs 34040416870, 34041526195, 34043323577) -> 13-20 min on 09-07 -> 12-24 min\n  on 09-08, hitting **22 min at `e4444413`** (run 34261096301) three minutes under its own 25-minute\n  wall. **Gradual over days, under no single gate change, is the shape of an environment term, not a\n  commit's.** Head growth is real but MINOR: +138 Phase A tests, +20 Phase B, HEAVY 34 -> 35.\n\n- **THE BOX IS AN OPERATOR DESKTOP (folded in from the retired IR-NEXT), and that turns every fixed\n  wall-clock budget in the Windows suite into a coin.** From the r2 arc, three attempts at ONE sha\n  (run 34262154550 @ `25e60015`): Phase B red each time on a **different single cell or none** — a1\n  234/234 (job red on disk floors only), a2 `spt::webserve_attachment_e2e` arm 12, a3\n  `spt-daemon::mesh_recovery roster_route_survives_a_transient_dial_failure_with_discovery_disabled`\n  (15.0s `converge()` budget, cell 15.715s; the same cell 9.8s / 7.2s on a1/a2). Phase A — 3,346\n  spawn-dominated unit cells — slowed **monotonically 448.7 -> 495.1 -> 542.6s at that one sha**.\n  Per-cell a3/a2 over 73 Phase B cells >= 1s: median 1.05x, mean 1.34x, 19 cells >= 1.5x, worst 5.2x\n  (`endpoint_lifecycle poll_vs_reap` 1.1 -> 5.8s) — **BURSTY, not uniform**. A rotating single victim\n  across attempts at one sha is ONE environment cause; hardening victims one at a time never closes\n  it (paid before: `e2e-leaked-daemons-shared-box`). The budgets that lost were ~1.5x the fast\n  observation — inside the box's measured variance, so they were coins that had been landing right.\n- **Box census (doyle 01:13-01:19Z, no cargo/rustc/nextest running, CPU 31%, ~1.1 of 16 cores busy):**\n  `qbittorrent.exe` seeding since 09-08 10:20Z (box tx 21.3 MB/s over 5s); fleet `spt daemon brain`\n  with 516 GB read since 09-07 08:03Z (~3.5 MB/s steady); Defender real-time ON, `MsMpEng` at\n  67.8/62.8/48.9/32.2/12.2% of a core over 5s **on the idle box**; a fresh 35 MB exe pays\n  2092/994/1171/1043 ms on FIRST execution against 31/263/19/260 ms on the second — **and every CI\n  attempt rebuilds every test binary fresh.** At 06:45Z on 09-09, with the twohost legs running:\n  MsMpEng 89% CPU / 991 MB WS, qbittorrent pid 47056 holding 7817 CPU-seconds (2.2 h) since\n  09-08 03:20, free 134 GiB (275 -> 197 -> 131 across the three r3 dispatches).\n- **⚠ AN UNREADABLE ROW IS NOT AN ABSENT ONE.** The Defender exclusion list cannot be read\n  unelevated on this box: `Get-MpPreference` returns the literal string\n  `N/A: Must be an administrator to view exclusions` **as the ExclusionPath VALUE**, so a\n  `-contains` test reads ABSENT and is meaningless; the HKLM `Windows Defender\\Exclusions\\Paths`\n  read throws `SecurityException`. Nobody may report the runner directory as unexcluded from an\n  unelevated shell.\n\n- **HYPOTHESIS ALREADY KILLED, so nobody re-runs it:** the Windows-only `ADAPTER_WEB_PENDING`\n  reconcile failure (servehost nudge) **cannot** explain this — spt-store monic and contextstore\n  never touch that path.\n\n- **WHAT IS STILL NOT ESTABLISHED (labelled, so it is not inherited as fact).** The dating argument\n  establishes environment-DOMINANT and bounds head growth as the minor term. It does **not**\n  apportion the environment term itself: Defender vs the third-party torrent load vs the fleet\n  brain's steady read vs anything else is unsplit, and **\"MsMpEng at 89%\" remains a correlate\n  measured beside the slowdown, not a proven cause.** The discriminator lane below is what settles\n  head-vs-environment on evidence rather than on the shape of a drift curve.\n\n- **REMEDY — none landed. This entry is the debt, and its middle arms need an operator.** Sequence\n  matters; run them in this order:\n  1. **DISCRIMINATOR LANE (hertz, one box, ~1.5-2 h).** Run the five named tests at `04e32c8c` and\n     at `f6110c2a` on hfenduleam. **Same-slow at both = environment; slow only at the head = head\n     growth.** Cheap and decidable, and it must precede any operator ask — do not spend an elevation\n     request on a hypothesis a one-lane measurement can test. Design note, because it is the part\n     that makes the number trustworthy: the arms run **INTERLEAVED** (A/B/A/B/A/B, 3 reps each), not\n     all-A-then-all-B, so drift that hits the whole box cancels in the comparison instead of landing\n     on one arm. **A measurement that only works if everyone behaves is not a measurement** — the\n     torrent client and Defender are running throughout and are the thing under test, not noise\n     anyone gets to remove. Confounder already excluded: the three test-bearing files\n     (`spt-daemon/tests/sync.rs`, `spt-store/src/monic.rs`, `spt-store/src/syncmerge.rs`) are\n     **byte-identical blobs at both shas**, so a difference cannot be the tests changing; the two\n     crates around them are not (+11,388 lines over 48 files).\n  2. **Remove the third-party load first.** No torrent client on the CI box during golden windows.\n     It is the cheapest variable to remove, and removing it first makes arm 3's benefit measurable\n     instead of confounded.\n  3. **OPERATOR ASK — Defender path exclusions** for `C:\\actions-runner\\_work` and the gate pools,\n     read from an ADMIN shell first (see the unreadable-row warning above), then re-measure the\n     first-touch tax on a file **under that path** — the scratchpad measurement is outside the\n     runner dir, so it proves the mechanism's size, not the runner's exposure. Unsettable\n     unelevated; same shape as **IR-89**'s elevated firewall rule.\n  4. **CI census, cheap and durable:** print `Get-MpComputerStatus` RealTimeProtectionEnabled plus\n     the ExclusionPath read **verbatim, refusal text included**, in the Windows job's census step,\n     so a run's own record says what Defender it ran under.\n  5. **Re-measure both caps after any arm lands — the arm a future reader will skip, so it is loud\n     here.** A cap sized against a degraded box is correct only while the box stays degraded.\n     Leaving 80 in place after a repair silently restores the original hazard: a wall so generous it\n     no longer catches a wedged test, which is the job the golden cap was added to do in the first\n     place (the 2026-06-03 handoff.rs ConPTY stall, 22 unbounded hosted minutes).\n- **Kin:** [[IR-76]] (the golden runner IS the builders' box — the structural reason a desktop's\n  load reaches CI at all), [[IR-64]] (box-level facts only the operator can move), [[IR-89]] (the\n  other elevated box-rule ask), `defender-first-touch-tax-on-fresh-test-binaries` and\n  `e2e-leaked-daemons-shared-box` (memory).\n- **Ripe when:** arm 1 now; arms 2-4 on the operator's answer; arm 5 at the next `golden.yml` touch\n  after any of them. · **Size:** arm 1 a measurement, arm 4 one census line, arm 5 two literals.\n- **AMENDMENT 2026-09-09 (two terms this entry did not name when it landed at `d32d5c4c`).**\n  1. **`ci.yml`'s `changes` job runs `unit` on BOTH runners for every push to `main`.** The classify\n     step at `.github/workflows/ci.yml:49` emits `code=true` for every non-`pull_request` event, so\n     the docs-only skip that PR runs #206/#207 demonstrated is **`pull_request`-only** — read from\n     `ci.yml` at `main` by doyle, who names it his own error after twice ruling the opposite from the\n     PR runs alone. Consequence for this entry's wall clock: run **34337797758** (the ff of\n     `b66a9612`, a docs-only delta over golden-green `a2f335f8`) ran `unit (Windows)` 09:59:57Z →\n     10:40:48Z and was **CANCELLED at the 40-minute job wall** (job timeout; conclusion `cancelled`,\n     step 6 `Unit tests` 10:08:23 → 10:40:03) — a red on `main` at a sha whose content cannot fail a\n     unit test. It is an IR-85 face, not a flake row.\n  2. **A near-full volume is an environment term for the slowdown**, alongside the Defender\n     first-touch tax and the operator-desktop load already recorded. **Deliberately unquantified:**\n     the discriminator window that would have apportioned it was VOID, because the one leg that\n     completed ran under both a CI job and a falling disk. See **IR-90**.\n- **WHAT THE VOIDED DISCRIMINATOR ESTABLISHED, negatively (hertz, 2026-09-09).** The fs-heavy\n  slowdown REPRODUCES at `04e32c8c`, which predates the +11,388-line head growth: spt-daemon\n  `concurrent_writes` 105.420 s, `two_tier_sync` 58.362 s, spt-store `clone_copies` 65.657 s,\n  `different_monics` 73.967 s, `syncmerge reconciled_write` 86.765 s, against the 09-06 baseline of\n  22.4 / 18.7 / 17.7 / 18.2 / 27.3 s — **3.2x to 4.7x on all five, at the OLD sha**. So head growth\n  is **not NECESSARY** for the slowdown. That is the whole of it: it does NOT measure how much the\n  environment explains, and it is not evidence about the head arm at all — that leg ran inside run\n  34337797758's window and on a volume that reached 0.018 GiB free, and the head arm never produced\n  a comparable pair. **Arm 1 stays OPEN**, its re-run deferred until **IR-90**'s guard exists and a\n  window with no `main` push and no CI job on the box can be scheduled.\n\n- **AMENDMENT 2026-09-10 (hertz, on THIS ENTRY'S OWN arm-1 design note).** The note says the arms run\n  **INTERLEAVED** A/B/A/B so box drift cancels. It does not cancel: **B is always the later arm within\n  each pair**, so a monotone drift across the session lands on B every time and is read as an arm\n  effect. Alternate the PAIR ORDER — **A/B then B/A** — record per-leg timestamps and conditions, and\n  describe the result as **REDUCING order confounding, not eliminating it**. Second binding change,\n  from the releases#294 triage: **instrument, do not infer.** `cargo nextest run --success-output\n  immediate` retains stdout for PASSING tests (deployah), so a passing arm can still print poll\n  elapsed, iteration count, IPC time and producer progress — **a failing arm is not required** for a\n  margin measurement (todlando, correcting deployah's \"it has to fail to be informative\"). Arm 1 was\n  never re-run, so this lands before the measurement, not after it.\n\n### IR-86 — golden's 32 GiB floor is BELOW the measured 67.4 GiB Windows suite footprint, so a start floor passes a box that cannot finish\n\n- **Status:** OPEN, filed by doyle 2026-09-08 at the #272/v0.68.0 golden r2 triage. · **Origin:**\n…\n  25,284,501,504 B RED at 19:31:55Z -> `FLOOR_END` RED. Consumed in-job: 67.4 GiB.\n…\n\n\n[Showing lines 4531-4987 of 5900. Use :4988 to continue]"}],"details":{"truncation":{"content":"\r\n### IR-82 — a daemon death leaves NO record of who died: autostart decides on a socket ping, says \"no daemon\", and the successor overwrites the only handle on the corpse\r\n\r\n- **Status:** RULED 2026-09-07 11:07Z (doyle), drafted by hertz 11:04Z on doyle's dispatch (11:03Z: *\"the autostart\r\n  death-cause item is an IR, not a board item — mint it IR-82 in your thin PR\"*). Register on main\r\n  ends at IR-78; 79/80/81 are drafts in the same PR. · **Origin:** the fleet-daemon death on\r\n  hfenduleam at 08:03:14.87Z ([[RCA-FLEET-DAEMON-14444]]) whose cause is **still UNNAMED after a day\r\n  of measurement** — and the reason it is unnamed is this entry. Filed as a defect in\r\n  OBSERVABILITY, not in the death.\r\n- **⚠ THIS IS NOT \"find the killer.\"** The killer hunt is the RCA and stays open there. This entry\r\n  is about the fact that a killer hunt had to be run at all from a cold start, with a watcher script\r\n  written by hand after the event, because the product recorded nothing about the transition at the\r\n  moment it noticed it.\r\n\r\n- **THE MEASUREMENT — all four facts read at source, no build (gate was live on both boxes).**\r\n\r\n  1. **The daemon writes its pid.** `crates/spt-daemon/src/daemon.rs:471` —\r\n     `let _ = std::fs::write(daemon_pid_path(), std::process::id().to_string());`, into\r\n     `<spt_home>/daemon.pid` (`crates/spt-daemon/src/endpoint.rs:81`). Unconditional overwrite, no\r\n     read-before-write, no rotation, no history.\r\n  2. **Autostart never looks at it.** `ensure_running_outcome`\r\n     (`crates/spt-daemon/src/daemon.rs:686-724`) decides on `is_running()`, which is\r\n     `seedmap::ping(&seed_socket_name()).is_ok()` (`daemon.rs:598-600`) — **a socket ping and\r\n     nothing else.** The decision consults no pid, no mtime, no prior state.\r\n  3. **The breadcrumb it emits carries no identity.** `daemon.rs:721` —\r\n     `DAEMON_AUTOSTART: no daemon and no standing operator stop — starting one`. Deliberately\r\n     \"always-on, ids-free\" per its own comment, because its job is to be COUNTED (the convoy\r\n     serialization observable that `daemon_stop_convoy_e2e` asserts at :178/:237). That design is\r\n     correct for what it was built for and is exactly why it answers nothing here.\r\n  4. **Then the successor destroys the evidence.** The new daemon reaches :471 and overwrites\r\n     `daemon.pid` with its own pid. The dead pid, and the file mtime that bracketed its life, are\r\n     gone — overwritten by the very event that should have recorded them.\r\n\r\n- **THE SHARP FORM — the file is read ONLY in the state where it can tell you nothing.** The only\r\n  two readers of `daemon_pid_path()` in the tree are `crates/spt/src/cli.rs:8581` and `:8754` (both inside `cmd_daemon_status`, :8573), and\r\n  **both are gated on `running`** (`if running { let pid = read(...) }`). So `daemon.pid` is consulted\r\n  exclusively when a daemon is alive — when its contents are guaranteed fresh and merely restate\r\n  what the ping already proved — and is ignored in the one state where its staleness is the only\r\n  evidence anyone has. Its doc comment (`endpoint.rs:82-85`) says *\"a stale pid here is harmless\r\n  because callers probe the socket, never this file.\"* **That is true for LIVENESS and false for\r\n  FORENSICS**, and the entry is that the codebase has only ever considered the first reading.\r\n\r\n- **WHAT IT COST, concretely, on 2026-09-07.** Daemon pid 14444 died at 08:03:14.87Z inside the ci\r\n  Windows unit leg's nextest LIST phase; successor 48232 cold-started at 08:03:20Z and\r\n  `DAEMON_RESTART_RESUME`d every session, orphaning live agents' monitors and readers and handing at\r\n  least one agent a stale brief. Neither peer ran a kill. To get ANY signal at all I had to hand-write\r\n  an external watcher (`C:\\Users\\decid\\.spt-watch\\watch-daemon.ps1`, 1s cadence, identity re-verified\r\n  by image path AND creation time every poll) **after** the death, which by construction cannot\r\n  observe the event it was written for. 6600+ polls later the successor is alive and the original\r\n  death is still uncharacterized. A product-side record of the transition would have cost bytes.\r\n\r\n- **WHY THIS IS NOT THE CONVOY BREADCRUMB'S JOB, and must not be bolted onto it.**\r\n  `DAEMON_AUTOSTART` is load-bearing as a COUNTABLE line: `daemon_stop_convoy_e2e` asserts *exactly\r\n  one* appears under a storm (:178) and counts N under a deliberate race (:237). Adding identity\r\n  fields to that line risks the count and buries a forensic record inside a line whose contract is\r\n  its cardinality. **The record belongs in its own line and its own artifact.**\r\n\r\n- **REMEDY — RULED 2026-09-07 11:07Z (doyle), APPROVED as proposed with two refinements. Small,\r\n  product-side, no wire change.** doyle re-derived the census independently at `f3c8495b` (one\r\n  writer `daemon.rs:471`, two readers `cli.rs:8581` + `:8754`, both inside `if running`) before\r\n  ruling — the falsifiable claim below has been checked, not taken.\r\n  1. **Read before you clobber.** At `daemon.rs:471`, read the existing `daemon.pid` and its mtime\r\n     BEFORE the write; if it holds a pid that is not ours, emit a distinct, greppable line naming\r\n     the predecessor pid and how long ago the file was last touched — e.g.\r\n     `DAEMON_SUCCEEDS_PID: prior=<pid> prior_pidfile_age_ms=<n> reason=<socket-ping-failed>`. The\r\n     value is that the successor is the only process in the system that is guaranteed to run at\r\n     exactly the moment the question becomes askable.\r\n  2. **Keep one generation.** Rename the existing `daemon.pid` to `daemon.pid.prev` instead of\r\n     overwriting it (best-effort, same directory, same failure posture as today's `let _ =`). One\r\n     generation is enough to answer \"which pid did I replace, and when did it last write?\" and costs\r\n     no rotation policy.\r\n  3. **REFINED BY THE RULING — the discriminator is a FIELD, not a second line.** I proposed a\r\n     separate \"what the ping saw\" record; doyle collapsed it: `prior=<pid|none>` already separates\r\n     the two incidents, because `none` **is** the fresh-home case. One line, one field, no second\r\n     breadcrumb to keep in sync.\r\n  4. **ADDED BY THE RULING — `alive=<bool>`, from a by-number liveness READ at write time.** With\r\n     the prior pid in hand, read whether that number is still live and put the answer on the line.\r\n     It splits the two incidents that otherwise look identical: **`alive` prior = two daemons racing\r\n     the seed bind** (the convoy case), **dead prior = the corpse** (the 14444 case). This is a\r\n     READ, not a kill — #285's identity-before-kill rule binds kills and is not weakened here; a\r\n     by-number read that informs a log line commits no action on the pid.\r\n  5. **UNIT, specified by the ruling:** seed a pidfile with a fake pid and an aged mtime, run the\r\n     write path, assert the emitted fields (`prior`, `age_ms`, `alive`) AND the `daemon.pid.prev`\r\n     bytes. The `.prev` bytes are part of the assertion, not an afterthought — the generation kept\r\n     is the half that survives the process.\r\n  6. **NOT proposed, and the ruling kept it out:** a liveness change. `is_running()` must stay the socket ping — this entry does\r\n     not argue the pidfile should become a liveness signal, which is the exact mistake\r\n     `endpoint.rs:82-85` was written to prevent. The pidfile stays advisory; it just stops being\r\n     silently destroyed.\r\n\r\n- **LANE — SPLIT BY THE RULING, and the two halves ship separately.** The **IR-82 ENTRY** (this\r\n  text) rides hertz's IR-37 thin PR alongside IR-79/80/81. The **PRODUCT REMEDY** rides **#285's\r\n  lane** (todlando, post-W2) because it is the same pid-identity gate: #285 makes a kill read an\r\n  identity, this makes a successor read the identity it is about to erase. One lane, one owner,\r\n  one review of the pid-identity question. Do not implement the remedy in the thin PR.\r\n\r\n- **Kin:** [[RCA-FLEET-DAEMON-14444]] (the open incident this serves — IR-82 does not close it and\r\n  must not be read as closing it), [[IR-81]] (a pid is not an identity — the same lesson from the\r\n  KILL side; here it is the RECORD side), [[IR-80]]/[[IR-79]] (processes outliving what should have\r\n  accounted for them). The through-line doyle named at 10:22Z holds: *a pid is not an identity and a\r\n  pid is not a tree* — and IR-82 adds that **a pid nobody wrote down is not evidence.**\r\n\r\n- **Falsifiable claim, so it can be checked rather than believed:** at `f3c8495b` the tree contains\r\n  exactly ONE writer of `daemon_pid_path()` (`daemon.rs:471`) and exactly TWO readers\r\n  (`cli.rs:8581`, `cli.rs:8754`), both inside a `running` gate. If a future reader appears in an\r\n  unguarded path, this entry's premise weakens and it should be re-measured, not re-asserted.\r\n\r\n### IR-83 — a two-host rig addressed over the tailnet cannot receive INBOUND on Windows, and the whole rig population had only ever run the admitted direction\r\n\r\n- **Status:** OPEN, minted by hertz 2026-09-07 11:41Z on doyle's dispatch (11:40Z). **Provenance: the\r\n  mechanism below is DOYLE'S measurement, not mine** — eight probe arms, each with sender, listener\r\n  and output file, recorded in `GATE-W2-272-CHECKLIST.md` rows 11:36Z–11:39Z. I am off cargo on both\r\n  boxes and have re-measured none of it; this entry is the register form of his finding plus the\r\n  structural reading it supports. Board face: **F18**. Register slot: IR-83 (79/80/81/82 are the\r\n  same thin PR).\r\n- **2026-09-11 ruling:** the original universal \"LAN, never tailnet\" prescription below is\r\n  SUPERSEDED by IR-89's measured tailnet ACL + Windows Firewall remediation and successful\r\n  tailnet probes. Admit the actual transport at each layer and retain an independent reverse\r\n  direction witness. The operator-blocked box remedy is spent; durable witness enforcement\r\n  and its acceptance record remain separate, OPEN work. No new box changes authorized here.\r\n\r\n- **HALF ONE — the tailnet ACL is per-node and ONE-WAY.** `hfenduleam` admits 9 sources and\r\n  `kitsubito` is **not** among them; `kitsubito` admits `hfenduleam`. So a rig cell needing INBOUND\r\n  to the Windows box over `100.x` fails **at the receiver**, and it fails there **whatever the host\r\n  firewall says** — which is why a host-firewall investigation can be run to completion, come back\r\n  clean, and explain nothing.\r\n\r\n- **HALF TWO — Windows defaults `BlockInbound`, and a hash-named test exe has no rule.** Test\r\n  binaries are built with hash-suffixed names, so a rule written against the *program* is keyed to a\r\n  name that changes on the next build. The stale `spt_net-d037…` rule is the precedent already in\r\n  the tree: a rule that was correct once, is present, greps fine, and admits nothing. **The durable\r\n  form is PORT-scoped, not program-scoped:** ports `7480-7499`, `remoteip` = the peer's LAN address,\r\n  added by the operator.\r\n\r\n- **WHY IT SURFACED ONLY NOW, and this is the part that generalizes.** The W2 helper cell is the\r\n  **first cell in the entire rig population that ever needed `kitsubito -> hfenduleam` inbound.**\r\n  W1's four xbox cells and golden's old-twohost job are all `hfenduleam -> kitsubito` — the admitted\r\n  direction. So the population had a **direction monoculture**, and a one-way ACL is invisible to a\r\n  suite that only ever runs the admitted way. Every green in that population was consistent with the\r\n  ACL being wide open and equally consistent with it being one-way; the suite could not tell the\r\n  difference, and nobody had reason to ask. **A capability exercised in only one direction is not\r\n  covered, it is merely unexamined** — the same shape as an assertion that only ever sees the\r\n  passing arm.\r\n\r\n- **THE SECOND STRUCTURAL POINT — a rule keyed to a MUTABLE identity is the lane's own through-line.**\r\n  A per-hash program rule is an exception bound to an identity the build changes underneath it,\r\n  exactly as [[IR-81]] is about a kill bound to a pid the OS may reassign and IR-80 Amendment 1's ENV\r\n  READ face is about a read bound to a process identity `exec` can change. Port-scoping replaces a\r\n  mutable identity with a stable property. That is the same remedy shape as reading an image path\r\n  before a kill and reporting an environment in-band: **stop keying on the thing that moves.** I am\r\n  flagging the rhyme, not claiming a fourth face — this is infrastructure config, not a code path,\r\n  and the amendment's standing prediction is about pid-shaped questions.\r\n\r\n- **FALSIFIABLE CLAIM (doyle's, recorded verbatim as the entry's test):** with the rig on **LAN\r\n  addresses AND the port-scoped rule present**, the helper cell's owner raw carries `WEB_SERVE_FOR`;\r\n  with **either** missing, it carries none. Both arms matter — this is a conjunction, so a single\r\n  green with one of the two absent would refute it, and a red with both present would too.\r\n\r\n- **WHAT THIS ENTRY DOES NOT CLAIM.** It does not say the host firewall was ever misconfigured; the\r\n  ACL half fails at the receiver independently. It does not close F17 or explain the vacuous-green\r\n  run (that was the mid-flight script rewrite — different cause, different fix, and the two were\r\n  live in the same hour, which is precisely why each needed its own named mechanism rather than one\r\n  story). It proposes no product change: both halves are rig addressing and operator-added firewall\r\n  config.\r\n\r\n- **REMEDY.** (1) Rig-side: address peers by LAN in two-host rigs, and make the tailnet address\r\n  unreachable-by-construction rather than merely unused, so a future rig cannot quietly pick it up.\r\n  (2) Operator-side: the port-scoped inbound rule (`7480-7499`, `remoteip` = peer LAN), replacing\r\n  per-hash program rules; the stale `spt_net-d037…` rule should be removed in the same pass so it\r\n  stops reading as coverage. (3) Population-side — **RULED 11:42Z (doyle), with a precision that\r\n  changes the shape:** this is NOT a new cell. **The W2 helper cell IS the first reverse-direction\r\n  cell**, and on LAN it exercises `kitsubito -> hfenduleam` inbound for real once the rule exists.\r\n  The remedy is therefore to **keep at least one reverse cell in the xbox battery permanently and\r\n  NAME it as the direction witness**, so its role is a stated property rather than an accident of\r\n  what W2 happened to need. A suite that only runs one way cannot discover the next one-way ACL\r\n  either, and the way that recurs is not \"nobody wrote the cell\" but \"the cell that had it stopped\r\n  being run.\"\r\n\r\n  **The hazard that follows from naming it, stated here so the naming is not decorative:** a witness\r\n  cell that is SKIPPED stops being a witness while still reporting green — the exact confusion this\r\n  lane already paid for, where a must-skip `role_b` PASS was indistinguishable from four cells that\r\n  no-opped. So the direction witness needs its skip to be loud: if it is filtered out, phase-reclassed,\r\n  or short-circuits on a missing precondition, that must read as ABSENT COVERAGE and not as a pass.\r\n  Whoever names it owns that half too. **Concrete enforcement, doyle-ruled 11:44Z and written up\r\n  as the RIDER 5 ADDENDUM:** the xbox driver's HELPER WITNESS verdict line already refuses a\r\n  `0.0x s` helper PASS and a `b.raw` without `WEB_SERVE_FOR outcome=registered`; it must ALSO\r\n  print `NOT-A-WITNESS` when the cell is absent from the LIST leg. Those first two are\r\n  *ran-but-vacuous*; absence is *never-ran*, and a verdict built only from the first two passes\r\n  it by omission — every refusal condition evaluates against output that does not exist, finds\r\n  nothing to object to, and falls through to green.\r\n\r\n- **GATING CLAUSE — added 2026-09-07 12:56Z on doyle's dispatch (gate reshape, same minute).** An\r\n  inbound-to-Windows cell in a two-host rig is **gated on the port-scoped rule being present**, and\r\n  without it the cell must **SKIP LOUDLY**: it may not run, may not report PASS, and may not be\r\n  silently filtered — its absence must render as ABSENT COVERAGE in the verdict, on the RIDER 5\r\n  ADDENDUM's `NOT-A-WITNESS:NEVER-RAN` face. The precondition is machine-readable, so the driver\r\n  reads `netsh` at start and the gate is a measured fact rather than a remembered one; a cell whose\r\n  precondition is unmet and which therefore emits nothing is exactly the case a verdict assembled\r\n  only from ran-but-vacuous refusals passes by omission. **This clause is what stops the rule's\r\n  ABSENCE from reading as the rig's health.**\r\n\r\n  **How the reshaped W2 F17 gate applies it (doyle 12:56Z, recorded, not re-measured by me — I am\r\n  still off cargo on both boxes).** With the rule absent 75+ minutes and no operator activity, and\r\n  golden carrying no cross-box `twohost_web`, the shortfall is a **rig blocker, not a golden one**.\r\n  So the HELPER WITNESS was reshaped to the **ONE-BOX pair on BOTH OSes** — doyle's gate tree on\r\n  Windows, a kitsubito clone at the tip on Linux with the rig shipped as the frozen copy — on the\r\n  basis that the 03:31Z one-box run at `f3c8495b` reproduced F17 end to end (A `outcome=unanswered`,\r\n  B `DISPATCH:4:Unknown`), i.e. the one-box pair drives the real dispatcher on both roles.\r\n  Mutation D must turn the classify unit cell red **and** the one-box helper cell red\r\n  (owner `family=Unknown`>0, `registered`=0) while deny/fetch stay green; revert dirty 0. The\r\n  cross-box pair still runs as the A->B regression (deny/fetch must PASS), and while the rule is\r\n  absent its helper/range TIMEOUTs are classified **F18-INFRA** — becoming a witness automatically\r\n  if the rule lands before the run, because the driver reads `netsh` at start.\r\n  **The cross-box helper witness therefore stays an OPEN rider on the operator's rule, not a land\r\n  blocker.** Note the shape this preserves: the reshape moves the witness to a pair that CAN run,\r\n  and leaves the direction it cannot exercise named and open — it does not let the one-box green\r\n  stand in for the direction coverage that is still missing. A one-box pair proves the dispatcher;\r\n  it cannot prove an inbound ACL, and nothing here claims it does.\r\n\r\n  **PROBE RESOLUTION — doyle 12:59Z, ADOPTED INTO THIS GATE (not deferred to the rider).** The\r\n  precondition read is now THREE-VALUE in `gate-w2-f17.sh`: `Rule Name` in stdout -> PRESENT,\r\n  `No rules match` -> ABSENT, empty stdout or anything else -> PROBE-FAILED. **PROBE-FAILED\r\n  classifies the cross-box helper/range as `UNCLASSIFIED: this run cannot tell INFRA from a real\r\n  red` — never F18-INFRA** — and xbox-D's skip line names the state. The raw probe (exit code +\r\n  first 3 lines) is printed into the driver log, so the classification is auditable after the fact\r\n  rather than inferred from what got bucketed. Exercised standalone on all three arms: real\r\n  `netsh` = exit 1 + `No rules match` -> ABSENT; forced bad args -> PROBE-FAILED; empty stdout ->\r\n  PROBE-FAILED.\r\n\r\n  **Recorded because it corrects the asker (me), not the implementer:** I proposed the three-value\r\n  shape AND, in the same message, proposed discriminating on the exit code. doyle's standalone\r\n  exercise measured `netsh` exiting **1 on a clean ABSENT**, so an exit-code discriminator would\r\n  have classified every legitimately-absent rule as an instrument fault — turning the run's most\r\n  common honest state into PROBE-FAILED and, with it, `UNCLASSIFIED`. The discriminator that landed\r\n  is STDOUT CONTENT. The general form belongs in the entry because it is the reason the third arm\r\n  needed measuring at all: **a CLI's exit code is a claim about the QUERY, not about the ANSWER**,\r\n  and an empty-but-correct result is reported non-zero by a great many tools. A third value added\r\n  to a probe needs its own evidence, obtained by making all three arms fire on purpose — which is\r\n  this lane's standing rule that a tool whose success path has never been made to fail on purpose\r\n  is untested, applied to a tool's FAILURE path instead.\r\n\r\n- **Kin:** [[IR-81]] and IR-80 Amendment 1 (keying on a mutable identity), the F17 riders (a witness\r\n  that never executed the direction it certifies).\r\n\r\n### IR-84 — the one `PUMP_PEER_FAIL` arm the rigs actually fire was the only one carrying no clock, so the stall that produced it could be counted but never timed\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-09 with the instrument that closes its first half. ·\r\n  **Origin:** the 65 s two-host helper stall (design written before the run,\r\n  `docs/design/RIDER-65S-DESIGN.md`). The number was branch-claimed 2026-09-08 by name only — IR-85\r\n  records that it carried no entry text in any register file in any worktree — and this is that text.\r\n- **Symptom:** `two_host_web_helper_role_a` takes **61.956–69.096 s** across five runs while its\r\n  siblings in the same binary and the same run take **0.135–0.753 s**. Every ladder rig —\r\n  win-onebox, linux-onebox, cross-box — logs **exactly ONE**\r\n  `PUMP_PEER_FAIL:<node>:peer reply-read: no progress within budget — dropping peer (brain IPC read\r\n  deadline elapsed)` on B before completing. **3/3, one each, never on A** (doyle's GATE-W3 readout).\r\n- **Cause of the DIAGNOSTIC failure, which is what this entry is about:** that line is emitted from\r\n  the `Err(e)` arm of `peer_leg_outcome` (`crates/spt-daemon/src/pump/mod.rs`), and at\r\n  `b0b67aaa` it read `emit_line_err!(\"PUMP_PEER_FAIL:{peer_hex}:{e}\")` — **no timestamp**. Measured\r\n  at that sha rather than recalled: the file carries **four** `PUMP_PEER_FAIL` emit sites, **three**\r\n  of them stamped `wall_ms=… mono_ms=…` (the submit arm, the no-route arm, and the\r\n  `PRESENCE_DIAL_FAILED` arm), and this one was **the only unstamped site left**. It is also the\r\n  arm the rigs actually fire — a `PEER_REPLY_READ_BUDGET` expiry reclassified out of `TimedOut` by\r\n  `brain::reclassify_peer_reply_err` so it drops one peer rather than poisoning the round. **The\r\n  single arm a reader most needs to time was the single arm that could not be timed.**\r\n- **What that cost, stated as the open question it left:** the arithmetic does not close and this\r\n  entry does not close it. `PUMP_PEER_IO_TIMEOUT` is **30 s** (`:118`) and `SUPERVISE_BACKOFF_BASE`\r\n  is **5 s** (`:121`) — read as constants, not recalled — so one deadline plus one supervise floor\r\n  accounts for **35 s** against **61.956–69.096 s** observed. **~27–34 s is unaccounted**, itself\r\n  close to another 30, which is exactly the coincidence the design document warns against; and the\r\n  count of **exactly one** fail forbids the easy reading that two deadlines elapsed. Three candidates\r\n  stay open and are NOT ranked here: a first ~30 s burned before the deadline's clock starts; a\r\n  second budget stacking on the first; or the restart's re-prime costing materially more than its\r\n  5 s floor. **Separating them needs the deadline's own timestamps against the fail line** — which\r\n  is precisely what the log did not carry.\r\n- **⚠ WHAT THIS ENTRY DOES NOT CLAIM.** The instrument does not explain the stall, does not shorten\r\n  it, and changes no product behaviour: the same peer is dropped at the same instant with the same\r\n  backoff. It makes the stall **answerable from a log that already contains the failure**, instead of\r\n  requiring a rebuild to learn when the budget started. `PUMP_PEER_IO_TIMEOUT` is a hard const with\r\n  no env knob, so varying it costs a rebuild — deliberately deferred until the stamps say which half\r\n  of the arithmetic is missing.\r\n- **Kin and the recurrence that matters:** this is the **SECOND** time an unstamped\r\n  `PUMP_PEER_FAIL` cost a hunt. The `PRESENCE_DIAL_FAILED` arm carries a comment naming the\r\n  \"2026-07-14 `PUMP_PEER_FAIL`-unstamped seed, folded here\", and **REQ-PUMP-STAGE-TRUTH** already\r\n  requires every peer failure \"stamped (wall+mono) and peer-attributed\", explicitly subsuming that\r\n  seed. So the contract was written, three of four sites complied, and the fourth stayed silent for\r\n  eight weeks — **a convention enforced by no mechanism degrades one arm at a time, and every reader\r\n  of a complying arm reports the convention as held**, the same shape as the `validate_docs_dir`\r\n  refusal-arm rider in the same design document. Also kin: **IR-83** (the rig population had only\r\n  ever run the admitted direction), `REQ-HAZARD-PUMP-IPC-DEADLINE` (a `TimedOut` brain-IPC read is a\r\n  supervised restart, never a per-peer retry), ADR-0039 Decision 5.\r\n- **Ripe when:** now, and it lands with this entry — the stamp is one emit line, tagged\r\n  `[impl->REQ-PUMP-STAGE-TRUTH]` at the site. · **Size:** one emit line plus its comment.\r\n  **Follow-up, not this lane:** a cell that walks every `PUMP_PEER_FAIL` arm and asserts each one\r\n  stamps, so the fifth site added cannot be born silent.\r\n### IR-85 — the Windows self-hosted box runs its fs-heavy tests 3-4x slower than a week ago; two CI wall clocks were sized for the old box, and a red run kept hiding it\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-09 at the #272/v0.68.0 golden r3/r4 arc, on doyle's\r\n  dispatch. Number ruled by doyle from his own census of main@`a2f335f8` (register ended at IR-83;\r\n  IR-84 was branch-claimed by name only, with no entry text in any register file in any worktree —\r\n  that gap is now closed: **IR-84 was filed 2026-09-09 in PR #213**, so this sentence records the\r\n  state at `a2f335f8` and is no longer a reason to go looking for a missing entry).\r\n  **Absorbs two drafts:** doyle's `IR-DRAFT-windows-fs-heavy-slowdown-and-golden-wall` (his IR-A +\r\n  IR-B) and his earlier `IR-NEXT` (operator-desktop load), both retired by reference — this is the\r\n  single entry. Every job/step and per-test timing below is **doyle's**, read via the job/step API.\r\n  · **Origin:** #272 golden r3 attempt 2 was CANCELLED by a wall clock with both test phases green.\r\n- **⚠ THE CAP CHANGE IN `a2f335f8` IS NOT THE FIX AND MUST NOT BE READ AS ONE.** It bounds the run;\r\n  it repairs nothing. A future reader who finds an 80-minute wall and no entry here would reasonably\r\n  conclude the problem was solved. It was only made visible.\r\n\r\n- **A GREEN RUN COSTS MORE THAN A RED ONE, WHICH IS WHY THIS WENT UNSEEN.** A failing run\r\n  short-circuits past the wall a green run has to cross. r3 att1 finished in **48m39s only because\r\n  it FAILED at Phase B**; att2, green, hit 49m59s and was cancelled. Every earlier docs-drift skip\r\n  therefore presented as \"upstream failure\" — the wall was never the reported cause of anything, and\r\n  the surviving evidence systematically flattered the budget.\r\n\r\n- **THE WALL.** Windows golden `test` job (48 steps), fully GREEN: **30m53s** (2026-08-30, run\r\n  33296634901) and **33m21s** (2026-09-06, run 34017906638). At the v0.68.0 head against the\r\n  then-current 50-minute cap — **r3 att2**, job 102352551368 at `f6110c2a`: Phase A 17m14s, Phase B\r\n  20m25s, doctests 1m04s, clippy 3m31s, **CANCELLED at step 30 at 49m59s with everything green**;\r\n  steps 31-42 (installer, docs floor, both docs-drift gates, dormancy) never ran. r2 att1\r\n  (`25e60015`, 09-08 18:47Z) reached step 34 at 44m30s. Steps 30..39 cost ~3m30s on the 09-06 green\r\n  (notify 47s, installer 13s, docs-drift 1m54s). Predicted green need ~**56 min**; cap raised to\r\n  **80** (need + ~40% for day-to-day variance) in `a2f335f8`, ci unit 25 -> 40 in the same commit.\r\n- **r4, GREEN — the first complete measurement at the head: 54m35s** (07:12:26Z -> 08:07:01Z),\r\n  **25m25s** headroom under 80; docs-drift (step 38) 2m23s; Phase A 15m51s, Phase B 22m56s. The ~56\r\n  prediction held to within 1.5 min, so the cap is sized on evidence, not generosity. **What that\r\n  does NOT establish:** it was a sizing forecast, and its holding says nothing about the cause\r\n  diagnosis below. Nor are att2-vs-r4 per-phase deltas a trend — att2 was cancelled mid-run, so only\r\n  its phase legs are comparable at all, and the spread they sit in is the same variance the 40% is\r\n  there to absorb.\r\n\r\n- **THE SLOWDOWN, per test, same box, same tests.** `spt-daemon::sync` concurrent_writes\r\n  **22.4s -> 74.8s**, two_tier_sync 18.7 -> 67.4; `spt-store` monic clone_copies 17.7 -> 62.9,\r\n  different_monics 18.2 -> 64.9; syncmerge reconciled_write 27.3 -> 51.2. **~25 spt-store/spt-daemon\r\n  tests now exceed 30s on Windows Phase A at `f6110c2a`, against 1-2s each on kitsubito.**\r\n  Phase-level: Phase A nextest 170s (09-06) -> 642s (att1) -> 1034s (att2); Phase B 710s -> 1164s.\r\n  The suite did not get more expensive — Linux is unchanged.\r\n\r\n- **DATING SAYS ENVIRONMENT DOMINATES, AND BY HOW MUCH.** main's own ci Windows `unit` job:\r\n  11-12 min on 09-06 (runs 34040416870, 34041526195, 34043323577) -> 13-20 min on 09-07 -> 12-24 min\r\n  on 09-08, hitting **22 min at `e4444413`** (run 34261096301) three minutes under its own 25-minute\r\n  wall. **Gradual over days, under no single gate change, is the shape of an environment term, not a\r\n  commit's.** Head growth is real but MINOR: +138 Phase A tests, +20 Phase B, HEAVY 34 -> 35.\r\n\r\n- **THE BOX IS AN OPERATOR DESKTOP (folded in from the retired IR-NEXT), and that turns every fixed\r\n  wall-clock budget in the Windows suite into a coin.** From the r2 arc, three attempts at ONE sha\r\n  (run 34262154550 @ `25e60015`): Phase B red each time on a **different single cell or none** — a1\r\n  234/234 (job red on disk floors only), a2 `spt::webserve_attachment_e2e` arm 12, a3\r\n  `spt-daemon::mesh_recovery roster_route_survives_a_transient_dial_failure_with_discovery_disabled`\r\n  (15.0s `converge()` budget, cell 15.715s; the same cell 9.8s / 7.2s on a1/a2). Phase A — 3,346\r\n  spawn-dominated unit cells — slowed **monotonically 448.7 -> 495.1 -> 542.6s at that one sha**.\r\n  Per-cell a3/a2 over 73 Phase B cells >= 1s: median 1.05x, mean 1.34x, 19 cells >= 1.5x, worst 5.2x\r\n  (`endpoint_lifecycle poll_vs_reap` 1.1 -> 5.8s) — **BURSTY, not uniform**. A rotating single victim\r\n  across attempts at one sha is ONE environment cause; hardening victims one at a time never closes\r\n  it (paid before: `e2e-leaked-daemons-shared-box`). The budgets that lost were ~1.5x the fast\r\n  observation — inside the box's measured variance, so they were coins that had been landing right.\r\n- **Box census (doyle 01:13-01:19Z, no cargo/rustc/nextest running, CPU 31%, ~1.1 of 16 cores busy):**\r\n  `qbittorrent.exe` seeding since 09-08 10:20Z (box tx 21.3 MB/s over 5s); fleet `spt daemon brain`\r\n  with 516 GB read since 09-07 08:03Z (~3.5 MB/s steady); Defender real-time ON, `MsMpEng` at\r\n  67.8/62.8/48.9/32.2/12.2% of a core over 5s **on the idle box**; a fresh 35 MB exe pays\r\n  2092/994/1171/1043 ms on FIRST execution against 31/263/19/260 ms on the second — **and every CI\r\n  attempt rebuilds every test binary fresh.** At 06:45Z on 09-09, with the twohost legs running:\r\n  MsMpEng 89% CPU / 991 MB WS, qbittorrent pid 47056 holding 7817 CPU-seconds (2.2 h) since\r\n  09-08 03:20, free 134 GiB (275 -> 197 -> 131 across the three r3 dispatches).\r\n- **⚠ AN UNREADABLE ROW IS NOT AN ABSENT ONE.** The Defender exclusion list cannot be read\r\n  unelevated on this box: `Get-MpPreference` returns the literal string\r\n  `N/A: Must be an administrator to view exclusions` **as the ExclusionPath VALUE**, so a\r\n  `-contains` test reads ABSENT and is meaningless; the HKLM `Windows Defender\\Exclusions\\Paths`\r\n  read throws `SecurityException`. Nobody may report the runner directory as unexcluded from an\r\n  unelevated shell.\r\n\r\n- **HYPOTHESIS ALREADY KILLED, so nobody re-runs it:** the Windows-only `ADAPTER_WEB_PENDING`\r\n  reconcile failure (servehost nudge) **cannot** explain this — spt-store monic and contextstore\r\n  never touch that path.\r\n\r\n- **WHAT IS STILL NOT ESTABLISHED (labelled, so it is not inherited as fact).** The dating argument\r\n  establishes environment-DOMINANT and bounds head growth as the minor term. It does **not**\r\n  apportion the environment term itself: Defender vs the third-party torrent load vs the fleet\r\n  brain's steady read vs anything else is unsplit, and **\"MsMpEng at 89%\" remains a correlate\r\n  measured beside the slowdown, not a proven cause.** The discriminator lane below is what settles\r\n  head-vs-environment on evidence rather than on the shape of a drift curve.\r\n\r\n- **REMEDY — none landed. This entry is the debt, and its middle arms need an operator.** Sequence\r\n  matters; run them in this order:\r\n  1. **DISCRIMINATOR LANE (hertz, one box, ~1.5-2 h).** Run the five named tests at `04e32c8c` and\r\n     at `f6110c2a` on hfenduleam. **Same-slow at both = environment; slow only at the head = head\r\n     growth.** Cheap and decidable, and it must precede any operator ask — do not spend an elevation\r\n     request on a hypothesis a one-lane measurement can test. Design note, because it is the part\r\n     that makes the number trustworthy: the arms run **INTERLEAVED** (A/B/A/B/A/B, 3 reps each), not\r\n     all-A-then-all-B, so drift that hits the whole box cancels in the comparison instead of landing\r\n     on one arm. **A measurement that only works if everyone behaves is not a measurement** — the\r\n     torrent client and Defender are running throughout and are the thing under test, not noise\r\n     anyone gets to remove. Confounder already excluded: the three test-bearing files\r\n     (`spt-daemon/tests/sync.rs`, `spt-store/src/monic.rs`, `spt-store/src/syncmerge.rs`) are\r\n     **byte-identical blobs at both shas**, so a difference cannot be the tests changing; the two\r\n     crates around them are not (+11,388 lines over 48 files).\r\n  2. **Remove the third-party load first.** No torrent client on the CI box during golden windows.\r\n     It is the cheapest variable to remove, and removing it first makes arm 3's benefit measurable\r\n     instead of confounded.\r\n  3. **OPERATOR ASK — Defender path exclusions** for `C:\\actions-runner\\_work` and the gate pools,\r\n     read from an ADMIN shell first (see the unreadable-row warning above), then re-measure the\r\n     first-touch tax on a file **under that path** — the scratchpad measurement is outside the\r\n     runner dir, so it proves the mechanism's size, not the runner's exposure. Unsettable\r\n     unelevated; same shape as **IR-89**'s elevated firewall rule.\r\n  4. **CI census, cheap and durable:** print `Get-MpComputerStatus` RealTimeProtectionEnabled plus\r\n     the ExclusionPath read **verbatim, refusal text included**, in the Windows job's census step,\r\n     so a run's own record says what Defender it ran under.\r\n  5. **Re-measure both caps after any arm lands — the arm a future reader will skip, so it is loud\r\n     here.** A cap sized against a degraded box is correct only while the box stays degraded.\r\n     Leaving 80 in place after a repair silently restores the original hazard: a wall so generous it\r\n     no longer catches a wedged test, which is the job the golden cap was added to do in the first\r\n     place (the 2026-06-03 handoff.rs ConPTY stall, 22 unbounded hosted minutes).\r\n- **Kin:** [[IR-76]] (the golden runner IS the builders' box — the structural reason a desktop's\r\n  load reaches CI at all), [[IR-64]] (box-level facts only the operator can move), [[IR-89]] (the\r\n  other elevated box-rule ask), `defender-first-touch-tax-on-fresh-test-binaries` and\r\n  `e2e-leaked-daemons-shared-box` (memory).\r\n- **Ripe when:** arm 1 now; arms 2-4 on the operator's answer; arm 5 at the next `golden.yml` touch\r\n  after any of them. · **Size:** arm 1 a measurement, arm 4 one census line, arm 5 two literals.\r\n- **AMENDMENT 2026-09-09 (two terms this entry did not name when it landed at `d32d5c4c`).**\r\n  1. **`ci.yml`'s `changes` job runs `unit` on BOTH runners for every push to `main`.** The classify\r\n     step at `.github/workflows/ci.yml:49` emits `code=true` for every non-`pull_request` event, so\r\n     the docs-only skip that PR runs #206/#207 demonstrated is **`pull_request`-only** — read from\r\n     `ci.yml` at `main` by doyle, who names it his own error after twice ruling the opposite from the\r\n     PR runs alone. Consequence for this entry's wall clock: run **34337797758** (the ff of\r\n     `b66a9612`, a docs-only delta over golden-green `a2f335f8`) ran `unit (Windows)` 09:59:57Z →\r\n     10:40:48Z and was **CANCELLED at the 40-minute job wall** (job timeout; conclusion `cancelled`,\r\n     step 6 `Unit tests` 10:08:23 → 10:40:03) — a red on `main` at a sha whose content cannot fail a\r\n     unit test. It is an IR-85 face, not a flake row.\r\n  2. **A near-full volume is an environment term for the slowdown**, alongside the Defender\r\n     first-touch tax and the operator-desktop load already recorded. **Deliberately unquantified:**\r\n     the discriminator window that would have apportioned it was VOID, because the one leg that\r\n     completed ran under both a CI job and a falling disk. See **IR-90**.\r\n- **WHAT THE VOIDED DISCRIMINATOR ESTABLISHED, negatively (hertz, 2026-09-09).** The fs-heavy\r\n  slowdown REPRODUCES at `04e32c8c`, which predates the +11,388-line head growth: spt-daemon\r\n  `concurrent_writes` 105.420 s, `two_tier_sync` 58.362 s, spt-store `clone_copies` 65.657 s,\r\n  `different_monics` 73.967 s, `syncmerge reconciled_write` 86.765 s, against the 09-06 baseline of\r\n  22.4 / 18.7 / 17.7 / 18.2 / 27.3 s — **3.2x to 4.7x on all five, at the OLD sha**. So head growth\r\n  is **not NECESSARY** for the slowdown. That is the whole of it: it does NOT measure how much the\r\n  environment explains, and it is not evidence about the head arm at all — that leg ran inside run\r\n  34337797758's window and on a volume that reached 0.018 GiB free, and the head arm never produced\r\n  a comparable pair. **Arm 1 stays OPEN**, its re-run deferred until **IR-90**'s guard exists and a\r\n  window with no `main` push and no CI job on the box can be scheduled.\r\n\r\n- **AMENDMENT 2026-09-10 (hertz, on THIS ENTRY'S OWN arm-1 design note).** The note says the arms run\r\n  **INTERLEAVED** A/B/A/B so box drift cancels. It does not cancel: **B is always the later arm within\r\n  each pair**, so a monotone drift across the session lands on B every time and is read as an arm\r\n  effect. Alternate the PAIR ORDER — **A/B then B/A** — record per-leg timestamps and conditions, and\r\n  describe the result as **REDUCING order confounding, not eliminating it**. Second binding change,\r\n  from the releases#294 triage: **instrument, do not infer.** `cargo nextest run --success-output\r\n  immediate` retains stdout for PASSING tests (deployah), so a passing arm can still print poll\r\n  elapsed, iteration count, IPC time and producer progress — **a failing arm is not required** for a\r\n  margin measurement (todlando, correcting deployah's \"it has to fail to be informative\"). Arm 1 was\r\n  never re-run, so this lands before the measurement, not after it.\r\n\r\n### IR-86 — golden's 32 GiB floor is BELOW the measured 67.4 GiB Windows suite footprint, so a start floor passes a box that cannot finish\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-08 at the #272/v0.68.0 golden r2 triage. · **Origin:**\r","truncated":true,"truncatedBy":"lines","totalLines":1370,"totalBytes":39039,"outputLines":457,"outputBytes":39039,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":5900,"displayContent":{"text":"### IR-81 — a process kill can be written scoped or machine-wide, and nothing makes the scoped form the only reachable one: both codebases carry the right pattern beside the wrong one\n…\n#### SCOPING ARM (a) — the product path has no intermediary; the fixture does\n…\n\r\n### IR-82 — a daemon death leaves NO record of who died: autostart decides on a socket ping, says \"no daemon\", and the successor overwrites the only handle on the corpse\r\n\r\n- **Status:** RULED 2026-09-07 11:07Z (doyle), drafted by hertz 11:04Z on doyle's dispatch (11:03Z: *\"the autostart\r\n  death-cause item is an IR, not a board item — mint it IR-82 in your thin PR\"*). Register on main\r\n  ends at IR-78; 79/80/81 are drafts in the same PR. · **Origin:** the fleet-daemon death on\r\n  hfenduleam at 08:03:14.87Z ([[RCA-FLEET-DAEMON-14444]]) whose cause is **still UNNAMED after a day\r\n  of measurement** — and the reason it is unnamed is this entry. Filed as a defect in\r\n  OBSERVABILITY, not in the death.\r\n- **⚠ THIS IS NOT \"find the killer.\"** The killer hunt is the RCA and stays open there. This entry\r\n  is about the fact that a killer hunt had to be run at all from a cold start, with a watcher script\r\n  written by hand after the event, because the product recorded nothing about the transition at the\r\n  moment it noticed it.\r\n\r\n- **THE MEASUREMENT — all four facts read at source, no build (gate was live on both boxes).**\r\n\r\n  1. **The daemon writes its pid.** `crates/spt-daemon/src/daemon.rs:471` —\r\n     `let _ = std::fs::write(daemon_pid_path(), std::process::id().to_string());`, into\r\n     `<spt_home>/daemon.pid` (`crates/spt-daemon/src/endpoint.rs:81`). Unconditional overwrite, no\r\n     read-before-write, no rotation, no history.\r\n  2. **Autostart never looks at it.** `ensure_running_outcome`\r\n     (`crates/spt-daemon/src/daemon.rs:686-724`) decides on `is_running()`, which is\r\n     `seedmap::ping(&seed_socket_name()).is_ok()` (`daemon.rs:598-600`) — **a socket ping and\r\n     nothing else.** The decision consults no pid, no mtime, no prior state.\r\n  3. **The breadcrumb it emits carries no identity.** `daemon.rs:721` —\r\n     `DAEMON_AUTOSTART: no daemon and no standing operator stop — starting one`. Deliberately\r\n     \"always-on, ids-free\" per its own comment, because its job is to be COUNTED (the convoy\r\n     serialization observable that `daemon_stop_convoy_e2e` asserts at :178/:237). That design is\r\n     correct for what it was built for and is exactly why it answers nothing here.\r\n  4. **Then the successor destroys the evidence.** The new daemon reaches :471 and overwrites\r\n     `daemon.pid` with its own pid. The dead pid, and the file mtime that bracketed its life, are\r\n     gone — overwritten by the very event that should have recorded them.\r\n\r\n- **THE SHARP FORM — the file is read ONLY in the state where it can tell you nothing.** The only\r\n  two readers of `daemon_pid_path()` in the tree are `crates/spt/src/cli.rs:8581` and `:8754` (both inside `cmd_daemon_status`, :8573), and\r\n  **both are gated on `running`** (`if running { let pid = read(...) }`). So `daemon.pid` is consulted\r\n  exclusively when a daemon is alive — when its contents are guaranteed fresh and merely restate\r\n  what the ping already proved — and is ignored in the one state where its staleness is the only\r\n  evidence anyone has. Its doc comment (`endpoint.rs:82-85`) says *\"a stale pid here is harmless\r\n  because callers probe the socket, never this file.\"* **That is true for LIVENESS and false for\r\n  FORENSICS**, and the entry is that the codebase has only ever considered the first reading.\r\n\r\n- **WHAT IT COST, concretely, on 2026-09-07.** Daemon pid 14444 died at 08:03:14.87Z inside the ci\r\n  Windows unit leg's nextest LIST phase; successor 48232 cold-started at 08:03:20Z and\r\n  `DAEMON_RESTART_RESUME`d every session, orphaning live agents' monitors and readers and handing at\r\n  least one agent a stale brief. Neither peer ran a kill. To get ANY signal at all I had to hand-write\r\n  an external watcher (`C:\\Users\\decid\\.spt-watch\\watch-daemon.ps1`, 1s cadence, identity re-verified\r\n  by image path AND creation time every poll) **after** the death, which by construction cannot\r\n  observe the event it was written for. 6600+ polls later the successor is alive and the original\r\n  death is still uncharacterized. A product-side record of the transition would have cost bytes.\r\n\r\n- **WHY THIS IS NOT THE CONVOY BREADCRUMB'S JOB, and must not be bolted onto it.**\r\n  `DAEMON_AUTOSTART` is load-bearing as a COUNTABLE line: `daemon_stop_convoy_e2e` asserts *exactly\r\n  one* appears under a storm (:178) and counts N under a deliberate race (:237). Adding identity\r\n  fields to that line risks the count and buries a forensic record inside a line whose contract is\r\n  its cardinality. **The record belongs in its own line and its own artifact.**\r\n\r\n- **REMEDY — RULED 2026-09-07 11:07Z (doyle), APPROVED as proposed with two refinements. Small,\r\n  product-side, no wire change.** doyle re-derived the census independently at `f3c8495b` (one\r\n  writer `daemon.rs:471`, two readers `cli.rs:8581` + `:8754`, both inside `if running`) before\r\n  ruling — the falsifiable claim below has been checked, not taken.\r\n  1. **Read before you clobber.** At `daemon.rs:471`, read the existing `daemon.pid` and its mtime\r\n     BEFORE the write; if it holds a pid that is not ours, emit a distinct, greppable line naming\r\n     the predecessor pid and how long ago the file was last touched — e.g.\r\n     `DAEMON_SUCCEEDS_PID: prior=<pid> prior_pidfile_age_ms=<n> reason=<socket-ping-failed>`. The\r\n     value is that the successor is the only process in the system that is guaranteed to run at\r\n     exactly the moment the question becomes askable.\r\n  2. **Keep one generation.** Rename the existing `daemon.pid` to `daemon.pid.prev` instead of\r\n     overwriting it (best-effort, same directory, same failure posture as today's `let _ =`). One\r\n     generation is enough to answer \"which pid did I replace, and when did it last write?\" and costs\r\n     no rotation policy.\r\n  3. **REFINED BY THE RULING — the discriminator is a FIELD, not a second line.** I proposed a\r\n     separate \"what the ping saw\" record; doyle collapsed it: `prior=<pid|none>` already separates\r\n     the two incidents, because `none` **is** the fresh-home case. One line, one field, no second\r\n     breadcrumb to keep in sync.\r\n  4. **ADDED BY THE RULING — `alive=<bool>`, from a by-number liveness READ at write time.** With\r\n     the prior pid in hand, read whether that number is still live and put the answer on the line.\r\n     It splits the two incidents that otherwise look identical: **`alive` prior = two daemons racing\r\n     the seed bind** (the convoy case), **dead prior = the corpse** (the 14444 case). This is a\r\n     READ, not a kill — #285's identity-before-kill rule binds kills and is not weakened here; a\r\n     by-number read that informs a log line commits no action on the pid.\r\n  5. **UNIT, specified by the ruling:** seed a pidfile with a fake pid and an aged mtime, run the\r\n     write path, assert the emitted fields (`prior`, `age_ms`, `alive`) AND the `daemon.pid.prev`\r\n     bytes. The `.prev` bytes are part of the assertion, not an afterthought — the generation kept\r\n     is the half that survives the process.\r\n  6. **NOT proposed, and the ruling kept it out:** a liveness change. `is_running()` must stay the socket ping — this entry does\r\n     not argue the pidfile should become a liveness signal, which is the exact mistake\r\n     `endpoint.rs:82-85` was written to prevent. The pidfile stays advisory; it just stops being\r\n     silently destroyed.\r\n\r\n- **LANE — SPLIT BY THE RULING, and the two halves ship separately.** The **IR-82 ENTRY** (this\r\n  text) rides hertz's IR-37 thin PR alongside IR-79/80/81. The **PRODUCT REMEDY** rides **#285's\r\n  lane** (todlando, post-W2) because it is the same pid-identity gate: #285 makes a kill read an\r\n  identity, this makes a successor read the identity it is about to erase. One lane, one owner,\r\n  one review of the pid-identity question. Do not implement the remedy in the thin PR.\r\n\r\n- **Kin:** [[RCA-FLEET-DAEMON-14444]] (the open incident this serves — IR-82 does not close it and\r\n  must not be read as closing it), [[IR-81]] (a pid is not an identity — the same lesson from the\r\n  KILL side; here it is the RECORD side), [[IR-80]]/[[IR-79]] (processes outliving what should have\r\n  accounted for them). The through-line doyle named at 10:22Z holds: *a pid is not an identity and a\r\n  pid is not a tree* — and IR-82 adds that **a pid nobody wrote down is not evidence.**\r\n\r\n- **Falsifiable claim, so it can be checked rather than believed:** at `f3c8495b` the tree contains\r\n  exactly ONE writer of `daemon_pid_path()` (`daemon.rs:471`) and exactly TWO readers\r\n  (`cli.rs:8581`, `cli.rs:8754`), both inside a `running` gate. If a future reader appears in an\r\n  unguarded path, this entry's premise weakens and it should be re-measured, not re-asserted.\r\n\r\n### IR-83 — a two-host rig addressed over the tailnet cannot receive INBOUND on Windows, and the whole rig population had only ever run the admitted direction\r\n\r\n- **Status:** OPEN, minted by hertz 2026-09-07 11:41Z on doyle's dispatch (11:40Z). **Provenance: the\r\n  mechanism below is DOYLE'S measurement, not mine** — eight probe arms, each with sender, listener\r\n  and output file, recorded in `GATE-W2-272-CHECKLIST.md` rows 11:36Z–11:39Z. I am off cargo on both\r\n  boxes and have re-measured none of it; this entry is the register form of his finding plus the\r\n  structural reading it supports. Board face: **F18**. Register slot: IR-83 (79/80/81/82 are the\r\n  same thin PR).\r\n- **2026-09-11 ruling:** the original universal \"LAN, never tailnet\" prescription below is\r\n  SUPERSEDED by IR-89's measured tailnet ACL + Windows Firewall remediation and successful\r\n  tailnet probes. Admit the actual transport at each layer and retain an independent reverse\r\n  direction witness. The operator-blocked box remedy is spent; durable witness enforcement\r\n  and its acceptance record remain separate, OPEN work. No new box changes authorized here.\r\n\r\n- **HALF ONE — the tailnet ACL is per-node and ONE-WAY.** `hfenduleam` admits 9 sources and\r\n  `kitsubito` is **not** among them; `kitsubito` admits `hfenduleam`. So a rig cell needing INBOUND\r\n  to the Windows box over `100.x` fails **at the receiver**, and it fails there **whatever the host\r\n  firewall says** — which is why a host-firewall investigation can be run to completion, come back\r\n  clean, and explain nothing.\r\n\r\n- **HALF TWO — Windows defaults `BlockInbound`, and a hash-named test exe has no rule.** Test\r\n  binaries are built with hash-suffixed names, so a rule written against the *program* is keyed to a\r\n  name that changes on the next build. The stale `spt_net-d037…` rule is the precedent already in\r\n  the tree: a rule that was correct once, is present, greps fine, and admits nothing. **The durable\r\n  form is PORT-scoped, not program-scoped:** ports `7480-7499`, `remoteip` = the peer's LAN address,\r\n  added by the operator.\r\n\r\n- **WHY IT SURFACED ONLY NOW, and this is the part that generalizes.** The W2 helper cell is the\r\n  **first cell in the entire rig population that ever needed `kitsubito -> hfenduleam` inbound.**\r\n  W1's four xbox cells and golden's old-twohost job are all `hfenduleam -> kitsubito` — the admitted\r\n  direction. So the population had a **direction monoculture**, and a one-way ACL is invisible to a\r\n  suite that only ever runs the admitted way. Every green in that population was consistent with the\r\n  ACL being wide open and equally consistent with it being one-way; the suite could not tell the\r\n  difference, and nobody had reason to ask. **A capability exercised in only one direction is not\r\n  covered, it is merely unexamined** — the same shape as an assertion that only ever sees the\r\n  passing arm.\r\n\r\n- **THE SECOND STRUCTURAL POINT — a rule keyed to a MUTABLE identity is the lane's own through-line.**\r\n  A per-hash program rule is an exception bound to an identity the build changes underneath it,\r\n  exactly as [[IR-81]] is about a kill bound to a pid the OS may reassign and IR-80 Amendment 1's ENV\r\n  READ face is about a read bound to a process identity `exec` can change. Port-scoping replaces a\r\n  mutable identity with a stable property. That is the same remedy shape as reading an image path\r\n  before a kill and reporting an environment in-band: **stop keying on the thing that moves.** I am\r\n  flagging the rhyme, not claiming a fourth face — this is infrastructure config, not a code path,\r\n  and the amendment's standing prediction is about pid-shaped questions.\r\n\r\n- **FALSIFIABLE CLAIM (doyle's, recorded verbatim as the entry's test):** with the rig on **LAN\r\n  addresses AND the port-scoped rule present**, the helper cell's owner raw carries `WEB_SERVE_FOR`;\r\n  with **either** missing, it carries none. Both arms matter — this is a conjunction, so a single\r\n  green with one of the two absent would refute it, and a red with both present would too.\r\n\r\n- **WHAT THIS ENTRY DOES NOT CLAIM.** It does not say the host firewall was ever misconfigured; the\r\n  ACL half fails at the receiver independently. It does not close F17 or explain the vacuous-green\r\n  run (that was the mid-flight script rewrite — different cause, different fix, and the two were\r\n  live in the same hour, which is precisely why each needed its own named mechanism rather than one\r\n  story). It proposes no product change: both halves are rig addressing and operator-added firewall\r\n  config.\r\n\r\n- **REMEDY.** (1) Rig-side: address peers by LAN in two-host rigs, and make the tailnet address\r\n  unreachable-by-construction rather than merely unused, so a future rig cannot quietly pick it up.\r\n  (2) Operator-side: the port-scoped inbound rule (`7480-7499`, `remoteip` = peer LAN), replacing\r\n  per-hash program rules; the stale `spt_net-d037…` rule should be removed in the same pass so it\r\n  stops reading as coverage. (3) Population-side — **RULED 11:42Z (doyle), with a precision that\r\n  changes the shape:** this is NOT a new cell. **The W2 helper cell IS the first reverse-direction\r\n  cell**, and on LAN it exercises `kitsubito -> hfenduleam` inbound for real once the rule exists.\r\n  The remedy is therefore to **keep at least one reverse cell in the xbox battery permanently and\r\n  NAME it as the direction witness**, so its role is a stated property rather than an accident of\r\n  what W2 happened to need. A suite that only runs one way cannot discover the next one-way ACL\r\n  either, and the way that recurs is not \"nobody wrote the cell\" but \"the cell that had it stopped\r\n  being run.\"\r\n\r\n  **The hazard that follows from naming it, stated here so the naming is not decorative:** a witness\r\n  cell that is SKIPPED stops being a witness while still reporting green — the exact confusion this\r\n  lane already paid for, where a must-skip `role_b` PASS was indistinguishable from four cells that\r\n  no-opped. So the direction witness needs its skip to be loud: if it is filtered out, phase-reclassed,\r\n  or short-circuits on a missing precondition, that must read as ABSENT COVERAGE and not as a pass.\r\n  Whoever names it owns that half too. **Concrete enforcement, doyle-ruled 11:44Z and written up\r\n  as the RIDER 5 ADDENDUM:** the xbox driver's HELPER WITNESS verdict line already refuses a\r\n  `0.0x s` helper PASS and a `b.raw` without `WEB_SERVE_FOR outcome=registered`; it must ALSO\r\n  print `NOT-A-WITNESS` when the cell is absent from the LIST leg. Those first two are\r\n  *ran-but-vacuous*; absence is *never-ran*, and a verdict built only from the first two passes\r\n  it by omission — every refusal condition evaluates against output that does not exist, finds\r\n  nothing to object to, and falls through to green.\r\n\r\n- **GATING CLAUSE — added 2026-09-07 12:56Z on doyle's dispatch (gate reshape, same minute).** An\r\n  inbound-to-Windows cell in a two-host rig is **gated on the port-scoped rule being present**, and\r\n  without it the cell must **SKIP LOUDLY**: it may not run, may not report PASS, and may not be\r\n  silently filtered — its absence must render as ABSENT COVERAGE in the verdict, on the RIDER 5\r\n  ADDENDUM's `NOT-A-WITNESS:NEVER-RAN` face. The precondition is machine-readable, so the driver\r\n  reads `netsh` at start and the gate is a measured fact rather than a remembered one; a cell whose\r\n  precondition is unmet and which therefore emits nothing is exactly the case a verdict assembled\r\n  only from ran-but-vacuous refusals passes by omission. **This clause is what stops the rule's\r\n  ABSENCE from reading as the rig's health.**\r\n\r\n  **How the reshaped W2 F17 gate applies it (doyle 12:56Z, recorded, not re-measured by me — I am\r\n  still off cargo on both boxes).** With the rule absent 75+ minutes and no operator activity, and\r\n  golden carrying no cross-box `twohost_web`, the shortfall is a **rig blocker, not a golden one**.\r\n  So the HELPER WITNESS was reshaped to the **ONE-BOX pair on BOTH OSes** — doyle's gate tree on\r\n  Windows, a kitsubito clone at the tip on Linux with the rig shipped as the frozen copy — on the\r\n  basis that the 03:31Z one-box run at `f3c8495b` reproduced F17 end to end (A `outcome=unanswered`,\r\n  B `DISPATCH:4:Unknown`), i.e. the one-box pair drives the real dispatcher on both roles.\r\n  Mutation D must turn the classify unit cell red **and** the one-box helper cell red\r\n  (owner `family=Unknown`>0, `registered`=0) while deny/fetch stay green; revert dirty 0. The\r\n  cross-box pair still runs as the A->B regression (deny/fetch must PASS), and while the rule is\r\n  absent its helper/range TIMEOUTs are classified **F18-INFRA** — becoming a witness automatically\r\n  if the rule lands before the run, because the driver reads `netsh` at start.\r\n  **The cross-box helper witness therefore stays an OPEN rider on the operator's rule, not a land\r\n  blocker.** Note the shape this preserves: the reshape moves the witness to a pair that CAN run,\r\n  and leaves the direction it cannot exercise named and open — it does not let the one-box green\r\n  stand in for the direction coverage that is still missing. A one-box pair proves the dispatcher;\r\n  it cannot prove an inbound ACL, and nothing here claims it does.\r\n\r\n  **PROBE RESOLUTION — doyle 12:59Z, ADOPTED INTO THIS GATE (not deferred to the rider).** The\r\n  precondition read is now THREE-VALUE in `gate-w2-f17.sh`: `Rule Name` in stdout -> PRESENT,\r\n  `No rules match` -> ABSENT, empty stdout or anything else -> PROBE-FAILED. **PROBE-FAILED\r\n  classifies the cross-box helper/range as `UNCLASSIFIED: this run cannot tell INFRA from a real\r\n  red` — never F18-INFRA** — and xbox-D's skip line names the state. The raw probe (exit code +\r\n  first 3 lines) is printed into the driver log, so the classification is auditable after the fact\r\n  rather than inferred from what got bucketed. Exercised standalone on all three arms: real\r\n  `netsh` = exit 1 + `No rules match` -> ABSENT; forced bad args -> PROBE-FAILED; empty stdout ->\r\n  PROBE-FAILED.\r\n\r\n  **Recorded because it corrects the asker (me), not the implementer:** I proposed the three-value\r\n  shape AND, in the same message, proposed discriminating on the exit code. doyle's standalone\r\n  exercise measured `netsh` exiting **1 on a clean ABSENT**, so an exit-code discriminator would\r\n  have classified every legitimately-absent rule as an instrument fault — turning the run's most\r\n  common honest state into PROBE-FAILED and, with it, `UNCLASSIFIED`. The discriminator that landed\r\n  is STDOUT CONTENT. The general form belongs in the entry because it is the reason the third arm\r\n  needed measuring at all: **a CLI's exit code is a claim about the QUERY, not about the ANSWER**,\r\n  and an empty-but-correct result is reported non-zero by a great many tools. A third value added\r\n  to a probe needs its own evidence, obtained by making all three arms fire on purpose — which is\r\n  this lane's standing rule that a tool whose success path has never been made to fail on purpose\r\n  is untested, applied to a tool's FAILURE path instead.\r\n\r\n- **Kin:** [[IR-81]] and IR-80 Amendment 1 (keying on a mutable identity), the F17 riders (a witness\r\n  that never executed the direction it certifies).\r\n\r\n### IR-84 — the one `PUMP_PEER_FAIL` arm the rigs actually fire was the only one carrying no clock, so the stall that produced it could be counted but never timed\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-09 with the instrument that closes its first half. ·\r\n  **Origin:** the 65 s two-host helper stall (design written before the run,\r\n  `docs/design/RIDER-65S-DESIGN.md`). The number was branch-claimed 2026-09-08 by name only — IR-85\r\n  records that it carried no entry text in any register file in any worktree — and this is that text.\r\n- **Symptom:** `two_host_web_helper_role_a` takes **61.956–69.096 s** across five runs while its\r\n  siblings in the same binary and the same run take **0.135–0.753 s**. Every ladder rig —\r\n  win-onebox, linux-onebox, cross-box — logs **exactly ONE**\r\n  `PUMP_PEER_FAIL:<node>:peer reply-read: no progress within budget — dropping peer (brain IPC read\r\n  deadline elapsed)` on B before completing. **3/3, one each, never on A** (doyle's GATE-W3 readout).\r\n- **Cause of the DIAGNOSTIC failure, which is what this entry is about:** that line is emitted from\r\n  the `Err(e)` arm of `peer_leg_outcome` (`crates/spt-daemon/src/pump/mod.rs`), and at\r\n  `b0b67aaa` it read `emit_line_err!(\"PUMP_PEER_FAIL:{peer_hex}:{e}\")` — **no timestamp**. Measured\r\n  at that sha rather than recalled: the file carries **four** `PUMP_PEER_FAIL` emit sites, **three**\r\n  of them stamped `wall_ms=… mono_ms=…` (the submit arm, the no-route arm, and the\r\n  `PRESENCE_DIAL_FAILED` arm), and this one was **the only unstamped site left**. It is also the\r\n  arm the rigs actually fire — a `PEER_REPLY_READ_BUDGET` expiry reclassified out of `TimedOut` by\r\n  `brain::reclassify_peer_reply_err` so it drops one peer rather than poisoning the round. **The\r\n  single arm a reader most needs to time was the single arm that could not be timed.**\r\n- **What that cost, stated as the open question it left:** the arithmetic does not close and this\r\n  entry does not close it. `PUMP_PEER_IO_TIMEOUT` is **30 s** (`:118`) and `SUPERVISE_BACKOFF_BASE`\r\n  is **5 s** (`:121`) — read as constants, not recalled — so one deadline plus one supervise floor\r\n  accounts for **35 s** against **61.956–69.096 s** observed. **~27–34 s is unaccounted**, itself\r\n  close to another 30, which is exactly the coincidence the design document warns against; and the\r\n  count of **exactly one** fail forbids the easy reading that two deadlines elapsed. Three candidates\r\n  stay open and are NOT ranked here: a first ~30 s burned before the deadline's clock starts; a\r\n  second budget stacking on the first; or the restart's re-prime costing materially more than its\r\n  5 s floor. **Separating them needs the deadline's own timestamps against the fail line** — which\r\n  is precisely what the log did not carry.\r\n- **⚠ WHAT THIS ENTRY DOES NOT CLAIM.** The instrument does not explain the stall, does not shorten\r\n  it, and changes no product behaviour: the same peer is dropped at the same instant with the same\r\n  backoff. It makes the stall **answerable from a log that already contains the failure**, instead of\r\n  requiring a rebuild to learn when the budget started. `PUMP_PEER_IO_TIMEOUT` is a hard const with\r\n  no env knob, so varying it costs a rebuild — deliberately deferred until the stamps say which half\r\n  of the arithmetic is missing.\r\n- **Kin and the recurrence that matters:** this is the **SECOND** time an unstamped\r\n  `PUMP_PEER_FAIL` cost a hunt. The `PRESENCE_DIAL_FAILED` arm carries a comment naming the\r\n  \"2026-07-14 `PUMP_PEER_FAIL`-unstamped seed, folded here\", and **REQ-PUMP-STAGE-TRUTH** already\r\n  requires every peer failure \"stamped (wall+mono) and peer-attributed\", explicitly subsuming that\r\n  seed. So the contract was written, three of four sites complied, and the fourth stayed silent for\r\n  eight weeks — **a convention enforced by no mechanism degrades one arm at a time, and every reader\r\n  of a complying arm reports the convention as held**, the same shape as the `validate_docs_dir`\r\n  refusal-arm rider in the same design document. Also kin: **IR-83** (the rig population had only\r\n  ever run the admitted direction), `REQ-HAZARD-PUMP-IPC-DEADLINE` (a `TimedOut` brain-IPC read is a\r\n  supervised restart, never a per-peer retry), ADR-0039 Decision 5.\r\n- **Ripe when:** now, and it lands with this entry — the stamp is one emit line, tagged\r\n  `[impl->REQ-PUMP-STAGE-TRUTH]` at the site. · **Size:** one emit line plus its comment.\r\n  **Follow-up, not this lane:** a cell that walks every `PUMP_PEER_FAIL` arm and asserts each one\r\n  stamps, so the fifth site added cannot be born silent.\r\n### IR-85 — the Windows self-hosted box runs its fs-heavy tests 3-4x slower than a week ago; two CI wall clocks were sized for the old box, and a red run kept hiding it\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-09 at the #272/v0.68.0 golden r3/r4 arc, on doyle's\r\n  dispatch. Number ruled by doyle from his own census of main@`a2f335f8` (register ended at IR-83;\r\n  IR-84 was branch-claimed by name only, with no entry text in any register file in any worktree —\r\n  that gap is now closed: **IR-84 was filed 2026-09-09 in PR #213**, so this sentence records the\r\n  state at `a2f335f8` and is no longer a reason to go looking for a missing entry).\r\n  **Absorbs two drafts:** doyle's `IR-DRAFT-windows-fs-heavy-slowdown-and-golden-wall` (his IR-A +\r\n  IR-B) and his earlier `IR-NEXT` (operator-desktop load), both retired by reference — this is the\r\n  single entry. Every job/step and per-test timing below is **doyle's**, read via the job/step API.\r\n  · **Origin:** #272 golden r3 attempt 2 was CANCELLED by a wall clock with both test phases green.\r\n- **⚠ THE CAP CHANGE IN `a2f335f8` IS NOT THE FIX AND MUST NOT BE READ AS ONE.** It bounds the run;\r\n  it repairs nothing. A future reader who finds an 80-minute wall and no entry here would reasonably\r\n  conclude the problem was solved. It was only made visible.\r\n\r\n- **A GREEN RUN COSTS MORE THAN A RED ONE, WHICH IS WHY THIS WENT UNSEEN.** A failing run\r\n  short-circuits past the wall a green run has to cross. r3 att1 finished in **48m39s only because\r\n  it FAILED at Phase B**; att2, green, hit 49m59s and was cancelled. Every earlier docs-drift skip\r\n  therefore presented as \"upstream failure\" — the wall was never the reported cause of anything, and\r\n  the surviving evidence systematically flattered the budget.\r\n\r\n- **THE WALL.** Windows golden `test` job (48 steps), fully GREEN: **30m53s** (2026-08-30, run\r\n  33296634901) and **33m21s** (2026-09-06, run 34017906638). At the v0.68.0 head against the\r\n  then-current 50-minute cap — **r3 att2**, job 102352551368 at `f6110c2a`: Phase A 17m14s, Phase B\r\n  20m25s, doctests 1m04s, clippy 3m31s, **CANCELLED at step 30 at 49m59s with everything green**;\r\n  steps 31-42 (installer, docs floor, both docs-drift gates, dormancy) never ran. r2 att1\r\n  (`25e60015`, 09-08 18:47Z) reached step 34 at 44m30s. Steps 30..39 cost ~3m30s on the 09-06 green\r\n  (notify 47s, installer 13s, docs-drift 1m54s). Predicted green need ~**56 min**; cap raised to\r\n  **80** (need + ~40% for day-to-day variance) in `a2f335f8`, ci unit 25 -> 40 in the same commit.\r\n- **r4, GREEN — the first complete measurement at the head: 54m35s** (07:12:26Z -> 08:07:01Z),\r\n  **25m25s** headroom under 80; docs-drift (step 38) 2m23s; Phase A 15m51s, Phase B 22m56s. The ~56\r\n  prediction held to within 1.5 min, so the cap is sized on evidence, not generosity. **What that\r\n  does NOT establish:** it was a sizing forecast, and its holding says nothing about the cause\r\n  diagnosis below. Nor are att2-vs-r4 per-phase deltas a trend — att2 was cancelled mid-run, so only\r\n  its phase legs are comparable at all, and the spread they sit in is the same variance the 40% is\r\n  there to absorb.\r\n\r\n- **THE SLOWDOWN, per test, same box, same tests.** `spt-daemon::sync` concurrent_writes\r\n  **22.4s -> 74.8s**, two_tier_sync 18.7 -> 67.4; `spt-store` monic clone_copies 17.7 -> 62.9,\r\n  different_monics 18.2 -> 64.9; syncmerge reconciled_write 27.3 -> 51.2. **~25 spt-store/spt-daemon\r\n  tests now exceed 30s on Windows Phase A at `f6110c2a`, against 1-2s each on kitsubito.**\r\n  Phase-level: Phase A nextest 170s (09-06) -> 642s (att1) -> 1034s (att2); Phase B 710s -> 1164s.\r\n  The suite did not get more expensive — Linux is unchanged.\r\n\r\n- **DATING SAYS ENVIRONMENT DOMINATES, AND BY HOW MUCH.** main's own ci Windows `unit` job:\r\n  11-12 min on 09-06 (runs 34040416870, 34041526195, 34043323577) -> 13-20 min on 09-07 -> 12-24 min\r\n  on 09-08, hitting **22 min at `e4444413`** (run 34261096301) three minutes under its own 25-minute\r\n  wall. **Gradual over days, under no single gate change, is the shape of an environment term, not a\r\n  commit's.** Head growth is real but MINOR: +138 Phase A tests, +20 Phase B, HEAVY 34 -> 35.\r\n\r\n- **THE BOX IS AN OPERATOR DESKTOP (folded in from the retired IR-NEXT), and that turns every fixed\r\n  wall-clock budget in the Windows suite into a coin.** From the r2 arc, three attempts at ONE sha\r\n  (run 34262154550 @ `25e60015`): Phase B red each time on a **different single cell or none** — a1\r\n  234/234 (job red on disk floors only), a2 `spt::webserve_attachment_e2e` arm 12, a3\r\n  `spt-daemon::mesh_recovery roster_route_survives_a_transient_dial_failure_with_discovery_disabled`\r\n  (15.0s `converge()` budget, cell 15.715s; the same cell 9.8s / 7.2s on a1/a2). Phase A — 3,346\r\n  spawn-dominated unit cells — slowed **monotonically 448.7 -> 495.1 -> 542.6s at that one sha**.\r\n  Per-cell a3/a2 over 73 Phase B cells >= 1s: median 1.05x, mean 1.34x, 19 cells >= 1.5x, worst 5.2x\r\n  (`endpoint_lifecycle poll_vs_reap` 1.1 -> 5.8s) — **BURSTY, not uniform**. A rotating single victim\r\n  across attempts at one sha is ONE environment cause; hardening victims one at a time never closes\r\n  it (paid before: `e2e-leaked-daemons-shared-box`). The budgets that lost were ~1.5x the fast\r\n  observation — inside the box's measured variance, so they were coins that had been landing right.\r\n- **Box census (doyle 01:13-01:19Z, no cargo/rustc/nextest running, CPU 31%, ~1.1 of 16 cores busy):**\r\n  `qbittorrent.exe` seeding since 09-08 10:20Z (box tx 21.3 MB/s over 5s); fleet `spt daemon brain`\r\n  with 516 GB read since 09-07 08:03Z (~3.5 MB/s steady); Defender real-time ON, `MsMpEng` at\r\n  67.8/62.8/48.9/32.2/12.2% of a core over 5s **on the idle box**; a fresh 35 MB exe pays\r\n  2092/994/1171/1043 ms on FIRST execution against 31/263/19/260 ms on the second — **and every CI\r\n  attempt rebuilds every test binary fresh.** At 06:45Z on 09-09, with the twohost legs running:\r\n  MsMpEng 89% CPU / 991 MB WS, qbittorrent pid 47056 holding 7817 CPU-seconds (2.2 h) since\r\n  09-08 03:20, free 134 GiB (275 -> 197 -> 131 across the three r3 dispatches).\r\n- **⚠ AN UNREADABLE ROW IS NOT AN ABSENT ONE.** The Defender exclusion list cannot be read\r\n  unelevated on this box: `Get-MpPreference` returns the literal string\r\n  `N/A: Must be an administrator to view exclusions` **as the ExclusionPath VALUE**, so a\r\n  `-contains` test reads ABSENT and is meaningless; the HKLM `Windows Defender\\Exclusions\\Paths`\r\n  read throws `SecurityException`. Nobody may report the runner directory as unexcluded from an\r\n  unelevated shell.\r\n\r\n- **HYPOTHESIS ALREADY KILLED, so nobody re-runs it:** the Windows-only `ADAPTER_WEB_PENDING`\r\n  reconcile failure (servehost nudge) **cannot** explain this — spt-store monic and contextstore\r\n  never touch that path.\r\n\r\n- **WHAT IS STILL NOT ESTABLISHED (labelled, so it is not inherited as fact).** The dating argument\r\n  establishes environment-DOMINANT and bounds head growth as the minor term. It does **not**\r\n  apportion the environment term itself: Defender vs the third-party torrent load vs the fleet\r\n  brain's steady read vs anything else is unsplit, and **\"MsMpEng at 89%\" remains a correlate\r\n  measured beside the slowdown, not a proven cause.** The discriminator lane below is what settles\r\n  head-vs-environment on evidence rather than on the shape of a drift curve.\r\n\r\n- **REMEDY — none landed. This entry is the debt, and its middle arms need an operator.** Sequence\r\n  matters; run them in this order:\r\n  1. **DISCRIMINATOR LANE (hertz, one box, ~1.5-2 h).** Run the five named tests at `04e32c8c` and\r\n     at `f6110c2a` on hfenduleam. **Same-slow at both = environment; slow only at the head = head\r\n     growth.** Cheap and decidable, and it must precede any operator ask — do not spend an elevation\r\n     request on a hypothesis a one-lane measurement can test. Design note, because it is the part\r\n     that makes the number trustworthy: the arms run **INTERLEAVED** (A/B/A/B/A/B, 3 reps each), not\r\n     all-A-then-all-B, so drift that hits the whole box cancels in the comparison instead of landing\r\n     on one arm. **A measurement that only works if everyone behaves is not a measurement** — the\r\n     torrent client and Defender are running throughout and are the thing under test, not noise\r\n     anyone gets to remove. Confounder already excluded: the three test-bearing files\r\n     (`spt-daemon/tests/sync.rs`, `spt-store/src/monic.rs`, `spt-store/src/syncmerge.rs`) are\r\n     **byte-identical blobs at both shas**, so a difference cannot be the tests changing; the two\r\n     crates around them are not (+11,388 lines over 48 files).\r\n  2. **Remove the third-party load first.** No torrent client on the CI box during golden windows.\r\n     It is the cheapest variable to remove, and removing it first makes arm 3's benefit measurable\r\n     instead of confounded.\r\n  3. **OPERATOR ASK — Defender path exclusions** for `C:\\actions-runner\\_work` and the gate pools,\r\n     read from an ADMIN shell first (see the unreadable-row warning above), then re-measure the\r\n     first-touch tax on a file **under that path** — the scratchpad measurement is outside the\r\n     runner dir, so it proves the mechanism's size, not the runner's exposure. Unsettable\r\n     unelevated; same shape as **IR-89**'s elevated firewall rule.\r\n  4. **CI census, cheap and durable:** print `Get-MpComputerStatus` RealTimeProtectionEnabled plus\r\n     the ExclusionPath read **verbatim, refusal text included**, in the Windows job's census step,\r\n     so a run's own record says what Defender it ran under.\r\n  5. **Re-measure both caps after any arm lands — the arm a future reader will skip, so it is loud\r\n     here.** A cap sized against a degraded box is correct only while the box stays degraded.\r\n     Leaving 80 in place after a repair silently restores the original hazard: a wall so generous it\r\n     no longer catches a wedged test, which is the job the golden cap was added to do in the first\r\n     place (the 2026-06-03 handoff.rs ConPTY stall, 22 unbounded hosted minutes).\r\n- **Kin:** [[IR-76]] (the golden runner IS the builders' box — the structural reason a desktop's\r\n  load reaches CI at all), [[IR-64]] (box-level facts only the operator can move), [[IR-89]] (the\r\n  other elevated box-rule ask), `defender-first-touch-tax-on-fresh-test-binaries` and\r\n  `e2e-leaked-daemons-shared-box` (memory).\r\n- **Ripe when:** arm 1 now; arms 2-4 on the operator's answer; arm 5 at the next `golden.yml` touch\r\n  after any of them. · **Size:** arm 1 a measurement, arm 4 one census line, arm 5 two literals.\r\n- **AMENDMENT 2026-09-09 (two terms this entry did not name when it landed at `d32d5c4c`).**\r\n  1. **`ci.yml`'s `changes` job runs `unit` on BOTH runners for every push to `main`.** The classify\r\n     step at `.github/workflows/ci.yml:49` emits `code=true` for every non-`pull_request` event, so\r\n     the docs-only skip that PR runs #206/#207 demonstrated is **`pull_request`-only** — read from\r\n     `ci.yml` at `main` by doyle, who names it his own error after twice ruling the opposite from the\r\n     PR runs alone. Consequence for this entry's wall clock: run **34337797758** (the ff of\r\n     `b66a9612`, a docs-only delta over golden-green `a2f335f8`) ran `unit (Windows)` 09:59:57Z →\r\n     10:40:48Z and was **CANCELLED at the 40-minute job wall** (job timeout; conclusion `cancelled`,\r\n     step 6 `Unit tests` 10:08:23 → 10:40:03) — a red on `main` at a sha whose content cannot fail a\r\n     unit test. It is an IR-85 face, not a flake row.\r\n  2. **A near-full volume is an environment term for the slowdown**, alongside the Defender\r\n     first-touch tax and the operator-desktop load already recorded. **Deliberately unquantified:**\r\n     the discriminator window that would have apportioned it was VOID, because the one leg that\r\n     completed ran under both a CI job and a falling disk. See **IR-90**.\r\n- **WHAT THE VOIDED DISCRIMINATOR ESTABLISHED, negatively (hertz, 2026-09-09).** The fs-heavy\r\n  slowdown REPRODUCES at `04e32c8c`, which predates the +11,388-line head growth: spt-daemon\r\n  `concurrent_writes` 105.420 s, `two_tier_sync` 58.362 s, spt-store `clone_copies` 65.657 s,\r\n  `different_monics` 73.967 s, `syncmerge reconciled_write` 86.765 s, against the 09-06 baseline of\r\n  22.4 / 18.7 / 17.7 / 18.2 / 27.3 s — **3.2x to 4.7x on all five, at the OLD sha**. So head growth\r\n  is **not NECESSARY** for the slowdown. That is the whole of it: it does NOT measure how much the\r\n  environment explains, and it is not evidence about the head arm at all — that leg ran inside run\r\n  34337797758's window and on a volume that reached 0.018 GiB free, and the head arm never produced\r\n  a comparable pair. **Arm 1 stays OPEN**, its re-run deferred until **IR-90**'s guard exists and a\r\n  window with no `main` push and no CI job on the box can be scheduled.\r\n\r\n- **AMENDMENT 2026-09-10 (hertz, on THIS ENTRY'S OWN arm-1 design note).** The note says the arms run\r\n  **INTERLEAVED** A/B/A/B so box drift cancels. It does not cancel: **B is always the later arm within\r\n  each pair**, so a monotone drift across the session lands on B every time and is read as an arm\r\n  effect. Alternate the PAIR ORDER — **A/B then B/A** — record per-leg timestamps and conditions, and\r\n  describe the result as **REDUCING order confounding, not eliminating it**. Second binding change,\r\n  from the releases#294 triage: **instrument, do not infer.** `cargo nextest run --success-output\r\n  immediate` retains stdout for PASSING tests (deployah), so a passing arm can still print poll\r\n  elapsed, iteration count, IPC time and producer progress — **a failing arm is not required** for a\r\n  margin measurement (todlando, correcting deployah's \"it has to fail to be informative\"). Arm 1 was\r\n  never re-run, so this lands before the measurement, not after it.\r\n\r\n### IR-86 — golden's 32 GiB floor is BELOW the measured 67.4 GiB Windows suite footprint, so a start floor passes a box that cannot finish\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-08 at the #272/v0.68.0 golden r2 triage. · **Origin:**\r\n…\n  25,284,501,504 B RED at 19:31:55Z -> `FLOOR_END` RED. Consumed in-job: 67.4 GiB.\n…\n","startLine":4407,"lineNumbers":[4407,null,4501,null,4531,4532,4533,4534,4535,4536,4537,4538,4539,4540,4541,4542,4543,4544,4545,4546,4547,4548,4549,4550,4551,4552,4553,4554,4555,4556,4557,4558,4559,4560,4561,4562,4563,4564,4565,4566,4567,4568,4569,4570,4571,4572,4573,4574,4575,4576,4577,4578,4579,4580,4581,4582,4583,4584,4585,4586,4587,4588,4589,4590,4591,4592,4593,4594,4595,4596,4597,4598,4599,4600,4601,4602,4603,4604,4605,4606,4607,4608,4609,4610,4611,4612,4613,4614,4615,4616,4617,4618,4619,4620,4621,4622,4623,4624,4625,4626,4627,4628,4629,4630,4631,4632,4633,4634,4635,4636,4637,4638,4639,4640,4641,4642,4643,4644,4645,4646,4647,4648,4649,4650,4651,4652,4653,4654,4655,4656,4657,4658,4659,4660,4661,4662,4663,4664,4665,4666,4667,4668,4669,4670,4671,4672,4673,4674,4675,4676,4677,4678,4679,4680,4681,4682,4683,4684,4685,4686,4687,4688,4689,4690,4691,4692,4693,4694,4695,4696,4697,4698,4699,4700,4701,4702,4703,4704,4705,4706,4707,4708,4709,4710,4711,4712,4713,4714,4715,4716,4717,4718,4719,4720,4721,4722,4723,4724,4725,4726,4727,4728,4729,4730,4731,4732,4733,4734,4735,4736,4737,4738,4739,4740,4741,4742,4743,4744,4745,4746,4747,4748,4749,4750,4751,4752,4753,4754,4755,4756,4757,4758,4759,4760,4761,4762,4763,4764,4765,4766,4767,4768,4769,4770,4771,4772,4773,4774,4775,4776,4777,4778,4779,4780,4781,4782,4783,4784,4785,4786,4787,4788,4789,4790,4791,4792,4793,4794,4795,4796,4797,4798,4799,4800,4801,4802,4803,4804,4805,4806,4807,4808,4809,4810,4811,4812,4813,4814,4815,4816,4817,4818,4819,4820,4821,4822,4823,4824,4825,4826,4827,4828,4829,4830,4831,4832,4833,4834,4835,4836,4837,4838,4839,4840,4841,4842,4843,4844,4845,4846,4847,4848,4849,4850,4851,4852,4853,4854,4855,4856,4857,4858,4859,4860,4861,4862,4863,4864,4865,4866,4867,4868,4869,4870,4871,4872,4873,4874,4875,4876,4877,4878,4879,4880,4881,4882,4883,4884,4885,4886,4887,4888,4889,4890,4891,4892,4893,4894,4895,4896,4897,4898,4899,4900,4901,4902,4903,4904,4905,4906,4907,4908,4909,4910,4911,4912,4913,4914,4915,4916,4917,4918,4919,4920,4921,4922,4923,4924,4925,4926,4927,4928,4929,4930,4931,4932,4933,4934,4935,4936,4937,4938,4939,4940,4941,4942,4943,4944,4945,4946,4947,4948,4949,4950,4951,4952,4953,4954,4955,4956,4957,4958,4959,4960,4961,4962,4963,4964,4965,4966,4967,4968,4969,4970,4971,4972,4973,4974,4975,4976,4977,4978,4979,4980,4981,4982,4983,4984,4985,4986,4987,null,4991,null,5023]},"fileSize":512411,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\INFRA-REGISTER.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":5900,"totalBytes":39039,"outputLines":457,"outputBytes":39039,"shownRange":{"start":4531,"end":4987},"nextOffset":4988}}},"isError":false,"timestamp":1789107053421}}
{"type":"message","id":"7043a550","parentId":"a2b68b12","timestamp":"2026-09-11T06:10:53.425Z","message":{"role":"toolResult","toolCallId":"call_kk3urpa1WBGsg73Uhi2QlJtH|fc_0330c101aa2c61dc016aa39b6afab487d1ae68643a97fc7b45","toolName":"read","content":[{"type":"text","text":"### IR-79 — 22 of the 31 rig binaries leak their daemon tree on a failing assert: teardown is a statement, not a guard\n…\n- **Status:** OPEN, filed by hertz 2026-09-07 on doyle's dispatch during PR #198's CI window,\n…\n- **Size:** medium — one guard in `common`, then 22 mechanical adoptions, each provable by\n…\n\n### IR-80 — five leaky cells on ONE module (`brainproc` / `supervise_brain`), Windows only: a candidate PRODUCT leak on the promotion/rollback path, or a cluster of names — nobody has looked yet\n\n- **Status:** OPEN for the residual population, not an undiagnosed five-name product claim.\n  Later amendments identify the brainproc shell-wrapper fixture mechanism and distinguish\n  production's direct spawn; they do not classify all 12 union members. Historical opening\n  hypotheses below are not current causal conclusions. Filed by hertz 2026-09-07 07:40Z on\n  doyle's ruling that this retains its own identity, separate from IR-79.\n  **Origin:** noticed while measuring the #198 HEAVY scan-root gap ([[IR-37]] rider 2); the leak\n  roster was read out of the baseline golden log for an unrelated reason.\n- **⚠ WHAT THIS ENTRY IS, STATED FIRST SO IT IS NOT OVERREAD: a CLUSTER OF NAMES.** Five cells\n  that leaked share one module and one code path by their identifiers. Nothing has been measured\n  about WHAT is left alive, and a shared module is not a shared cause. Do not cite this as a\n  product defect until the census below has run.\n- **The observation, exact.** Golden run **34017906638**, sha `04e32c8c95cf`, both boxes, Phase A.\n  Windows (hfenduleam) reported **9 leaky** cells; Linux (kitsubito) **1** (`livehost::tests::\n  legacy_psyche_sweep_guard_is_id_specific_and_fail_safe`, unrelated). **Five of the Windows nine\n  are the same module:**\n\n  | cell | kind | time |\n  |---|---|---|\n  | `spt-daemon brainproc::tests::clear_before_spawn_defeats_exact_generation_stale_file` (:2200) | lib | 0.457s |\n  | `spt-daemon brainproc::tests::ready_but_old_gen_never_drains_does_not_promote_rolls_back` (:1834) | lib | 0.554s |\n  | `spt-daemon brainproc::tests::stale_generation_minus_one_ready_never_promotes` (:2155) | lib | 0.731s |\n  | `spt-daemon brainproc::tests::trial_kills_alive_never_ready_candidate_before_rollback` (:2109) | lib | 0.582s |\n  | `spt-daemon::false_promote ready_candidate_does_not_promote_until_the_wedged_old_gen_conn_drains` | int | 1.744s |\n\n  Denominator for the lib half: `brainproc`'s test module holds **26** `#[test]`/`#[tokio::test]`\n  cells, so **4 of 26 leaked, and all four are the trial/promote/rollback cells by name.** The\n  fifth is the integration rig that drives the same path.\n- **Why it is worth an entry even unmeasured:** four of the five are `kind(lib)`, so they run in\n  **`ci.yml` on every push**, not only in golden — if something really is left alive it is being\n  left alive on the shared Windows box many times a day. That is the same standing cost as\n  [[IR-79]]'s daemon face, arrived at from the opposite direction.\n- **HYPOTHESIS, labelled as such and NOT measured.** `supervise_brain` (:935) takes an injected\n  `spawn_child: impl FnMut(...) -> io::Result<Child>` (:941) and reaps candidates with bare\n  `let _ = child.kill();` at :998, :1015, :1055, :1071, :1081 — **`kill()` with no `wait()`.** On\n  Windows termination is asynchronous, and a killed-but-unreaped child can still hold the\n  inherited stdout/stderr pipe past the test's exit, which is exactly what nextest reports as\n  LEAK. The production spawner's own doc comment at :1190 states the intent — \"dies with no\n  orphaning. NOT `spawn_detached`\" — so if this is the mechanism, the code's intent and its\n  behaviour have diverged on one platform. **Every clause of this bullet is a reading of source,\n  not an observation of a live process. It may be entirely wrong.**\n- **FIRST MEASUREMENT — and doyle sharpened it 07:41Z from a census into a FALSIFIER, which is the\n  form to run:** on a free Windows box after W2, run\n  `trial_kills_alive_never_ready_candidate_before_rollback` **alone** and read one thing —\n  **is the killed pid still present, with the pipe handle open?** That is a yes/no against the\n  hypothesis above, not an open look at what happens to be running, and it is the difference\n  between a reading that settles the entry and a reading that produces more names. Capture pid,\n  image path and parent alongside the answer so a YES is immediately actionable, but the ANSWER is\n  the deliverable. One cell, one read. **Owner stays UNASSIGNED until it is taken** (doyle) — a\n  product path and a rig artifact are not distinguishable from here, and assigning before the read\n  would pick one by guess.\n- **Limits, so the entry cannot be overread:** nextest `LEAK` is **not a failure** — none of these\n  cells reds anything, and the run was green. Windows-only in **one** run; no trend established.\n  The clustering is by identifier and shared module, which is suggestive and is not causation.\n  I have not run any of these cells. Everything above is source plus one golden log — no box, no\n  build.\n- **Kin:** [[IR-79]] (children outliving the cell — the rig-teardown face of the same symptom, and\n  the reason doyle ruled these must stay SEPARATE: same symptom, different suspected owner),\n  [[IR-37]] rider 2 (the measurement that surfaced it), FLAKE-LEDGER's `resident_service_e2e` :664\n  teardown LEAK row.\n- **Ripe when:** the first free Windows box after W2 lands — it is a single-cell census, so it\n  fits any gap.\n- **Size:** unknown until the census. Tiny if it is a missing `wait()`; not tiny if the promotion\n  path leaves a real candidate brain alive on rollback.\n\n---\n\n#### THE LEAK SET IS NOISY — measured across three shas, 2026-09-07 (hertz)\n\n**This retracts the \"8 -> 5 leaky, direction favourable\" reading I flagged at 09:31Z.** It is not a\nfix and not an improvement; it is threshold noise, and the census this draft was built on inherits\nthat noise.\n\nWindows `ci` unit leg (`--workspace -E 'kind(lib) + kind(bin)'`), three consecutive shas:\n\n| cell | ff4b405d | e3bd53d4 | 401a19ad |\n|---|---|---|---|\n| brainproc::clear_before_spawn_defeats_exact_generation_stale_file | ● | ● | ● |\n| brainproc::ready_but_old_gen_never_drains_does_not_promote_rolls_back | ● | ● | ● |\n| brainproc::trial_kills_alive_never_ready_candidate_before_rollback | ● | ● | ● |\n| spt-runtime runtime::bounded_run_kills_on_timeout | ● | ● | ● |\n| brainproc::stale_generation_minus_one_ready_never_promotes | ● | ● | — |\n| spt-live digest::extractor_timeout_errors | ● | ● | — |\n| spt-live history::fetcher_timeout_errors | ● | ● | — |\n| spt-daemon broker::windows_session_is_zombie_sees_a_handle_held_corpse_as_dead | ● | — | — |\n| spt-daemon shellwake::kill_waker_at_still_kills_a_matching_pair | — | ● | ● |\n| **total** | **8** | **8** | **5** |\n\n**Causality check, which is what makes this a retraction rather than a hypothesis:** the three\ncommits between e3bd53d4 and 401a19ad touch **zero files** in brainproc, spt-live, spt-runtime,\nshellwake or broker (`git diff --name-only` over those paths returns nothing). The count fell by 3\nwith no change to any leaking module. So the drop cannot be a fix; the membership simply moves.\nNine cells appear in the union, only **four** are present at all three shas, and one\n(`shellwake::kill_waker_at`) *appeared* rather than vanished — a count that falls while a new member\njoins is the signature of a threshold, not of a repair.\n\n#### Three consequences for this draft\n\n1. **A count is not a quality signal here, in either direction.** Any future \"leaky went down\"\n   claim needs the NAME diff and a causality check against the changed files, or it is noise\n   reported as progress. I made exactly that error and it survived about twenty minutes.\n2. **The five-cell cluster is really \"three stable + one intermittent\".**\n   `stale_generation_minus_one_ready_never_promotes` is absent at 401a19ad. The cluster framing\n   still holds — three brainproc cells leak at every sha and they are all one module — but the\n   membership count must not be quoted as fixed.\n3. **doyle's falsifier beats my census, and this is the evidence.** The census (count the leaky\n   cells, name the cluster) is exactly what the noise destroys. His falsifier — *after\n   `trial_kills_alive_never_ready_candidate_before_rollback` on Windows, is the killed pid still\n   present with the pipe handle open?* — names ONE cell and probes a MECHANISM, and that cell is\n   **leaky at all three shas**, so it is the most stable target available. A mechanism probe is\n   immune to the threshold that moves the population. Owner stays UNASSIGNED until that read.\n\n#### One structural finding the noise does NOT touch\n**All nine union members spawn a child and then kill it, let it time out, or inspect its corpse** —\n`trial_kills_alive`, `kill_waker_at`, `bounded_run_kills_on_timeout`, `extractor_timeout_errors`,\n`fetcher_timeout_errors`, `windows_session_is_zombie_sees_a_handle_held_corpse_as_dead`, and the\nthree brainproc spawn/promote/rollback cells. Not one unrelated cell is in the set. Membership\nfluctuates; the *kind* of cell does not. That is a real signal about where child-process teardown\nis unreliable on Windows, and it is the same territory as [[ir79]] (rigs leaking daemons on a\nfailing assert) and [[ir81]] (kill scoping) — three drafts converging on one seam.\n\n---\n\n#### THE 12-CELL UNION — 4 shas x 2 OSes, membership beside the invariant (hertz, 2026-09-07 10:15Z)\n\nMachine-generated from the eight ci unit logs, not transcribed (a hand-typed 12x8 matrix is where\ntranscription errors live). `X` = reported LEAK at that sha on that box.\n\n| cell | W ff4b405d | W e3bd53d4 | W 401a19ad | W f3c8495b | L ff4b405d | L e3bd53d4 | L 401a19ad | L f3c8495b |\n|---|---|---|---|---|---|---|---|---|\n| `spt-daemon brainproc::tests::clear_before_spawn_defeats_exact_generation_stale_file` | X | X | X | X | . | . | . | . |\n| `spt-daemon brainproc::tests::ready_but_old_gen_never_drains_does_not_promote_rolls_back` | X | X | X | X | . | . | . | . |\n| `spt-daemon brainproc::tests::stale_generation_minus_one_ready_never_promotes` | X | X | . | X | . | . | . | . |\n| `spt-daemon brainproc::tests::trial_kills_alive_never_ready_candidate_before_rollback` | X | X | X | X | . | . | . | . |\n| `spt-daemon broker::tests::windows_session_is_zombie_sees_a_handle_held_corpse_as_dead` | X | . | . | X | . | . | . | . |\n| `spt-daemon livehost::tests::legacy_psyche_sweep_guard_is_id_specific_and_fail_safe` | . | . | . | . | X | X | X | . |\n| `spt-daemon shellhost::tests::kill_shell_at_still_kills_a_matching_pair` | . | . | . | X | . | . | . | . |\n| `spt-daemon shellwake::tests::kill_waker_at_still_kills_a_matching_pair` | . | X | X | X | . | . | . | . |\n| `spt-live digest::tests::extractor_timeout_errors` | X | X | . | X | . | . | . | . |\n| `spt-live history::tests::fetcher_timeout_errors` | X | X | . | . | . | . | . | . |\n| `spt-runtime runtime::tests::bounded_run_kills_on_timeout` | X | X | X | X | . | . | . | . |\n| `spt-store proc::tests::process_cmdline_reads_a_live_arg_marker` | . | . | . | . | X | X | X | X |\n| **leaky count** | 8 | 8 | 5 | 9 | 2 | 2 | 2 | 1 |\n\nUnion = 12 cells across 4 shas x 2 OSes. Present at EVERY Windows sha: 4. Present at every Linux sha: 1.\n\n#### Three readings, in increasing order of what they support\n\n**1. The churn is total and it is the whole point.** Windows counts run 8, 8, 5, 9 — the HIGHEST\nvalue is at `f3c8495b`, the tip carrying every fix F1-F16. Only **4 of 12** cells are present at\nevery Windows sha; only **1 of 2** at every Linux sha. Read as a quality signal the series says W2\nmade leaking worse, which is exactly as wrong as my retracted \"8 -> 5, favourable\" read and wrong\nfor the same reason. **A leaky count is not a signal in either direction.**\n\n**2. NEW, and I had not said it before building this table: the two OS sets are DISJOINT.** Ten\ncells leak only on Windows, two only on Linux, and **not one cell leaks on both**. Windows carries\n8-9 leaky cells per run against Linux's 1-2. So this is not one flaky population sampled twice —\nit is two populations with no overlap, and the Windows one is roughly five times larger. Any\nexplanation that treats \"leaky tests\" as a single phenomenon has to account for a clean partition\nby OS.\n\n**This is an OPEN QUESTION and the draft does not answer it. I do not have that explanation yet.**\nRecorded deliberately without a candidate cause: the partition is a measurement, and the temptation\nto pair a striking measurement with a plausible story is how the \"8 -> 5 is favourable\" reading got\ninto the record in the first place. Whoever takes this should arrive at a cause by reading, not by\ninheriting one from me.\n\n**SCOPED CAUSE, IN SOURCE, FOR ONE FAMILY ONLY (doyle ruled 10:22Z: source beats story; a source\ncause covering one family is a measurement and is filed as one).** The brainproc family leaks on\nWindows and not Linux because *its own fixture is asymmetric*: `long_child()` (brainproc.rs:1359)\nspawns `Command::new(\"cmd\").args([\"/C\",\"ping\",\"-n\",\"30\",\"127.0.0.1\"])` on Windows but\n`Command::new(\"sleep\").arg(\"30\")` on Unix — a shell wrapper on one box, a bare process on the other.\nThe Windows candidate the supervisor kills is `cmd`; the process burning 29 seconds is its child.\nThat is two lines of source, not an inference from the symptom. **And it is NOT the whole partition:**\n`process_cmdline_reads_a_live_arg_marker` uses a shell on BOTH arms (`sh -c \"sleep 30; : marker\"` /\n`cmd /C \"ping … & rem marker\"`) yet leaks on **Linux only** — the shell mechanism predicts it should\nleak on both boxes and it does not. So one family has a cause I can point at in the source, the\npartition as a whole remains OPEN, and the counterexample stands in this paragraph rather than a\nfootnote so no one carries the cause further than it goes.\n\n**THE PRODUCT PATH HAS NO INTERMEDIARY; THE FIXTURE DOES.** I chased the obvious escalation — if the\nreal supervisor also killed a shell wrapper, then \"never two live brains\"\n(REQ-HAZARD-BROKER-PROCESS-ISOLATION, the invariant this very cell guards) could be violated on\nWindows in production while the test stayed green. It cannot: `spawn_brain_child` (brainproc.rs:1224)\ndoes `Command::new(exe)` — the brain is spawned DIRECTLY, no shell, no grandchild, so a single-pid\nkill reaches it. **This is a test-fixture artifact, not a product defect**, and the fixture's shell\nis a Windows-only convenience for \"a process that blocks ~30s\" that introduced a layer the real path\ndoes not have. The negative is the useful half: it keeps the crashloop invariant out of IR-81 (a).\n\n**Why the cell passed review for as long as it did.** It asserts `pid != 0 && !pid_alive(pid)` before\nrollback, and that assertion is TRUE — `cmd` really is dead. The process still doing work is the one\nit never looks at. The leak and the green are not in tension; they are the same fact from two ends.\n**An assertion over a pid cannot see a tree.**\n\n**3. The invariant holds at 12 of 12, and it survived the population being shuffled three times.**\nEvery union member spawns a child process and then kills it, lets it time out, or inspects its\ncorpse — `trial_kills_alive`, `kill_shell_at`, `kill_waker_at`, `bounded_run_kills_on_timeout`,\n`extractor_timeout_errors`, `fetcher_timeout_errors`, `windows_session_is_zombie_..._corpse_as_dead`,\n`legacy_psyche_sweep_guard_...`, `process_cmdline_reads_a_live_arg_marker`, and the three brainproc\nspawn/promote/rollback cells. Membership churns freely across four shas and two OSes; the KIND of\ncell has not varied once. **This is the IR-80 headline** and it is better supported now than when it\nrested on a stable-looking five-cell cluster, precisely because the population underneath it has\nbeen reshuffled and the invariant did not move.\n\n#### A MECHANISM, read out of the source of the two Linux cells — calibrated, not generalized\n`process_cmdline_reads_a_live_arg_marker` spawns **`sh -c \"sleep 30; : marker\"`**, and the test's\nown comment says the trailing `; :` is deliberate — it keeps the shell RESIDENT so its\n`/proc/<pid>/cmdline` still carries the marker instead of being tail-exec-replaced by `sleep`. The\nteardown is `child.kill()` then `child.wait()`. **But `child` is the SHELL, and `sleep 30` is the\nshell's own child.** Killing the shell orphans the sleeper, which outlives the test by up to 30\nseconds — which is precisely what nextest reports as a LEAK. The Windows arm has the same shape:\n`cmd /C \"ping -n 30 127.0.0.1 >NUL & rem marker\"`, where `cmd` forks `ping`.\nSo the very construct that makes the test work (a resident shell, so the cmdline stays readable) is\nwhat guarantees a grandchild that a single-pid kill cannot reach.\n\n**What is verified and what is not, stated separately because the difference decides who owns this.**\nVERIFIED by reading source: this shape in BOTH Linux-only cells. CONSISTENT but not proven: the\nWindows family kills the same way — `kill_waker_at_still_kills_a_matching_pair` tears down with\n`kill_shell_pid(ours.id())`, a single-pid kill — so the mechanism is available to it, but I have not\nread every spawn helper. UNVERIFIED: the brainproc, broker and spt-live cells; those spawn real\nbrains and time out extractors, and may leak for unrelated reasons.\n\n**Why this matters beyond IR-80:** a single-pid kill that cannot reach a grandchild is exactly\n[[ir81]] arm (a) — identity and tree-awareness pushed into `kill_pid_tree`/`kill_pid` so no caller\ncan express the unreachable kill. If the mechanism above generalizes, IR-79 (rigs leaking daemons\non a failing assert), IR-80 (this) and IR-81 (kill scoping) are not three findings that share a\nseam, they are three FACES of one defect: **the codebase kills pids, and the things it needs dead\nare trees.** That is a claim worth testing, not asserting — and doyle's one-cell mechanism probe\nis still the right instrument, now with a sharper question: after the kill, is the surviving\nprocess the CHILD or the GRANDCHILD?\n\n---\n\n#### AMENDMENT 1 — \"a pid is not a tree\" has THREE faces, and only one of them is a kill\n\n*(hertz 2026-09-07, ruled by doyle 11:17Z: write this as an IR-80 amendment naming the three faces\nrather than three separate entries, so a reader hunting any one face lands on all three.)*\n\nThe register sentence this lane has been running on is doyle's: **a pid is not an identity and a pid\nis not a tree.** IR-80 and IR-81 were both filed against the KILL side, which made the sentence read\nlike a rule about killing. It is not. It is a rule about **which process you are talking about**, and\nkilling is only the face we happened to find first. Three faces are now measured, each found by a\ndifferent agent working a different problem:\n\n| face | the operation | what going one level too high produces | measured |\n|---|---|---|---|\n| **KILL** | `kill_pid(pid)` on a wrapper | the wrapper dies, the grandchild keeps working — the leak | IR-80's 12-cell union; `proc.rs:430`'s own doc states it |\n| **IDENTITY** | `kill_pid_tree(remembered_pid)` with no image read | you kill *a* process with that number, not the one you meant | IR-81 / #285, `broker.rs:8102` vs `servicehost.rs:651` |\n| **ENV READ** | `psutil.Process(child.pid).environ()` | the wrapper's env certifies a launch the battery would have failed | hertz 2026-09-07, self-test of `.github/bench/launch-battery.py` |\n\n**The third face, in full, because it is the newest and the least intuitive.** Reading back the\nenvironment of the process you spawned is the standard remedy for \"did my scrub/export actually\nland\" — it is what this project's own memory banked after the W0 perch-identity leak. It is\ninsufficient, and it fails in the flattering direction. A wrapper (`env VAR=x`, `cargo`, `nextest`,\n`bash -lc`) modifies the environment it hands the process **below** it, while its own `environ()`\nstill shows exactly what you passed in. So the read-back agrees with your intent, prints PROVEN, and\nsays nothing whatsoever about the process under test. Measured: the first version of\n`launch-battery.py` passed BOTH deliberately-negative tests. The corrected version walks descendants\nand, in the refusal, prints the wrapper as CLEAN beside the grandchild as VIOLATOR — that contrast\nis the face made visible in one line of output.\n\n**Why this belongs in IR-80 rather than in a new entry.** All three are the same error committed at\nthe same seam: an operation is aimed at a pid when the thing it needs to reach is a tree (or a\nspecific member of one). The remedies rhyme — walk the tree, read the identity, report the scope you\nactually covered — and a reader who finds any one face is one paragraph away from the other two.\nFiling them separately would have hidden that, which is the concrete cost doyle's ruling avoids.\n\n**What this amendment does NOT claim.** It does not widen IR-80's population: the 12-cell union\ntable and its Windows/Linux partition are unchanged, and the env face is not a test leak. It does\nnot add a remedy owner — the ENV face's fix is a tool (`.github/bench/launch-battery.py`), not product code, and the KILL and\nIDENTITY faces keep the owners they already have (#285 / todlando post-W2). It is a naming, and its\nwhole value is that the next instance of this error gets recognized as an instance instead of being\nfiled fresh.\n\n**Standing prediction, so this is falsifiable rather than tidy:** a fourth face exists wherever the\ncodebase asks a question *of* a pid that is really a question *about* a tree. The candidates I would\nlook at first are (a) liveness — `process_exists(pid)` answering \"is the work still running\" when\nthe work is a grandchild, and (b) resource attribution — reading a pid's handles/memory to decide\nwhether a lane is finished. Neither is measured; both are named so that finding one counts as\nconfirmation and finding none over the next few incidents counts against the generalization.\n\n### IR-81 — a process kill can be written scoped or machine-wide, and nothing makes the scoped form the only reachable one: both codebases carry the right pattern beside the wrong one\n\n- **Status:** OPEN, drafted by hertz 2026-09-07 08:38Z on doyle's dispatch (08:36Z), from the\n  fleet-daemon death on hfenduleam at 08:03:15Z ([[RCA-FLEET-DAEMON-14444]], cause still UNNAMED).\n  Census body: `docs/PID-KILL-CENSUS.md`. · **Origin:** doyle asked which sites kill a REMEMBERED\n  pid without re-verifying identity AT KILL TIME. The census answered that, and then answered a\n  better question nobody asked: **why the unguarded sites exist at all when the guarded ones sit\n  feet away.**\n- **⚠ THIS ENTRY IS NOT \"FIX THESE TWO SITES.\"** Both individual fixes are small and are dispatched\n  elsewhere (broker.rs:8102 → todlando's lane post-W2; live-relay-int.sh:78 → filed to perri). This\n  entry is about the thing that PRODUCED them and will produce the next one: the scoped form and the\n  machine-wide form are equally easy to write, equally plausible on review, and only one of them is\n  correct on a shared box.\n- **THE PAIRED EXHIBITS — same repo, same hand, feet apart.**\n\n  | | correct, and it says why | incorrect |\n  |---|---|---|\n  | **spt-core** | `spt-daemon/src/servicehost.rs:651` — `provably_gone` first, then `exe_path(pid)` compared to the parked image via `same_image`, then a FRESH post-kill read. Its comment IS the rule: *\"The pid is live. WHO is it? The image path decides — never the number.\"* | `spt-daemon/src/broker.rs:8102` — kills `spid`, a pid REMEMBERED off the session record, through `kill_pid_tree`. `zombie_verdict` consults liveness BY NUMBER (`process_exists`/`is_process_alive`), `adapter_labeled` (a property of the RECORD, not the live process), descendants and grace. **The live process's image is never read.** |\n  | **spt-claude-code** | `ci/launcher/bind-int.sh:50` — `wmic process where \"name='claude-spt.exe' and commandline like '%$ID%'\"`, scoped to this run's unique id, comment *\"never wall-a's\"*. Also `multi-subnet-bringup-int.sh:117` ($C3_ID) and `wake-survival-int.sh:64` (`-match '$PROBE'`). | `ci/psyche/live-relay-int.sh:78` — `for p in $(tasklist \\| grep -i claude-spt \\| awk '{print $2}'); do taskkill //PID \"$p\" //T //F; done` — **every** `claude-spt.exe` on the box, tree-force, no run-scoping. Comment: *\"by marker pid then name.\"* |\n\n  **The knowledge is not missing in either codebase. It is present, written down, and adjacent.**\n  Three correct sites to one wrong one in the adapter; a rule-stating comment in core. What is\n  missing is any mechanism that makes the wrong spelling hard to reach.\n- **Why \"just fix the sites\" is the wrong remedy:** it has already been tried implicitly — someone\n  wrote the scoped form three times, which is what a team looks like when it knows the rule and\n  still ships the exception. A fourth correct site does not prevent a fifth incorrect one. The\n  remedy has to change what is REACHABLE, not what is written.\n- **REMEDY — RULED 2026-09-07 08:40Z (doyle): (a) AND (b), not a choice between them. Two owners,\n  two lanes, and they cover different halves of the hazard.**\n  1. **(a) PRODUCT — push the identity requirement into the primitive.** `spt_store::proc::kill_pid_tree`\n     / `kill_pid` take an expected identity (image path, or a `same_image` closure) and refuse\n     without it, so a caller **cannot express** the unguarded kill; `servicehost.rs:651` stops being\n     the exception among callers and becomes the shape of all of them. **Owner: todlando, post-W2.**\n     ⇄ **This IS the fix shape of the `broker.rs:8102` board BUGFIX — that item and this entry\n     cross-reference each other; neither is complete alone.** Reaches Rust callers only.\n  2. **(b) GATE — `xtask check` refuses the unscoped spelling in CI scripts.** A `tasklist` /\n     `Get-Process` enumeration piped into a kill, or a bare `taskkill` with no\n     `commandline like` / `-match` scope in the same block, is a build failure. **Owner: hertz,\n     rides the IR-37 thin PR after W2 lands.** This is the half remedy (a) can NEVER reach — the\n     unguarded adapter site is a shell script, and no Rust signature constrains a shell script.\n  3. **(c) Fix the two sites and stop.** Recorded as CONSIDERED AND LOSING, not omitted: it has\n     already been tried implicitly — the adapter's author wrote the scoped form three times and\n     shipped the exception anyway — so a fourth correct site does not prevent a fifth wrong one.\n     It leaves the next instance free to appear.\n  **The (a)/(b) split is the entry's real content:** the hazard lives in two languages, and a remedy\n  in one of them is a half-measure that will read as a fix.\n- **STANDING LIMIT, so this entry is not overread as an incident cause:** none of these sites\n  explains the 08:03:15Z death. broker.rs:8102 would have been saved from firing by\n  `has_live_descendants` (the daemon had a live brain) — accidental protection, not deliberate —\n  and every claude-spt site enumerates `claude-spt.exe` while the dead process was `spt.exe`. The\n  census found a real hazard while looking for a different one. **Do not let this entry close the\n  incident.** The instrument at `C:\\Users\\decid\\.spt-watch\\daemon-watch.log` is what will answer\n  that, or fail to.\n- **Kin:** [[IR-79]] and [[IR-80]] (children outliving their cell; the leak family), the\n  [[RCA-FLEET-DAEMON-14444]] timeline, `servicehost.rs`'s own \"image path decides\" comment as the\n  in-tree statement of the rule, and the paired-exhibit method itself — a correct and an incorrect\n  site in one repo is stronger evidence about PROCESS than either site is about code.\n- **Ripe when:** the next touch of `spt-store/src/proc.rs` (for remedy 1) or of `xtask check`'s\n  gate family (for remedy 2). The adapter half is perri's, filed separately, and does not wait\n  on this.\n- **Size:** small for remedy 2, medium for remedy 1 (signature + every caller). The census that\n  justifies either is already written and does not need redoing.\n\n---\n\n#### ADAPTER-SIDE ARM: CLOSED (claude-spt, perri, 2026-09-07)\n\n**Status: closed in the consumer repo, test-only, does not close IR-81 here.**\n\n- **Commit `9c87372`** (spt-claude-code). Broad `tasklist | grep claude-spt | taskkill` replaced\n  with an **id-scoped wmic** call, **name-pinned so wmic cannot self-match**; the three\n  remembered-pid kills additionally got a **kill-time recheck**, covering the stale-identity face\n  as well as the unscoped-pattern face.\n- **Guard: `tests/ci-kill-scoping.sh`, traced as `REQ-HAZARD-CI-KILL-SCOPING`.** Gate green.\n  This is the check-shape arm (b) proposes for spt-core, already landed once — precedent, not\n  merely agreement.\n- **Scope: test/CI infrastructure only.** No product code changed. (doyle, 08:50Z.)\n- **`live-relay-int.sh:78` is retained as the historical RED exhibit** — the one genuinely\n  machine-wide kill found in the whole fleet census. It is the reason this hazard is written as a\n  hazard rather than a style note; do not quietly replace the exhibit with the fixed line.\n\n**Population lesson carried into arm (b)'s census.** I filed ONE site; perri confirmed **four**, and\nreports the idiom was already present in that repo **3x** before the filing. A filing that names one\nline under-counts its class by 3-4x in a single repo. **Census the ACT — any taskkill / pkill /\nwmic-delete reachable from a script root — never the literal string that led me to the first site.**\nState the walked roots in the check's own message, and give the gate a negative control that goes\nRED on a known-bad line before its green is trusted.\n\n**Still open here, unchanged:** arm (a), Rust-side identity pushed into `kill_pid_tree` / `kill_pid`\nso no Rust caller can express the unguarded kill (todlando, post-W2, cross-referenced with the\nbroker.rs:8102 board BUGFIX); and arm (b), the xtask script gate (mine, rides IR-37).\n\n---\n\n#### SCOPING ARM (a) — the product path has no intermediary; the fixture does\n*(hertz 2026-09-07, ruled by doyle 10:22Z off the IR-80 leak work.)*\n\n> **A pid is not an identity and a pid is not a tree. IR-80 needs CALLERS, not code.**\n> *(The register's sentence — doyle 10:23Z. Arm (a) fixes the identity half in\n> `kill_pid`/`kill_pid_tree`; the tree half needs no new machinery, because `kill_pid_tree` already\n> exists at proc.rs:430 with the defect stated in its own doc. This is why IR-79, IR-80 and IR-81\n> converge on one seam without collapsing into one finding.)*\n\nMeasured, not inferred: **`spawn_brain_child` (crates/spt-daemon/src/brainproc.rs:1224) does\n`Command::new(exe)`** — the real brain is spawned DIRECTLY, with no shell and no launcher between\nthe daemon and the process it supervises. So on the crashloop/rollback path a single-pid kill\n*does* reach the thing it aims at, and the \"orphaned grandchild\" mechanism found in the IR-80 leak\ncells is **a property of the TEST FIXTURE**, whose `long_child()` (brainproc.rs:1359) goes through\n`cmd /C` on Windows, not of the product.\n\n**What that scopes.** Arm (a) is NOT about the brain-supervision path and must not be sold as\nprotecting `REQ-HAZARD-BROKER-PROCESS-ISOLATION` (\"never two live brains\") — that invariant is not\nat risk here, and claiming it would be borrowing urgency this arm has not earned. Arm (a) stays\npointed at **the broker.rs:8102 reap, where the image is never read** — a kill aimed by pid alone\nat a process whose identity was never verified. That is the real unguarded form, and it is a\ndifferent failure (kill the wrong process) from the one IR-80 surfaced (fail to kill the right\none).\n\n**The two failures are different, which is why the drafts converge without collapsing.** Arm (a) is\n*kill the wrong process* (identity never read); IR-80 is *fail to kill the right one* (tree never\nwalked). The identity half is todlando's, post-W2. The tree half is already solved in-tree —\n`kill_pid_tree` at proc.rs:430, whose doc states the defect outright (\"a single-pid `kill_pid` leaves\nthe wrapper's harness children orphaned + running\") — so IR-80 ships callers, not machinery. See\n[[RIDER 4]] for the two test-side callers.\n\n### IR-82 — a daemon death leaves NO record of who died: autostart decides on a socket ping, says \"no daemon\", and the successor overwrites the only handle on the corpse\n\n- **Status:** RULED 2026-09-07 11:07Z (doyle), drafted by hertz 11:04Z on doyle's dispatch (11:03Z: *\"the autostart\n…\n  OBSERVABILITY, not in the death.\n…\n\n\n[Showing lines 4124-4534 of 5900. Use :4535 to continue]"}],"details":{"truncation":{"content":"\r\n### IR-80 — five leaky cells on ONE module (`brainproc` / `supervise_brain`), Windows only: a candidate PRODUCT leak on the promotion/rollback path, or a cluster of names — nobody has looked yet\r\n\r\n- **Status:** OPEN for the residual population, not an undiagnosed five-name product claim.\r\n  Later amendments identify the brainproc shell-wrapper fixture mechanism and distinguish\r\n  production's direct spawn; they do not classify all 12 union members. Historical opening\r\n  hypotheses below are not current causal conclusions. Filed by hertz 2026-09-07 07:40Z on\r\n  doyle's ruling that this retains its own identity, separate from IR-79.\r\n  **Origin:** noticed while measuring the #198 HEAVY scan-root gap ([[IR-37]] rider 2); the leak\r\n  roster was read out of the baseline golden log for an unrelated reason.\r\n- **⚠ WHAT THIS ENTRY IS, STATED FIRST SO IT IS NOT OVERREAD: a CLUSTER OF NAMES.** Five cells\r\n  that leaked share one module and one code path by their identifiers. Nothing has been measured\r\n  about WHAT is left alive, and a shared module is not a shared cause. Do not cite this as a\r\n  product defect until the census below has run.\r\n- **The observation, exact.** Golden run **34017906638**, sha `04e32c8c95cf`, both boxes, Phase A.\r\n  Windows (hfenduleam) reported **9 leaky** cells; Linux (kitsubito) **1** (`livehost::tests::\r\n  legacy_psyche_sweep_guard_is_id_specific_and_fail_safe`, unrelated). **Five of the Windows nine\r\n  are the same module:**\r\n\r\n  | cell | kind | time |\r\n  |---|---|---|\r\n  | `spt-daemon brainproc::tests::clear_before_spawn_defeats_exact_generation_stale_file` (:2200) | lib | 0.457s |\r\n  | `spt-daemon brainproc::tests::ready_but_old_gen_never_drains_does_not_promote_rolls_back` (:1834) | lib | 0.554s |\r\n  | `spt-daemon brainproc::tests::stale_generation_minus_one_ready_never_promotes` (:2155) | lib | 0.731s |\r\n  | `spt-daemon brainproc::tests::trial_kills_alive_never_ready_candidate_before_rollback` (:2109) | lib | 0.582s |\r\n  | `spt-daemon::false_promote ready_candidate_does_not_promote_until_the_wedged_old_gen_conn_drains` | int | 1.744s |\r\n\r\n  Denominator for the lib half: `brainproc`'s test module holds **26** `#[test]`/`#[tokio::test]`\r\n  cells, so **4 of 26 leaked, and all four are the trial/promote/rollback cells by name.** The\r\n  fifth is the integration rig that drives the same path.\r\n- **Why it is worth an entry even unmeasured:** four of the five are `kind(lib)`, so they run in\r\n  **`ci.yml` on every push**, not only in golden — if something really is left alive it is being\r\n  left alive on the shared Windows box many times a day. That is the same standing cost as\r\n  [[IR-79]]'s daemon face, arrived at from the opposite direction.\r\n- **HYPOTHESIS, labelled as such and NOT measured.** `supervise_brain` (:935) takes an injected\r\n  `spawn_child: impl FnMut(...) -> io::Result<Child>` (:941) and reaps candidates with bare\r\n  `let _ = child.kill();` at :998, :1015, :1055, :1071, :1081 — **`kill()` with no `wait()`.** On\r\n  Windows termination is asynchronous, and a killed-but-unreaped child can still hold the\r\n  inherited stdout/stderr pipe past the test's exit, which is exactly what nextest reports as\r\n  LEAK. The production spawner's own doc comment at :1190 states the intent — \"dies with no\r\n  orphaning. NOT `spawn_detached`\" — so if this is the mechanism, the code's intent and its\r\n  behaviour have diverged on one platform. **Every clause of this bullet is a reading of source,\r\n  not an observation of a live process. It may be entirely wrong.**\r\n- **FIRST MEASUREMENT — and doyle sharpened it 07:41Z from a census into a FALSIFIER, which is the\r\n  form to run:** on a free Windows box after W2, run\r\n  `trial_kills_alive_never_ready_candidate_before_rollback` **alone** and read one thing —\r\n  **is the killed pid still present, with the pipe handle open?** That is a yes/no against the\r\n  hypothesis above, not an open look at what happens to be running, and it is the difference\r\n  between a reading that settles the entry and a reading that produces more names. Capture pid,\r\n  image path and parent alongside the answer so a YES is immediately actionable, but the ANSWER is\r\n  the deliverable. One cell, one read. **Owner stays UNASSIGNED until it is taken** (doyle) — a\r\n  product path and a rig artifact are not distinguishable from here, and assigning before the read\r\n  would pick one by guess.\r\n- **Limits, so the entry cannot be overread:** nextest `LEAK` is **not a failure** — none of these\r\n  cells reds anything, and the run was green. Windows-only in **one** run; no trend established.\r\n  The clustering is by identifier and shared module, which is suggestive and is not causation.\r\n  I have not run any of these cells. Everything above is source plus one golden log — no box, no\r\n  build.\r\n- **Kin:** [[IR-79]] (children outliving the cell — the rig-teardown face of the same symptom, and\r\n  the reason doyle ruled these must stay SEPARATE: same symptom, different suspected owner),\r\n  [[IR-37]] rider 2 (the measurement that surfaced it), FLAKE-LEDGER's `resident_service_e2e` :664\r\n  teardown LEAK row.\r\n- **Ripe when:** the first free Windows box after W2 lands — it is a single-cell census, so it\r\n  fits any gap.\r\n- **Size:** unknown until the census. Tiny if it is a missing `wait()`; not tiny if the promotion\r\n  path leaves a real candidate brain alive on rollback.\r\n\r\n---\r\n\r\n#### THE LEAK SET IS NOISY — measured across three shas, 2026-09-07 (hertz)\r\n\r\n**This retracts the \"8 -> 5 leaky, direction favourable\" reading I flagged at 09:31Z.** It is not a\r\nfix and not an improvement; it is threshold noise, and the census this draft was built on inherits\r\nthat noise.\r\n\r\nWindows `ci` unit leg (`--workspace -E 'kind(lib) + kind(bin)'`), three consecutive shas:\r\n\r\n| cell | ff4b405d | e3bd53d4 | 401a19ad |\r\n|---|---|---|---|\r\n| brainproc::clear_before_spawn_defeats_exact_generation_stale_file | ● | ● | ● |\r\n| brainproc::ready_but_old_gen_never_drains_does_not_promote_rolls_back | ● | ● | ● |\r\n| brainproc::trial_kills_alive_never_ready_candidate_before_rollback | ● | ● | ● |\r\n| spt-runtime runtime::bounded_run_kills_on_timeout | ● | ● | ● |\r\n| brainproc::stale_generation_minus_one_ready_never_promotes | ● | ● | — |\r\n| spt-live digest::extractor_timeout_errors | ● | ● | — |\r\n| spt-live history::fetcher_timeout_errors | ● | ● | — |\r\n| spt-daemon broker::windows_session_is_zombie_sees_a_handle_held_corpse_as_dead | ● | — | — |\r\n| spt-daemon shellwake::kill_waker_at_still_kills_a_matching_pair | — | ● | ● |\r\n| **total** | **8** | **8** | **5** |\r\n\r\n**Causality check, which is what makes this a retraction rather than a hypothesis:** the three\r\ncommits between e3bd53d4 and 401a19ad touch **zero files** in brainproc, spt-live, spt-runtime,\r\nshellwake or broker (`git diff --name-only` over those paths returns nothing). The count fell by 3\r\nwith no change to any leaking module. So the drop cannot be a fix; the membership simply moves.\r\nNine cells appear in the union, only **four** are present at all three shas, and one\r\n(`shellwake::kill_waker_at`) *appeared* rather than vanished — a count that falls while a new member\r\njoins is the signature of a threshold, not of a repair.\r\n\r\n#### Three consequences for this draft\r\n\r\n1. **A count is not a quality signal here, in either direction.** Any future \"leaky went down\"\r\n   claim needs the NAME diff and a causality check against the changed files, or it is noise\r\n   reported as progress. I made exactly that error and it survived about twenty minutes.\r\n2. **The five-cell cluster is really \"three stable + one intermittent\".**\r\n   `stale_generation_minus_one_ready_never_promotes` is absent at 401a19ad. The cluster framing\r\n   still holds — three brainproc cells leak at every sha and they are all one module — but the\r\n   membership count must not be quoted as fixed.\r\n3. **doyle's falsifier beats my census, and this is the evidence.** The census (count the leaky\r\n   cells, name the cluster) is exactly what the noise destroys. His falsifier — *after\r\n   `trial_kills_alive_never_ready_candidate_before_rollback` on Windows, is the killed pid still\r\n   present with the pipe handle open?* — names ONE cell and probes a MECHANISM, and that cell is\r\n   **leaky at all three shas**, so it is the most stable target available. A mechanism probe is\r\n   immune to the threshold that moves the population. Owner stays UNASSIGNED until that read.\r\n\r\n#### One structural finding the noise does NOT touch\r\n**All nine union members spawn a child and then kill it, let it time out, or inspect its corpse** —\r\n`trial_kills_alive`, `kill_waker_at`, `bounded_run_kills_on_timeout`, `extractor_timeout_errors`,\r\n`fetcher_timeout_errors`, `windows_session_is_zombie_sees_a_handle_held_corpse_as_dead`, and the\r\nthree brainproc spawn/promote/rollback cells. Not one unrelated cell is in the set. Membership\r\nfluctuates; the *kind* of cell does not. That is a real signal about where child-process teardown\r\nis unreliable on Windows, and it is the same territory as [[ir79]] (rigs leaking daemons on a\r\nfailing assert) and [[ir81]] (kill scoping) — three drafts converging on one seam.\r\n\r\n---\r\n\r\n#### THE 12-CELL UNION — 4 shas x 2 OSes, membership beside the invariant (hertz, 2026-09-07 10:15Z)\r\n\r\nMachine-generated from the eight ci unit logs, not transcribed (a hand-typed 12x8 matrix is where\r\ntranscription errors live). `X` = reported LEAK at that sha on that box.\r\n\r\n| cell | W ff4b405d | W e3bd53d4 | W 401a19ad | W f3c8495b | L ff4b405d | L e3bd53d4 | L 401a19ad | L f3c8495b |\r\n|---|---|---|---|---|---|---|---|---|\r\n| `spt-daemon brainproc::tests::clear_before_spawn_defeats_exact_generation_stale_file` | X | X | X | X | . | . | . | . |\r\n| `spt-daemon brainproc::tests::ready_but_old_gen_never_drains_does_not_promote_rolls_back` | X | X | X | X | . | . | . | . |\r\n| `spt-daemon brainproc::tests::stale_generation_minus_one_ready_never_promotes` | X | X | . | X | . | . | . | . |\r\n| `spt-daemon brainproc::tests::trial_kills_alive_never_ready_candidate_before_rollback` | X | X | X | X | . | . | . | . |\r\n| `spt-daemon broker::tests::windows_session_is_zombie_sees_a_handle_held_corpse_as_dead` | X | . | . | X | . | . | . | . |\r\n| `spt-daemon livehost::tests::legacy_psyche_sweep_guard_is_id_specific_and_fail_safe` | . | . | . | . | X | X | X | . |\r\n| `spt-daemon shellhost::tests::kill_shell_at_still_kills_a_matching_pair` | . | . | . | X | . | . | . | . |\r\n| `spt-daemon shellwake::tests::kill_waker_at_still_kills_a_matching_pair` | . | X | X | X | . | . | . | . |\r\n| `spt-live digest::tests::extractor_timeout_errors` | X | X | . | X | . | . | . | . |\r\n| `spt-live history::tests::fetcher_timeout_errors` | X | X | . | . | . | . | . | . |\r\n| `spt-runtime runtime::tests::bounded_run_kills_on_timeout` | X | X | X | X | . | . | . | . |\r\n| `spt-store proc::tests::process_cmdline_reads_a_live_arg_marker` | . | . | . | . | X | X | X | X |\r\n| **leaky count** | 8 | 8 | 5 | 9 | 2 | 2 | 2 | 1 |\r\n\r\nUnion = 12 cells across 4 shas x 2 OSes. Present at EVERY Windows sha: 4. Present at every Linux sha: 1.\r\n\r\n#### Three readings, in increasing order of what they support\r\n\r\n**1. The churn is total and it is the whole point.** Windows counts run 8, 8, 5, 9 — the HIGHEST\r\nvalue is at `f3c8495b`, the tip carrying every fix F1-F16. Only **4 of 12** cells are present at\r\nevery Windows sha; only **1 of 2** at every Linux sha. Read as a quality signal the series says W2\r\nmade leaking worse, which is exactly as wrong as my retracted \"8 -> 5, favourable\" read and wrong\r\nfor the same reason. **A leaky count is not a signal in either direction.**\r\n\r\n**2. NEW, and I had not said it before building this table: the two OS sets are DISJOINT.** Ten\r\ncells leak only on Windows, two only on Linux, and **not one cell leaks on both**. Windows carries\r\n8-9 leaky cells per run against Linux's 1-2. So this is not one flaky population sampled twice —\r\nit is two populations with no overlap, and the Windows one is roughly five times larger. Any\r\nexplanation that treats \"leaky tests\" as a single phenomenon has to account for a clean partition\r\nby OS.\r\n\r\n**This is an OPEN QUESTION and the draft does not answer it. I do not have that explanation yet.**\r\nRecorded deliberately without a candidate cause: the partition is a measurement, and the temptation\r\nto pair a striking measurement with a plausible story is how the \"8 -> 5 is favourable\" reading got\r\ninto the record in the first place. Whoever takes this should arrive at a cause by reading, not by\r\ninheriting one from me.\r\n\r\n**SCOPED CAUSE, IN SOURCE, FOR ONE FAMILY ONLY (doyle ruled 10:22Z: source beats story; a source\r\ncause covering one family is a measurement and is filed as one).** The brainproc family leaks on\r\nWindows and not Linux because *its own fixture is asymmetric*: `long_child()` (brainproc.rs:1359)\r\nspawns `Command::new(\"cmd\").args([\"/C\",\"ping\",\"-n\",\"30\",\"127.0.0.1\"])` on Windows but\r\n`Command::new(\"sleep\").arg(\"30\")` on Unix — a shell wrapper on one box, a bare process on the other.\r\nThe Windows candidate the supervisor kills is `cmd`; the process burning 29 seconds is its child.\r\nThat is two lines of source, not an inference from the symptom. **And it is NOT the whole partition:**\r\n`process_cmdline_reads_a_live_arg_marker` uses a shell on BOTH arms (`sh -c \"sleep 30; : marker\"` /\r\n`cmd /C \"ping … & rem marker\"`) yet leaks on **Linux only** — the shell mechanism predicts it should\r\nleak on both boxes and it does not. So one family has a cause I can point at in the source, the\r\npartition as a whole remains OPEN, and the counterexample stands in this paragraph rather than a\r\nfootnote so no one carries the cause further than it goes.\r\n\r\n**THE PRODUCT PATH HAS NO INTERMEDIARY; THE FIXTURE DOES.** I chased the obvious escalation — if the\r\nreal supervisor also killed a shell wrapper, then \"never two live brains\"\r\n(REQ-HAZARD-BROKER-PROCESS-ISOLATION, the invariant this very cell guards) could be violated on\r\nWindows in production while the test stayed green. It cannot: `spawn_brain_child` (brainproc.rs:1224)\r\ndoes `Command::new(exe)` — the brain is spawned DIRECTLY, no shell, no grandchild, so a single-pid\r\nkill reaches it. **This is a test-fixture artifact, not a product defect**, and the fixture's shell\r\nis a Windows-only convenience for \"a process that blocks ~30s\" that introduced a layer the real path\r\ndoes not have. The negative is the useful half: it keeps the crashloop invariant out of IR-81 (a).\r\n\r\n**Why the cell passed review for as long as it did.** It asserts `pid != 0 && !pid_alive(pid)` before\r\nrollback, and that assertion is TRUE — `cmd` really is dead. The process still doing work is the one\r\nit never looks at. The leak and the green are not in tension; they are the same fact from two ends.\r\n**An assertion over a pid cannot see a tree.**\r\n\r\n**3. The invariant holds at 12 of 12, and it survived the population being shuffled three times.**\r\nEvery union member spawns a child process and then kills it, lets it time out, or inspects its\r\ncorpse — `trial_kills_alive`, `kill_shell_at`, `kill_waker_at`, `bounded_run_kills_on_timeout`,\r\n`extractor_timeout_errors`, `fetcher_timeout_errors`, `windows_session_is_zombie_..._corpse_as_dead`,\r\n`legacy_psyche_sweep_guard_...`, `process_cmdline_reads_a_live_arg_marker`, and the three brainproc\r\nspawn/promote/rollback cells. Membership churns freely across four shas and two OSes; the KIND of\r\ncell has not varied once. **This is the IR-80 headline** and it is better supported now than when it\r\nrested on a stable-looking five-cell cluster, precisely because the population underneath it has\r\nbeen reshuffled and the invariant did not move.\r\n\r\n#### A MECHANISM, read out of the source of the two Linux cells — calibrated, not generalized\r\n`process_cmdline_reads_a_live_arg_marker` spawns **`sh -c \"sleep 30; : marker\"`**, and the test's\r\nown comment says the trailing `; :` is deliberate — it keeps the shell RESIDENT so its\r\n`/proc/<pid>/cmdline` still carries the marker instead of being tail-exec-replaced by `sleep`. The\r\nteardown is `child.kill()` then `child.wait()`. **But `child` is the SHELL, and `sleep 30` is the\r\nshell's own child.** Killing the shell orphans the sleeper, which outlives the test by up to 30\r\nseconds — which is precisely what nextest reports as a LEAK. The Windows arm has the same shape:\r\n`cmd /C \"ping -n 30 127.0.0.1 >NUL & rem marker\"`, where `cmd` forks `ping`.\r\nSo the very construct that makes the test work (a resident shell, so the cmdline stays readable) is\r\nwhat guarantees a grandchild that a single-pid kill cannot reach.\r\n\r\n**What is verified and what is not, stated separately because the difference decides who owns this.**\r\nVERIFIED by reading source: this shape in BOTH Linux-only cells. CONSISTENT but not proven: the\r\nWindows family kills the same way — `kill_waker_at_still_kills_a_matching_pair` tears down with\r\n`kill_shell_pid(ours.id())`, a single-pid kill — so the mechanism is available to it, but I have not\r\nread every spawn helper. UNVERIFIED: the brainproc, broker and spt-live cells; those spawn real\r\nbrains and time out extractors, and may leak for unrelated reasons.\r\n\r\n**Why this matters beyond IR-80:** a single-pid kill that cannot reach a grandchild is exactly\r\n[[ir81]] arm (a) — identity and tree-awareness pushed into `kill_pid_tree`/`kill_pid` so no caller\r\ncan express the unreachable kill. If the mechanism above generalizes, IR-79 (rigs leaking daemons\r\non a failing assert), IR-80 (this) and IR-81 (kill scoping) are not three findings that share a\r\nseam, they are three FACES of one defect: **the codebase kills pids, and the things it needs dead\r\nare trees.** That is a claim worth testing, not asserting — and doyle's one-cell mechanism probe\r\nis still the right instrument, now with a sharper question: after the kill, is the surviving\r\nprocess the CHILD or the GRANDCHILD?\r\n\r\n---\r\n\r\n#### AMENDMENT 1 — \"a pid is not a tree\" has THREE faces, and only one of them is a kill\r\n\r\n*(hertz 2026-09-07, ruled by doyle 11:17Z: write this as an IR-80 amendment naming the three faces\r\nrather than three separate entries, so a reader hunting any one face lands on all three.)*\r\n\r\nThe register sentence this lane has been running on is doyle's: **a pid is not an identity and a pid\r\nis not a tree.** IR-80 and IR-81 were both filed against the KILL side, which made the sentence read\r\nlike a rule about killing. It is not. It is a rule about **which process you are talking about**, and\r\nkilling is only the face we happened to find first. Three faces are now measured, each found by a\r\ndifferent agent working a different problem:\r\n\r\n| face | the operation | what going one level too high produces | measured |\r\n|---|---|---|---|\r\n| **KILL** | `kill_pid(pid)` on a wrapper | the wrapper dies, the grandchild keeps working — the leak | IR-80's 12-cell union; `proc.rs:430`'s own doc states it |\r\n| **IDENTITY** | `kill_pid_tree(remembered_pid)` with no image read | you kill *a* process with that number, not the one you meant | IR-81 / #285, `broker.rs:8102` vs `servicehost.rs:651` |\r\n| **ENV READ** | `psutil.Process(child.pid).environ()` | the wrapper's env certifies a launch the battery would have failed | hertz 2026-09-07, self-test of `.github/bench/launch-battery.py` |\r\n\r\n**The third face, in full, because it is the newest and the least intuitive.** Reading back the\r\nenvironment of the process you spawned is the standard remedy for \"did my scrub/export actually\r\nland\" — it is what this project's own memory banked after the W0 perch-identity leak. It is\r\ninsufficient, and it fails in the flattering direction. A wrapper (`env VAR=x`, `cargo`, `nextest`,\r\n`bash -lc`) modifies the environment it hands the process **below** it, while its own `environ()`\r\nstill shows exactly what you passed in. So the read-back agrees with your intent, prints PROVEN, and\r\nsays nothing whatsoever about the process under test. Measured: the first version of\r\n`launch-battery.py` passed BOTH deliberately-negative tests. The corrected version walks descendants\r\nand, in the refusal, prints the wrapper as CLEAN beside the grandchild as VIOLATOR — that contrast\r\nis the face made visible in one line of output.\r\n\r\n**Why this belongs in IR-80 rather than in a new entry.** All three are the same error committed at\r\nthe same seam: an operation is aimed at a pid when the thing it needs to reach is a tree (or a\r\nspecific member of one). The remedies rhyme — walk the tree, read the identity, report the scope you\r\nactually covered — and a reader who finds any one face is one paragraph away from the other two.\r\nFiling them separately would have hidden that, which is the concrete cost doyle's ruling avoids.\r\n\r\n**What this amendment does NOT claim.** It does not widen IR-80's population: the 12-cell union\r\ntable and its Windows/Linux partition are unchanged, and the env face is not a test leak. It does\r\nnot add a remedy owner — the ENV face's fix is a tool (`.github/bench/launch-battery.py`), not product code, and the KILL and\r\nIDENTITY faces keep the owners they already have (#285 / todlando post-W2). It is a naming, and its\r\nwhole value is that the next instance of this error gets recognized as an instance instead of being\r\nfiled fresh.\r\n\r\n**Standing prediction, so this is falsifiable rather than tidy:** a fourth face exists wherever the\r\ncodebase asks a question *of* a pid that is really a question *about* a tree. The candidates I would\r\nlook at first are (a) liveness — `process_exists(pid)` answering \"is the work still running\" when\r\nthe work is a grandchild, and (b) resource attribution — reading a pid's handles/memory to decide\r\nwhether a lane is finished. Neither is measured; both are named so that finding one counts as\r\nconfirmation and finding none over the next few incidents counts against the generalization.\r\n\r\n### IR-81 — a process kill can be written scoped or machine-wide, and nothing makes the scoped form the only reachable one: both codebases carry the right pattern beside the wrong one\r\n\r\n- **Status:** OPEN, drafted by hertz 2026-09-07 08:38Z on doyle's dispatch (08:36Z), from the\r\n  fleet-daemon death on hfenduleam at 08:03:15Z ([[RCA-FLEET-DAEMON-14444]], cause still UNNAMED).\r\n  Census body: `docs/PID-KILL-CENSUS.md`. · **Origin:** doyle asked which sites kill a REMEMBERED\r\n  pid without re-verifying identity AT KILL TIME. The census answered that, and then answered a\r\n  better question nobody asked: **why the unguarded sites exist at all when the guarded ones sit\r\n  feet away.**\r\n- **⚠ THIS ENTRY IS NOT \"FIX THESE TWO SITES.\"** Both individual fixes are small and are dispatched\r\n  elsewhere (broker.rs:8102 → todlando's lane post-W2; live-relay-int.sh:78 → filed to perri). This\r\n  entry is about the thing that PRODUCED them and will produce the next one: the scoped form and the\r\n  machine-wide form are equally easy to write, equally plausible on review, and only one of them is\r\n  correct on a shared box.\r\n- **THE PAIRED EXHIBITS — same repo, same hand, feet apart.**\r\n\r\n  | | correct, and it says why | incorrect |\r\n  |---|---|---|\r\n  | **spt-core** | `spt-daemon/src/servicehost.rs:651` — `provably_gone` first, then `exe_path(pid)` compared to the parked image via `same_image`, then a FRESH post-kill read. Its comment IS the rule: *\"The pid is live. WHO is it? The image path decides — never the number.\"* | `spt-daemon/src/broker.rs:8102` — kills `spid`, a pid REMEMBERED off the session record, through `kill_pid_tree`. `zombie_verdict` consults liveness BY NUMBER (`process_exists`/`is_process_alive`), `adapter_labeled` (a property of the RECORD, not the live process), descendants and grace. **The live process's image is never read.** |\r\n  | **spt-claude-code** | `ci/launcher/bind-int.sh:50` — `wmic process where \"name='claude-spt.exe' and commandline like '%$ID%'\"`, scoped to this run's unique id, comment *\"never wall-a's\"*. Also `multi-subnet-bringup-int.sh:117` ($C3_ID) and `wake-survival-int.sh:64` (`-match '$PROBE'`). | `ci/psyche/live-relay-int.sh:78` — `for p in $(tasklist \\| grep -i claude-spt \\| awk '{print $2}'); do taskkill //PID \"$p\" //T //F; done` — **every** `claude-spt.exe` on the box, tree-force, no run-scoping. Comment: *\"by marker pid then name.\"* |\r\n\r\n  **The knowledge is not missing in either codebase. It is present, written down, and adjacent.**\r\n  Three correct sites to one wrong one in the adapter; a rule-stating comment in core. What is\r\n  missing is any mechanism that makes the wrong spelling hard to reach.\r\n- **Why \"just fix the sites\" is the wrong remedy:** it has already been tried implicitly — someone\r\n  wrote the scoped form three times, which is what a team looks like when it knows the rule and\r\n  still ships the exception. A fourth correct site does not prevent a fifth incorrect one. The\r\n  remedy has to change what is REACHABLE, not what is written.\r\n- **REMEDY — RULED 2026-09-07 08:40Z (doyle): (a) AND (b), not a choice between them. Two owners,\r\n  two lanes, and they cover different halves of the hazard.**\r\n  1. **(a) PRODUCT — push the identity requirement into the primitive.** `spt_store::proc::kill_pid_tree`\r\n     / `kill_pid` take an expected identity (image path, or a `same_image` closure) and refuse\r\n     without it, so a caller **cannot express** the unguarded kill; `servicehost.rs:651` stops being\r\n     the exception among callers and becomes the shape of all of them. **Owner: todlando, post-W2.**\r\n     ⇄ **This IS the fix shape of the `broker.rs:8102` board BUGFIX — that item and this entry\r\n     cross-reference each other; neither is complete alone.** Reaches Rust callers only.\r\n  2. **(b) GATE — `xtask check` refuses the unscoped spelling in CI scripts.** A `tasklist` /\r\n     `Get-Process` enumeration piped into a kill, or a bare `taskkill` with no\r\n     `commandline like` / `-match` scope in the same block, is a build failure. **Owner: hertz,\r\n     rides the IR-37 thin PR after W2 lands.** This is the half remedy (a) can NEVER reach — the\r\n     unguarded adapter site is a shell script, and no Rust signature constrains a shell script.\r\n  3. **(c) Fix the two sites and stop.** Recorded as CONSIDERED AND LOSING, not omitted: it has\r\n     already been tried implicitly — the adapter's author wrote the scoped form three times and\r\n     shipped the exception anyway — so a fourth correct site does not prevent a fifth wrong one.\r\n     It leaves the next instance free to appear.\r\n  **The (a)/(b) split is the entry's real content:** the hazard lives in two languages, and a remedy\r\n  in one of them is a half-measure that will read as a fix.\r\n- **STANDING LIMIT, so this entry is not overread as an incident cause:** none of these sites\r\n  explains the 08:03:15Z death. broker.rs:8102 would have been saved from firing by\r\n  `has_live_descendants` (the daemon had a live brain) — accidental protection, not deliberate —\r\n  and every claude-spt site enumerates `claude-spt.exe` while the dead process was `spt.exe`. The\r\n  census found a real hazard while looking for a different one. **Do not let this entry close the\r\n  incident.** The instrument at `C:\\Users\\decid\\.spt-watch\\daemon-watch.log` is what will answer\r\n  that, or fail to.\r\n- **Kin:** [[IR-79]] and [[IR-80]] (children outliving their cell; the leak family), the\r\n  [[RCA-FLEET-DAEMON-14444]] timeline, `servicehost.rs`'s own \"image path decides\" comment as the\r\n  in-tree statement of the rule, and the paired-exhibit method itself — a correct and an incorrect\r\n  site in one repo is stronger evidence about PROCESS than either site is about code.\r\n- **Ripe when:** the next touch of `spt-store/src/proc.rs` (for remedy 1) or of `xtask check`'s\r\n  gate family (for remedy 2). The adapter half is perri's, filed separately, and does not wait\r\n  on this.\r\n- **Size:** small for remedy 2, medium for remedy 1 (signature + every caller). The census that\r\n  justifies either is already written and does not need redoing.\r\n\r\n---\r\n\r\n#### ADAPTER-SIDE ARM: CLOSED (claude-spt, perri, 2026-09-07)\r\n\r\n**Status: closed in the consumer repo, test-only, does not close IR-81 here.**\r\n\r\n- **Commit `9c87372`** (spt-claude-code). Broad `tasklist | grep claude-spt | taskkill` replaced\r\n  with an **id-scoped wmic** call, **name-pinned so wmic cannot self-match**; the three\r\n  remembered-pid kills additionally got a **kill-time recheck**, covering the stale-identity face\r\n  as well as the unscoped-pattern face.\r\n- **Guard: `tests/ci-kill-scoping.sh`, traced as `REQ-HAZARD-CI-KILL-SCOPING`.** Gate green.\r\n  This is the check-shape arm (b) proposes for spt-core, already landed once — precedent, not\r\n  merely agreement.\r\n- **Scope: test/CI infrastructure only.** No product code changed. (doyle, 08:50Z.)\r\n- **`live-relay-int.sh:78` is retained as the historical RED exhibit** — the one genuinely\r\n  machine-wide kill found in the whole fleet census. It is the reason this hazard is written as a\r\n  hazard rather than a style note; do not quietly replace the exhibit with the fixed line.\r\n\r\n**Population lesson carried into arm (b)'s census.** I filed ONE site; perri confirmed **four**, and\r\nreports the idiom was already present in that repo **3x** before the filing. A filing that names one\r\nline under-counts its class by 3-4x in a single repo. **Census the ACT — any taskkill / pkill /\r\nwmic-delete reachable from a script root — never the literal string that led me to the first site.**\r\nState the walked roots in the check's own message, and give the gate a negative control that goes\r\nRED on a known-bad line before its green is trusted.\r\n\r\n**Still open here, unchanged:** arm (a), Rust-side identity pushed into `kill_pid_tree` / `kill_pid`\r\nso no Rust caller can express the unguarded kill (todlando, post-W2, cross-referenced with the\r\nbroker.rs:8102 board BUGFIX); and arm (b), the xtask script gate (mine, rides IR-37).\r\n\r\n---\r\n\r\n#### SCOPING ARM (a) — the product path has no intermediary; the fixture does\r\n*(hertz 2026-09-07, ruled by doyle 10:22Z off the IR-80 leak work.)*\r\n\r\n> **A pid is not an identity and a pid is not a tree. IR-80 needs CALLERS, not code.**\r\n> *(The register's sentence — doyle 10:23Z. Arm (a) fixes the identity half in\r\n> `kill_pid`/`kill_pid_tree`; the tree half needs no new machinery, because `kill_pid_tree` already\r\n> exists at proc.rs:430 with the defect stated in its own doc. This is why IR-79, IR-80 and IR-81\r\n> converge on one seam without collapsing into one finding.)*\r\n\r\nMeasured, not inferred: **`spawn_brain_child` (crates/spt-daemon/src/brainproc.rs:1224) does\r\n`Command::new(exe)`** — the real brain is spawned DIRECTLY, with no shell and no launcher between\r\nthe daemon and the process it supervises. So on the crashloop/rollback path a single-pid kill\r\n*does* reach the thing it aims at, and the \"orphaned grandchild\" mechanism found in the IR-80 leak\r\ncells is **a property of the TEST FIXTURE**, whose `long_child()` (brainproc.rs:1359) goes through\r\n`cmd /C` on Windows, not of the product.\r\n\r\n**What that scopes.** Arm (a) is NOT about the brain-supervision path and must not be sold as\r\nprotecting `REQ-HAZARD-BROKER-PROCESS-ISOLATION` (\"never two live brains\") — that invariant is not\r\nat risk here, and claiming it would be borrowing urgency this arm has not earned. Arm (a) stays\r\npointed at **the broker.rs:8102 reap, where the image is never read** — a kill aimed by pid alone\r\nat a process whose identity was never verified. That is the real unguarded form, and it is a\r\ndifferent failure (kill the wrong process) from the one IR-80 surfaced (fail to kill the right\r\none).\r\n\r\n**The two failures are different, which is why the drafts converge without collapsing.** Arm (a) is\r\n*kill the wrong process* (identity never read); IR-80 is *fail to kill the right one* (tree never\r\nwalked). The identity half is todlando's, post-W2. The tree half is already solved in-tree —\r\n`kill_pid_tree` at proc.rs:430, whose doc states the defect outright (\"a single-pid `kill_pid` leaves\r\nthe wrapper's harness children orphaned + running\") — so IR-80 ships callers, not machinery. See\r\n[[RIDER 4]] for the two test-side callers.\r\n\r\n### IR-82 — a daemon death leaves NO record of who died: autostart decides on a socket ping, says \"no daemon\", and the successor overwrites the only handle on the corpse\r\n\r\n- **Status:** RULED 2026-09-07 11:07Z (doyle), drafted by hertz 11:04Z on doyle's dispatch (11:03Z: *\"the autostart\r","truncated":true,"truncatedBy":"lines","totalLines":1777,"totalBytes":32629,"outputLines":411,"outputBytes":32629,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":5900,"displayContent":{"text":"### IR-79 — 22 of the 31 rig binaries leak their daemon tree on a failing assert: teardown is a statement, not a guard\n…\n- **Status:** OPEN, filed by hertz 2026-09-07 on doyle's dispatch during PR #198's CI window,\n…\n- **Size:** medium — one guard in `common`, then 22 mechanical adoptions, each provable by\n…\n\r\n### IR-80 — five leaky cells on ONE module (`brainproc` / `supervise_brain`), Windows only: a candidate PRODUCT leak on the promotion/rollback path, or a cluster of names — nobody has looked yet\r\n\r\n- **Status:** OPEN for the residual population, not an undiagnosed five-name product claim.\r\n  Later amendments identify the brainproc shell-wrapper fixture mechanism and distinguish\r\n  production's direct spawn; they do not classify all 12 union members. Historical opening\r\n  hypotheses below are not current causal conclusions. Filed by hertz 2026-09-07 07:40Z on\r\n  doyle's ruling that this retains its own identity, separate from IR-79.\r\n  **Origin:** noticed while measuring the #198 HEAVY scan-root gap ([[IR-37]] rider 2); the leak\r\n  roster was read out of the baseline golden log for an unrelated reason.\r\n- **⚠ WHAT THIS ENTRY IS, STATED FIRST SO IT IS NOT OVERREAD: a CLUSTER OF NAMES.** Five cells\r\n  that leaked share one module and one code path by their identifiers. Nothing has been measured\r\n  about WHAT is left alive, and a shared module is not a shared cause. Do not cite this as a\r\n  product defect until the census below has run.\r\n- **The observation, exact.** Golden run **34017906638**, sha `04e32c8c95cf`, both boxes, Phase A.\r\n  Windows (hfenduleam) reported **9 leaky** cells; Linux (kitsubito) **1** (`livehost::tests::\r\n  legacy_psyche_sweep_guard_is_id_specific_and_fail_safe`, unrelated). **Five of the Windows nine\r\n  are the same module:**\r\n\r\n  | cell | kind | time |\r\n  |---|---|---|\r\n  | `spt-daemon brainproc::tests::clear_before_spawn_defeats_exact_generation_stale_file` (:2200) | lib | 0.457s |\r\n  | `spt-daemon brainproc::tests::ready_but_old_gen_never_drains_does_not_promote_rolls_back` (:1834) | lib | 0.554s |\r\n  | `spt-daemon brainproc::tests::stale_generation_minus_one_ready_never_promotes` (:2155) | lib | 0.731s |\r\n  | `spt-daemon brainproc::tests::trial_kills_alive_never_ready_candidate_before_rollback` (:2109) | lib | 0.582s |\r\n  | `spt-daemon::false_promote ready_candidate_does_not_promote_until_the_wedged_old_gen_conn_drains` | int | 1.744s |\r\n\r\n  Denominator for the lib half: `brainproc`'s test module holds **26** `#[test]`/`#[tokio::test]`\r\n  cells, so **4 of 26 leaked, and all four are the trial/promote/rollback cells by name.** The\r\n  fifth is the integration rig that drives the same path.\r\n- **Why it is worth an entry even unmeasured:** four of the five are `kind(lib)`, so they run in\r\n  **`ci.yml` on every push**, not only in golden — if something really is left alive it is being\r\n  left alive on the shared Windows box many times a day. That is the same standing cost as\r\n  [[IR-79]]'s daemon face, arrived at from the opposite direction.\r\n- **HYPOTHESIS, labelled as such and NOT measured.** `supervise_brain` (:935) takes an injected\r\n  `spawn_child: impl FnMut(...) -> io::Result<Child>` (:941) and reaps candidates with bare\r\n  `let _ = child.kill();` at :998, :1015, :1055, :1071, :1081 — **`kill()` with no `wait()`.** On\r\n  Windows termination is asynchronous, and a killed-but-unreaped child can still hold the\r\n  inherited stdout/stderr pipe past the test's exit, which is exactly what nextest reports as\r\n  LEAK. The production spawner's own doc comment at :1190 states the intent — \"dies with no\r\n  orphaning. NOT `spawn_detached`\" — so if this is the mechanism, the code's intent and its\r\n  behaviour have diverged on one platform. **Every clause of this bullet is a reading of source,\r\n  not an observation of a live process. It may be entirely wrong.**\r\n- **FIRST MEASUREMENT — and doyle sharpened it 07:41Z from a census into a FALSIFIER, which is the\r\n  form to run:** on a free Windows box after W2, run\r\n  `trial_kills_alive_never_ready_candidate_before_rollback` **alone** and read one thing —\r\n  **is the killed pid still present, with the pipe handle open?** That is a yes/no against the\r\n  hypothesis above, not an open look at what happens to be running, and it is the difference\r\n  between a reading that settles the entry and a reading that produces more names. Capture pid,\r\n  image path and parent alongside the answer so a YES is immediately actionable, but the ANSWER is\r\n  the deliverable. One cell, one read. **Owner stays UNASSIGNED until it is taken** (doyle) — a\r\n  product path and a rig artifact are not distinguishable from here, and assigning before the read\r\n  would pick one by guess.\r\n- **Limits, so the entry cannot be overread:** nextest `LEAK` is **not a failure** — none of these\r\n  cells reds anything, and the run was green. Windows-only in **one** run; no trend established.\r\n  The clustering is by identifier and shared module, which is suggestive and is not causation.\r\n  I have not run any of these cells. Everything above is source plus one golden log — no box, no\r\n  build.\r\n- **Kin:** [[IR-79]] (children outliving the cell — the rig-teardown face of the same symptom, and\r\n  the reason doyle ruled these must stay SEPARATE: same symptom, different suspected owner),\r\n  [[IR-37]] rider 2 (the measurement that surfaced it), FLAKE-LEDGER's `resident_service_e2e` :664\r\n  teardown LEAK row.\r\n- **Ripe when:** the first free Windows box after W2 lands — it is a single-cell census, so it\r\n  fits any gap.\r\n- **Size:** unknown until the census. Tiny if it is a missing `wait()`; not tiny if the promotion\r\n  path leaves a real candidate brain alive on rollback.\r\n\r\n---\r\n\r\n#### THE LEAK SET IS NOISY — measured across three shas, 2026-09-07 (hertz)\r\n\r\n**This retracts the \"8 -> 5 leaky, direction favourable\" reading I flagged at 09:31Z.** It is not a\r\nfix and not an improvement; it is threshold noise, and the census this draft was built on inherits\r\nthat noise.\r\n\r\nWindows `ci` unit leg (`--workspace -E 'kind(lib) + kind(bin)'`), three consecutive shas:\r\n\r\n| cell | ff4b405d | e3bd53d4 | 401a19ad |\r\n|---|---|---|---|\r\n| brainproc::clear_before_spawn_defeats_exact_generation_stale_file | ● | ● | ● |\r\n| brainproc::ready_but_old_gen_never_drains_does_not_promote_rolls_back | ● | ● | ● |\r\n| brainproc::trial_kills_alive_never_ready_candidate_before_rollback | ● | ● | ● |\r\n| spt-runtime runtime::bounded_run_kills_on_timeout | ● | ● | ● |\r\n| brainproc::stale_generation_minus_one_ready_never_promotes | ● | ● | — |\r\n| spt-live digest::extractor_timeout_errors | ● | ● | — |\r\n| spt-live history::fetcher_timeout_errors | ● | ● | — |\r\n| spt-daemon broker::windows_session_is_zombie_sees_a_handle_held_corpse_as_dead | ● | — | — |\r\n| spt-daemon shellwake::kill_waker_at_still_kills_a_matching_pair | — | ● | ● |\r\n| **total** | **8** | **8** | **5** |\r\n\r\n**Causality check, which is what makes this a retraction rather than a hypothesis:** the three\r\ncommits between e3bd53d4 and 401a19ad touch **zero files** in brainproc, spt-live, spt-runtime,\r\nshellwake or broker (`git diff --name-only` over those paths returns nothing). The count fell by 3\r\nwith no change to any leaking module. So the drop cannot be a fix; the membership simply moves.\r\nNine cells appear in the union, only **four** are present at all three shas, and one\r\n(`shellwake::kill_waker_at`) *appeared* rather than vanished — a count that falls while a new member\r\njoins is the signature of a threshold, not of a repair.\r\n\r\n#### Three consequences for this draft\r\n\r\n1. **A count is not a quality signal here, in either direction.** Any future \"leaky went down\"\r\n   claim needs the NAME diff and a causality check against the changed files, or it is noise\r\n   reported as progress. I made exactly that error and it survived about twenty minutes.\r\n2. **The five-cell cluster is really \"three stable + one intermittent\".**\r\n   `stale_generation_minus_one_ready_never_promotes` is absent at 401a19ad. The cluster framing\r\n   still holds — three brainproc cells leak at every sha and they are all one module — but the\r\n   membership count must not be quoted as fixed.\r\n3. **doyle's falsifier beats my census, and this is the evidence.** The census (count the leaky\r\n   cells, name the cluster) is exactly what the noise destroys. His falsifier — *after\r\n   `trial_kills_alive_never_ready_candidate_before_rollback` on Windows, is the killed pid still\r\n   present with the pipe handle open?* — names ONE cell and probes a MECHANISM, and that cell is\r\n   **leaky at all three shas**, so it is the most stable target available. A mechanism probe is\r\n   immune to the threshold that moves the population. Owner stays UNASSIGNED until that read.\r\n\r\n#### One structural finding the noise does NOT touch\r\n**All nine union members spawn a child and then kill it, let it time out, or inspect its corpse** —\r\n`trial_kills_alive`, `kill_waker_at`, `bounded_run_kills_on_timeout`, `extractor_timeout_errors`,\r\n`fetcher_timeout_errors`, `windows_session_is_zombie_sees_a_handle_held_corpse_as_dead`, and the\r\nthree brainproc spawn/promote/rollback cells. Not one unrelated cell is in the set. Membership\r\nfluctuates; the *kind* of cell does not. That is a real signal about where child-process teardown\r\nis unreliable on Windows, and it is the same territory as [[ir79]] (rigs leaking daemons on a\r\nfailing assert) and [[ir81]] (kill scoping) — three drafts converging on one seam.\r\n\r\n---\r\n\r\n#### THE 12-CELL UNION — 4 shas x 2 OSes, membership beside the invariant (hertz, 2026-09-07 10:15Z)\r\n\r\nMachine-generated from the eight ci unit logs, not transcribed (a hand-typed 12x8 matrix is where\r\ntranscription errors live). `X` = reported LEAK at that sha on that box.\r\n\r\n| cell | W ff4b405d | W e3bd53d4 | W 401a19ad | W f3c8495b | L ff4b405d | L e3bd53d4 | L 401a19ad | L f3c8495b |\r\n|---|---|---|---|---|---|---|---|---|\r\n| `spt-daemon brainproc::tests::clear_before_spawn_defeats_exact_generation_stale_file` | X | X | X | X | . | . | . | . |\r\n| `spt-daemon brainproc::tests::ready_but_old_gen_never_drains_does_not_promote_rolls_back` | X | X | X | X | . | . | . | . |\r\n| `spt-daemon brainproc::tests::stale_generation_minus_one_ready_never_promotes` | X | X | . | X | . | . | . | . |\r\n| `spt-daemon brainproc::tests::trial_kills_alive_never_ready_candidate_before_rollback` | X | X | X | X | . | . | . | . |\r\n| `spt-daemon broker::tests::windows_session_is_zombie_sees_a_handle_held_corpse_as_dead` | X | . | . | X | . | . | . | . |\r\n| `spt-daemon livehost::tests::legacy_psyche_sweep_guard_is_id_specific_and_fail_safe` | . | . | . | . | X | X | X | . |\r\n| `spt-daemon shellhost::tests::kill_shell_at_still_kills_a_matching_pair` | . | . | . | X | . | . | . | . |\r\n| `spt-daemon shellwake::tests::kill_waker_at_still_kills_a_matching_pair` | . | X | X | X | . | . | . | . |\r\n| `spt-live digest::tests::extractor_timeout_errors` | X | X | . | X | . | . | . | . |\r\n| `spt-live history::tests::fetcher_timeout_errors` | X | X | . | . | . | . | . | . |\r\n| `spt-runtime runtime::tests::bounded_run_kills_on_timeout` | X | X | X | X | . | . | . | . |\r\n| `spt-store proc::tests::process_cmdline_reads_a_live_arg_marker` | . | . | . | . | X | X | X | X |\r\n| **leaky count** | 8 | 8 | 5 | 9 | 2 | 2 | 2 | 1 |\r\n\r\nUnion = 12 cells across 4 shas x 2 OSes. Present at EVERY Windows sha: 4. Present at every Linux sha: 1.\r\n\r\n#### Three readings, in increasing order of what they support\r\n\r\n**1. The churn is total and it is the whole point.** Windows counts run 8, 8, 5, 9 — the HIGHEST\r\nvalue is at `f3c8495b`, the tip carrying every fix F1-F16. Only **4 of 12** cells are present at\r\nevery Windows sha; only **1 of 2** at every Linux sha. Read as a quality signal the series says W2\r\nmade leaking worse, which is exactly as wrong as my retracted \"8 -> 5, favourable\" read and wrong\r\nfor the same reason. **A leaky count is not a signal in either direction.**\r\n\r\n**2. NEW, and I had not said it before building this table: the two OS sets are DISJOINT.** Ten\r\ncells leak only on Windows, two only on Linux, and **not one cell leaks on both**. Windows carries\r\n8-9 leaky cells per run against Linux's 1-2. So this is not one flaky population sampled twice —\r\nit is two populations with no overlap, and the Windows one is roughly five times larger. Any\r\nexplanation that treats \"leaky tests\" as a single phenomenon has to account for a clean partition\r\nby OS.\r\n\r\n**This is an OPEN QUESTION and the draft does not answer it. I do not have that explanation yet.**\r\nRecorded deliberately without a candidate cause: the partition is a measurement, and the temptation\r\nto pair a striking measurement with a plausible story is how the \"8 -> 5 is favourable\" reading got\r\ninto the record in the first place. Whoever takes this should arrive at a cause by reading, not by\r\ninheriting one from me.\r\n\r\n**SCOPED CAUSE, IN SOURCE, FOR ONE FAMILY ONLY (doyle ruled 10:22Z: source beats story; a source\r\ncause covering one family is a measurement and is filed as one).** The brainproc family leaks on\r\nWindows and not Linux because *its own fixture is asymmetric*: `long_child()` (brainproc.rs:1359)\r\nspawns `Command::new(\"cmd\").args([\"/C\",\"ping\",\"-n\",\"30\",\"127.0.0.1\"])` on Windows but\r\n`Command::new(\"sleep\").arg(\"30\")` on Unix — a shell wrapper on one box, a bare process on the other.\r\nThe Windows candidate the supervisor kills is `cmd`; the process burning 29 seconds is its child.\r\nThat is two lines of source, not an inference from the symptom. **And it is NOT the whole partition:**\r\n`process_cmdline_reads_a_live_arg_marker` uses a shell on BOTH arms (`sh -c \"sleep 30; : marker\"` /\r\n`cmd /C \"ping … & rem marker\"`) yet leaks on **Linux only** — the shell mechanism predicts it should\r\nleak on both boxes and it does not. So one family has a cause I can point at in the source, the\r\npartition as a whole remains OPEN, and the counterexample stands in this paragraph rather than a\r\nfootnote so no one carries the cause further than it goes.\r\n\r\n**THE PRODUCT PATH HAS NO INTERMEDIARY; THE FIXTURE DOES.** I chased the obvious escalation — if the\r\nreal supervisor also killed a shell wrapper, then \"never two live brains\"\r\n(REQ-HAZARD-BROKER-PROCESS-ISOLATION, the invariant this very cell guards) could be violated on\r\nWindows in production while the test stayed green. It cannot: `spawn_brain_child` (brainproc.rs:1224)\r\ndoes `Command::new(exe)` — the brain is spawned DIRECTLY, no shell, no grandchild, so a single-pid\r\nkill reaches it. **This is a test-fixture artifact, not a product defect**, and the fixture's shell\r\nis a Windows-only convenience for \"a process that blocks ~30s\" that introduced a layer the real path\r\ndoes not have. The negative is the useful half: it keeps the crashloop invariant out of IR-81 (a).\r\n\r\n**Why the cell passed review for as long as it did.** It asserts `pid != 0 && !pid_alive(pid)` before\r\nrollback, and that assertion is TRUE — `cmd` really is dead. The process still doing work is the one\r\nit never looks at. The leak and the green are not in tension; they are the same fact from two ends.\r\n**An assertion over a pid cannot see a tree.**\r\n\r\n**3. The invariant holds at 12 of 12, and it survived the population being shuffled three times.**\r\nEvery union member spawns a child process and then kills it, lets it time out, or inspects its\r\ncorpse — `trial_kills_alive`, `kill_shell_at`, `kill_waker_at`, `bounded_run_kills_on_timeout`,\r\n`extractor_timeout_errors`, `fetcher_timeout_errors`, `windows_session_is_zombie_..._corpse_as_dead`,\r\n`legacy_psyche_sweep_guard_...`, `process_cmdline_reads_a_live_arg_marker`, and the three brainproc\r\nspawn/promote/rollback cells. Membership churns freely across four shas and two OSes; the KIND of\r\ncell has not varied once. **This is the IR-80 headline** and it is better supported now than when it\r\nrested on a stable-looking five-cell cluster, precisely because the population underneath it has\r\nbeen reshuffled and the invariant did not move.\r\n\r\n#### A MECHANISM, read out of the source of the two Linux cells — calibrated, not generalized\r\n`process_cmdline_reads_a_live_arg_marker` spawns **`sh -c \"sleep 30; : marker\"`**, and the test's\r\nown comment says the trailing `; :` is deliberate — it keeps the shell RESIDENT so its\r\n`/proc/<pid>/cmdline` still carries the marker instead of being tail-exec-replaced by `sleep`. The\r\nteardown is `child.kill()` then `child.wait()`. **But `child` is the SHELL, and `sleep 30` is the\r\nshell's own child.** Killing the shell orphans the sleeper, which outlives the test by up to 30\r\nseconds — which is precisely what nextest reports as a LEAK. The Windows arm has the same shape:\r\n`cmd /C \"ping -n 30 127.0.0.1 >NUL & rem marker\"`, where `cmd` forks `ping`.\r\nSo the very construct that makes the test work (a resident shell, so the cmdline stays readable) is\r\nwhat guarantees a grandchild that a single-pid kill cannot reach.\r\n\r\n**What is verified and what is not, stated separately because the difference decides who owns this.**\r\nVERIFIED by reading source: this shape in BOTH Linux-only cells. CONSISTENT but not proven: the\r\nWindows family kills the same way — `kill_waker_at_still_kills_a_matching_pair` tears down with\r\n`kill_shell_pid(ours.id())`, a single-pid kill — so the mechanism is available to it, but I have not\r\nread every spawn helper. UNVERIFIED: the brainproc, broker and spt-live cells; those spawn real\r\nbrains and time out extractors, and may leak for unrelated reasons.\r\n\r\n**Why this matters beyond IR-80:** a single-pid kill that cannot reach a grandchild is exactly\r\n[[ir81]] arm (a) — identity and tree-awareness pushed into `kill_pid_tree`/`kill_pid` so no caller\r\ncan express the unreachable kill. If the mechanism above generalizes, IR-79 (rigs leaking daemons\r\non a failing assert), IR-80 (this) and IR-81 (kill scoping) are not three findings that share a\r\nseam, they are three FACES of one defect: **the codebase kills pids, and the things it needs dead\r\nare trees.** That is a claim worth testing, not asserting — and doyle's one-cell mechanism probe\r\nis still the right instrument, now with a sharper question: after the kill, is the surviving\r\nprocess the CHILD or the GRANDCHILD?\r\n\r\n---\r\n\r\n#### AMENDMENT 1 — \"a pid is not a tree\" has THREE faces, and only one of them is a kill\r\n\r\n*(hertz 2026-09-07, ruled by doyle 11:17Z: write this as an IR-80 amendment naming the three faces\r\nrather than three separate entries, so a reader hunting any one face lands on all three.)*\r\n\r\nThe register sentence this lane has been running on is doyle's: **a pid is not an identity and a pid\r\nis not a tree.** IR-80 and IR-81 were both filed against the KILL side, which made the sentence read\r\nlike a rule about killing. It is not. It is a rule about **which process you are talking about**, and\r\nkilling is only the face we happened to find first. Three faces are now measured, each found by a\r\ndifferent agent working a different problem:\r\n\r\n| face | the operation | what going one level too high produces | measured |\r\n|---|---|---|---|\r\n| **KILL** | `kill_pid(pid)` on a wrapper | the wrapper dies, the grandchild keeps working — the leak | IR-80's 12-cell union; `proc.rs:430`'s own doc states it |\r\n| **IDENTITY** | `kill_pid_tree(remembered_pid)` with no image read | you kill *a* process with that number, not the one you meant | IR-81 / #285, `broker.rs:8102` vs `servicehost.rs:651` |\r\n| **ENV READ** | `psutil.Process(child.pid).environ()` | the wrapper's env certifies a launch the battery would have failed | hertz 2026-09-07, self-test of `.github/bench/launch-battery.py` |\r\n\r\n**The third face, in full, because it is the newest and the least intuitive.** Reading back the\r\nenvironment of the process you spawned is the standard remedy for \"did my scrub/export actually\r\nland\" — it is what this project's own memory banked after the W0 perch-identity leak. It is\r\ninsufficient, and it fails in the flattering direction. A wrapper (`env VAR=x`, `cargo`, `nextest`,\r\n`bash -lc`) modifies the environment it hands the process **below** it, while its own `environ()`\r\nstill shows exactly what you passed in. So the read-back agrees with your intent, prints PROVEN, and\r\nsays nothing whatsoever about the process under test. Measured: the first version of\r\n`launch-battery.py` passed BOTH deliberately-negative tests. The corrected version walks descendants\r\nand, in the refusal, prints the wrapper as CLEAN beside the grandchild as VIOLATOR — that contrast\r\nis the face made visible in one line of output.\r\n\r\n**Why this belongs in IR-80 rather than in a new entry.** All three are the same error committed at\r\nthe same seam: an operation is aimed at a pid when the thing it needs to reach is a tree (or a\r\nspecific member of one). The remedies rhyme — walk the tree, read the identity, report the scope you\r\nactually covered — and a reader who finds any one face is one paragraph away from the other two.\r\nFiling them separately would have hidden that, which is the concrete cost doyle's ruling avoids.\r\n\r\n**What this amendment does NOT claim.** It does not widen IR-80's population: the 12-cell union\r\ntable and its Windows/Linux partition are unchanged, and the env face is not a test leak. It does\r\nnot add a remedy owner — the ENV face's fix is a tool (`.github/bench/launch-battery.py`), not product code, and the KILL and\r\nIDENTITY faces keep the owners they already have (#285 / todlando post-W2). It is a naming, and its\r\nwhole value is that the next instance of this error gets recognized as an instance instead of being\r\nfiled fresh.\r\n\r\n**Standing prediction, so this is falsifiable rather than tidy:** a fourth face exists wherever the\r\ncodebase asks a question *of* a pid that is really a question *about* a tree. The candidates I would\r\nlook at first are (a) liveness — `process_exists(pid)` answering \"is the work still running\" when\r\nthe work is a grandchild, and (b) resource attribution — reading a pid's handles/memory to decide\r\nwhether a lane is finished. Neither is measured; both are named so that finding one counts as\r\nconfirmation and finding none over the next few incidents counts against the generalization.\r\n\r\n### IR-81 — a process kill can be written scoped or machine-wide, and nothing makes the scoped form the only reachable one: both codebases carry the right pattern beside the wrong one\r\n\r\n- **Status:** OPEN, drafted by hertz 2026-09-07 08:38Z on doyle's dispatch (08:36Z), from the\r\n  fleet-daemon death on hfenduleam at 08:03:15Z ([[RCA-FLEET-DAEMON-14444]], cause still UNNAMED).\r\n  Census body: `docs/PID-KILL-CENSUS.md`. · **Origin:** doyle asked which sites kill a REMEMBERED\r\n  pid without re-verifying identity AT KILL TIME. The census answered that, and then answered a\r\n  better question nobody asked: **why the unguarded sites exist at all when the guarded ones sit\r\n  feet away.**\r\n- **⚠ THIS ENTRY IS NOT \"FIX THESE TWO SITES.\"** Both individual fixes are small and are dispatched\r\n  elsewhere (broker.rs:8102 → todlando's lane post-W2; live-relay-int.sh:78 → filed to perri). This\r\n  entry is about the thing that PRODUCED them and will produce the next one: the scoped form and the\r\n  machine-wide form are equally easy to write, equally plausible on review, and only one of them is\r\n  correct on a shared box.\r\n- **THE PAIRED EXHIBITS — same repo, same hand, feet apart.**\r\n\r\n  | | correct, and it says why | incorrect |\r\n  |---|---|---|\r\n  | **spt-core** | `spt-daemon/src/servicehost.rs:651` — `provably_gone` first, then `exe_path(pid)` compared to the parked image via `same_image`, then a FRESH post-kill read. Its comment IS the rule: *\"The pid is live. WHO is it? The image path decides — never the number.\"* | `spt-daemon/src/broker.rs:8102` — kills `spid`, a pid REMEMBERED off the session record, through `kill_pid_tree`. `zombie_verdict` consults liveness BY NUMBER (`process_exists`/`is_process_alive`), `adapter_labeled` (a property of the RECORD, not the live process), descendants and grace. **The live process's image is never read.** |\r\n  | **spt-claude-code** | `ci/launcher/bind-int.sh:50` — `wmic process where \"name='claude-spt.exe' and commandline like '%$ID%'\"`, scoped to this run's unique id, comment *\"never wall-a's\"*. Also `multi-subnet-bringup-int.sh:117` ($C3_ID) and `wake-survival-int.sh:64` (`-match '$PROBE'`). | `ci/psyche/live-relay-int.sh:78` — `for p in $(tasklist \\| grep -i claude-spt \\| awk '{print $2}'); do taskkill //PID \"$p\" //T //F; done` — **every** `claude-spt.exe` on the box, tree-force, no run-scoping. Comment: *\"by marker pid then name.\"* |\r\n\r\n  **The knowledge is not missing in either codebase. It is present, written down, and adjacent.**\r\n  Three correct sites to one wrong one in the adapter; a rule-stating comment in core. What is\r\n  missing is any mechanism that makes the wrong spelling hard to reach.\r\n- **Why \"just fix the sites\" is the wrong remedy:** it has already been tried implicitly — someone\r\n  wrote the scoped form three times, which is what a team looks like when it knows the rule and\r\n  still ships the exception. A fourth correct site does not prevent a fifth incorrect one. The\r\n  remedy has to change what is REACHABLE, not what is written.\r\n- **REMEDY — RULED 2026-09-07 08:40Z (doyle): (a) AND (b), not a choice between them. Two owners,\r\n  two lanes, and they cover different halves of the hazard.**\r\n  1. **(a) PRODUCT — push the identity requirement into the primitive.** `spt_store::proc::kill_pid_tree`\r\n     / `kill_pid` take an expected identity (image path, or a `same_image` closure) and refuse\r\n     without it, so a caller **cannot express** the unguarded kill; `servicehost.rs:651` stops being\r\n     the exception among callers and becomes the shape of all of them. **Owner: todlando, post-W2.**\r\n     ⇄ **This IS the fix shape of the `broker.rs:8102` board BUGFIX — that item and this entry\r\n     cross-reference each other; neither is complete alone.** Reaches Rust callers only.\r\n  2. **(b) GATE — `xtask check` refuses the unscoped spelling in CI scripts.** A `tasklist` /\r\n     `Get-Process` enumeration piped into a kill, or a bare `taskkill` with no\r\n     `commandline like` / `-match` scope in the same block, is a build failure. **Owner: hertz,\r\n     rides the IR-37 thin PR after W2 lands.** This is the half remedy (a) can NEVER reach — the\r\n     unguarded adapter site is a shell script, and no Rust signature constrains a shell script.\r\n  3. **(c) Fix the two sites and stop.** Recorded as CONSIDERED AND LOSING, not omitted: it has\r\n     already been tried implicitly — the adapter's author wrote the scoped form three times and\r\n     shipped the exception anyway — so a fourth correct site does not prevent a fifth wrong one.\r\n     It leaves the next instance free to appear.\r\n  **The (a)/(b) split is the entry's real content:** the hazard lives in two languages, and a remedy\r\n  in one of them is a half-measure that will read as a fix.\r\n- **STANDING LIMIT, so this entry is not overread as an incident cause:** none of these sites\r\n  explains the 08:03:15Z death. broker.rs:8102 would have been saved from firing by\r\n  `has_live_descendants` (the daemon had a live brain) — accidental protection, not deliberate —\r\n  and every claude-spt site enumerates `claude-spt.exe` while the dead process was `spt.exe`. The\r\n  census found a real hazard while looking for a different one. **Do not let this entry close the\r\n  incident.** The instrument at `C:\\Users\\decid\\.spt-watch\\daemon-watch.log` is what will answer\r\n  that, or fail to.\r\n- **Kin:** [[IR-79]] and [[IR-80]] (children outliving their cell; the leak family), the\r\n  [[RCA-FLEET-DAEMON-14444]] timeline, `servicehost.rs`'s own \"image path decides\" comment as the\r\n  in-tree statement of the rule, and the paired-exhibit method itself — a correct and an incorrect\r\n  site in one repo is stronger evidence about PROCESS than either site is about code.\r\n- **Ripe when:** the next touch of `spt-store/src/proc.rs` (for remedy 1) or of `xtask check`'s\r\n  gate family (for remedy 2). The adapter half is perri's, filed separately, and does not wait\r\n  on this.\r\n- **Size:** small for remedy 2, medium for remedy 1 (signature + every caller). The census that\r\n  justifies either is already written and does not need redoing.\r\n\r\n---\r\n\r\n#### ADAPTER-SIDE ARM: CLOSED (claude-spt, perri, 2026-09-07)\r\n\r\n**Status: closed in the consumer repo, test-only, does not close IR-81 here.**\r\n\r\n- **Commit `9c87372`** (spt-claude-code). Broad `tasklist | grep claude-spt | taskkill` replaced\r\n  with an **id-scoped wmic** call, **name-pinned so wmic cannot self-match**; the three\r\n  remembered-pid kills additionally got a **kill-time recheck**, covering the stale-identity face\r\n  as well as the unscoped-pattern face.\r\n- **Guard: `tests/ci-kill-scoping.sh`, traced as `REQ-HAZARD-CI-KILL-SCOPING`.** Gate green.\r\n  This is the check-shape arm (b) proposes for spt-core, already landed once — precedent, not\r\n  merely agreement.\r\n- **Scope: test/CI infrastructure only.** No product code changed. (doyle, 08:50Z.)\r\n- **`live-relay-int.sh:78` is retained as the historical RED exhibit** — the one genuinely\r\n  machine-wide kill found in the whole fleet census. It is the reason this hazard is written as a\r\n  hazard rather than a style note; do not quietly replace the exhibit with the fixed line.\r\n\r\n**Population lesson carried into arm (b)'s census.** I filed ONE site; perri confirmed **four**, and\r\nreports the idiom was already present in that repo **3x** before the filing. A filing that names one\r\nline under-counts its class by 3-4x in a single repo. **Census the ACT — any taskkill / pkill /\r\nwmic-delete reachable from a script root — never the literal string that led me to the first site.**\r\nState the walked roots in the check's own message, and give the gate a negative control that goes\r\nRED on a known-bad line before its green is trusted.\r\n\r\n**Still open here, unchanged:** arm (a), Rust-side identity pushed into `kill_pid_tree` / `kill_pid`\r\nso no Rust caller can express the unguarded kill (todlando, post-W2, cross-referenced with the\r\nbroker.rs:8102 board BUGFIX); and arm (b), the xtask script gate (mine, rides IR-37).\r\n\r\n---\r\n\r\n#### SCOPING ARM (a) — the product path has no intermediary; the fixture does\r\n*(hertz 2026-09-07, ruled by doyle 10:22Z off the IR-80 leak work.)*\r\n\r\n> **A pid is not an identity and a pid is not a tree. IR-80 needs CALLERS, not code.**\r\n> *(The register's sentence — doyle 10:23Z. Arm (a) fixes the identity half in\r\n> `kill_pid`/`kill_pid_tree`; the tree half needs no new machinery, because `kill_pid_tree` already\r\n> exists at proc.rs:430 with the defect stated in its own doc. This is why IR-79, IR-80 and IR-81\r\n> converge on one seam without collapsing into one finding.)*\r\n\r\nMeasured, not inferred: **`spawn_brain_child` (crates/spt-daemon/src/brainproc.rs:1224) does\r\n`Command::new(exe)`** — the real brain is spawned DIRECTLY, with no shell and no launcher between\r\nthe daemon and the process it supervises. So on the crashloop/rollback path a single-pid kill\r\n*does* reach the thing it aims at, and the \"orphaned grandchild\" mechanism found in the IR-80 leak\r\ncells is **a property of the TEST FIXTURE**, whose `long_child()` (brainproc.rs:1359) goes through\r\n`cmd /C` on Windows, not of the product.\r\n\r\n**What that scopes.** Arm (a) is NOT about the brain-supervision path and must not be sold as\r\nprotecting `REQ-HAZARD-BROKER-PROCESS-ISOLATION` (\"never two live brains\") — that invariant is not\r\nat risk here, and claiming it would be borrowing urgency this arm has not earned. Arm (a) stays\r\npointed at **the broker.rs:8102 reap, where the image is never read** — a kill aimed by pid alone\r\nat a process whose identity was never verified. That is the real unguarded form, and it is a\r\ndifferent failure (kill the wrong process) from the one IR-80 surfaced (fail to kill the right\r\none).\r\n\r\n**The two failures are different, which is why the drafts converge without collapsing.** Arm (a) is\r\n*kill the wrong process* (identity never read); IR-80 is *fail to kill the right one* (tree never\r\nwalked). The identity half is todlando's, post-W2. The tree half is already solved in-tree —\r\n`kill_pid_tree` at proc.rs:430, whose doc states the defect outright (\"a single-pid `kill_pid` leaves\r\nthe wrapper's harness children orphaned + running\") — so IR-80 ships callers, not machinery. See\r\n[[RIDER 4]] for the two test-side callers.\r\n\r\n### IR-82 — a daemon death leaves NO record of who died: autostart decides on a socket ping, says \"no daemon\", and the successor overwrites the only handle on the corpse\r\n\r\n- **Status:** RULED 2026-09-07 11:07Z (doyle), drafted by hertz 11:04Z on doyle's dispatch (11:03Z: *\"the autostart\r\n…\n  OBSERVABILITY, not in the death.\n…\n","startLine":4044,"lineNumbers":[4044,null,4046,null,4122,null,4124,4125,4126,4127,4128,4129,4130,4131,4132,4133,4134,4135,4136,4137,4138,4139,4140,4141,4142,4143,4144,4145,4146,4147,4148,4149,4150,4151,4152,4153,4154,4155,4156,4157,4158,4159,4160,4161,4162,4163,4164,4165,4166,4167,4168,4169,4170,4171,4172,4173,4174,4175,4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187,4188,4189,4190,4191,4192,4193,4194,4195,4196,4197,4198,4199,4200,4201,4202,4203,4204,4205,4206,4207,4208,4209,4210,4211,4212,4213,4214,4215,4216,4217,4218,4219,4220,4221,4222,4223,4224,4225,4226,4227,4228,4229,4230,4231,4232,4233,4234,4235,4236,4237,4238,4239,4240,4241,4242,4243,4244,4245,4246,4247,4248,4249,4250,4251,4252,4253,4254,4255,4256,4257,4258,4259,4260,4261,4262,4263,4264,4265,4266,4267,4268,4269,4270,4271,4272,4273,4274,4275,4276,4277,4278,4279,4280,4281,4282,4283,4284,4285,4286,4287,4288,4289,4290,4291,4292,4293,4294,4295,4296,4297,4298,4299,4300,4301,4302,4303,4304,4305,4306,4307,4308,4309,4310,4311,4312,4313,4314,4315,4316,4317,4318,4319,4320,4321,4322,4323,4324,4325,4326,4327,4328,4329,4330,4331,4332,4333,4334,4335,4336,4337,4338,4339,4340,4341,4342,4343,4344,4345,4346,4347,4348,4349,4350,4351,4352,4353,4354,4355,4356,4357,4358,4359,4360,4361,4362,4363,4364,4365,4366,4367,4368,4369,4370,4371,4372,4373,4374,4375,4376,4377,4378,4379,4380,4381,4382,4383,4384,4385,4386,4387,4388,4389,4390,4391,4392,4393,4394,4395,4396,4397,4398,4399,4400,4401,4402,4403,4404,4405,4406,4407,4408,4409,4410,4411,4412,4413,4414,4415,4416,4417,4418,4419,4420,4421,4422,4423,4424,4425,4426,4427,4428,4429,4430,4431,4432,4433,4434,4435,4436,4437,4438,4439,4440,4441,4442,4443,4444,4445,4446,4447,4448,4449,4450,4451,4452,4453,4454,4455,4456,4457,4458,4459,4460,4461,4462,4463,4464,4465,4466,4467,4468,4469,4470,4471,4472,4473,4474,4475,4476,4477,4478,4479,4480,4481,4482,4483,4484,4485,4486,4487,4488,4489,4490,4491,4492,4493,4494,4495,4496,4497,4498,4499,4500,4501,4502,4503,4504,4505,4506,4507,4508,4509,4510,4511,4512,4513,4514,4515,4516,4517,4518,4519,4520,4521,4522,4523,4524,4525,4526,4527,4528,4529,4530,4531,4532,4533,4534,null,4539,null,4637]},"fileSize":512411,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\INFRA-REGISTER.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":5900,"totalBytes":32629,"outputLines":411,"outputBytes":32629,"shownRange":{"start":4124,"end":4534},"nextOffset":4535}}},"isError":false,"timestamp":1789107053425}}
{"type":"message","id":"6ed3e6ac","parentId":"7043a550","timestamp":"2026-09-11T06:10:53.429Z","message":{"role":"toolResult","toolCallId":"call_uL8BDte8MN9R7CWkRrplZGG3|fc_0330c101aa2c61dc016aa39b6afaac87d183265cb9b8470897","toolName":"read","content":[{"type":"text","text":"### IR-68 — PSYCHE_INGEST_FAIL cause class unproven: git index.lock did NOT reproduce the ingest failure it was blamed for\n…\n- **Status:** OPEN, investigation-shaped · **Origin:** todlando measurement at the W2 int-leg rig\n…\n- **NOT claimed:** that the field incident was misattributed to ingest failure generally — the\n  files did survive with failed-ingest log lines; what is unproven is the index.lock CAUSE.\n- **Ripe when:** next PSYCHE_INGEST_FAIL sighting in the field (capture the failing store state\n  before touching it), or a dedicated probe slot. W2's COMMUNE_FAIL event now pushes a NAMED\n  reason on every failure, so the next occurrence self-reports its cause — read that first.\n  **Size:** investigation; no product change until the mechanism is pinned.\n\n### IR-69 — inherited stderr tokens can tear between format fragments; 26 test consumers parse that surface as structured truth\n\n- **Status:** OPEN for the #243 residual population and anchored-consumer work. The original\n  product remedy LANDED at `ec6da9b0`, as recorded in this entry's later amendment; it is not\n  still parked awaiting assembly. Releases#241 retains its original lane evidence in comment\n  5461613480. This entry is the exposure map and census discipline; residual conversion,\n  generator repair and a SHA-pinned zero recensus remain owed. · **Origin:** CONDUIT #236 r3\n  golden attempt 2,\n  2026-08-29: `endpoint_autostart_e2e` missed its contiguous\n  `ENDPOINT_AUTOSTART:gwauto` keystone although the matching fresh session id proved the replay\n  happened. Attempt 3 was clean on the same discarded SHA after 139 GB was reaped; unequal load\n  makes the pair corroborating, never a rate.\n- **Mechanism, recovered from the literal torn bytes:** two daemon processes inherited one stderr\n  pipe. `BRAIN_UP` and `ENDPOINT_AUTOSTART` are each one `eprintln!`, but `write_fmt` may reach the\n  handle once per format fragment; the per-process stderr lock cannot serialize the other process.\n  The observed interleave split the autostart token between `ENDPOINT_AUTOSTART:` and `gwauto`.\n  This is fragment-level cross-process interleaving, not a failed replay and not a two-thread race.\n- **Durable remedy, ruled product-side:** render a complete diagnostic line into one buffer and\n  issue the complete rendered text, newline included, as **ONE handle call**. An OS short-write\n  may retry the late tail so completeness wins over a silently truncated line; the deterministic\n  property pins application-side fragmentation, not syscall count under that rare retry. It makes\n  no claim that the OS write is atomic on Windows, and no CI re-fire against a 1-of-2 observation\n  may stand in for it. Widening one test's grep is refused: it greens one consumer while every\n  sibling token remains exposed.\n- **Cut-SHA census** (todlando generator, independently hash-verified by hertz), measured from\n  `4d6007ac4ee3d0991f4bc60b7e1a55825aad1aaf` via `git show`, not a dirty worktree:\n  **486 real emitter sites / 383 distinct tokens / 26 consumer test files**. The generator emitted\n  487 site rows, but one is a known phantom: `sealverb.rs:456` is a `format!` inside `map_err`\n  that the four-line lookback attributed to a neighbouring real `eprintln!`. Corrected real emitters\n  by crate: spt-daemon 270, spt 194, spt-runtime 8, spt-live 5, spt-net 5, spt-store 4; by macro:\n  `eprintln!` 484, `println!` 1, `eprint!` 1. `DRIVEN_BY` is the sole stdout row and therefore\n  outside the stderr remedy. A consumer means the test both mentions `TOKEN:` and reads a\n  stderr/log surface; bare-token matching inflated the population to 72 files by admitting prose.\n  This is an **exposure map**, not a rate and not a claim that all 26 have torn.\n- **Artifacts (the preserved raw generator outputs contain 487 site rows):** cut census SHA-256:\n  sites `f10d6bfe5e0399f98945cf63bb5719a01a62e1251be84165c73030fa9bb224f5`,\n  tokens `80b0d1835d9d46376b2f200b1c50be4ca0e185a135168444414255f9308ed92b`,\n  consumers `249a2e33df43a30570ca82b5bd200d8b6e2bf07aa8250fcc8bace47fe23e3cbc`.\n  The sealed sites file's macro column is wrong on 7 of its 487 raw rows; the corrected raw split\n  is `eprintln!` 485 / `println!` 1 / `eprint!` 1. The sealed tokens file has no final newline, so\n  `wc -l` reports 382 although it contains 383 logical records. The sealed files remain unedited;\n  these corrections are textual.\n  Generator `81df82f01ef33a82307920d9804a2394b787ef2ffbe3b41d2d7dda560d9a62a9`\n  was recorded as asserting newline-terminated output, but the sealed tokens artifact refutes that\n  claim for at least one output. Its remaining guards cover logical record counts, a known-positive\n  `SUBSCRIBE_DECISION` sentinel, four-line macro lookback, and truncation only at a\n  `#[cfg(test)]` that opens a module.\n- **Census hazards paid for while constructing and reconciling the population:** the provisional\n  instrument moved `277/243 → 286 → 412 → 487 raw → 486 real` as four silent assumptions were\n  found: same-line matching misses multi-line macros; truncating at the first `#[cfg(test)]` drops\n  later shipping code; lookback must prefer the token line's own macro over a neighbouring arm;\n  and even that lookback can promote a nested token literal beneath a real macro into a phantom\n  second site. A file without a final newline also makes `wc -l` silently undercount logical\n  records by one. Every future census must name its SHA, assert a known member, count records\n  inside the generator, and reconcile emitted rows to real sites.\n- **Separate anchored-matcher finding:** `IDLE`, `DISPATCH`, `BUSY`, and `BOUND` are common words\n  matched as substrings in exposed consumers. One-write emission does not prevent an unrelated log\n  line from satisfying them; those predicates need anchored token matching. Keep this separate from\n  the tear remedy so neither defect is claimed to close the other.\n- **Kin:** [[IR-50]] (the sink must be read before its absence means anything), [[IR-40]] (a\n  confident signal that does not describe the source truth), [[IR-8]] (a plausible census whose\n  blind spot returns a clean answer).\n- **CLOSE-OUT ADDENDUM 2026-08-30 (#242/v0.66.0 sweep — the entry's own close-out re-census RAN\n  and FOUND the predicted blind spot LIVE; entry stays OPEN):** re-census at the landed sha\n  `ec6da9b0` (independent containment-classified meter, reconciled with todlando's independent\n  meter — full write-up `EMISSION-RESIDUAL-CENSUS-FINDING.md`): the generator truncated\n  `crates/spt/src/cli.rs` at its FIRST module-opening `#[cfg(test)]` (line 3007, module closes\n  3164, file runs to 39118) and never scanned the rest — **338 TOKEN-shaped shipping sites remain\n  bare (332 colon-form, i.e. misses under the sealed census's own predicate, + 6 space-form)**,\n  plus `main.rs` 2 sites behind the same mechanism; exactly TWO files tree-wide carry the\n  triggering property (first module-opening cfg(test) precedes shipping code) — the generator\n  fix's owed blind-spot measurement, answered. The census-hazards bullet above already NAMES this\n  third-face truncation hazard; the module-opening fix narrowed the trigger and kept the blind\n  spot for files where a test module CLOSES and shipping resumes — IR-8 shape, predicted by this\n  entry's own text. The shipped #241 conversions are UNAFFECTED (495 removals ≈ censused 486 +\n  space family; the SEEN population is closed; golden green stands). Residual conversion +\n  generator fix + enforcement-at-the-seam = **releases#243** (BACKLOG, operator triages);\n  delivery.rs:149/313 are post-cut MINTS relative to the census sha (todlando's own, settled\n  attribution), deliberately outside #243's census-mechanism scope — and ALREADY CONVERTED: the\n  fix rode his breadcrumb branch (`60a12056`) into the r4 head and shipped IN-TAG (todlando\n  flagged the stale \"his thin lane converts post-cut\" claim 2026-08-30; re-measured — zero bare\n  TOKEN `eprintln!` in delivery.rs at both `d931dd63` and origin/main). No lane is owed for it. Re-runnable meter\n  `EMISSION-RESIDUAL-CENSUS-METER.py` (repo root, untracked; version-control rides #243's lane).\n  **Common-word matcher RULED at this sweep (discharges the \"decide\" clause below):** the four\n  common-word consumers (`IDLE`/`DISPATCH`/`BUSY`/`BOUND` substring predicates) get a SEPARATE\n  hertz test-side rider — anchored token matching is consumer-predicate work, NOT folded into\n  #243 (keeps #243 product-scoped) and not claimed closed by one-write emission; lane-link when\n  hertz's spool drains.\n- **Closes when:** releases#243's residual conversion + generator fix land and a re-census at\n  that sha reads zero shipping residue under both delimiter forms. **Size:** product lane\n  complete elsewhere; register follow-through small.\n\n### IR-70 — a hand-built `IoBus` silently omitted later sinks while every gate stayed green\n\n- **Status:** OPEN, remedy unscheduled; the v0.65.0 respin fixed the witnessed call site on PR #173.\n  This entry owns the recurrence class, not that shipped correction. · **Origin:** releases#234,\n  commit `c5459795167`, CONDUIT #236 respin.\n- **Mechanism:** `publish_commune_io` constructed `IoBus` itself and registered only the sink it\n  knew. `default_bus` already existed as the assembly point and its module contract explicitly says\n  emitters must know only `IoBus::publish`, so adding a later sink costs one registration rather\n  than an emitter sweep. The hand-built publisher recreated exactly the drift that contract warned\n  against: `COMMUNE` and `COMMUNE_FAIL` reached the old sink but never the adapter log, leaving\n  `spt api io-events` permanently short on two documented kinds.\n- **Why the complete battery was green:** the e2e was vacuous on the broken kinds; units synthesized\n  rows without traversing `publish_commune_io`; and traceability checked attached tags, not whether\n  the tagged path exercised the real publisher. Three green instruments shared one blind seam.\n  The respin routed the site through `crate::iobus::default_bus`, and its source comment now records\n  the failure shape.\n- **Durable remedy direction (todlando mechanism, not scheduled):** enforce the assembly point so\n  the next hand-built bus is impossible rather than found — make production publishers obtain the\n  composed bus through one construction API, and gate the real publish path for every documented\n  kind. A search or comment is not enforcement; another emitter can satisfy both while rebuilding\n  a partial sink list.\n- **Kin:** [[IR-39]] (a green fixture never reached the missing dependency), [[IR-37]]\n  (traceability tags prove coverage bookkeeping, not behavioral truth), [[IR-58]] (a hand-built\n  population returns an orderly but incomplete answer).\n- **Ripe when:** the next `IoBus` construction/API touch, or a new sink registration. **Size:**\n  small-to-medium assembly-point enforcement plus a real-path population test.\n\n### IR-71 — controller-seat release has no persisted breadcrumb, so tests cannot distinguish propagation lag from a missing detach\n\n- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\n  `er_brief_once_per_session_e2e` intermittent, classified test-side and fixed on PR #174.\n- **What/why:** killing rc1 reaps the controller process, but the broker is another process and\n  notices the socket close later. On that detach edge it clears `driven_by` and `controlled` in\n  `info.json`; rc2's preflight reads that file locally and can race the write, refuse normally, and\n  exit 0 without dialing the broker. The test originally spawned rc2 immediately and had no\n  observable precondition separating “release is propagating” from “release never happened.”\n- **The missing surface:** broker lifecycle state records `session-detach was_controller=true`, but\n  there is no always-on persisted breadcrumb that states the controller stamp was cleared, names\n  the resulting `driven_by`/`controlled` state, or measures detach-to-persist latency. The repaired\n  test therefore polls `info.json` itself, prints elapsed time (0.075s on the first local real run),\n  and uses a named 60s timeout whose failure promotes the finding from timing to missing release.\n  Its deliberately latched-seat unit proves the barrier can red.\n- **Remedy direction:** add one structured release breadcrumb after the persisted clear, carrying\n  session/connection identity and the resulting control state; if latency is carried, measure it\n  from the detach edge. It must ride the persisted daemon sink and remain distinct from\n  `session-detach`, which proves the connection event but not the file write.\n- **Kin:** [[IR-50]] (the sink a test must actually read), [[IR-40]] (an event timestamp is not a\n  completion signal), REQ-HAZARD-CONTROL-STAMP-CONVERGENCE.\n- **Ripe when:** the next controller lifecycle or structured-breadcrumb touch, or a field timeout\n  from PR #174's barrier. **Size:** small emitter plus one contract-level assertion.\n\n### IR-72 — no product read verb surfaces which process holds a perch or controller seat\n\n- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\n  two-host RCA and PR #174 (`70c1a303`), corrected by doyle after IR-18 and daemon-status were\n  ruled out as different classes.\n- **Source-verified boundary:** the holder identity already exists in durable/internal records\n  (`InfoJson.pid`, `parent_pid`, and the broker's session pid), and product internals read it for\n  liveness, teardown, and self-detection. No product **read verb** returns the process that holds a\n  named perch/seat. PID-bearing teardown messages are failure outcomes, not an inspection surface;\n  daemon status is process-wide, not perch- or seat-scoped. This also does not collapse into\n  [[IR-18]], where an existing internal `read_pid` collapses absent and unreadable records.\n- **Paid-for consequence 1 — rigs manufacture custody:** PR #174's two-host repair had to add\n  `PidHolder` in `crates/spt/tests/twohost_cli.rs:401-437`, spawn a long-lived sibling process,\n  write that pid directly into each synthetic perch, retain the child handle, and kill+wait it on\n  drop. The rig can make a known holder; it cannot ask the product which holder the product sees.\n- **Paid-for consequence 2 — ambiguity stayed latent until behavior flipped:** the r3 fixture\n  seeded three perches with one test-process pid. Self-detection then enumerated a directory whose\n  first matching row was a filesystem-order coin, so a green could name the wrong perch. The\n  repaired resolver refuses an ambiguous candidate set instead of guessing, and the fixture's\n  `assert_only_ancestor_candidate` now re-reads every `info.json` rig-side\n  (`twohost_cli.rs:439-457`). Refusal is enforcement, not observability: it proves a tie but still\n  offers no supported verb that names each holding process.\n- **Remedy direction:** add one machine-readable, named-perch inspection surface that reports the\n  custody fields the product actually used — holder pid and role/source (bind relay, stable harness\n  parent, brokered controller/session) — without asking callers to parse private `info.json` or\n  scan the process table. PID alone is recyclable; where a birth/image/session stamp exists, carry\n  it so the output does not become a new bare-pid oracle.\n- **Kin:** [[IR-18]] (read primitive loses error class, explicitly distinct), [[IR-71]] (release\n  completion lacks a persisted breadcrumb), REQ-HAZARD-SELF-DETECT-TIE (refuse ambiguous ancestry\n  rather than select by enumeration order).\n- **Ripe when:** the next roster/status read-model change or another rig needs to reap a named\n  holder. **Size:** small read-model/API addition, medium if seat and perch custody need separate\n  typed variants.\n\n### IR-73 — ci.yml and release.yml still read the free-space floor PRE-checkout (literal-first sites off the golden path); and any job's floor is stale by its last heavy step\n\n- **Status:** CLOSED / BUILT — source reconciliation 2026-09-11 at `e5a2fed9`: all five\n  `ci.yml` sites and all three `release.yml` sites now read after checkout, with IR-73 comments;\n  `golden.yml` has both docs-floor rereads. IR-86 records the docs reread's live catch.\n  The original two halves below are implemented; capacity sizing and docs dependency coupling\n  remain OPEN under IR-86, not a reason to redispatch these eight reorders.\n  Filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep (deployah flag 2026-08-29).\n  · **Origin:** #242's two lost golden attempts exposed the pre-checkout read; the original\n  golden-only correction deliberately left the eight other sites for the now-built rider.\n- **What/why:** review each of the 8 sites' comments for checkout-protective purpose (the\n  `ac7d2609` method), then reorder the read after checkout or RECORD why not, per site. The\n  \"other jobs keep the literal-first shape\" clause is the trap's carrier: every un-reviewed site\n  is a queued golden-attempt loss on a loaded box.\n- **Second half (from #242 r4, same family):** a single job-start floor read is stale by the\n  job's LAST heavy step — the r4 LNK1318 low-water face recorded on [[IR-59]] (sixth face);\n  the within-job re-read before the docs-drift build rides the next workflow commit alongside\n  this entry's reorders.\n- **Kin:** [[IR-46]] (a floor asserts an instant), [[IR-59]] (full volume reds as a linker\n  defect), REQ-CI-FREE-SPACE-PREFLIGHT.\n- **Ripe when:** next touch of `ci.yml`/`release.yml`, or the next intake's tooling-rider slot\n  (compose with IR-59/IR-57's standing pair). · **Size:** small — reorder or comment per site,\n  8 sites.\n\n### IR-74 — kitsubito holds 21,643 /tmp endpoint homes: box-side accumulation nothing bounds or measures\n\n- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep; measurement by\n  hertz (2026-08-29). · **Origin:** rig work on kitsubito found `/tmp` carrying 21,643 endpoint\n  homes — per-run spt homes that outlive their runs.\n- **What/why:** sibling of the [[IR-31]]/[[IR-59]]/[[IR-64]] family (box accumulation the\n  preflights never see): each is small, the population is not, and /tmp on a long-lived box is\n  never reaped by CI. Un-reaped homes also widen every by-path census a rig runs. Needs a\n  bounded lifecycle (per-run temp root reaped at run end, or a box-side sweep with a stated\n  retention), and the reap must state its count so a zero is a claim.\n- **Ripe when:** next kitsubito rig touch, or the between-milestone box-audit slot.\n- **Size:** small (one sweep script + adoption in the box's rig steps); the measurement rerun is\n  one `find | wc`.\n\n### IR-75 — traceable-reqs is not installed on kitsubito, so every Linux gate driver's treqs leg exits 127 (vacuous, wrapper-green shape)\n\n- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep (deployah\n  co-flagged at intake). · **Origin:** ASM-241 Linux battery — `ASM_treqs.exit` = 127, raw\n  `env: 'traceable-reqs': No such file or directory`; leg vacuous, covered that day by the\n  Windows treqs = 0 at the identical tree (treqs is a platform-independent text scan).\n- **What/why:** a 127 leg is exactly the wrapper-green shape [[IR-60]] documents — a driver that\n  doesn't read the exit FILE would report the leg green. Fix is either: install traceable-reqs on\n  kitsubito (then the leg is real), or DROP the leg from Linux gate drivers and state the\n  Windows-covers-it rule in the driver comment. Do NOT reopen [[IR-37]] for this — IR-37's\n  consume lane is spt-core CI (GitHub runners, green all week); this is BOX tooling, a different\n  surface (ruled at the sweep against the enumerating agent's overcautious flag).\n- **Ripe when:** next Linux gate-driver touch or kitsubito box-audit slot.\n- **Size:** trivial (install or one driver edit + comment).\n\n### IR-76 — hfenduleam is the golden Windows runner AND the builders' box: a local workspace nextest fully contained a golden Phase A and manufactured a load-timing red, and the job-start census cannot see it\n\n- **Status:** OPEN, filed by doyle 2026-09-06 during v0.67.1 golden triage (run 34017906638\n  att2). · **Origin:** the Windows Phase A red on\n  `spt-store::wtlock_two_process_int two_processes_commit_into_one_worktree_without_failing`\n  (B hit the 10 s worktree-lock bound while A's six serial commits took 13.5 s; 12 other\n  cells ran >10 s in the same phase). Load audit by todlando from his own `.raw`\n  CreationTimeUtc / `.exit` LastWriteTimeUtc: his #276 gate's 1240-cell workspace nextest\n  (`--no-fail-fast`, test phase 08:50:06–08:58:00Z) FULLY CONTAINED the golden Phase A\n  (08:52:38–08:56:49Z), every core saturated. He had been dispatched into that window and\n  never told the box was under a golden hold; perri and hertz had been.\n- **What/why:** two mechanisms, both unmeasured by anything in CI today. (1) The box is\n  shared by design — every agent's gate rig, adapter build and workspace nextest runs on the\n  same host as the self-hosted golden Windows runner, so a golden Windows leg is a QUIET\n  WINDOW only if every agent knows it is open; nothing says so, and a dispatch brief that\n  starts a gate is exactly how a builder lands inside it. (2) The job-start\n  `reap-census.ps1` counts the SPT FAMILY only (`family_total=12 scoped=0 unscoped=12` at\n  att2's 08:39:46Z start, with a builder's prebuild live on the box); cargo/nextest/rustc\n  load is outside its predicate, so the one instrument that runs at the right moment is\n  blind to the load that matters. Every load-timing red on Windows therefore triages as a\n  random victim with the cause off the record — the [[IR-63]] \"one random victim per sweep\"\n  face, now with a named source.\n- **Fix shape:** (a) driver templates (every gate/battery driver an agent authors here)\n  gain a PRE-FLIGHT leg with THREE outcomes, never two (todlando's amendment at filing: an\n  empty `gh run list` is the same bytes for CLEAR and for a broken meter — wrong filter,\n  expired token, rate limit, wrong repo default all return exit 0 and no rows — so a\n  two-arm guard fails OPEN into the exact hazard it guards, the `--commit <short-sha>`\n  confident-EMPTY class): run `gh run list --workflow golden --status in_progress`; rows\n  present -> HOLD, print the run id; no rows AND a positive control (`gh run list -L 1`\n  unfiltered, or `gh auth status`) returns a row -> CLEAR; control empty or erroring ->\n  REFUSE and say the meter is broken. A refusal, not a warning, so a wrapper-green shape\n  cannot swallow it ([[IR-60]]); the dispatch-brief line in (b) is likewise a MEASURED\n  clear with a live meter, never the absence of a sentence; (b) dispatch briefs that start a gate NAME the hold state of the box; (c)\n  the job-start census gains a second predicate — cargo/nextest/rustc/link processes by\n  image name, count + total CPU — reported beside the family count so a red's triage can\n  place foreign load from the log alone; (d) the golden hand-off contract\n  (docs/golden-head-intake) states the quiet-window rule once.\n- **Kin:** [[IR-63]] (random victim per sweep), [[IR-59]] (box conditions the preflights\n  never see), [[IR-64]] (hfenduleam's non-CI payload), FLAKE-LEDGER rows for\n  `wtlock_two_process_int` and `attach_link_push_e2e` (2026-09-06).\n- **Ripe when:** next driver-template touch (a/b are text; a is one leg), next `ci.yml`\n  touch for (c) — compose with [[IR-73]]'s reorders; (d) rides the next runbook edit.\n- **Size:** small — one pre-flight leg + one census predicate + two doc sentences.\n\n### IR-77 — nothing stamps the interval between a daemon child's spawn and the brain's first log line, so a readiness-deadline red cannot say WHERE the time went\n\n- **Status:** OPEN, filed by hertz 2026-09-07 from the W1 #249 kitsubito battery at the gated\n  sha `8d980fdf`; doyle-ruled at filing to be a register entry rather than a lane rider. ·\n  **Origin:** FLAKE-LEDGER `resident_service_e2e` :453 PRECONDITION (53 s) and\n  `resume_no_control_steal_e2e` (46 s), co-victims of ONE window — nextest exit 100, ONE\n  Summary `2999 tests run: 2997 passed (8 slow, 1 leaky), 2 failed, 1 skipped`. Evidence\n  preserved at `.spt/preserved/w1-kitsubito-8d980fdf/nextest.raw`, sha256\n  `9c456e21a6a0f75d8b0375ac648f232dba07f3887ec5e8dc232daef36253b51e`, hash-verified against\n  the kitsubito original.\n- **What/why:** both reds are a 45 s wait on `brain.ready` that expired, and the panel each\n  one prints shows the tree ALIVE — `BRAIN_UP`, `BRAIN_PHASE:announce done in 1ms`,\n  `BRAIN_PHASE:resume done in 0ms`, `SERVICE_STARTED` for both services, both later reaped\n  with an empty survivor set. So the daemon came up; it came up after the clock. WHERE those\n  45 s went is not recoverable from any artifact we keep: the first timestamped line in the\n  daemon's own sink is emitted by a process that has already started, and nothing stamps the\n  interval from the test's `Command::spawn` to it. The consequence is that every red of this\n  family is triaged by inference — v0.66.0 measured a ~10.1 s exe-hash on the ready path, and\n  that number is a CANDIDATE for the gap and can never be more than a candidate while the\n  interval is unmeasured. Remedy: one monotonic breadcrumb at daemon-child entry (before any\n  work), a second at the point `brain.ready` is stamped, both into the stderr sink the panel\n  already renders — then a red of this family reports its own split without a rerun.\n- **Kin:** [[IR-71]] (a seat release with no breadcrumb, same shape one layer over),\n  FLAKE-LEDGER `resident_service_e2e` :453 and `resume_no_control_steal_e2e` (2026-09-07),\n  and the HEAVY census stanza in `.config/nextest.toml`, which hardens the RECIPE these reds\n  came from and deliberately leaves the deadlines alone — a budget retune is the same race\n  with a different number, and it would also destroy the only signal this entry wants.\n- **Ripe when:** the next touch of the daemon boot path or of `brainproc`'s ready stamp; also\n  ripe as a rider on any lane that re-opens this test family.\n- **Size:** small — two `emit_line_err!` breadcrumbs and the sentence in the panel that says\n  what they mean.\n\n### IR-78 — `SPT_TEST_EPHEMERAL_ADVISORY_PORTS` silently overrides an explicitly set `SPT_DOCS_PORT`\n\n- **Status:** OPEN, filed by hertz 2026-09-07, MEASURED by doyle the same night on his W2\n  field pair (both boxes). · **Origin:** the 5474 rig-hygiene sweep in\n  `test/rig-advisory-ports-and-heavy-class`, which sets the rig flag at 37 `spt daemon run`\n  spawn sites.\n- **What/why:** `resolve_daemon_docs_port` (crates/spt-daemon/src/docshost.rs) returns `0`\n  whenever the rig flag is set, BEFORE the `SPT_DOCS_PORT` env override is consulted. With\n  both set, doyle's rig daemons took ephemeral ports (`DOCS_SERVER_UP` on 55369 Windows,\n  44015 Linux) while `SPT_DOCS_PORT=5480` was ignored without a word. The precedence itself is\n  defensible — the rig flag exists precisely so a test tree cannot take a well-known port —\n  but a SET override discarded in SILENCE is the shape IR-37 files under a different name: the\n  operator is left believing the value they set is the value in force. Remedy is a line, not a\n  redesign: emit one notice naming both env vars when the flag wins. No test cell is proposed\n  with it — none of the 31 swept binaries asserts on a docs port, so a cell here would assert\n  a behaviour nothing consumes.\n- **Kin:** [[IR-37]] (a set input silently ignored), the 5474 hygiene sweep, and the\n  `DOCS_SERVER_BIND_FAIL: port 5474: Address already in use (os error 98)` lines in\n  `.spt/preserved/w1-kitsubito-8d980fdf/nextest.raw` that started the sweep.\n- **NOT measured, stated so nobody reads it as covered:** doyle measured that the WMI\n  auto-start rung DOES carry the caller's environment (rig daemon pid 50088 on hfenduleam:\n  `DAEMON_LAUNCH_VIA_WMI`, its environ carrying `SPT_HOME`, `SPT_DOCS_PORT` and the rig flag\n  as his shell set them, `brain.ready` in the rig home). The schtasks (at-logon) rung was NOT\n  measured, and neither was the unix path.\n- **Ripe when:** the next `docshost.rs` touch, or the first time someone sets `SPT_DOCS_PORT`\n  on a rig and believes it.\n- **Size:** tiny — one emitted notice.\n\n### IR-79 — 22 of the 31 rig binaries leak their daemon tree on a failing assert: teardown is a statement, not a guard\n\n- **Status:** OPEN, filed by hertz 2026-09-07 on doyle's dispatch during PR #198's CI window,\n  from todlando's red 6 (a stale same-port daemon from his own previous run answering the next\n  one). · **Origin:** PR #198 moved 31 rigs to `SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1`. Under an\n  ephemeral port a leaked daemon can no longer ANSWER the next run, so that PR is right as it\n  stands and this entry is not a defect in it; what remains is the orphan process itself — it pins\n  `spt.exe` (the Windows delete-and-rebuild hazard) and holds an `SPT_HOME` that nothing reaps. · **SCOPE BROADENED 07:20Z:** the title says \"on a failing\n  assert\" because that is the face it was filed from; the SECOND FACE bullet below shows the same\n  mechanism firing on a nextest TIMEOUT and leaking THREADS rather than a daemon. Read the title as\n  the handle, not the boundary — the trigger is any exit that does not reach the teardown statement.\n- **What/why:** measured over the 31, classifying each binary by whether its daemon teardown\n  survives a panic (a failing `assert!` unwinds, so only a guard or an ordering discipline saves\n  the child):\n  - **panic-safe, 9:** `impl Drop` guard — `endpoint_autostart_e2e`,\n    `knock_mutual_cross_node_e2e`, `twohost_cli`; `catch_unwind` teardown —\n    `activity_link_push_e2e`, `attach_link_push_e2e`, `wake_resume_bind_e2e`;\n    teardown-then-assert with zero exposed asserts — `endpoint_teardown_authority_e2e`,\n    `er_briefing_session_scoped_e2e`, `er_sequestered_cwd_e2e`.\n  - **leaks on a failing assert, 22** (exposed asserts / total asserts in the test body):\n    `projindex_writer_e2e` 21/21, `projindex_reader_e2e` 18/18,\n    `live_adapt_translation_swap_e2e` 15/38, `brain_split` 12/12,\n    `er_briefing_presented_e2e` 10/28, `rc_attach_truth` 8/29, `brain_respawn_rename` 6/6,\n    `dummy_harness_e2e` 4/11, `idle_edge_drain_e2e` 4/11, `multi_subnet_bringup_e2e` 4/20,\n    `bind_honest_cross_perch_e2e` 3/6, `idle_edge_seal_e2e` 3/17, `resident_service_e2e` 3/24,\n    `attach_wedge_e2e` 2/8, `bind_cwd_project_e2e` 2/8, `daemon_refresh_e2e` 2/11,\n    `er_brief_once_per_session_e2e` 2/13, `n1_pairing` 2/5, `resume_template_e2e` 2/10,\n    `run_no_dup_session_e2e` 2/14, `er_briefing_presentation_e2e` 1/4,\n    `livehost_bootgate_e2e` 1/3.\n  **FIRST WAVE of the Drop-guard generalization lane (doyle-ruled 2026-09-07, composed at the next\n  register sweep, not now): `projindex_writer_e2e`, `projindex_reader_e2e`, `brain_split`,\n  `brain_respawn_rename`.** These four expose EVERY assert they have — their teardown is the last\n  statement in the body, so any red at all leaks, which makes them both the worst cases and the\n  cleanest proofs that a guard works. The remedy already exists in this tree —\n  todlando's `DaemonReaper`, a `Drop` guard armed BEFORE the first CLI call — and the follow-up\n  lane is to generalise it into `crates/spt/tests/common` and adopt it at these 22 sites, which is\n  also the only shape that covers a `SIGKILL`-free timeout kill by nextest.\n- **METHOD, and its limits, so the count can be re-derived and challenged:** the classifier reads\n  each `#[test]` body, resolves file-local helper fns whose own body tears down (so a teardown\n  called through `sweep()` counts), and reports every `assert!`/`panic!` positioned before the LAST\n  teardown call in that body. It therefore (a) misses asserts written inline inside a closure or a\n  macro argument rather than at statement position, (b) treats the last teardown as THE teardown —\n  a partial earlier teardown still leaves the tree, so the true exposure is >= this count, and\n  (c) does not model `?` or early `return`. Spot-verified by hand on `resident_service_e2e`, whose\n  3 exposed asserts are real: they fire in the `wait_until` legs well before the `sweep()` at :435\n  that the \"── ASSERTIONS ──\" block follows.\n- **TONIGHT'S LIVE SAMPLE, so this is not an academic count (doyle's hfenduleam census 06:43Z):**\n  10 leaked `spt.exe` from todlando's pool, pairing by start time, from his pre-yield legs — a\n  single evening's rig work on one box. Each pins the binary against a rebuild and holds an\n  `SPT_HOME` nothing reaps.\n- **SECOND FACE — the same hazard in THREAD clothes, and it blocks the RUNNER, not just the box\n  (measured by todlando 07:17Z, relayed by doyle 07:20Z; I did not measure it myself and record it\n  as his testimony):** a nextest TIMEOUT on a `twohost_web` cell left the cell's child process\n  holding the broker + listener THREADS. Consequences, with his numbers:\n  - nextest itself blocked **14 minutes** at **0.61 CPU-seconds** — a wall-clock hang with\n    essentially no CPU, which is the signature of a parent waiting on a child's pipe rather than\n    of work being done;\n  - **`a.exit` was never written**, while **every verdict was already in `a.raw`** — so the leg\n    read as INCOMPLETE at the exact moment its results were complete. A reader who trusts the\n    exit file over the raw would call this a hung or failed leg and rerun it;\n  - **killing the path-verified orphan let the parent finish at once** — which is the causal test,\n    not a correlation: the kill is the intervention and the unblock is the response.\n  **Why it belongs in THIS entry rather than a new one:** the leaked thing is a thread inside a\n  child, not a daemon, but the mechanism is identical — a teardown that is a STATEMENT does not run\n  when the body does not reach it, and a timeout kill reaches the body even less reliably than a\n  panic does. The `Drop`-guard lane covers both faces with one remedy, which is doyle's ruling and\n  the reason no separate entry is opened. It also raises the lane's value: the daemon face costs a\n  pinned binary and an unreaped `SPT_HOME`, this face costs **14 minutes of a serialized golden\n  leg** and manufactures a false INCOMPLETE.\n  **Reading rule this hands the gate, worth stating because it is cheap:** when a leg's `.exit` is\n  missing, read the `.raw` for a Summary BEFORE concluding the leg hung — kin to\n  [[a-stopped-local-ssh-does-not-stop-its-remote-command]], where the raw was likewise the honest\n  record and the wrapper was not.\n- **Kin:** FLAKE-LEDGER `resident_service_e2e` :664 teardown LEAK row (3 occurrences, the Windows\n  face of the same class), [[IR-34]], [[IR-74]] (kitsubito's 21,643 `/tmp` endpoint homes — this is\n  one of the producers), and todlando's red 6.\n- **Ripe when:** the next lane that touches `crates/spt/tests/common` — the guard belongs there,\n  not copied 22 times.\n- **Size:** medium — one guard in `common`, then 22 mechanical adoptions, each provable by\n  panicking the body under a temporary test and watching the census go quiet.\n\n### IR-80 — five leaky cells on ONE module (`brainproc` / `supervise_brain`), Windows only: a candidate PRODUCT leak on the promotion/rollback path, or a cluster of names — nobody has looked yet\n\n- **Status:** OPEN for the residual population, not an undiagnosed five-name product claim.\n…\n  roster was read out of the baseline golden log for an unrelated reason.\n…\n\n…\n\n\n[Showing lines 3703-4127 of 5900. Use :4128 to continue]"}],"details":{"truncation":{"content":"- **NOT claimed:** that the field incident was misattributed to ingest failure generally — the\r\n  files did survive with failed-ingest log lines; what is unproven is the index.lock CAUSE.\r\n- **Ripe when:** next PSYCHE_INGEST_FAIL sighting in the field (capture the failing store state\r\n  before touching it), or a dedicated probe slot. W2's COMMUNE_FAIL event now pushes a NAMED\r\n  reason on every failure, so the next occurrence self-reports its cause — read that first.\r\n  **Size:** investigation; no product change until the mechanism is pinned.\r\n\r\n### IR-69 — inherited stderr tokens can tear between format fragments; 26 test consumers parse that surface as structured truth\r\n\r\n- **Status:** OPEN for the #243 residual population and anchored-consumer work. The original\r\n  product remedy LANDED at `ec6da9b0`, as recorded in this entry's later amendment; it is not\r\n  still parked awaiting assembly. Releases#241 retains its original lane evidence in comment\r\n  5461613480. This entry is the exposure map and census discipline; residual conversion,\r\n  generator repair and a SHA-pinned zero recensus remain owed. · **Origin:** CONDUIT #236 r3\r\n  golden attempt 2,\r\n  2026-08-29: `endpoint_autostart_e2e` missed its contiguous\r\n  `ENDPOINT_AUTOSTART:gwauto` keystone although the matching fresh session id proved the replay\r\n  happened. Attempt 3 was clean on the same discarded SHA after 139 GB was reaped; unequal load\r\n  makes the pair corroborating, never a rate.\r\n- **Mechanism, recovered from the literal torn bytes:** two daemon processes inherited one stderr\r\n  pipe. `BRAIN_UP` and `ENDPOINT_AUTOSTART` are each one `eprintln!`, but `write_fmt` may reach the\r\n  handle once per format fragment; the per-process stderr lock cannot serialize the other process.\r\n  The observed interleave split the autostart token between `ENDPOINT_AUTOSTART:` and `gwauto`.\r\n  This is fragment-level cross-process interleaving, not a failed replay and not a two-thread race.\r\n- **Durable remedy, ruled product-side:** render a complete diagnostic line into one buffer and\r\n  issue the complete rendered text, newline included, as **ONE handle call**. An OS short-write\r\n  may retry the late tail so completeness wins over a silently truncated line; the deterministic\r\n  property pins application-side fragmentation, not syscall count under that rare retry. It makes\r\n  no claim that the OS write is atomic on Windows, and no CI re-fire against a 1-of-2 observation\r\n  may stand in for it. Widening one test's grep is refused: it greens one consumer while every\r\n  sibling token remains exposed.\r\n- **Cut-SHA census** (todlando generator, independently hash-verified by hertz), measured from\r\n  `4d6007ac4ee3d0991f4bc60b7e1a55825aad1aaf` via `git show`, not a dirty worktree:\r\n  **486 real emitter sites / 383 distinct tokens / 26 consumer test files**. The generator emitted\r\n  487 site rows, but one is a known phantom: `sealverb.rs:456` is a `format!` inside `map_err`\r\n  that the four-line lookback attributed to a neighbouring real `eprintln!`. Corrected real emitters\r\n  by crate: spt-daemon 270, spt 194, spt-runtime 8, spt-live 5, spt-net 5, spt-store 4; by macro:\r\n  `eprintln!` 484, `println!` 1, `eprint!` 1. `DRIVEN_BY` is the sole stdout row and therefore\r\n  outside the stderr remedy. A consumer means the test both mentions `TOKEN:` and reads a\r\n  stderr/log surface; bare-token matching inflated the population to 72 files by admitting prose.\r\n  This is an **exposure map**, not a rate and not a claim that all 26 have torn.\r\n- **Artifacts (the preserved raw generator outputs contain 487 site rows):** cut census SHA-256:\r\n  sites `f10d6bfe5e0399f98945cf63bb5719a01a62e1251be84165c73030fa9bb224f5`,\r\n  tokens `80b0d1835d9d46376b2f200b1c50be4ca0e185a135168444414255f9308ed92b`,\r\n  consumers `249a2e33df43a30570ca82b5bd200d8b6e2bf07aa8250fcc8bace47fe23e3cbc`.\r\n  The sealed sites file's macro column is wrong on 7 of its 487 raw rows; the corrected raw split\r\n  is `eprintln!` 485 / `println!` 1 / `eprint!` 1. The sealed tokens file has no final newline, so\r\n  `wc -l` reports 382 although it contains 383 logical records. The sealed files remain unedited;\r\n  these corrections are textual.\r\n  Generator `81df82f01ef33a82307920d9804a2394b787ef2ffbe3b41d2d7dda560d9a62a9`\r\n  was recorded as asserting newline-terminated output, but the sealed tokens artifact refutes that\r\n  claim for at least one output. Its remaining guards cover logical record counts, a known-positive\r\n  `SUBSCRIBE_DECISION` sentinel, four-line macro lookback, and truncation only at a\r\n  `#[cfg(test)]` that opens a module.\r\n- **Census hazards paid for while constructing and reconciling the population:** the provisional\r\n  instrument moved `277/243 → 286 → 412 → 487 raw → 486 real` as four silent assumptions were\r\n  found: same-line matching misses multi-line macros; truncating at the first `#[cfg(test)]` drops\r\n  later shipping code; lookback must prefer the token line's own macro over a neighbouring arm;\r\n  and even that lookback can promote a nested token literal beneath a real macro into a phantom\r\n  second site. A file without a final newline also makes `wc -l` silently undercount logical\r\n  records by one. Every future census must name its SHA, assert a known member, count records\r\n  inside the generator, and reconcile emitted rows to real sites.\r\n- **Separate anchored-matcher finding:** `IDLE`, `DISPATCH`, `BUSY`, and `BOUND` are common words\r\n  matched as substrings in exposed consumers. One-write emission does not prevent an unrelated log\r\n  line from satisfying them; those predicates need anchored token matching. Keep this separate from\r\n  the tear remedy so neither defect is claimed to close the other.\r\n- **Kin:** [[IR-50]] (the sink must be read before its absence means anything), [[IR-40]] (a\r\n  confident signal that does not describe the source truth), [[IR-8]] (a plausible census whose\r\n  blind spot returns a clean answer).\r\n- **CLOSE-OUT ADDENDUM 2026-08-30 (#242/v0.66.0 sweep — the entry's own close-out re-census RAN\r\n  and FOUND the predicted blind spot LIVE; entry stays OPEN):** re-census at the landed sha\r\n  `ec6da9b0` (independent containment-classified meter, reconciled with todlando's independent\r\n  meter — full write-up `EMISSION-RESIDUAL-CENSUS-FINDING.md`): the generator truncated\r\n  `crates/spt/src/cli.rs` at its FIRST module-opening `#[cfg(test)]` (line 3007, module closes\r\n  3164, file runs to 39118) and never scanned the rest — **338 TOKEN-shaped shipping sites remain\r\n  bare (332 colon-form, i.e. misses under the sealed census's own predicate, + 6 space-form)**,\r\n  plus `main.rs` 2 sites behind the same mechanism; exactly TWO files tree-wide carry the\r\n  triggering property (first module-opening cfg(test) precedes shipping code) — the generator\r\n  fix's owed blind-spot measurement, answered. The census-hazards bullet above already NAMES this\r\n  third-face truncation hazard; the module-opening fix narrowed the trigger and kept the blind\r\n  spot for files where a test module CLOSES and shipping resumes — IR-8 shape, predicted by this\r\n  entry's own text. The shipped #241 conversions are UNAFFECTED (495 removals ≈ censused 486 +\r\n  space family; the SEEN population is closed; golden green stands). Residual conversion +\r\n  generator fix + enforcement-at-the-seam = **releases#243** (BACKLOG, operator triages);\r\n  delivery.rs:149/313 are post-cut MINTS relative to the census sha (todlando's own, settled\r\n  attribution), deliberately outside #243's census-mechanism scope — and ALREADY CONVERTED: the\r\n  fix rode his breadcrumb branch (`60a12056`) into the r4 head and shipped IN-TAG (todlando\r\n  flagged the stale \"his thin lane converts post-cut\" claim 2026-08-30; re-measured — zero bare\r\n  TOKEN `eprintln!` in delivery.rs at both `d931dd63` and origin/main). No lane is owed for it. Re-runnable meter\r\n  `EMISSION-RESIDUAL-CENSUS-METER.py` (repo root, untracked; version-control rides #243's lane).\r\n  **Common-word matcher RULED at this sweep (discharges the \"decide\" clause below):** the four\r\n  common-word consumers (`IDLE`/`DISPATCH`/`BUSY`/`BOUND` substring predicates) get a SEPARATE\r\n  hertz test-side rider — anchored token matching is consumer-predicate work, NOT folded into\r\n  #243 (keeps #243 product-scoped) and not claimed closed by one-write emission; lane-link when\r\n  hertz's spool drains.\r\n- **Closes when:** releases#243's residual conversion + generator fix land and a re-census at\r\n  that sha reads zero shipping residue under both delimiter forms. **Size:** product lane\r\n  complete elsewhere; register follow-through small.\r\n\r\n### IR-70 — a hand-built `IoBus` silently omitted later sinks while every gate stayed green\r\n\r\n- **Status:** OPEN, remedy unscheduled; the v0.65.0 respin fixed the witnessed call site on PR #173.\r\n  This entry owns the recurrence class, not that shipped correction. · **Origin:** releases#234,\r\n  commit `c5459795167`, CONDUIT #236 respin.\r\n- **Mechanism:** `publish_commune_io` constructed `IoBus` itself and registered only the sink it\r\n  knew. `default_bus` already existed as the assembly point and its module contract explicitly says\r\n  emitters must know only `IoBus::publish`, so adding a later sink costs one registration rather\r\n  than an emitter sweep. The hand-built publisher recreated exactly the drift that contract warned\r\n  against: `COMMUNE` and `COMMUNE_FAIL` reached the old sink but never the adapter log, leaving\r\n  `spt api io-events` permanently short on two documented kinds.\r\n- **Why the complete battery was green:** the e2e was vacuous on the broken kinds; units synthesized\r\n  rows without traversing `publish_commune_io`; and traceability checked attached tags, not whether\r\n  the tagged path exercised the real publisher. Three green instruments shared one blind seam.\r\n  The respin routed the site through `crate::iobus::default_bus`, and its source comment now records\r\n  the failure shape.\r\n- **Durable remedy direction (todlando mechanism, not scheduled):** enforce the assembly point so\r\n  the next hand-built bus is impossible rather than found — make production publishers obtain the\r\n  composed bus through one construction API, and gate the real publish path for every documented\r\n  kind. A search or comment is not enforcement; another emitter can satisfy both while rebuilding\r\n  a partial sink list.\r\n- **Kin:** [[IR-39]] (a green fixture never reached the missing dependency), [[IR-37]]\r\n  (traceability tags prove coverage bookkeeping, not behavioral truth), [[IR-58]] (a hand-built\r\n  population returns an orderly but incomplete answer).\r\n- **Ripe when:** the next `IoBus` construction/API touch, or a new sink registration. **Size:**\r\n  small-to-medium assembly-point enforcement plus a real-path population test.\r\n\r\n### IR-71 — controller-seat release has no persisted breadcrumb, so tests cannot distinguish propagation lag from a missing detach\r\n\r\n- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\r\n  `er_brief_once_per_session_e2e` intermittent, classified test-side and fixed on PR #174.\r\n- **What/why:** killing rc1 reaps the controller process, but the broker is another process and\r\n  notices the socket close later. On that detach edge it clears `driven_by` and `controlled` in\r\n  `info.json`; rc2's preflight reads that file locally and can race the write, refuse normally, and\r\n  exit 0 without dialing the broker. The test originally spawned rc2 immediately and had no\r\n  observable precondition separating “release is propagating” from “release never happened.”\r\n- **The missing surface:** broker lifecycle state records `session-detach was_controller=true`, but\r\n  there is no always-on persisted breadcrumb that states the controller stamp was cleared, names\r\n  the resulting `driven_by`/`controlled` state, or measures detach-to-persist latency. The repaired\r\n  test therefore polls `info.json` itself, prints elapsed time (0.075s on the first local real run),\r\n  and uses a named 60s timeout whose failure promotes the finding from timing to missing release.\r\n  Its deliberately latched-seat unit proves the barrier can red.\r\n- **Remedy direction:** add one structured release breadcrumb after the persisted clear, carrying\r\n  session/connection identity and the resulting control state; if latency is carried, measure it\r\n  from the detach edge. It must ride the persisted daemon sink and remain distinct from\r\n  `session-detach`, which proves the connection event but not the file write.\r\n- **Kin:** [[IR-50]] (the sink a test must actually read), [[IR-40]] (an event timestamp is not a\r\n  completion signal), REQ-HAZARD-CONTROL-STAMP-CONVERGENCE.\r\n- **Ripe when:** the next controller lifecycle or structured-breadcrumb touch, or a field timeout\r\n  from PR #174's barrier. **Size:** small emitter plus one contract-level assertion.\r\n\r\n### IR-72 — no product read verb surfaces which process holds a perch or controller seat\r\n\r\n- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\r\n  two-host RCA and PR #174 (`70c1a303`), corrected by doyle after IR-18 and daemon-status were\r\n  ruled out as different classes.\r\n- **Source-verified boundary:** the holder identity already exists in durable/internal records\r\n  (`InfoJson.pid`, `parent_pid`, and the broker's session pid), and product internals read it for\r\n  liveness, teardown, and self-detection. No product **read verb** returns the process that holds a\r\n  named perch/seat. PID-bearing teardown messages are failure outcomes, not an inspection surface;\r\n  daemon status is process-wide, not perch- or seat-scoped. This also does not collapse into\r\n  [[IR-18]], where an existing internal `read_pid` collapses absent and unreadable records.\r\n- **Paid-for consequence 1 — rigs manufacture custody:** PR #174's two-host repair had to add\r\n  `PidHolder` in `crates/spt/tests/twohost_cli.rs:401-437`, spawn a long-lived sibling process,\r\n  write that pid directly into each synthetic perch, retain the child handle, and kill+wait it on\r\n  drop. The rig can make a known holder; it cannot ask the product which holder the product sees.\r\n- **Paid-for consequence 2 — ambiguity stayed latent until behavior flipped:** the r3 fixture\r\n  seeded three perches with one test-process pid. Self-detection then enumerated a directory whose\r\n  first matching row was a filesystem-order coin, so a green could name the wrong perch. The\r\n  repaired resolver refuses an ambiguous candidate set instead of guessing, and the fixture's\r\n  `assert_only_ancestor_candidate` now re-reads every `info.json` rig-side\r\n  (`twohost_cli.rs:439-457`). Refusal is enforcement, not observability: it proves a tie but still\r\n  offers no supported verb that names each holding process.\r\n- **Remedy direction:** add one machine-readable, named-perch inspection surface that reports the\r\n  custody fields the product actually used — holder pid and role/source (bind relay, stable harness\r\n  parent, brokered controller/session) — without asking callers to parse private `info.json` or\r\n  scan the process table. PID alone is recyclable; where a birth/image/session stamp exists, carry\r\n  it so the output does not become a new bare-pid oracle.\r\n- **Kin:** [[IR-18]] (read primitive loses error class, explicitly distinct), [[IR-71]] (release\r\n  completion lacks a persisted breadcrumb), REQ-HAZARD-SELF-DETECT-TIE (refuse ambiguous ancestry\r\n  rather than select by enumeration order).\r\n- **Ripe when:** the next roster/status read-model change or another rig needs to reap a named\r\n  holder. **Size:** small read-model/API addition, medium if seat and perch custody need separate\r\n  typed variants.\r\n\r\n### IR-73 — ci.yml and release.yml still read the free-space floor PRE-checkout (literal-first sites off the golden path); and any job's floor is stale by its last heavy step\r\n\r\n- **Status:** CLOSED / BUILT — source reconciliation 2026-09-11 at `e5a2fed9`: all five\r\n  `ci.yml` sites and all three `release.yml` sites now read after checkout, with IR-73 comments;\r\n  `golden.yml` has both docs-floor rereads. IR-86 records the docs reread's live catch.\r\n  The original two halves below are implemented; capacity sizing and docs dependency coupling\r\n  remain OPEN under IR-86, not a reason to redispatch these eight reorders.\r\n  Filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep (deployah flag 2026-08-29).\r\n  · **Origin:** #242's two lost golden attempts exposed the pre-checkout read; the original\r\n  golden-only correction deliberately left the eight other sites for the now-built rider.\r\n- **What/why:** review each of the 8 sites' comments for checkout-protective purpose (the\r\n  `ac7d2609` method), then reorder the read after checkout or RECORD why not, per site. The\r\n  \"other jobs keep the literal-first shape\" clause is the trap's carrier: every un-reviewed site\r\n  is a queued golden-attempt loss on a loaded box.\r\n- **Second half (from #242 r4, same family):** a single job-start floor read is stale by the\r\n  job's LAST heavy step — the r4 LNK1318 low-water face recorded on [[IR-59]] (sixth face);\r\n  the within-job re-read before the docs-drift build rides the next workflow commit alongside\r\n  this entry's reorders.\r\n- **Kin:** [[IR-46]] (a floor asserts an instant), [[IR-59]] (full volume reds as a linker\r\n  defect), REQ-CI-FREE-SPACE-PREFLIGHT.\r\n- **Ripe when:** next touch of `ci.yml`/`release.yml`, or the next intake's tooling-rider slot\r\n  (compose with IR-59/IR-57's standing pair). · **Size:** small — reorder or comment per site,\r\n  8 sites.\r\n\r\n### IR-74 — kitsubito holds 21,643 /tmp endpoint homes: box-side accumulation nothing bounds or measures\r\n\r\n- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep; measurement by\r\n  hertz (2026-08-29). · **Origin:** rig work on kitsubito found `/tmp` carrying 21,643 endpoint\r\n  homes — per-run spt homes that outlive their runs.\r\n- **What/why:** sibling of the [[IR-31]]/[[IR-59]]/[[IR-64]] family (box accumulation the\r\n  preflights never see): each is small, the population is not, and /tmp on a long-lived box is\r\n  never reaped by CI. Un-reaped homes also widen every by-path census a rig runs. Needs a\r\n  bounded lifecycle (per-run temp root reaped at run end, or a box-side sweep with a stated\r\n  retention), and the reap must state its count so a zero is a claim.\r\n- **Ripe when:** next kitsubito rig touch, or the between-milestone box-audit slot.\r\n- **Size:** small (one sweep script + adoption in the box's rig steps); the measurement rerun is\r\n  one `find | wc`.\r\n\r\n### IR-75 — traceable-reqs is not installed on kitsubito, so every Linux gate driver's treqs leg exits 127 (vacuous, wrapper-green shape)\r\n\r\n- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep (deployah\r\n  co-flagged at intake). · **Origin:** ASM-241 Linux battery — `ASM_treqs.exit` = 127, raw\r\n  `env: 'traceable-reqs': No such file or directory`; leg vacuous, covered that day by the\r\n  Windows treqs = 0 at the identical tree (treqs is a platform-independent text scan).\r\n- **What/why:** a 127 leg is exactly the wrapper-green shape [[IR-60]] documents — a driver that\r\n  doesn't read the exit FILE would report the leg green. Fix is either: install traceable-reqs on\r\n  kitsubito (then the leg is real), or DROP the leg from Linux gate drivers and state the\r\n  Windows-covers-it rule in the driver comment. Do NOT reopen [[IR-37]] for this — IR-37's\r\n  consume lane is spt-core CI (GitHub runners, green all week); this is BOX tooling, a different\r\n  surface (ruled at the sweep against the enumerating agent's overcautious flag).\r\n- **Ripe when:** next Linux gate-driver touch or kitsubito box-audit slot.\r\n- **Size:** trivial (install or one driver edit + comment).\r\n\r\n### IR-76 — hfenduleam is the golden Windows runner AND the builders' box: a local workspace nextest fully contained a golden Phase A and manufactured a load-timing red, and the job-start census cannot see it\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-06 during v0.67.1 golden triage (run 34017906638\r\n  att2). · **Origin:** the Windows Phase A red on\r\n  `spt-store::wtlock_two_process_int two_processes_commit_into_one_worktree_without_failing`\r\n  (B hit the 10 s worktree-lock bound while A's six serial commits took 13.5 s; 12 other\r\n  cells ran >10 s in the same phase). Load audit by todlando from his own `.raw`\r\n  CreationTimeUtc / `.exit` LastWriteTimeUtc: his #276 gate's 1240-cell workspace nextest\r\n  (`--no-fail-fast`, test phase 08:50:06–08:58:00Z) FULLY CONTAINED the golden Phase A\r\n  (08:52:38–08:56:49Z), every core saturated. He had been dispatched into that window and\r\n  never told the box was under a golden hold; perri and hertz had been.\r\n- **What/why:** two mechanisms, both unmeasured by anything in CI today. (1) The box is\r\n  shared by design — every agent's gate rig, adapter build and workspace nextest runs on the\r\n  same host as the self-hosted golden Windows runner, so a golden Windows leg is a QUIET\r\n  WINDOW only if every agent knows it is open; nothing says so, and a dispatch brief that\r\n  starts a gate is exactly how a builder lands inside it. (2) The job-start\r\n  `reap-census.ps1` counts the SPT FAMILY only (`family_total=12 scoped=0 unscoped=12` at\r\n  att2's 08:39:46Z start, with a builder's prebuild live on the box); cargo/nextest/rustc\r\n  load is outside its predicate, so the one instrument that runs at the right moment is\r\n  blind to the load that matters. Every load-timing red on Windows therefore triages as a\r\n  random victim with the cause off the record — the [[IR-63]] \"one random victim per sweep\"\r\n  face, now with a named source.\r\n- **Fix shape:** (a) driver templates (every gate/battery driver an agent authors here)\r\n  gain a PRE-FLIGHT leg with THREE outcomes, never two (todlando's amendment at filing: an\r\n  empty `gh run list` is the same bytes for CLEAR and for a broken meter — wrong filter,\r\n  expired token, rate limit, wrong repo default all return exit 0 and no rows — so a\r\n  two-arm guard fails OPEN into the exact hazard it guards, the `--commit <short-sha>`\r\n  confident-EMPTY class): run `gh run list --workflow golden --status in_progress`; rows\r\n  present -> HOLD, print the run id; no rows AND a positive control (`gh run list -L 1`\r\n  unfiltered, or `gh auth status`) returns a row -> CLEAR; control empty or erroring ->\r\n  REFUSE and say the meter is broken. A refusal, not a warning, so a wrapper-green shape\r\n  cannot swallow it ([[IR-60]]); the dispatch-brief line in (b) is likewise a MEASURED\r\n  clear with a live meter, never the absence of a sentence; (b) dispatch briefs that start a gate NAME the hold state of the box; (c)\r\n  the job-start census gains a second predicate — cargo/nextest/rustc/link processes by\r\n  image name, count + total CPU — reported beside the family count so a red's triage can\r\n  place foreign load from the log alone; (d) the golden hand-off contract\r\n  (docs/golden-head-intake) states the quiet-window rule once.\r\n- **Kin:** [[IR-63]] (random victim per sweep), [[IR-59]] (box conditions the preflights\r\n  never see), [[IR-64]] (hfenduleam's non-CI payload), FLAKE-LEDGER rows for\r\n  `wtlock_two_process_int` and `attach_link_push_e2e` (2026-09-06).\r\n- **Ripe when:** next driver-template touch (a/b are text; a is one leg), next `ci.yml`\r\n  touch for (c) — compose with [[IR-73]]'s reorders; (d) rides the next runbook edit.\r\n- **Size:** small — one pre-flight leg + one census predicate + two doc sentences.\r\n\r\n### IR-77 — nothing stamps the interval between a daemon child's spawn and the brain's first log line, so a readiness-deadline red cannot say WHERE the time went\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-07 from the W1 #249 kitsubito battery at the gated\r\n  sha `8d980fdf`; doyle-ruled at filing to be a register entry rather than a lane rider. ·\r\n  **Origin:** FLAKE-LEDGER `resident_service_e2e` :453 PRECONDITION (53 s) and\r\n  `resume_no_control_steal_e2e` (46 s), co-victims of ONE window — nextest exit 100, ONE\r\n  Summary `2999 tests run: 2997 passed (8 slow, 1 leaky), 2 failed, 1 skipped`. Evidence\r\n  preserved at `.spt/preserved/w1-kitsubito-8d980fdf/nextest.raw`, sha256\r\n  `9c456e21a6a0f75d8b0375ac648f232dba07f3887ec5e8dc232daef36253b51e`, hash-verified against\r\n  the kitsubito original.\r\n- **What/why:** both reds are a 45 s wait on `brain.ready` that expired, and the panel each\r\n  one prints shows the tree ALIVE — `BRAIN_UP`, `BRAIN_PHASE:announce done in 1ms`,\r\n  `BRAIN_PHASE:resume done in 0ms`, `SERVICE_STARTED` for both services, both later reaped\r\n  with an empty survivor set. So the daemon came up; it came up after the clock. WHERE those\r\n  45 s went is not recoverable from any artifact we keep: the first timestamped line in the\r\n  daemon's own sink is emitted by a process that has already started, and nothing stamps the\r\n  interval from the test's `Command::spawn` to it. The consequence is that every red of this\r\n  family is triaged by inference — v0.66.0 measured a ~10.1 s exe-hash on the ready path, and\r\n  that number is a CANDIDATE for the gap and can never be more than a candidate while the\r\n  interval is unmeasured. Remedy: one monotonic breadcrumb at daemon-child entry (before any\r\n  work), a second at the point `brain.ready` is stamped, both into the stderr sink the panel\r\n  already renders — then a red of this family reports its own split without a rerun.\r\n- **Kin:** [[IR-71]] (a seat release with no breadcrumb, same shape one layer over),\r\n  FLAKE-LEDGER `resident_service_e2e` :453 and `resume_no_control_steal_e2e` (2026-09-07),\r\n  and the HEAVY census stanza in `.config/nextest.toml`, which hardens the RECIPE these reds\r\n  came from and deliberately leaves the deadlines alone — a budget retune is the same race\r\n  with a different number, and it would also destroy the only signal this entry wants.\r\n- **Ripe when:** the next touch of the daemon boot path or of `brainproc`'s ready stamp; also\r\n  ripe as a rider on any lane that re-opens this test family.\r\n- **Size:** small — two `emit_line_err!` breadcrumbs and the sentence in the panel that says\r\n  what they mean.\r\n\r\n### IR-78 — `SPT_TEST_EPHEMERAL_ADVISORY_PORTS` silently overrides an explicitly set `SPT_DOCS_PORT`\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-07, MEASURED by doyle the same night on his W2\r\n  field pair (both boxes). · **Origin:** the 5474 rig-hygiene sweep in\r\n  `test/rig-advisory-ports-and-heavy-class`, which sets the rig flag at 37 `spt daemon run`\r\n  spawn sites.\r\n- **What/why:** `resolve_daemon_docs_port` (crates/spt-daemon/src/docshost.rs) returns `0`\r\n  whenever the rig flag is set, BEFORE the `SPT_DOCS_PORT` env override is consulted. With\r\n  both set, doyle's rig daemons took ephemeral ports (`DOCS_SERVER_UP` on 55369 Windows,\r\n  44015 Linux) while `SPT_DOCS_PORT=5480` was ignored without a word. The precedence itself is\r\n  defensible — the rig flag exists precisely so a test tree cannot take a well-known port —\r\n  but a SET override discarded in SILENCE is the shape IR-37 files under a different name: the\r\n  operator is left believing the value they set is the value in force. Remedy is a line, not a\r\n  redesign: emit one notice naming both env vars when the flag wins. No test cell is proposed\r\n  with it — none of the 31 swept binaries asserts on a docs port, so a cell here would assert\r\n  a behaviour nothing consumes.\r\n- **Kin:** [[IR-37]] (a set input silently ignored), the 5474 hygiene sweep, and the\r\n  `DOCS_SERVER_BIND_FAIL: port 5474: Address already in use (os error 98)` lines in\r\n  `.spt/preserved/w1-kitsubito-8d980fdf/nextest.raw` that started the sweep.\r\n- **NOT measured, stated so nobody reads it as covered:** doyle measured that the WMI\r\n  auto-start rung DOES carry the caller's environment (rig daemon pid 50088 on hfenduleam:\r\n  `DAEMON_LAUNCH_VIA_WMI`, its environ carrying `SPT_HOME`, `SPT_DOCS_PORT` and the rig flag\r\n  as his shell set them, `brain.ready` in the rig home). The schtasks (at-logon) rung was NOT\r\n  measured, and neither was the unix path.\r\n- **Ripe when:** the next `docshost.rs` touch, or the first time someone sets `SPT_DOCS_PORT`\r\n  on a rig and believes it.\r\n- **Size:** tiny — one emitted notice.\r\n\r\n### IR-79 — 22 of the 31 rig binaries leak their daemon tree on a failing assert: teardown is a statement, not a guard\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-07 on doyle's dispatch during PR #198's CI window,\r\n  from todlando's red 6 (a stale same-port daemon from his own previous run answering the next\r\n  one). · **Origin:** PR #198 moved 31 rigs to `SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1`. Under an\r\n  ephemeral port a leaked daemon can no longer ANSWER the next run, so that PR is right as it\r\n  stands and this entry is not a defect in it; what remains is the orphan process itself — it pins\r\n  `spt.exe` (the Windows delete-and-rebuild hazard) and holds an `SPT_HOME` that nothing reaps. · **SCOPE BROADENED 07:20Z:** the title says \"on a failing\r\n  assert\" because that is the face it was filed from; the SECOND FACE bullet below shows the same\r\n  mechanism firing on a nextest TIMEOUT and leaking THREADS rather than a daemon. Read the title as\r\n  the handle, not the boundary — the trigger is any exit that does not reach the teardown statement.\r\n- **What/why:** measured over the 31, classifying each binary by whether its daemon teardown\r\n  survives a panic (a failing `assert!` unwinds, so only a guard or an ordering discipline saves\r\n  the child):\r\n  - **panic-safe, 9:** `impl Drop` guard — `endpoint_autostart_e2e`,\r\n    `knock_mutual_cross_node_e2e`, `twohost_cli`; `catch_unwind` teardown —\r\n    `activity_link_push_e2e`, `attach_link_push_e2e`, `wake_resume_bind_e2e`;\r\n    teardown-then-assert with zero exposed asserts — `endpoint_teardown_authority_e2e`,\r\n    `er_briefing_session_scoped_e2e`, `er_sequestered_cwd_e2e`.\r\n  - **leaks on a failing assert, 22** (exposed asserts / total asserts in the test body):\r\n    `projindex_writer_e2e` 21/21, `projindex_reader_e2e` 18/18,\r\n    `live_adapt_translation_swap_e2e` 15/38, `brain_split` 12/12,\r\n    `er_briefing_presented_e2e` 10/28, `rc_attach_truth` 8/29, `brain_respawn_rename` 6/6,\r\n    `dummy_harness_e2e` 4/11, `idle_edge_drain_e2e` 4/11, `multi_subnet_bringup_e2e` 4/20,\r\n    `bind_honest_cross_perch_e2e` 3/6, `idle_edge_seal_e2e` 3/17, `resident_service_e2e` 3/24,\r\n    `attach_wedge_e2e` 2/8, `bind_cwd_project_e2e` 2/8, `daemon_refresh_e2e` 2/11,\r\n    `er_brief_once_per_session_e2e` 2/13, `n1_pairing` 2/5, `resume_template_e2e` 2/10,\r\n    `run_no_dup_session_e2e` 2/14, `er_briefing_presentation_e2e` 1/4,\r\n    `livehost_bootgate_e2e` 1/3.\r\n  **FIRST WAVE of the Drop-guard generalization lane (doyle-ruled 2026-09-07, composed at the next\r\n  register sweep, not now): `projindex_writer_e2e`, `projindex_reader_e2e`, `brain_split`,\r\n  `brain_respawn_rename`.** These four expose EVERY assert they have — their teardown is the last\r\n  statement in the body, so any red at all leaks, which makes them both the worst cases and the\r\n  cleanest proofs that a guard works. The remedy already exists in this tree —\r\n  todlando's `DaemonReaper`, a `Drop` guard armed BEFORE the first CLI call — and the follow-up\r\n  lane is to generalise it into `crates/spt/tests/common` and adopt it at these 22 sites, which is\r\n  also the only shape that covers a `SIGKILL`-free timeout kill by nextest.\r\n- **METHOD, and its limits, so the count can be re-derived and challenged:** the classifier reads\r\n  each `#[test]` body, resolves file-local helper fns whose own body tears down (so a teardown\r\n  called through `sweep()` counts), and reports every `assert!`/`panic!` positioned before the LAST\r\n  teardown call in that body. It therefore (a) misses asserts written inline inside a closure or a\r\n  macro argument rather than at statement position, (b) treats the last teardown as THE teardown —\r\n  a partial earlier teardown still leaves the tree, so the true exposure is >= this count, and\r\n  (c) does not model `?` or early `return`. Spot-verified by hand on `resident_service_e2e`, whose\r\n  3 exposed asserts are real: they fire in the `wait_until` legs well before the `sweep()` at :435\r\n  that the \"── ASSERTIONS ──\" block follows.\r\n- **TONIGHT'S LIVE SAMPLE, so this is not an academic count (doyle's hfenduleam census 06:43Z):**\r\n  10 leaked `spt.exe` from todlando's pool, pairing by start time, from his pre-yield legs — a\r\n  single evening's rig work on one box. Each pins the binary against a rebuild and holds an\r\n  `SPT_HOME` nothing reaps.\r\n- **SECOND FACE — the same hazard in THREAD clothes, and it blocks the RUNNER, not just the box\r\n  (measured by todlando 07:17Z, relayed by doyle 07:20Z; I did not measure it myself and record it\r\n  as his testimony):** a nextest TIMEOUT on a `twohost_web` cell left the cell's child process\r\n  holding the broker + listener THREADS. Consequences, with his numbers:\r\n  - nextest itself blocked **14 minutes** at **0.61 CPU-seconds** — a wall-clock hang with\r\n    essentially no CPU, which is the signature of a parent waiting on a child's pipe rather than\r\n    of work being done;\r\n  - **`a.exit` was never written**, while **every verdict was already in `a.raw`** — so the leg\r\n    read as INCOMPLETE at the exact moment its results were complete. A reader who trusts the\r\n    exit file over the raw would call this a hung or failed leg and rerun it;\r\n  - **killing the path-verified orphan let the parent finish at once** — which is the causal test,\r\n    not a correlation: the kill is the intervention and the unblock is the response.\r\n  **Why it belongs in THIS entry rather than a new one:** the leaked thing is a thread inside a\r\n  child, not a daemon, but the mechanism is identical — a teardown that is a STATEMENT does not run\r\n  when the body does not reach it, and a timeout kill reaches the body even less reliably than a\r\n  panic does. The `Drop`-guard lane covers both faces with one remedy, which is doyle's ruling and\r\n  the reason no separate entry is opened. It also raises the lane's value: the daemon face costs a\r\n  pinned binary and an unreaped `SPT_HOME`, this face costs **14 minutes of a serialized golden\r\n  leg** and manufactures a false INCOMPLETE.\r\n  **Reading rule this hands the gate, worth stating because it is cheap:** when a leg's `.exit` is\r\n  missing, read the `.raw` for a Summary BEFORE concluding the leg hung — kin to\r\n  [[a-stopped-local-ssh-does-not-stop-its-remote-command]], where the raw was likewise the honest\r\n  record and the wrapper was not.\r\n- **Kin:** FLAKE-LEDGER `resident_service_e2e` :664 teardown LEAK row (3 occurrences, the Windows\r\n  face of the same class), [[IR-34]], [[IR-74]] (kitsubito's 21,643 `/tmp` endpoint homes — this is\r\n  one of the producers), and todlando's red 6.\r\n- **Ripe when:** the next lane that touches `crates/spt/tests/common` — the guard belongs there,\r\n  not copied 22 times.\r\n- **Size:** medium — one guard in `common`, then 22 mechanical adoptions, each provable by\r\n  panicking the body under a temporary test and watching the census go quiet.\r\n\r\n### IR-80 — five leaky cells on ONE module (`brainproc` / `supervise_brain`), Windows only: a candidate PRODUCT leak on the promotion/rollback path, or a cluster of names — nobody has looked yet\r\n\r\n- **Status:** OPEN for the residual population, not an undiagnosed five-name product claim.\r","truncated":true,"truncatedBy":"lines","totalLines":2198,"totalBytes":35564,"outputLines":425,"outputBytes":35564,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":5900,"displayContent":{"text":"### IR-68 — PSYCHE_INGEST_FAIL cause class unproven: git index.lock did NOT reproduce the ingest failure it was blamed for\n…\n- **Status:** OPEN, investigation-shaped · **Origin:** todlando measurement at the W2 int-leg rig\n…\n- **NOT claimed:** that the field incident was misattributed to ingest failure generally — the\r\n  files did survive with failed-ingest log lines; what is unproven is the index.lock CAUSE.\r\n- **Ripe when:** next PSYCHE_INGEST_FAIL sighting in the field (capture the failing store state\r\n  before touching it), or a dedicated probe slot. W2's COMMUNE_FAIL event now pushes a NAMED\r\n  reason on every failure, so the next occurrence self-reports its cause — read that first.\r\n  **Size:** investigation; no product change until the mechanism is pinned.\r\n\r\n### IR-69 — inherited stderr tokens can tear between format fragments; 26 test consumers parse that surface as structured truth\r\n\r\n- **Status:** OPEN for the #243 residual population and anchored-consumer work. The original\r\n  product remedy LANDED at `ec6da9b0`, as recorded in this entry's later amendment; it is not\r\n  still parked awaiting assembly. Releases#241 retains its original lane evidence in comment\r\n  5461613480. This entry is the exposure map and census discipline; residual conversion,\r\n  generator repair and a SHA-pinned zero recensus remain owed. · **Origin:** CONDUIT #236 r3\r\n  golden attempt 2,\r\n  2026-08-29: `endpoint_autostart_e2e` missed its contiguous\r\n  `ENDPOINT_AUTOSTART:gwauto` keystone although the matching fresh session id proved the replay\r\n  happened. Attempt 3 was clean on the same discarded SHA after 139 GB was reaped; unequal load\r\n  makes the pair corroborating, never a rate.\r\n- **Mechanism, recovered from the literal torn bytes:** two daemon processes inherited one stderr\r\n  pipe. `BRAIN_UP` and `ENDPOINT_AUTOSTART` are each one `eprintln!`, but `write_fmt` may reach the\r\n  handle once per format fragment; the per-process stderr lock cannot serialize the other process.\r\n  The observed interleave split the autostart token between `ENDPOINT_AUTOSTART:` and `gwauto`.\r\n  This is fragment-level cross-process interleaving, not a failed replay and not a two-thread race.\r\n- **Durable remedy, ruled product-side:** render a complete diagnostic line into one buffer and\r\n  issue the complete rendered text, newline included, as **ONE handle call**. An OS short-write\r\n  may retry the late tail so completeness wins over a silently truncated line; the deterministic\r\n  property pins application-side fragmentation, not syscall count under that rare retry. It makes\r\n  no claim that the OS write is atomic on Windows, and no CI re-fire against a 1-of-2 observation\r\n  may stand in for it. Widening one test's grep is refused: it greens one consumer while every\r\n  sibling token remains exposed.\r\n- **Cut-SHA census** (todlando generator, independently hash-verified by hertz), measured from\r\n  `4d6007ac4ee3d0991f4bc60b7e1a55825aad1aaf` via `git show`, not a dirty worktree:\r\n  **486 real emitter sites / 383 distinct tokens / 26 consumer test files**. The generator emitted\r\n  487 site rows, but one is a known phantom: `sealverb.rs:456` is a `format!` inside `map_err`\r\n  that the four-line lookback attributed to a neighbouring real `eprintln!`. Corrected real emitters\r\n  by crate: spt-daemon 270, spt 194, spt-runtime 8, spt-live 5, spt-net 5, spt-store 4; by macro:\r\n  `eprintln!` 484, `println!` 1, `eprint!` 1. `DRIVEN_BY` is the sole stdout row and therefore\r\n  outside the stderr remedy. A consumer means the test both mentions `TOKEN:` and reads a\r\n  stderr/log surface; bare-token matching inflated the population to 72 files by admitting prose.\r\n  This is an **exposure map**, not a rate and not a claim that all 26 have torn.\r\n- **Artifacts (the preserved raw generator outputs contain 487 site rows):** cut census SHA-256:\r\n  sites `f10d6bfe5e0399f98945cf63bb5719a01a62e1251be84165c73030fa9bb224f5`,\r\n  tokens `80b0d1835d9d46376b2f200b1c50be4ca0e185a135168444414255f9308ed92b`,\r\n  consumers `249a2e33df43a30570ca82b5bd200d8b6e2bf07aa8250fcc8bace47fe23e3cbc`.\r\n  The sealed sites file's macro column is wrong on 7 of its 487 raw rows; the corrected raw split\r\n  is `eprintln!` 485 / `println!` 1 / `eprint!` 1. The sealed tokens file has no final newline, so\r\n  `wc -l` reports 382 although it contains 383 logical records. The sealed files remain unedited;\r\n  these corrections are textual.\r\n  Generator `81df82f01ef33a82307920d9804a2394b787ef2ffbe3b41d2d7dda560d9a62a9`\r\n  was recorded as asserting newline-terminated output, but the sealed tokens artifact refutes that\r\n  claim for at least one output. Its remaining guards cover logical record counts, a known-positive\r\n  `SUBSCRIBE_DECISION` sentinel, four-line macro lookback, and truncation only at a\r\n  `#[cfg(test)]` that opens a module.\r\n- **Census hazards paid for while constructing and reconciling the population:** the provisional\r\n  instrument moved `277/243 → 286 → 412 → 487 raw → 486 real` as four silent assumptions were\r\n  found: same-line matching misses multi-line macros; truncating at the first `#[cfg(test)]` drops\r\n  later shipping code; lookback must prefer the token line's own macro over a neighbouring arm;\r\n  and even that lookback can promote a nested token literal beneath a real macro into a phantom\r\n  second site. A file without a final newline also makes `wc -l` silently undercount logical\r\n  records by one. Every future census must name its SHA, assert a known member, count records\r\n  inside the generator, and reconcile emitted rows to real sites.\r\n- **Separate anchored-matcher finding:** `IDLE`, `DISPATCH`, `BUSY`, and `BOUND` are common words\r\n  matched as substrings in exposed consumers. One-write emission does not prevent an unrelated log\r\n  line from satisfying them; those predicates need anchored token matching. Keep this separate from\r\n  the tear remedy so neither defect is claimed to close the other.\r\n- **Kin:** [[IR-50]] (the sink must be read before its absence means anything), [[IR-40]] (a\r\n  confident signal that does not describe the source truth), [[IR-8]] (a plausible census whose\r\n  blind spot returns a clean answer).\r\n- **CLOSE-OUT ADDENDUM 2026-08-30 (#242/v0.66.0 sweep — the entry's own close-out re-census RAN\r\n  and FOUND the predicted blind spot LIVE; entry stays OPEN):** re-census at the landed sha\r\n  `ec6da9b0` (independent containment-classified meter, reconciled with todlando's independent\r\n  meter — full write-up `EMISSION-RESIDUAL-CENSUS-FINDING.md`): the generator truncated\r\n  `crates/spt/src/cli.rs` at its FIRST module-opening `#[cfg(test)]` (line 3007, module closes\r\n  3164, file runs to 39118) and never scanned the rest — **338 TOKEN-shaped shipping sites remain\r\n  bare (332 colon-form, i.e. misses under the sealed census's own predicate, + 6 space-form)**,\r\n  plus `main.rs` 2 sites behind the same mechanism; exactly TWO files tree-wide carry the\r\n  triggering property (first module-opening cfg(test) precedes shipping code) — the generator\r\n  fix's owed blind-spot measurement, answered. The census-hazards bullet above already NAMES this\r\n  third-face truncation hazard; the module-opening fix narrowed the trigger and kept the blind\r\n  spot for files where a test module CLOSES and shipping resumes — IR-8 shape, predicted by this\r\n  entry's own text. The shipped #241 conversions are UNAFFECTED (495 removals ≈ censused 486 +\r\n  space family; the SEEN population is closed; golden green stands). Residual conversion +\r\n  generator fix + enforcement-at-the-seam = **releases#243** (BACKLOG, operator triages);\r\n  delivery.rs:149/313 are post-cut MINTS relative to the census sha (todlando's own, settled\r\n  attribution), deliberately outside #243's census-mechanism scope — and ALREADY CONVERTED: the\r\n  fix rode his breadcrumb branch (`60a12056`) into the r4 head and shipped IN-TAG (todlando\r\n  flagged the stale \"his thin lane converts post-cut\" claim 2026-08-30; re-measured — zero bare\r\n  TOKEN `eprintln!` in delivery.rs at both `d931dd63` and origin/main). No lane is owed for it. Re-runnable meter\r\n  `EMISSION-RESIDUAL-CENSUS-METER.py` (repo root, untracked; version-control rides #243's lane).\r\n  **Common-word matcher RULED at this sweep (discharges the \"decide\" clause below):** the four\r\n  common-word consumers (`IDLE`/`DISPATCH`/`BUSY`/`BOUND` substring predicates) get a SEPARATE\r\n  hertz test-side rider — anchored token matching is consumer-predicate work, NOT folded into\r\n  #243 (keeps #243 product-scoped) and not claimed closed by one-write emission; lane-link when\r\n  hertz's spool drains.\r\n- **Closes when:** releases#243's residual conversion + generator fix land and a re-census at\r\n  that sha reads zero shipping residue under both delimiter forms. **Size:** product lane\r\n  complete elsewhere; register follow-through small.\r\n\r\n### IR-70 — a hand-built `IoBus` silently omitted later sinks while every gate stayed green\r\n\r\n- **Status:** OPEN, remedy unscheduled; the v0.65.0 respin fixed the witnessed call site on PR #173.\r\n  This entry owns the recurrence class, not that shipped correction. · **Origin:** releases#234,\r\n  commit `c5459795167`, CONDUIT #236 respin.\r\n- **Mechanism:** `publish_commune_io` constructed `IoBus` itself and registered only the sink it\r\n  knew. `default_bus` already existed as the assembly point and its module contract explicitly says\r\n  emitters must know only `IoBus::publish`, so adding a later sink costs one registration rather\r\n  than an emitter sweep. The hand-built publisher recreated exactly the drift that contract warned\r\n  against: `COMMUNE` and `COMMUNE_FAIL` reached the old sink but never the adapter log, leaving\r\n  `spt api io-events` permanently short on two documented kinds.\r\n- **Why the complete battery was green:** the e2e was vacuous on the broken kinds; units synthesized\r\n  rows without traversing `publish_commune_io`; and traceability checked attached tags, not whether\r\n  the tagged path exercised the real publisher. Three green instruments shared one blind seam.\r\n  The respin routed the site through `crate::iobus::default_bus`, and its source comment now records\r\n  the failure shape.\r\n- **Durable remedy direction (todlando mechanism, not scheduled):** enforce the assembly point so\r\n  the next hand-built bus is impossible rather than found — make production publishers obtain the\r\n  composed bus through one construction API, and gate the real publish path for every documented\r\n  kind. A search or comment is not enforcement; another emitter can satisfy both while rebuilding\r\n  a partial sink list.\r\n- **Kin:** [[IR-39]] (a green fixture never reached the missing dependency), [[IR-37]]\r\n  (traceability tags prove coverage bookkeeping, not behavioral truth), [[IR-58]] (a hand-built\r\n  population returns an orderly but incomplete answer).\r\n- **Ripe when:** the next `IoBus` construction/API touch, or a new sink registration. **Size:**\r\n  small-to-medium assembly-point enforcement plus a real-path population test.\r\n\r\n### IR-71 — controller-seat release has no persisted breadcrumb, so tests cannot distinguish propagation lag from a missing detach\r\n\r\n- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\r\n  `er_brief_once_per_session_e2e` intermittent, classified test-side and fixed on PR #174.\r\n- **What/why:** killing rc1 reaps the controller process, but the broker is another process and\r\n  notices the socket close later. On that detach edge it clears `driven_by` and `controlled` in\r\n  `info.json`; rc2's preflight reads that file locally and can race the write, refuse normally, and\r\n  exit 0 without dialing the broker. The test originally spawned rc2 immediately and had no\r\n  observable precondition separating “release is propagating” from “release never happened.”\r\n- **The missing surface:** broker lifecycle state records `session-detach was_controller=true`, but\r\n  there is no always-on persisted breadcrumb that states the controller stamp was cleared, names\r\n  the resulting `driven_by`/`controlled` state, or measures detach-to-persist latency. The repaired\r\n  test therefore polls `info.json` itself, prints elapsed time (0.075s on the first local real run),\r\n  and uses a named 60s timeout whose failure promotes the finding from timing to missing release.\r\n  Its deliberately latched-seat unit proves the barrier can red.\r\n- **Remedy direction:** add one structured release breadcrumb after the persisted clear, carrying\r\n  session/connection identity and the resulting control state; if latency is carried, measure it\r\n  from the detach edge. It must ride the persisted daemon sink and remain distinct from\r\n  `session-detach`, which proves the connection event but not the file write.\r\n- **Kin:** [[IR-50]] (the sink a test must actually read), [[IR-40]] (an event timestamp is not a\r\n  completion signal), REQ-HAZARD-CONTROL-STAMP-CONVERGENCE.\r\n- **Ripe when:** the next controller lifecycle or structured-breadcrumb touch, or a field timeout\r\n  from PR #174's barrier. **Size:** small emitter plus one contract-level assertion.\r\n\r\n### IR-72 — no product read verb surfaces which process holds a perch or controller seat\r\n\r\n- **Status:** OPEN, observability gap; no remedy scheduled. · **Origin:** CONDUIT #236 r3\r\n  two-host RCA and PR #174 (`70c1a303`), corrected by doyle after IR-18 and daemon-status were\r\n  ruled out as different classes.\r\n- **Source-verified boundary:** the holder identity already exists in durable/internal records\r\n  (`InfoJson.pid`, `parent_pid`, and the broker's session pid), and product internals read it for\r\n  liveness, teardown, and self-detection. No product **read verb** returns the process that holds a\r\n  named perch/seat. PID-bearing teardown messages are failure outcomes, not an inspection surface;\r\n  daemon status is process-wide, not perch- or seat-scoped. This also does not collapse into\r\n  [[IR-18]], where an existing internal `read_pid` collapses absent and unreadable records.\r\n- **Paid-for consequence 1 — rigs manufacture custody:** PR #174's two-host repair had to add\r\n  `PidHolder` in `crates/spt/tests/twohost_cli.rs:401-437`, spawn a long-lived sibling process,\r\n  write that pid directly into each synthetic perch, retain the child handle, and kill+wait it on\r\n  drop. The rig can make a known holder; it cannot ask the product which holder the product sees.\r\n- **Paid-for consequence 2 — ambiguity stayed latent until behavior flipped:** the r3 fixture\r\n  seeded three perches with one test-process pid. Self-detection then enumerated a directory whose\r\n  first matching row was a filesystem-order coin, so a green could name the wrong perch. The\r\n  repaired resolver refuses an ambiguous candidate set instead of guessing, and the fixture's\r\n  `assert_only_ancestor_candidate` now re-reads every `info.json` rig-side\r\n  (`twohost_cli.rs:439-457`). Refusal is enforcement, not observability: it proves a tie but still\r\n  offers no supported verb that names each holding process.\r\n- **Remedy direction:** add one machine-readable, named-perch inspection surface that reports the\r\n  custody fields the product actually used — holder pid and role/source (bind relay, stable harness\r\n  parent, brokered controller/session) — without asking callers to parse private `info.json` or\r\n  scan the process table. PID alone is recyclable; where a birth/image/session stamp exists, carry\r\n  it so the output does not become a new bare-pid oracle.\r\n- **Kin:** [[IR-18]] (read primitive loses error class, explicitly distinct), [[IR-71]] (release\r\n  completion lacks a persisted breadcrumb), REQ-HAZARD-SELF-DETECT-TIE (refuse ambiguous ancestry\r\n  rather than select by enumeration order).\r\n- **Ripe when:** the next roster/status read-model change or another rig needs to reap a named\r\n  holder. **Size:** small read-model/API addition, medium if seat and perch custody need separate\r\n  typed variants.\r\n\r\n### IR-73 — ci.yml and release.yml still read the free-space floor PRE-checkout (literal-first sites off the golden path); and any job's floor is stale by its last heavy step\r\n\r\n- **Status:** CLOSED / BUILT — source reconciliation 2026-09-11 at `e5a2fed9`: all five\r\n  `ci.yml` sites and all three `release.yml` sites now read after checkout, with IR-73 comments;\r\n  `golden.yml` has both docs-floor rereads. IR-86 records the docs reread's live catch.\r\n  The original two halves below are implemented; capacity sizing and docs dependency coupling\r\n  remain OPEN under IR-86, not a reason to redispatch these eight reorders.\r\n  Filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep (deployah flag 2026-08-29).\r\n  · **Origin:** #242's two lost golden attempts exposed the pre-checkout read; the original\r\n  golden-only correction deliberately left the eight other sites for the now-built rider.\r\n- **What/why:** review each of the 8 sites' comments for checkout-protective purpose (the\r\n  `ac7d2609` method), then reorder the read after checkout or RECORD why not, per site. The\r\n  \"other jobs keep the literal-first shape\" clause is the trap's carrier: every un-reviewed site\r\n  is a queued golden-attempt loss on a loaded box.\r\n- **Second half (from #242 r4, same family):** a single job-start floor read is stale by the\r\n  job's LAST heavy step — the r4 LNK1318 low-water face recorded on [[IR-59]] (sixth face);\r\n  the within-job re-read before the docs-drift build rides the next workflow commit alongside\r\n  this entry's reorders.\r\n- **Kin:** [[IR-46]] (a floor asserts an instant), [[IR-59]] (full volume reds as a linker\r\n  defect), REQ-CI-FREE-SPACE-PREFLIGHT.\r\n- **Ripe when:** next touch of `ci.yml`/`release.yml`, or the next intake's tooling-rider slot\r\n  (compose with IR-59/IR-57's standing pair). · **Size:** small — reorder or comment per site,\r\n  8 sites.\r\n\r\n### IR-74 — kitsubito holds 21,643 /tmp endpoint homes: box-side accumulation nothing bounds or measures\r\n\r\n- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep; measurement by\r\n  hertz (2026-08-29). · **Origin:** rig work on kitsubito found `/tmp` carrying 21,643 endpoint\r\n  homes — per-run spt homes that outlive their runs.\r\n- **What/why:** sibling of the [[IR-31]]/[[IR-59]]/[[IR-64]] family (box accumulation the\r\n  preflights never see): each is small, the population is not, and /tmp on a long-lived box is\r\n  never reaped by CI. Un-reaped homes also widen every by-path census a rig runs. Needs a\r\n  bounded lifecycle (per-run temp root reaped at run end, or a box-side sweep with a stated\r\n  retention), and the reap must state its count so a zero is a claim.\r\n- **Ripe when:** next kitsubito rig touch, or the between-milestone box-audit slot.\r\n- **Size:** small (one sweep script + adoption in the box's rig steps); the measurement rerun is\r\n  one `find | wc`.\r\n\r\n### IR-75 — traceable-reqs is not installed on kitsubito, so every Linux gate driver's treqs leg exits 127 (vacuous, wrapper-green shape)\r\n\r\n- **Status:** OPEN, filed by doyle 2026-08-30 at the #242/v0.66.0 close sweep (deployah\r\n  co-flagged at intake). · **Origin:** ASM-241 Linux battery — `ASM_treqs.exit` = 127, raw\r\n  `env: 'traceable-reqs': No such file or directory`; leg vacuous, covered that day by the\r\n  Windows treqs = 0 at the identical tree (treqs is a platform-independent text scan).\r\n- **What/why:** a 127 leg is exactly the wrapper-green shape [[IR-60]] documents — a driver that\r\n  doesn't read the exit FILE would report the leg green. Fix is either: install traceable-reqs on\r\n  kitsubito (then the leg is real), or DROP the leg from Linux gate drivers and state the\r\n  Windows-covers-it rule in the driver comment. Do NOT reopen [[IR-37]] for this — IR-37's\r\n  consume lane is spt-core CI (GitHub runners, green all week); this is BOX tooling, a different\r\n  surface (ruled at the sweep against the enumerating agent's overcautious flag).\r\n- **Ripe when:** next Linux gate-driver touch or kitsubito box-audit slot.\r\n- **Size:** trivial (install or one driver edit + comment).\r\n\r\n### IR-76 — hfenduleam is the golden Windows runner AND the builders' box: a local workspace nextest fully contained a golden Phase A and manufactured a load-timing red, and the job-start census cannot see it\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-06 during v0.67.1 golden triage (run 34017906638\r\n  att2). · **Origin:** the Windows Phase A red on\r\n  `spt-store::wtlock_two_process_int two_processes_commit_into_one_worktree_without_failing`\r\n  (B hit the 10 s worktree-lock bound while A's six serial commits took 13.5 s; 12 other\r\n  cells ran >10 s in the same phase). Load audit by todlando from his own `.raw`\r\n  CreationTimeUtc / `.exit` LastWriteTimeUtc: his #276 gate's 1240-cell workspace nextest\r\n  (`--no-fail-fast`, test phase 08:50:06–08:58:00Z) FULLY CONTAINED the golden Phase A\r\n  (08:52:38–08:56:49Z), every core saturated. He had been dispatched into that window and\r\n  never told the box was under a golden hold; perri and hertz had been.\r\n- **What/why:** two mechanisms, both unmeasured by anything in CI today. (1) The box is\r\n  shared by design — every agent's gate rig, adapter build and workspace nextest runs on the\r\n  same host as the self-hosted golden Windows runner, so a golden Windows leg is a QUIET\r\n  WINDOW only if every agent knows it is open; nothing says so, and a dispatch brief that\r\n  starts a gate is exactly how a builder lands inside it. (2) The job-start\r\n  `reap-census.ps1` counts the SPT FAMILY only (`family_total=12 scoped=0 unscoped=12` at\r\n  att2's 08:39:46Z start, with a builder's prebuild live on the box); cargo/nextest/rustc\r\n  load is outside its predicate, so the one instrument that runs at the right moment is\r\n  blind to the load that matters. Every load-timing red on Windows therefore triages as a\r\n  random victim with the cause off the record — the [[IR-63]] \"one random victim per sweep\"\r\n  face, now with a named source.\r\n- **Fix shape:** (a) driver templates (every gate/battery driver an agent authors here)\r\n  gain a PRE-FLIGHT leg with THREE outcomes, never two (todlando's amendment at filing: an\r\n  empty `gh run list` is the same bytes for CLEAR and for a broken meter — wrong filter,\r\n  expired token, rate limit, wrong repo default all return exit 0 and no rows — so a\r\n  two-arm guard fails OPEN into the exact hazard it guards, the `--commit <short-sha>`\r\n  confident-EMPTY class): run `gh run list --workflow golden --status in_progress`; rows\r\n  present -> HOLD, print the run id; no rows AND a positive control (`gh run list -L 1`\r\n  unfiltered, or `gh auth status`) returns a row -> CLEAR; control empty or erroring ->\r\n  REFUSE and say the meter is broken. A refusal, not a warning, so a wrapper-green shape\r\n  cannot swallow it ([[IR-60]]); the dispatch-brief line in (b) is likewise a MEASURED\r\n  clear with a live meter, never the absence of a sentence; (b) dispatch briefs that start a gate NAME the hold state of the box; (c)\r\n  the job-start census gains a second predicate — cargo/nextest/rustc/link processes by\r\n  image name, count + total CPU — reported beside the family count so a red's triage can\r\n  place foreign load from the log alone; (d) the golden hand-off contract\r\n  (docs/golden-head-intake) states the quiet-window rule once.\r\n- **Kin:** [[IR-63]] (random victim per sweep), [[IR-59]] (box conditions the preflights\r\n  never see), [[IR-64]] (hfenduleam's non-CI payload), FLAKE-LEDGER rows for\r\n  `wtlock_two_process_int` and `attach_link_push_e2e` (2026-09-06).\r\n- **Ripe when:** next driver-template touch (a/b are text; a is one leg), next `ci.yml`\r\n  touch for (c) — compose with [[IR-73]]'s reorders; (d) rides the next runbook edit.\r\n- **Size:** small — one pre-flight leg + one census predicate + two doc sentences.\r\n\r\n### IR-77 — nothing stamps the interval between a daemon child's spawn and the brain's first log line, so a readiness-deadline red cannot say WHERE the time went\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-07 from the W1 #249 kitsubito battery at the gated\r\n  sha `8d980fdf`; doyle-ruled at filing to be a register entry rather than a lane rider. ·\r\n  **Origin:** FLAKE-LEDGER `resident_service_e2e` :453 PRECONDITION (53 s) and\r\n  `resume_no_control_steal_e2e` (46 s), co-victims of ONE window — nextest exit 100, ONE\r\n  Summary `2999 tests run: 2997 passed (8 slow, 1 leaky), 2 failed, 1 skipped`. Evidence\r\n  preserved at `.spt/preserved/w1-kitsubito-8d980fdf/nextest.raw`, sha256\r\n  `9c456e21a6a0f75d8b0375ac648f232dba07f3887ec5e8dc232daef36253b51e`, hash-verified against\r\n  the kitsubito original.\r\n- **What/why:** both reds are a 45 s wait on `brain.ready` that expired, and the panel each\r\n  one prints shows the tree ALIVE — `BRAIN_UP`, `BRAIN_PHASE:announce done in 1ms`,\r\n  `BRAIN_PHASE:resume done in 0ms`, `SERVICE_STARTED` for both services, both later reaped\r\n  with an empty survivor set. So the daemon came up; it came up after the clock. WHERE those\r\n  45 s went is not recoverable from any artifact we keep: the first timestamped line in the\r\n  daemon's own sink is emitted by a process that has already started, and nothing stamps the\r\n  interval from the test's `Command::spawn` to it. The consequence is that every red of this\r\n  family is triaged by inference — v0.66.0 measured a ~10.1 s exe-hash on the ready path, and\r\n  that number is a CANDIDATE for the gap and can never be more than a candidate while the\r\n  interval is unmeasured. Remedy: one monotonic breadcrumb at daemon-child entry (before any\r\n  work), a second at the point `brain.ready` is stamped, both into the stderr sink the panel\r\n  already renders — then a red of this family reports its own split without a rerun.\r\n- **Kin:** [[IR-71]] (a seat release with no breadcrumb, same shape one layer over),\r\n  FLAKE-LEDGER `resident_service_e2e` :453 and `resume_no_control_steal_e2e` (2026-09-07),\r\n  and the HEAVY census stanza in `.config/nextest.toml`, which hardens the RECIPE these reds\r\n  came from and deliberately leaves the deadlines alone — a budget retune is the same race\r\n  with a different number, and it would also destroy the only signal this entry wants.\r\n- **Ripe when:** the next touch of the daemon boot path or of `brainproc`'s ready stamp; also\r\n  ripe as a rider on any lane that re-opens this test family.\r\n- **Size:** small — two `emit_line_err!` breadcrumbs and the sentence in the panel that says\r\n  what they mean.\r\n\r\n### IR-78 — `SPT_TEST_EPHEMERAL_ADVISORY_PORTS` silently overrides an explicitly set `SPT_DOCS_PORT`\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-07, MEASURED by doyle the same night on his W2\r\n  field pair (both boxes). · **Origin:** the 5474 rig-hygiene sweep in\r\n  `test/rig-advisory-ports-and-heavy-class`, which sets the rig flag at 37 `spt daemon run`\r\n  spawn sites.\r\n- **What/why:** `resolve_daemon_docs_port` (crates/spt-daemon/src/docshost.rs) returns `0`\r\n  whenever the rig flag is set, BEFORE the `SPT_DOCS_PORT` env override is consulted. With\r\n  both set, doyle's rig daemons took ephemeral ports (`DOCS_SERVER_UP` on 55369 Windows,\r\n  44015 Linux) while `SPT_DOCS_PORT=5480` was ignored without a word. The precedence itself is\r\n  defensible — the rig flag exists precisely so a test tree cannot take a well-known port —\r\n  but a SET override discarded in SILENCE is the shape IR-37 files under a different name: the\r\n  operator is left believing the value they set is the value in force. Remedy is a line, not a\r\n  redesign: emit one notice naming both env vars when the flag wins. No test cell is proposed\r\n  with it — none of the 31 swept binaries asserts on a docs port, so a cell here would assert\r\n  a behaviour nothing consumes.\r\n- **Kin:** [[IR-37]] (a set input silently ignored), the 5474 hygiene sweep, and the\r\n  `DOCS_SERVER_BIND_FAIL: port 5474: Address already in use (os error 98)` lines in\r\n  `.spt/preserved/w1-kitsubito-8d980fdf/nextest.raw` that started the sweep.\r\n- **NOT measured, stated so nobody reads it as covered:** doyle measured that the WMI\r\n  auto-start rung DOES carry the caller's environment (rig daemon pid 50088 on hfenduleam:\r\n  `DAEMON_LAUNCH_VIA_WMI`, its environ carrying `SPT_HOME`, `SPT_DOCS_PORT` and the rig flag\r\n  as his shell set them, `brain.ready` in the rig home). The schtasks (at-logon) rung was NOT\r\n  measured, and neither was the unix path.\r\n- **Ripe when:** the next `docshost.rs` touch, or the first time someone sets `SPT_DOCS_PORT`\r\n  on a rig and believes it.\r\n- **Size:** tiny — one emitted notice.\r\n\r\n### IR-79 — 22 of the 31 rig binaries leak their daemon tree on a failing assert: teardown is a statement, not a guard\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-07 on doyle's dispatch during PR #198's CI window,\r\n  from todlando's red 6 (a stale same-port daemon from his own previous run answering the next\r\n  one). · **Origin:** PR #198 moved 31 rigs to `SPT_TEST_EPHEMERAL_ADVISORY_PORTS=1`. Under an\r\n  ephemeral port a leaked daemon can no longer ANSWER the next run, so that PR is right as it\r\n  stands and this entry is not a defect in it; what remains is the orphan process itself — it pins\r\n  `spt.exe` (the Windows delete-and-rebuild hazard) and holds an `SPT_HOME` that nothing reaps. · **SCOPE BROADENED 07:20Z:** the title says \"on a failing\r\n  assert\" because that is the face it was filed from; the SECOND FACE bullet below shows the same\r\n  mechanism firing on a nextest TIMEOUT and leaking THREADS rather than a daemon. Read the title as\r\n  the handle, not the boundary — the trigger is any exit that does not reach the teardown statement.\r\n- **What/why:** measured over the 31, classifying each binary by whether its daemon teardown\r\n  survives a panic (a failing `assert!` unwinds, so only a guard or an ordering discipline saves\r\n  the child):\r\n  - **panic-safe, 9:** `impl Drop` guard — `endpoint_autostart_e2e`,\r\n    `knock_mutual_cross_node_e2e`, `twohost_cli`; `catch_unwind` teardown —\r\n    `activity_link_push_e2e`, `attach_link_push_e2e`, `wake_resume_bind_e2e`;\r\n    teardown-then-assert with zero exposed asserts — `endpoint_teardown_authority_e2e`,\r\n    `er_briefing_session_scoped_e2e`, `er_sequestered_cwd_e2e`.\r\n  - **leaks on a failing assert, 22** (exposed asserts / total asserts in the test body):\r\n    `projindex_writer_e2e` 21/21, `projindex_reader_e2e` 18/18,\r\n    `live_adapt_translation_swap_e2e` 15/38, `brain_split` 12/12,\r\n    `er_briefing_presented_e2e` 10/28, `rc_attach_truth` 8/29, `brain_respawn_rename` 6/6,\r\n    `dummy_harness_e2e` 4/11, `idle_edge_drain_e2e` 4/11, `multi_subnet_bringup_e2e` 4/20,\r\n    `bind_honest_cross_perch_e2e` 3/6, `idle_edge_seal_e2e` 3/17, `resident_service_e2e` 3/24,\r\n    `attach_wedge_e2e` 2/8, `bind_cwd_project_e2e` 2/8, `daemon_refresh_e2e` 2/11,\r\n    `er_brief_once_per_session_e2e` 2/13, `n1_pairing` 2/5, `resume_template_e2e` 2/10,\r\n    `run_no_dup_session_e2e` 2/14, `er_briefing_presentation_e2e` 1/4,\r\n    `livehost_bootgate_e2e` 1/3.\r\n  **FIRST WAVE of the Drop-guard generalization lane (doyle-ruled 2026-09-07, composed at the next\r\n  register sweep, not now): `projindex_writer_e2e`, `projindex_reader_e2e`, `brain_split`,\r\n  `brain_respawn_rename`.** These four expose EVERY assert they have — their teardown is the last\r\n  statement in the body, so any red at all leaks, which makes them both the worst cases and the\r\n  cleanest proofs that a guard works. The remedy already exists in this tree —\r\n  todlando's `DaemonReaper`, a `Drop` guard armed BEFORE the first CLI call — and the follow-up\r\n  lane is to generalise it into `crates/spt/tests/common` and adopt it at these 22 sites, which is\r\n  also the only shape that covers a `SIGKILL`-free timeout kill by nextest.\r\n- **METHOD, and its limits, so the count can be re-derived and challenged:** the classifier reads\r\n  each `#[test]` body, resolves file-local helper fns whose own body tears down (so a teardown\r\n  called through `sweep()` counts), and reports every `assert!`/`panic!` positioned before the LAST\r\n  teardown call in that body. It therefore (a) misses asserts written inline inside a closure or a\r\n  macro argument rather than at statement position, (b) treats the last teardown as THE teardown —\r\n  a partial earlier teardown still leaves the tree, so the true exposure is >= this count, and\r\n  (c) does not model `?` or early `return`. Spot-verified by hand on `resident_service_e2e`, whose\r\n  3 exposed asserts are real: they fire in the `wait_until` legs well before the `sweep()` at :435\r\n  that the \"── ASSERTIONS ──\" block follows.\r\n- **TONIGHT'S LIVE SAMPLE, so this is not an academic count (doyle's hfenduleam census 06:43Z):**\r\n  10 leaked `spt.exe` from todlando's pool, pairing by start time, from his pre-yield legs — a\r\n  single evening's rig work on one box. Each pins the binary against a rebuild and holds an\r\n  `SPT_HOME` nothing reaps.\r\n- **SECOND FACE — the same hazard in THREAD clothes, and it blocks the RUNNER, not just the box\r\n  (measured by todlando 07:17Z, relayed by doyle 07:20Z; I did not measure it myself and record it\r\n  as his testimony):** a nextest TIMEOUT on a `twohost_web` cell left the cell's child process\r\n  holding the broker + listener THREADS. Consequences, with his numbers:\r\n  - nextest itself blocked **14 minutes** at **0.61 CPU-seconds** — a wall-clock hang with\r\n    essentially no CPU, which is the signature of a parent waiting on a child's pipe rather than\r\n    of work being done;\r\n  - **`a.exit` was never written**, while **every verdict was already in `a.raw`** — so the leg\r\n    read as INCOMPLETE at the exact moment its results were complete. A reader who trusts the\r\n    exit file over the raw would call this a hung or failed leg and rerun it;\r\n  - **killing the path-verified orphan let the parent finish at once** — which is the causal test,\r\n    not a correlation: the kill is the intervention and the unblock is the response.\r\n  **Why it belongs in THIS entry rather than a new one:** the leaked thing is a thread inside a\r\n  child, not a daemon, but the mechanism is identical — a teardown that is a STATEMENT does not run\r\n  when the body does not reach it, and a timeout kill reaches the body even less reliably than a\r\n  panic does. The `Drop`-guard lane covers both faces with one remedy, which is doyle's ruling and\r\n  the reason no separate entry is opened. It also raises the lane's value: the daemon face costs a\r\n  pinned binary and an unreaped `SPT_HOME`, this face costs **14 minutes of a serialized golden\r\n  leg** and manufactures a false INCOMPLETE.\r\n  **Reading rule this hands the gate, worth stating because it is cheap:** when a leg's `.exit` is\r\n  missing, read the `.raw` for a Summary BEFORE concluding the leg hung — kin to\r\n  [[a-stopped-local-ssh-does-not-stop-its-remote-command]], where the raw was likewise the honest\r\n  record and the wrapper was not.\r\n- **Kin:** FLAKE-LEDGER `resident_service_e2e` :664 teardown LEAK row (3 occurrences, the Windows\r\n  face of the same class), [[IR-34]], [[IR-74]] (kitsubito's 21,643 `/tmp` endpoint homes — this is\r\n  one of the producers), and todlando's red 6.\r\n- **Ripe when:** the next lane that touches `crates/spt/tests/common` — the guard belongs there,\r\n  not copied 22 times.\r\n- **Size:** medium — one guard in `common`, then 22 mechanical adoptions, each provable by\r\n  panicking the body under a temporary test and watching the census go quiet.\r\n\r\n### IR-80 — five leaky cells on ONE module (`brainproc` / `supervise_brain`), Windows only: a candidate PRODUCT leak on the promotion/rollback path, or a cluster of names — nobody has looked yet\r\n\r\n- **Status:** OPEN for the residual population, not an undiagnosed five-name product claim.\r\n…\n  roster was read out of the baseline golden log for an unrelated reason.\n…\n\n…\n","startLine":3682,"lineNumbers":[3682,null,3684,null,3703,3704,3705,3706,3707,3708,3709,3710,3711,3712,3713,3714,3715,3716,3717,3718,3719,3720,3721,3722,3723,3724,3725,3726,3727,3728,3729,3730,3731,3732,3733,3734,3735,3736,3737,3738,3739,3740,3741,3742,3743,3744,3745,3746,3747,3748,3749,3750,3751,3752,3753,3754,3755,3756,3757,3758,3759,3760,3761,3762,3763,3764,3765,3766,3767,3768,3769,3770,3771,3772,3773,3774,3775,3776,3777,3778,3779,3780,3781,3782,3783,3784,3785,3786,3787,3788,3789,3790,3791,3792,3793,3794,3795,3796,3797,3798,3799,3800,3801,3802,3803,3804,3805,3806,3807,3808,3809,3810,3811,3812,3813,3814,3815,3816,3817,3818,3819,3820,3821,3822,3823,3824,3825,3826,3827,3828,3829,3830,3831,3832,3833,3834,3835,3836,3837,3838,3839,3840,3841,3842,3843,3844,3845,3846,3847,3848,3849,3850,3851,3852,3853,3854,3855,3856,3857,3858,3859,3860,3861,3862,3863,3864,3865,3866,3867,3868,3869,3870,3871,3872,3873,3874,3875,3876,3877,3878,3879,3880,3881,3882,3883,3884,3885,3886,3887,3888,3889,3890,3891,3892,3893,3894,3895,3896,3897,3898,3899,3900,3901,3902,3903,3904,3905,3906,3907,3908,3909,3910,3911,3912,3913,3914,3915,3916,3917,3918,3919,3920,3921,3922,3923,3924,3925,3926,3927,3928,3929,3930,3931,3932,3933,3934,3935,3936,3937,3938,3939,3940,3941,3942,3943,3944,3945,3946,3947,3948,3949,3950,3951,3952,3953,3954,3955,3956,3957,3958,3959,3960,3961,3962,3963,3964,3965,3966,3967,3968,3969,3970,3971,3972,3973,3974,3975,3976,3977,3978,3979,3980,3981,3982,3983,3984,3985,3986,3987,3988,3989,3990,3991,3992,3993,3994,3995,3996,3997,3998,3999,4000,4001,4002,4003,4004,4005,4006,4007,4008,4009,4010,4011,4012,4013,4014,4015,4016,4017,4018,4019,4020,4021,4022,4023,4024,4025,4026,4027,4028,4029,4030,4031,4032,4033,4034,4035,4036,4037,4038,4039,4040,4041,4042,4043,4044,4045,4046,4047,4048,4049,4050,4051,4052,4053,4054,4055,4056,4057,4058,4059,4060,4061,4062,4063,4064,4065,4066,4067,4068,4069,4070,4071,4072,4073,4074,4075,4076,4077,4078,4079,4080,4081,4082,4083,4084,4085,4086,4087,4088,4089,4090,4091,4092,4093,4094,4095,4096,4097,4098,4099,4100,4101,4102,4103,4104,4105,4106,4107,4108,4109,4110,4111,4112,4113,4114,4115,4116,4117,4118,4119,4120,4121,4122,4123,4124,4125,4126,4127,null,4133,null,4190,null,4406]},"fileSize":512411,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\INFRA-REGISTER.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":5900,"totalBytes":35564,"outputLines":425,"outputBytes":35564,"shownRange":{"start":3703,"end":4127},"nextOffset":4128}}},"isError":false,"timestamp":1789107053429}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_QSgZhoFnAXQ0hPoJyqu5BAn0|fc_0330c101aa2c61dc016aa39b739b8c87d1ba6e8b2d05d89ca7","toolName":"read","startedAt":"2026-09-11T06:11:02.036Z","args":{"path":"docs/INFRA-REGISTER.md:4988-5404"},"intent":"Reading remaining register capacity entries"},"id":"f5e0bc40","parentId":"6ed3e6ac","timestamp":"2026-09-11T06:11:02.036Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_hTpV277YoFnrWGHlQnPcKk7N|fc_0330c101aa2c61dc016aa39b739b9887d1bc614f18aaedb9e8","toolName":"read","startedAt":"2026-09-11T06:11:02.036Z","args":{"path":"docs/INFRA-REGISTER.md:5405-5900"},"intent":"Reading final register entries"},"id":"4b84a48f","parentId":"f5e0bc40","timestamp":"2026-09-11T06:11:02.036Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_q80EtOd43vcv1eFRkV85eAEP|fc_0330c101aa2c61dc016aa39b739ba487d1b53655ebed36d720","toolName":"grep","startedAt":"2026-09-11T06:11:02.036Z","args":{"path":"docs"},"intent":"Locating close reconciliation evidence"},"id":"c9499d1c","parentId":"4b84a48f","timestamp":"2026-09-11T06:11:02.036Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_ApWKh6YJsHgT9hQLqIqfuYLr|fc_0330c101aa2c61dc016aa39b739ba887d1aca38b69832057d1","toolName":"read","startedAt":"2026-09-11T06:11:02.036Z","args":{"path":"CONTEXT.md:1-100"},"intent":"Reading project current model"},"id":"572954a6","parentId":"c9499d1c","timestamp":"2026-09-11T06:11:02.036Z"}
{"type":"message","id":"83ee0759","parentId":"572954a6","timestamp":"2026-09-11T06:11:02.037Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_QSgZhoFnAXQ0hPoJyqu5BAn0|fc_0330c101aa2c61dc016aa39b739b8c87d1ba6e8b2d05d89ca7","name":"read","arguments":{"i":"Reading remaining register capacity entries","path":"docs/INFRA-REGISTER.md:4988-5404"},"intent":"Reading remaining register capacity entries"},{"type":"toolCall","id":"call_hTpV277YoFnrWGHlQnPcKk7N|fc_0330c101aa2c61dc016aa39b739b9887d1bc614f18aaedb9e8","name":"read","arguments":{"i":"Reading final register entries","path":"docs/INFRA-REGISTER.md:5405-5900"},"intent":"Reading final register entries"},{"type":"toolCall","id":"call_q80EtOd43vcv1eFRkV85eAEP|fc_0330c101aa2c61dc016aa39b739ba487d1b53655ebed36d720","name":"grep","arguments":{"i":"Locating close reconciliation evidence","pattern":"IR-(57|59|63|72|78|79|81|82|84|89|90|93|94|95|97)|REMOTE-FRICTION|#304","path":"docs","case":false,"gitignore":true,"skip":null},"intent":"Locating close reconciliation evidence"},{"type":"toolCall","id":"call_ApWKh6YJsHgT9hQLqIqfuYLr|fc_0330c101aa2c61dc016aa39b739ba887d1aca38b69832057d1","name":"read","arguments":{"i":"Reading project current model","path":"CONTEXT.md:1-100"},"intent":"Reading project current model"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":30985,"output":188,"cacheRead":34688,"cacheWrite":0,"totalTokens":65861,"cost":{"input":0.30985,"output":0.0094,"cacheRead":0.034688,"cacheWrite":0,"total":0.35393800000000003}},"stopReason":"toolUse","timestamp":1789107053473,"responseId":"resp_0330c101aa2c61dc016aa39b6b6ee887d184662833f18e89c1","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0330c101aa2c61dc016aa39b739b8c87d1ba6e8b2d05d89ca7","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading remaining register capacity entries\",\"path\":\"docs/INFRA-REGISTER.md:4988-5404\"}","call_id":"call_QSgZhoFnAXQ0hPoJyqu5BAn0","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b739b9887d1bc614f18aaedb9e8","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading final register entries\",\"path\":\"docs/INFRA-REGISTER.md:5405-5900\"}","call_id":"call_hTpV277YoFnrWGHlQnPcKk7N","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b739ba487d1b53655ebed36d720","type":"function_call","status":"completed","arguments":"{\"i\":\"Locating close reconciliation evidence\",\"pattern\":\"IR-(57|59|63|72|78|79|81|82|84|89|90|93|94|95|97)|REMOTE-FRICTION|#304\",\"path\":\"docs\",\"case\":false,\"gitignore\":true,\"skip\":null}","call_id":"call_q80EtOd43vcv1eFRkV85eAEP","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"grep","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b739ba887d1aca38b69832057d1","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading project current model\",\"path\":\"CONTEXT.md:1-100\"}","call_id":"call_ApWKh6YJsHgT9hQLqIqfuYLr","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}}]},"duration":8549.477199999616,"ttft":8487.987299999222,"completedAt":1789107062034,"contextSnapshot":{"promptTokens":65673,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"message","id":"e5085ead","parentId":"83ee0759","timestamp":"2026-09-11T06:11:02.045Z","message":{"role":"toolResult","toolCallId":"call_QSgZhoFnAXQ0hPoJyqu5BAn0|fc_0330c101aa2c61dc016aa39b739b8c87d1ba6e8b2d05d89ca7","toolName":"read","content":[{"type":"text","text":"### IR-86 — golden's 32 GiB floor is BELOW the measured 67.4 GiB Windows suite footprint, so a start floor passes a box that cannot finish\n…\n- **Status:** OPEN, filed by doyle 2026-09-08 at the #272/v0.68.0 golden r2 triage. · **Origin:**\n  run 34262154550 @ `25e60015` (shaped on `e4444413`), Windows test job 102182665033: every product\n  step green (Phase A 3346/3346, Phase B 234/234, Summary 2, FAIL 0), the ONLY reds were the two\n  in-job floor gates. `FLOOR_START` 97,649,786,880 B PASS at 18:47:23Z -> `FLOOR_DOCS`\n  25,284,501,504 B RED at 19:31:55Z -> `FLOOR_END` RED. Consumed in-job: 67.4 GiB.\n- **Mechanism:** `golden.yml` derives 32 GiB as \"the observed tens-of-GB full-suite footprint\n  rounded up to the next binary boundary, preserving headroom for one complete run\" (comment\n  above the Windows start floor). The measured footprint is 67.4 GiB, so a start reading anywhere\n  in [32, ~100) GiB passes and the job then walks under the floor by construction: box baseline\n  91 GiB minus 67.4 = 23.5 < 32. This is a shortfall of the DERIVATION, not a rate, not a product\n  red, and not the instant-vs-sustained face IR-46 files (that face is fixed by the FLOOR_DOCS\n  re-read, which is what caught it). The start floor must be footprint + end-floor (~100 GiB) or\n  it asserts nothing about finishing.\n- **Coverage consequence (the load-bearing part):** the Windows `Docs drift gate (CLI ref + llms\n  links)` step is sequenced BEHIND `FLOOR_DOCS`, so it SKIPPED and r2 held NO Windows CLI-ref\n  axis at that sha until the rerun. A floor red that skips a gate is a coverage hole wearing a\n  disk red.\n- **Kin:** [[IR-46]] (a floor asserts an instant), [[IR-59]] (pool arithmetic, LNK-class reds\n  that name no disk), [[IR-64]] (the operator-payload reservoir that sets the box baseline; its\n  ripe-when arm — a golden that dies at the floor despite adopted pool discipline — FIRED here\n  in the in-job form), [[IR-73]] (second half BUILT: the within-job re-read exists and is what\n  produced the FLOOR_DOCS reading), REQ-CI-FREE-SPACE-PREFLIGHT.\n- **Coupling (deployah 23:54Z, from `golden.yml` at `25e60015`):** the Windows `DISK docs floor`\n  (:616) and `Docs drift gate — windows` (:629) carry only `if: runner.os == 'Windows'`, no\n  `always()`, while `DISK end floor` does (`always() && runner.os == 'Windows'`, ~:705). Actions'\n  default is \"previous steps succeeded\", so ANY Phase B red skips the docs axis by construction —\n  observed three times at this sha (floor red, ttl cell, ttl cell). The docs gate is therefore never\n  independent evidence: it can only be banked when Phase B is green in the same job. Remedy line:\n  gate the two docs steps on `!cancelled()` plus the success of the steps they actually depend on\n  (checkout/build), not on Phase B — a rig change, new sha, hertz workflow rider slot.\n- **Remedy shape:** re-derive the start floor from the measured footprint (67.4 GiB Windows,\n  Linux to be measured) plus the 32 GiB end floor, print the footprint (start minus end free)\n  on every run so the number re-measures itself, and keep the 32 GiB literal only for\n  `FLOOR_END`.\n- **Ripe when:** next `golden.yml` touch (hertz workflow rider slot). · **Size:** small — one\n  literal per start-floor site + one printed subtraction.\n\n### IR-87 — two-host ceremony halves are INDEPENDENT jobs on DIFFERENT runners (A Windows/hfenduleam, B Linux/kitsubito); B's 900 s budget runs on B's own clock, so any older queued Windows job starves A and reds B deterministically, and the panic text blames pairing\n\n- **Status:** OPEN, filed by doyle 2026-09-08 at the #272 golden r2 triage. · **Origin:**\n  run 34262154550, twohost-b job 102207296960 (log 81,692 B, sha256 67403f04…8030): role B built,\n  rostered, polled PAIR_MEET_UP every 30 s from 19:34:30Z, and hit the rig_wait barrier\n  \"pairing: A rostered via the daemon-hosted responder\" at its 900 s deadline 19:49:17Z\n  (`crates/spt-daemon/tests/twohost.rs`, exit 101, 2 passed 1 failed). twohost-a (102207296985)\n  was QUEUED from 19:32:13Z with no runner: the Windows runner went to thin ci run 34261096301\n  (post-merge on main @ `e4444413`) the second the golden test job released it at 19:31:56Z.\n- **Mechanism:** `golden.yml` sequences twohost-a and twohost-b after `test`, but they are two\n  jobs on two runners (measured 2026-09-08 20:56Z via the jobs API `runner_name`: twohost-a on\n  hfenduleam, twohost-b on kitsubito), and GitHub's queue does not honour a workflow's intra-run\n  job ordering against a FOREIGN run on either runner. B starts, its whole budget ticks against a partner that has not been\n  scheduled, and `rig_wait` panics `never converged on the rig: {what}` — a text that reads as a\n  pairing defect. The lanes were not at fault, and twohost-a's outcome was predetermined once B\n  exited (a later A pass would be vacuous).\n- **Kin:** [[IR-76]] (hfenduleam is golden runner AND builders' box; the job-start census cannot\n  see a competing GitHub run either), [[IR-62]] (rig collisions on shared runners), the W1 two-host\n  rig, `a-barrier-cannot-ride-a-carrier-its-sender-outlives` (memory, same family: a barrier needs\n  the receiver's own answer).\n- **Remedy shape (pick at rider time):** (1) start barrier on B keyed to A's job having STARTED\n  (a run-scoped artifact or a `needs`+matrix collapse into ONE job that spawns both roles), or\n  (2) B's deadline clock starts at first A-rostered signal with a separate, longer \"A never\n  appeared\" budget, or (3) the panic names the missing partner's job state so triage does not\n  chase pairing. Any option: the two-host halves must never share a runner queue with a foreign\n  run while one half waits.\n- **Ripe when:** next `golden.yml`/twohost rig touch. · **Size:** small-medium (job shape or\n  barrier rework + panic text).\n\n- **AMENDMENT 2026-09-10 (releases#294, golden 34445961595 att1 @ `a9e786b2`) — THE STARVING RUN CAN\n  BE GOLDEN'S OWN PR, which makes this self-inflicted and recurrent on every golden run with a PR\n  open.** Measured timeline: **07:18:59Z** golden `test (Windows)` completes and releases hfenduleam;\n  **07:18:59Z** twohost-a queued; **07:19:01Z** PR run **34446095808** job `unit (Windows,\n  hfenduleam)` SEIZES the runner; **07:19:02Z** twohost-b starts on the free kitsubito; **07:36:16Z**\n  twohost-b fails at **900.41s** — `never converged on the rig: pairing: A rostered via the\n  daemon-hosted responder`. The origin case (2026-09-08) was a post-merge push on `main`: a run\n  belonging to someone else. **Here the starving run is the `pull_request` run of the very PR carrying\n  the golden head**, so opening the golden PR arms the starvation of that same head's twohost pair.\n  **Consequence for the remedy shape above: any option that only de-conflicts against OTHER lanes'\n  runs does not reach this case.** The golden head's own PR has to be excluded from the Windows\n  runner for the duration of the golden run (or the pair collapsed into one job, option 1).\n- **SECOND-ORDER FACE (deployah, same run): starvation does not merely red B — it desynchronises the\n  pair past repair.** twohost-b was TERMINAL at 07:36:16Z; twohost-a did not start until **07:48:07Z**\n  — the two halves never overlapped for a single second, so twohost-a's outcome is uninformative\n  **whatever it says**, and a red there must not be counted as a second product failure. Recorded\n  honestly at deployah's own insistence: **VOID is his SCORING interpretation, not a fact about the\n  run** — the release record carries GitHub's raw `conclusion` for both jobs beside the scoring, not\n  laundered into it.\n- **⚠ ITS WALL CLOCK IS INDISTINGUISHABLE FROM [[IR-89]]'s.** A 900 s twohost red whose panel blames\n  pairing is ALSO the exact signature of the banked Windows-firewall hazard. The panel alone cannot\n  separate them; **the job TIMELINE can**. Check the schedule before accepting the firewall hazard for\n  any 900 s twohost red — this one fit that signature perfectly and was not it.\n\n### IR-88 — `pool-release` via `cargo run -p xtask` REBUILDS xtask INTO the pool it is releasing, so a reaped pool regrows ~2.8 GB in silence\n\n- **Status:** OPEN, filed by doyle 2026-09-08 from hertz's reap report (20:00Z) during the #272\n  golden r2 repair. · **Origin:** hertz reaped hertz-lane4 / hertz-repin / hertz-percell-id target\n  subtrees (Length-sum upper bounds 68.16 / 47.11 / 8.79 GB) and then ran `cargo run -p xtask --\n  pool-release …` from each worktree: cargo rebuilt xtask into the just-reaped `target/` (2.8 GB\n  back in lane4, partial in repin), nothing printed said so, and the descendancy stopper killed\n  the second before it finished. Removed by hand afterwards; the post-reap free reading on the\n  record (275.95 GiB at 19:55:51Z) predates the regrowth.\n- **Mechanism:** the documented verb (AGENTS.md: \"drop it with `pool-release`\") is a `cargo run`,\n  and cargo's default target for that run IS the pool being released. The verb's own success path\n  recreates the state the operator just measured away; a teardown step that runs it AFTER a reap\n  undoes part of the reap and leaves the recorded free reading stale.\n- **Remedy shape:** either (a) `pool-release` documented and scripted as a PREBUILT `xtask.exe`\n  invoked against `--pool <dir>` from another pool, or (b) the verb refuses when its own\n  `CARGO_TARGET_DIR`/default target equals `--pool` and prints the prebuilt form, or (c) the reap\n  recipe orders release BEFORE the subtree delete. Memory banked 2026-09-08\n  (`pool-release-rebuilds-xtask-into-the-pool-you-just-reaped`); this entry is the durable home.\n- **POSITIVE CONTROL (hertz, 2026-09-09, ruling-3 gate-r3 teardown):** the same release run\n  from a PREBUILT `xtask.exe` invoked from outside the pool regrew NOTHING — the pool's own\n  `xtask.exe` still carried its original 21:00:42 mtime afterwards, and the reap that followed\n  reclaimed 63.71 GiB (132.03 -> 195.74 GiB free) against a 64.88 GiB Length-sum. So the\n  regrowth is a property of the `cargo run` VEHICLE, not of the verb, and remedy (a) is proven\n  rather than merely proposed.\n- **Kin:** [[IR-31]] (pool budgeting), [[IR-56]] (pool-claim identity from CWD — same verb\n  family, same \"the tool acts on where it stands\" shape), releases#103.\n- **Ripe when:** next xtask pool-verb touch or the teardown runbook edit. · **Size:** tiny —\n  one guard or one doc line.\n\n### IR-89 — hfenduleam's Windows Firewall drops cold inbound UDP to the runner-built test exes, so the two-host rig's first B→A claim (W2 helper) reds for its whole 900 s budget and the panic blames A\n\n- **Status:** BOX HALF **APPLIED** 2026-09-08; WORKFLOW HALF **BUILT** 2026-09-09 — PR #211\n  (`9b96d7e7` + this amendment), **LANDED, exact golden-step acceptance unreconciled**.\n  Subsequent goldens have run: \"until the next golden\" is no longer a future trigger.\n  This sweep does not infer probe execution from a run's existence or overall conclusion;\n  retain the step-specific exercised/skipped/failed evidence before closing. Filed by doyle 2026-09-08\n  at the #272 golden r2 terminal triage; the operator-blocked flag is retired here, because\n  the operator acted.\n  The operator applied BOTH layers that evening — the Windows inbound rule (~23:41Z) and the\n  tailnet ACL grant (~23:56Z) — and the re-probe with the same rule-less pwsh listener read\n  **3/3 over Tailscale on 7483 AND 3/3 on 7489 at 23:57:50Z** from `100.98.197.12`, with a\n  post-terminal probe 3/3 on both ports at attempt 4. v0.68.0 then shipped at `a2f335f8` with\n  both two-host legs GREEN on golden r4, so the box half is closed by measurement and not by\n  assertion. **Durable half BUILT, acceptance reconciliation OPEN:** the pre-ceremony B→A\n  probe and its corrections are documented below. Do not redispatch a workflow guard that\n  already landed, or reopen the spent operator permission. The next box/ACL reset remains a\n  recheck trigger. · **Origin:** run 34262154550 @ `25e60015`, twohost-a 102229928746\n  (`two_host_web_helper_role_a`, :968, 900.40 s) and twohost-b 102229928689\n  (`two_host_web_role_b`, :559, 910.20 s): B logged 75 × \"A not ready … broker QUIC op exceeded\n  the 10s bound (peer unresponsive)\" from 20:49:49Z to 21:04:37Z and was never ADMITTED. Ladder\n  green both sides; both halves started 20:41:23Z on their own runners (not IR-87's starvation).\n- **Mechanism (MEASURED 21:11Z):** the box's firewall policy is `BlockInbound,AllowOutbound` on\n  all three profiles (Ethernet and Tailscale both Private). Inbound allow rules exist only for\n  exes under `Documents\\projects\\spt-core\\target` (interactive Allow clicks) and under the DEAD\n  pre-rename runner path `_work\\spt-core\\spt-core`; exactly ONE under `_work\\spt-bs-core` (its\n  `target\\debug\\spt.exe`, the CLI, not the binder — deployah's count, mine had said zero), none for\n  any `twohost_web-*.exe`. `Get-NetFirewallProfile` shows `DefaultInboundAction = NotConfigured`,\n  whose effective default IS block: the block is Windows' default, not a configured policy, so there\n  is no policy to \"restore\". The runner is a service (`.\\decid`), so the Allow dialog that minted the\n  old rules cannot appear. A's helper cell 3 bound `broker udp 7483` inside\n  `_work\\spt-bs-core\\spt-bs-core\\target\\debug\\deps\\twohost_web-f73bc44be13353fb.exe`; B dialled\n  `100.68.35.65:7483` cold. Probe: a rule-less pwsh UDP listener on hfenduleam:7483 received 0 of\n  3 datagrams from kitsubito `100.98.197.12`; the reverse control (python listener on\n  kitsubito:7483) received 3 of 3 from hfenduleam.\n- **Why three faces from one cause:** the shared-key rig (pre-`e4444413`) reached A only through\n  holes A's OUT-dialling cells (7480–7482) had opened for `id_a` — six 10 s bounds until B's\n  magicsock fell onto one of those paths, then ADMITTED (the 63 s stall, helper-stall memory), or\n  onto a live same-key sibling that never replied (the 21 min hang in 34239258523). Per-cell A\n  identity (`id_a_for`, `e4444413`) removed the accidental route by construction, leaving only\n  the cold path, which the firewall drops. hertz's one-box discriminator \"vanishes\" was true on\n  one box because one box never crosses the firewall. Product and rig are both exonerated; the\n  rig's `a_addr` comment already names W2 as the first A-ward claim.\n- **Remedy (two halves):** (1) BOX, operator-owned, elevated on hfenduleam:\n  `New-NetFirewallRule -DisplayName \"spt-ci two-host rig UDP-In (kitsubito only)\" -Direction Inbound -Action Allow -Protocol UDP -LocalPort 7460-7499 -RemoteAddress 100.98.197.12 -Profile Any`\n  (rig ports at the sha: ladder 7460/7461; web `PORT_OFFSET` 20 → A cells 7480–7483, B 7481; the\n  A-ward surface today is exactly UDP 7480–7483 — deployah's tighter range — and the whole range\n  moves with any `SPT_TWO_HOST_PORT_A` override, so the rule must move with it);\n  program-path rules are the wrong shape because the exe hash changes per build. Verify with the\n  same probe (3/3) before any rerun. (2) WORKFLOW, hertz: a B→A UDP probe step in the twohost\n  jobs before the ceremony, so this reds in 10 s with its own name instead of 900 s blaming\n  pairing; and retire the dead `_work\\spt-core` rules note in the runner runbook.\n- **Kin:** [[IR-83]] (the tailnet-ACL face of a cross-box inbound block — KIN, **NOT the same\n  finding**: that entry is the tailnet policy layer, this one is the Windows firewall layer, and\n  the SECOND LAYER note below is exactly the measurement that separates them), [[IR-87]] (the\n  other way a half waits 900 s on a partner), [[IR-76]] (golden runner\n  is the operator's box), [[IR-64]] (box-level facts only the operator can move),\n  `twohost-web-helper-stall-shared-a-identity-stale-path` (memory; its CONFIRMED arm is re-read\n  by this entry).\n- **AMENDMENT 2026-09-09 — the WORKFLOW half is BUILT and FIELD-MEASURED; it is LANDED-pending-golden\n  (hertz).** The guard is two cells in `twohost_web.rs` plus a step per half in `golden.yml`, and it\n  grew four design corrections that are worth more than the guard itself, because each one is a way a\n  probe can certify the fault it exists to catch.\n  1. **A FIXED SYMMETRIC WINDOW ADDS A THIRD CAUSE THAT LOOKS LIKE THE OTHER TWO.** The step boundary\n     orders the probe on ONE host; it does not align two, and after the ladder each half pays its own\n     wrapper and `cargo test` (on Windows a fingerprint scan plus Defender's first touch of a fresh\n     exe). MEASURED: the first hand-run in the A=kitsubito direction (13:14:13 → 13:14:51Z) redded\n     `INBOUND_BLOCKED` at 10.24 s with text asserting \"a BOX rule, not a product or rig fault\" — and\n     the cause was `cargo`'s start-up on the SENDER putting its first datagram after the receiver's\n     10 s window closed. An innocent box, the guard's own words against it. What stopped it being\n     filed as a kitsubito block was that the box facts contradicted the text (`tailscale debug\n     netmap` on kitsubito lists `100.68.35.65/32` among its permitted inbound sources, and `ufw` is\n     inactive) — a failure text that contradicts a measured box is the text's defect. So the\n     rendezvous is DATA: A listens up to the rig budget and beacons once a second; B binds first,\n     waits for a beacon, and only then starts a ten-second clock, so B's red has already excluded\n     \"A is not up\". That is a FOURTH outcome with its own name, `PROBE_NO_BEACON`, never\n     `INBOUND_BLOCKED`.\n  2. **THE LISTENING SOCKET MUST NEVER SEND.** Any outbound datagram from the measured port opens\n     stateful return state for it, so B's probe then arrives SOLICITED and crosses under both layers\n     — this entry's own \"solicited return traffic works under either fault\" applied to the guard\n     rather than to the ceremony. MEASURED: with the beacon sharing A's listening socket, the\n     out-of-grant control went **GREEN at 13:28Z** on a port a listen-only run had measured BLOCKED\n     at 13:20Z; a further green at 13:31Z with the beacon moved but the ack still leaving that socket\n     was residual state from 13:28 — true BY ELIMINATION rather than by assertion: nothing in the\n     13:31 run sent from 7509 before the first arrival, so the only outbound that could have opened\n     that port's return state belongs to the previous run. Beacon and ack both leave an ephemeral socket now, and B sends\n     from an ephemeral port too, so no run repeats a 4-tuple a previous run opened.\n  3. **THE ACK IS ADDRESSED TO B'S RIG PORT, not to the probe's source port.** MEASURED: acking to\n     `from` produced a run that CONTRADICTED ITSELF — A said `INBOUND OK` and B said\n     `INBOUND_BLOCKED`, same run, 13:41:33 → 13:41:50Z — because A's ack leaves its ephemeral\n     socket, is therefore not return traffic of the flow B opened, and a receiver whose inbound rule\n     is a port RANGE drops it. The rig port is the only address either host is reachable on cold.\n  4. **THE FALSIFIER, and it is the operator's own rule used as an instrument.** Forcing the probe\n     port to **7509** (`SPT_TWO_HOST_PORT_A=7480`), one port outside the granted udp 7460-7499, reds\n     the guard on demand with no elevation and no policy edit. Run TWICE BACK TO BACK at the final\n     code, 13:43:41 → 13:44:23Z and 13:44:25 → 13:45:07Z: **RED, RED** — A after 40 s having sent\n     39 beacons, B in its ten seconds having sent 48 and 47 datagrams with no ack, both exit 101.\n     One red would only prove a state timeout expired; two consecutive reds prove the design writes\n     none. The grant boundary is therefore measured from inside the test binary: 7489 crosses, 7509\n     does not, same hosts, same binary, one env var apart.\n  5. **ONE ACK IS NOT ENOUGH — the same split verdict arrives by packet loss** (doyle, reviewing the\n     built lane). A acking ONCE and breaking leaves B's red resting on a single unrepeated UDP\n     datagram: lose it and A prints `INBOUND OK` while B reds `INBOUND_BLOCKED`, blaming a firewall\n     for ordinary loss — correction 3's defect reached by a different road. A now keeps draining for\n     a short window after its own verdict is already settled and acks EVERY probe in it, while B\n     stops on the first ack. The A-side assertion is unchanged: it was decided by the first datagram.\n  6. **THE PROBE STEPS CARRY THEIR OWN BUDGET, 300 s, set EXPLICITLY** beside ceremony steps that say\n     900. It bounds RENDEZVOUS skew, not pairing, so a blocked link costs 300 s ONCE instead of 900\n     per cell per half. Left unset it would have been `from_env`'s invisible default sitting next to\n     a visible 900 on the step below — a number the next reader would have inferred wrongly, which is\n     this entry's whole failure mode in miniature.\n- **FIELD PROOF, 2026-09-09, and it is the ONLY proof this guard has:** `dir 1` (A=hfenduleam,\n  B=kitsubito) 13:45:14 → 13:45:18Z and `dir 2` (A=kitsubito, B=hfenduleam) 13:45:41 → 13:45:58Z,\n  both GREEN with the ack after ONE datagram, both exits 0, both hosts running byte-identical source\n  (md5 `f31779339266f8034dcd72917c56a37e`, checked on both sides). Free space 174.38 GiB, flat across\n  all four arms.\n  ⚠ **THE `golden.yml` STEPS THEMSELVES ARE UNEXERCISED UNTIL THE NEXT GOLDEN RUN.** Thin CI\n  compiles the cells and SKIPS them — `Rig::from_env` returns `None` without `SPT_TWO_HOST`, so a\n  green thin run says the code builds and nothing about the steps. The wall times above are the field\n  proof; treat the workflow half as landed-pending-golden and not as verified by its own PR.\n- **Ripe when:** the next GOLDEN run, which is the first thing that exercises the steps — the\n  code half is built and field-measured (PR #211). (The box half was ripe \"now\" against\n  `25e60015` and is done; #272 golden acceptance is no longer blocked by it.) · **Size:** one\n  workflow step remaining; the elevated command is spent.\n- **SECOND LAYER (measured 23:41–23:50Z, after the operator applied the Windows rule exactly as\n  asked and the re-probe STILL read 0/3):** the tailnet ACL. The same `python.exe` listener (own\n  program rule) received 3/3 from kitsubito over the LAN (`192.168.1.168 → 192.168.1.81:7483`) and\n  0/3 over Tailscale (`100.98.197.12 → 100.68.35.65`), TCP connect over Tailscale times out too,\n  solicited return over Tailscale works, ShieldsUp false both ends. `tailscale debug netmap` on\n  hfenduleam: one PacketFilter rule, 18 permitted inbound sources, kitsubito ABSENT; kitsubito is\n  `tag:eye-tracking-resource` owned by a different tailnet user, and its own filter DOES permit\n  hfenduleam. Asymmetric policy: member device → tagged resource allowed, reverse denied. The\n  Windows rule was NECESSARY (rule-less exe, LAN probe 0/2 earlier) and NOT SUFFICIENT. Remedy\n  half (1) gains an ACL grant, operator-owned in the admin console:\n  `{\"action\":\"accept\",\"src\":[\"tag:eye-tracking-resource\"],\"dst\":[\"hfenduleam:7460-7499\"],\"proto\":\"udp\"}`.\n  Rider 4's failure text names both layers and the LAN-vs-Tailscale probe as the discriminator.\n  Lesson for the entry: a cross-box \"unresponsive\" has at least THREE layers (Windows rule, tailnet\n  policy, the exe's own bind); probe through the SAME path the rig uses, and re-probe after every\n  single change — the first fix reading as \"applied\" is not the probe reading 3/3.\n- **Corroboration + reading traps (deployah 23:50Z, from the box):** Windows rule found present by\n  FILTER search (`netsh advfirewall firewall show rule name=all dir=in verbose`), not by name — the\n  operator's name is hyphenated \"two-host\" and a `twohost` grep reads it ABSENT. Netmap: the single\n  filter permits ALL ports and ALL protocols from its 18 sources, so the grant is SOURCE-scoped, not\n  port-scoped — \"this peer is not a permitted source at all\", which is why TCP timed out beside UDP.\n  Two permitted sources (100.98.213.33, 100.98.214.87) share kitsubito's 100.98/16 and read as hits\n  to an eyeball scan for \"100.98.\"; test membership of the full /32, never a prefix. His first netmap\n  read extracted a non-existent field (`SrcIPs`; the real key is `Srcs`), printed an empty list and\n  minted a confident \"ABSENT\" — an empty extraction cannot witness absence; the 18-count is from the\n  corrected read. Prefs on the box: ShieldsUp false, NoStatefulFiltering true, RouteAll true,\n  NetfilterMode 2 — nothing there explains the drop.\n- **Probe-rider design rule (hertz, d882297f):** the pre-ceremony probe reds `INBOUND_BLOCKED` for\n  EITHER layer and does not pretend to know which — its job is \"the box cannot receive, stop triaging\n  the product\"; the layer is named only by the one measurement that decides it (same listener, LAN\n  vs Tailscale), which the failure text prints as a recipe. A guard that names a cause it did not\n  measure is the defect class this whole entry documents.\n\n### IR-90 — a full disk on the self-hosted box reds a rig as a PRODUCT refusal, not a build error, and no rig or gate records the free space that would falsify it\n\n- **Status:** OPEN, filed by hertz 2026-09-09 from the disk-full incident on hfenduleam. ·\n  **Origin:** the IR-85 discriminator lane's head arm, killed by the volume rather than by the code\n  under test.\n- **Symptom:** `spt-daemon::sync concurrent_writes_reconcile_on_elected_node_and_converge` FAILED at\n  67.588 s with a panic in our own test at `crates\\spt-daemon\\tests\\sync.rs:198`:\n  `pull: Custom { kind: Other, error: \"sync refused: bundle failed: git -C <tmp>\\tracked-b\\.seed.git\n  bundle create <tmp>\\scratch\\serve\\serve-pull-6.bundle ^d12a7134... a-doyle failed (exit Some(1)):\n  fatal: sha1 file '<stdout>' write error. Out of diskspace\\nerror: pack-objects died\" }`, then a\n  second panic at `:213` (`pull thread: Any { .. }`) as the harness thread unwound.\n- **Cause:** `C:` was at **0.018 GiB free of 1862.02 GiB (0.00%)** at that instant\n  (`Win32_LogicalDisk`, 10:57Z). `git bundle create` could not write; the daemon's serve path turned\n  that into its real product refusal string `sync refused: bundle failed`; the test asserted on the\n  refusal. **Every layer behaved correctly, and the report reads as a sync regression at the sha\n  under test.**\n- **Why it is worse than the disk faces already known:** the two banked faces\n  (`disk-full-reds-as-lnk1318-pdb-error`) are TOOLCHAIN costumes — `LNK1318` at link, and rustc\n  I/O before any link — and both route a reader to \"the box is sick\". This one routes to a CODE\n  OWNER: it names our file, our line and our refusal string, and the disk word sits in the FOURTH\n  nested clause behind a git exit code. It arrived mid-discriminator with an old sha and a new sha\n  side by side, where the cheapest reading — \"the head arm failed, the old arm passed\" — is a\n  head regression that does not exist.\n- **Blast radius, same incident:** the volume also carried a live `unit (self-hosted, Windows,\n  hfenduleam)` job (run 34341010297) compiling into it, which completed FAILURE on its own and was\n  ruled VOID after the fact. doyle's cancel of THAT run returned `Cannot cancel a workflow run that\n  is completed` — recorded because a register that credits a controlled action nobody performed\n  teaches the next reader that the box was under control. (The earlier run 34337797758, in\n  **IR-85**'s amendment, is a different run with a different ending: CANCELLED at the job wall. One\n  register putting one cancel string on the wrong run is the same defect, one run over.) `spt daemon status` went to peer pump last tick 185 s with 24 brain\n  subscribers stall-evicted (last evict 10:51:22Z, inside the disk window), with an operator restart\n  under consideration — a restart that risks the releases#287 shell stranding and that, had it\n  appeared to help, would have taught everyone the wrong cause.\n- **⚠ Two things that looked like disk fallout and are NOT**, recorded so this entry does not\n  overclaim. (a) `serve list` returning `SERVE_UNCONFIRMED`: doyle read it from source —\n  `servehost.rs` and `KIND_SERVE_REQUEST` are ABSENT at 0.67.0/0.67.1 and were minted by 0.68.0, and\n  the resident broker is still the 0.67.0 image after the brain-only flip, so the CLI's 10 s bound\n  times out **by design** against an older daemon. (b) `peer reachability: DEGRADED, 4 of 7 peers\n  unreachable for 882775 s` — 10.2 days, predating the incident entirely. Even the pump term is\n  claimed as CONCURRENT, not caused: hertz called the pump recovered off ONE post-reclaim sample\n  (54 s) and doyle falsified it two minutes later (133 s), because a single reading of a monotonic\n  \"last tick N s ago\" counter cannot separate STILL TICKING from TICKED ONCE, and a fresh project\n  index proves the coordinator loop, not the pump.\n- **Remedy — one guard, two placements, and it REFUSES rather than runs:**\n  1. **Rig start.** For the two-host rig and any test rig that shells out to `git bundle` or writes a\n     store: read free space on the volume holding the rig's temp root and `target`, and under a floor\n     fail immediately with a message that says DISK and prints the number — never enter the\n     ceremony. Floor: start at **10 GiB**, above the largest single artifact these rigs write and far\n     below any healthy state of this box; tune only with a measurement.\n  2. **Failure text**, for the case where space runs out MID-run and no start check can catch it:\n     when a shelled-out git/store operation fails, append the current free space to the error before\n     it becomes a product refusal string, so the panic that reaches a human already carries the\n     falsifier.\n- **WHY BOTH, measured rather than argued (hertz, 2026-09-09, the #209 lane):** a floor read ONCE at\n  rig start would have PASSED that run and the run still ended nearly empty — `cargo check` started\n  at **136.32 GiB** free, the test-profile build of 221 binaries took it to **40.18 GiB in ten\n  minutes**, the legs finished at **16.24 GiB**, and it read **12.27 GiB** ninety seconds later. A\n  start-only guard is a guard against yesterday's disk. That last ~4 GiB fell with those legs already\n  terminal; the candidates are the runner's CI job and its `_work` tree, unsampled and therefore\n  UNATTRIBUTED.\n- **The record itself, and the only one that caught the dip (hertz, 2026-09-09):**\n  `.spt/preserved/hertz-leak-670-legs/disk-full-trace.log` — **139 samples, 11:52:46Z–13:57:07Z, one\n  per minute**, max **238.41 GiB** @12:45:20Z, min **12.53 GiB** @12:12:45Z. Two samples fall under\n  15 GiB — **14.85** @12:12:11Z and **12.53** @12:12:45Z — both inside the #209 leak lane's\n  build-and-teardown window, i.e. AFTER a start floor would have passed the run at **136.15 GiB**\n  (the window's first sample). Two caveats, both binding on any reading of it: **the true minimum is\n  unbounded below 12.53 — the sampler cannot see between its samples**, and **it attributes nothing:\n  hertz's own legs and the runner's CI job are indistinguishable in it.** It is the SECOND instrument\n  on this incident and the only one covering the dip: doyle's 30 s trace, preserved at\n  `.spt/preserved/ir90-free-space-trace-2026-09-09/free-sampler-12-13Z-to-12-28Z.txt`, runs\n  12:15:37Z–12:31:10Z and so begins after hertz's reap — it records the RECOVERY, this one records\n  the FALL. sha256 `d58ce838b677e62d4a017e77524f899fda81e7bacf73a0e2a05a1192e60abaf2`\n  (doyle's, `8bdae01bc151597070d7011443a2cdc74614232dbc962faec1b1b1833c71f22a`).\n- **Explicitly NOT the remedy:** a bigger disk, or a reap schedule. ~195 GiB of headroom was consumed\n  by ordinary work, ACCRUED across a ~45-minute build phase; **no reading bounds a rate** — the\n  free-space observations either side are endpoints of an accrual, and a rate derived from them\n  retargets a hunt (deployah's went to runaway logs, VSS and torrent preallocation on the strength of\n  a `>150 MB/s` derived that way, while the measured live box-wide write rate was ~1.5 MB/s). What\n  consumed it: two `cargo nextest run -E <5-test filter>` lanes at **82.88** and **64.44 GiB** — a\n  filter narrows the RUN, never the BUILD, and both built 221 test binaries under the `test` profile\n  — plus 40.93 GiB of `C:\\actions-runner\\_work` and 9.8 GiB of `%TEMP%`. Any headroom this box\n  has is two cold pools away from gone, so the guard must be a REFUSAL, not a budget.\n- **Kin:** **IR-85** (the same box's fs-heavy slowdown; a near-full volume is now a named environment\n  term there), **IR-86** (a start floor that passes a box which cannot finish — the same defect one\n  layer up, and this entry is its mid-run half), **IR-76** (the golden runner is the operator's\n  desktop), `disk-full-reds-as-lnk1318-pdb-error` (memory; this is its third face and its standing\n  gap), `test-profile-pool-outgrows-the-disk-floor`, `free-space-floor-blocks-golden`.\n- **Ripe when:** now. · **Size:** one assertion plus one error-context append, both test-side.\n\n### IR-91 — 561 untracked files sat at the repo root, 18 of them cited by tracked files, and the census that classified them used a corpus that made the discriminator invisible\n\n- **Status:** CLOSED by the lane that filed it (the root-scratch classify PR), hertz 2026-09-09 on\n  doyle's census and rulings. · **Origin:** the `.spt/` ignore lane (PR #212) named 561 untracked\n  root files as explicitly out of scope; this is that half.\n- **The population, measured at `2037bcb8`:** `git status --porcelain --untracked-files=all` = **561\n  `??` rows, all at the repo root, zero in subdirectories**, 50,034,994 bytes (47.7 MiB). By\n  extension: 268 `.raw`, 184 `.exit`, 87 `.md`, 7 `.out`, 4 `.log`, 4 `.done`, 2 `.txt`,\n  2 `.stackdump`, 2 `.sh`, 1 `.py`. **A `git add -A` at the root staged every one of them**, which\n  is the same landmine `.spt/` carried before #212 and the reason this is one arc in two lanes.\n- **⚠ THE FINDING, and it is about the CENSUS, not the files:** the first classification put two\n  cited files in the \"bury\" class. `W3-196-CENSUS.md` and `WEBSERVE-272-JIT.md` were recorded as\n  \"cited only from other root scratch\" — citing files `W3-196-JIT.md` and `W3-272-MEASUREMENTS.md`,\n  which are **TRACKED**. The census corpus was tracked-only, so **every hit it produced was a\n  tracked citation by construction**; the two were then relabelled by their PATH, because a `.md`\n  sitting at the repo root reads as scratch. **The discriminator is TRACKED-OR-NOT, never\n  ROOT-OR-NOT** — and a corpus that can only return tracked hits cannot tell you which of its own\n  hits are tracked, because it has already thrown away the distinction. Burying those two would have\n  left two tracked files citing paths that no longer existed: the `launch-battery.py` mechanism from\n  **IR-90**'s sibling lane with the sides swapped, caught here only because the burial list was\n  re-verified against the corpus a second time by a different reader.\n- **The second finding, which withdrew the lane's own destinations:** the repo root **already holds\n  140 tracked files, 134 of them `.md`, 25 with `JIT` in the name** — `IDLE-EDGE-JIT.md`,\n  `W3-196-JIT.md`, `WEBSERVE-272-W2-JIT.md`, every `M*-PLAN.md`, `MESH-D*-PLAN.md`,\n  `RESTORATION-D*-PLAN.md`. **The house convention is measured, not assumed: a plan or record lives\n  at the repo root and is TRACKED.** The first ruling would have relocated the cited files into\n  `docs/intake/`, `docs/design/` and `docs/gate-records/` — splitting siblings across two homes\n  (`WEBSERVE-272-W2-JIT.md` at root, `WEBSERVE-272-W3-DRIFT-RIDERS.md` in `docs/intake/`) and\n  repointing 18 citation lines to buy that split. **Destinations withdrawn; the 18 are tracked where\n  they are.** Zero moves, zero repoints, zero sha-transfer risk. A lane that tidies against a\n  measured convention is not tidying.\n- **THE RULE, which is what this entry is for:** *a plan or record cited from a tracked file is\n  itself tracked, at the path the citation already names.* The root is a legal home. What decides a\n  file's fate is whether the repo points at it — not where it sits, not what it is called, and not\n  whether it looks like scratch.\n- **What the lane did:** **18 Class A** files `git add`ed in place. **473 Class B** gate legs\n  (`.raw`/`.exit`/`.done`/`.log`/`.out`/`.stackdump`/`.sh`/`.txt`, zero tracked citations, each\n  word-bounded against the whole 911-file tracked corpus) **MOVED — not deleted** — to\n  `.spt/preserved/root-gate-legs-2026-09-09/` with a sha256 manifest, every file hashed before and\n  after the move. **70 Class C** uncited `.md` likewise to `.spt/preserved/root-md-2026-09-09/`.\n  Then five **root-anchored** ignore lines: `/*.raw` `/*.exit` `/*.done` `/*.out` `/*.stackdump`.\n- **Why those five and not more.** Legs are the one class whose FUTURE instances are scratch **by\n  construction**, so ignoring them institutionalizes no loss. `/*.md`, `/*.log`, `/*.sh` and\n  `/*.txt` are deliberately NOT ignored: a plan or script dropped at the root must keep showing as\n  `??` so the next census classifies it — **that is exactly the pattern that produced this repo's\n  140-file tracked root corpus**, and an ignore line there would hide the next one. The anchoring is\n  load-bearing and was proved with a negative control: `crates/probe.raw` is **not** ignored, which\n  an unanchored `*.raw` would have swallowed.\n- **Kin:** the `.spt/` ignore lane (PR #212 — same arc, and its `launch-battery.py` case is why\n  nothing here was deleted), **IR-90** (a citation into `.spt/preserved/` is machine-bound evidence,\n  never a repo path), `ignoring-a-directory-buries-what-the-repo-cites-in-it` (memory).\n- **Ripe when:** landed with this entry. · **Size:** one `.gitignore` stanza, 18 adds, 543\n  preserved files, no deletions.\n\n### IR-92 — the message that WAKES an idle spt-hosted endpoint rides a delivery leg that never publishes MSG_IN, so a woken agent's own funnel holds none of the messages that woke it\n\n- **Status:** OPEN — filed doyle 2026-09-09 from hertz's census, probe and proposed text (his by\n…\n  the chase exposed that neither agent's io-events log held the messages that woke it.\n…\n\n\n[Showing lines 4987-5407 of 5900. Use :5408 to continue]"}],"details":{"truncation":{"content":"- **Status:** OPEN, filed by doyle 2026-09-08 at the #272/v0.68.0 golden r2 triage. · **Origin:**\r\n  run 34262154550 @ `25e60015` (shaped on `e4444413`), Windows test job 102182665033: every product\r\n  step green (Phase A 3346/3346, Phase B 234/234, Summary 2, FAIL 0), the ONLY reds were the two\r\n  in-job floor gates. `FLOOR_START` 97,649,786,880 B PASS at 18:47:23Z -> `FLOOR_DOCS`\r\n  25,284,501,504 B RED at 19:31:55Z -> `FLOOR_END` RED. Consumed in-job: 67.4 GiB.\r\n- **Mechanism:** `golden.yml` derives 32 GiB as \"the observed tens-of-GB full-suite footprint\r\n  rounded up to the next binary boundary, preserving headroom for one complete run\" (comment\r\n  above the Windows start floor). The measured footprint is 67.4 GiB, so a start reading anywhere\r\n  in [32, ~100) GiB passes and the job then walks under the floor by construction: box baseline\r\n  91 GiB minus 67.4 = 23.5 < 32. This is a shortfall of the DERIVATION, not a rate, not a product\r\n  red, and not the instant-vs-sustained face IR-46 files (that face is fixed by the FLOOR_DOCS\r\n  re-read, which is what caught it). The start floor must be footprint + end-floor (~100 GiB) or\r\n  it asserts nothing about finishing.\r\n- **Coverage consequence (the load-bearing part):** the Windows `Docs drift gate (CLI ref + llms\r\n  links)` step is sequenced BEHIND `FLOOR_DOCS`, so it SKIPPED and r2 held NO Windows CLI-ref\r\n  axis at that sha until the rerun. A floor red that skips a gate is a coverage hole wearing a\r\n  disk red.\r\n- **Kin:** [[IR-46]] (a floor asserts an instant), [[IR-59]] (pool arithmetic, LNK-class reds\r\n  that name no disk), [[IR-64]] (the operator-payload reservoir that sets the box baseline; its\r\n  ripe-when arm — a golden that dies at the floor despite adopted pool discipline — FIRED here\r\n  in the in-job form), [[IR-73]] (second half BUILT: the within-job re-read exists and is what\r\n  produced the FLOOR_DOCS reading), REQ-CI-FREE-SPACE-PREFLIGHT.\r\n- **Coupling (deployah 23:54Z, from `golden.yml` at `25e60015`):** the Windows `DISK docs floor`\r\n  (:616) and `Docs drift gate — windows` (:629) carry only `if: runner.os == 'Windows'`, no\r\n  `always()`, while `DISK end floor` does (`always() && runner.os == 'Windows'`, ~:705). Actions'\r\n  default is \"previous steps succeeded\", so ANY Phase B red skips the docs axis by construction —\r\n  observed three times at this sha (floor red, ttl cell, ttl cell). The docs gate is therefore never\r\n  independent evidence: it can only be banked when Phase B is green in the same job. Remedy line:\r\n  gate the two docs steps on `!cancelled()` plus the success of the steps they actually depend on\r\n  (checkout/build), not on Phase B — a rig change, new sha, hertz workflow rider slot.\r\n- **Remedy shape:** re-derive the start floor from the measured footprint (67.4 GiB Windows,\r\n  Linux to be measured) plus the 32 GiB end floor, print the footprint (start minus end free)\r\n  on every run so the number re-measures itself, and keep the 32 GiB literal only for\r\n  `FLOOR_END`.\r\n- **Ripe when:** next `golden.yml` touch (hertz workflow rider slot). · **Size:** small — one\r\n  literal per start-floor site + one printed subtraction.\r\n\r\n### IR-87 — two-host ceremony halves are INDEPENDENT jobs on DIFFERENT runners (A Windows/hfenduleam, B Linux/kitsubito); B's 900 s budget runs on B's own clock, so any older queued Windows job starves A and reds B deterministically, and the panic text blames pairing\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-08 at the #272 golden r2 triage. · **Origin:**\r\n  run 34262154550, twohost-b job 102207296960 (log 81,692 B, sha256 67403f04…8030): role B built,\r\n  rostered, polled PAIR_MEET_UP every 30 s from 19:34:30Z, and hit the rig_wait barrier\r\n  \"pairing: A rostered via the daemon-hosted responder\" at its 900 s deadline 19:49:17Z\r\n  (`crates/spt-daemon/tests/twohost.rs`, exit 101, 2 passed 1 failed). twohost-a (102207296985)\r\n  was QUEUED from 19:32:13Z with no runner: the Windows runner went to thin ci run 34261096301\r\n  (post-merge on main @ `e4444413`) the second the golden test job released it at 19:31:56Z.\r\n- **Mechanism:** `golden.yml` sequences twohost-a and twohost-b after `test`, but they are two\r\n  jobs on two runners (measured 2026-09-08 20:56Z via the jobs API `runner_name`: twohost-a on\r\n  hfenduleam, twohost-b on kitsubito), and GitHub's queue does not honour a workflow's intra-run\r\n  job ordering against a FOREIGN run on either runner. B starts, its whole budget ticks against a partner that has not been\r\n  scheduled, and `rig_wait` panics `never converged on the rig: {what}` — a text that reads as a\r\n  pairing defect. The lanes were not at fault, and twohost-a's outcome was predetermined once B\r\n  exited (a later A pass would be vacuous).\r\n- **Kin:** [[IR-76]] (hfenduleam is golden runner AND builders' box; the job-start census cannot\r\n  see a competing GitHub run either), [[IR-62]] (rig collisions on shared runners), the W1 two-host\r\n  rig, `a-barrier-cannot-ride-a-carrier-its-sender-outlives` (memory, same family: a barrier needs\r\n  the receiver's own answer).\r\n- **Remedy shape (pick at rider time):** (1) start barrier on B keyed to A's job having STARTED\r\n  (a run-scoped artifact or a `needs`+matrix collapse into ONE job that spawns both roles), or\r\n  (2) B's deadline clock starts at first A-rostered signal with a separate, longer \"A never\r\n  appeared\" budget, or (3) the panic names the missing partner's job state so triage does not\r\n  chase pairing. Any option: the two-host halves must never share a runner queue with a foreign\r\n  run while one half waits.\r\n- **Ripe when:** next `golden.yml`/twohost rig touch. · **Size:** small-medium (job shape or\r\n  barrier rework + panic text).\r\n\r\n- **AMENDMENT 2026-09-10 (releases#294, golden 34445961595 att1 @ `a9e786b2`) — THE STARVING RUN CAN\r\n  BE GOLDEN'S OWN PR, which makes this self-inflicted and recurrent on every golden run with a PR\r\n  open.** Measured timeline: **07:18:59Z** golden `test (Windows)` completes and releases hfenduleam;\r\n  **07:18:59Z** twohost-a queued; **07:19:01Z** PR run **34446095808** job `unit (Windows,\r\n  hfenduleam)` SEIZES the runner; **07:19:02Z** twohost-b starts on the free kitsubito; **07:36:16Z**\r\n  twohost-b fails at **900.41s** — `never converged on the rig: pairing: A rostered via the\r\n  daemon-hosted responder`. The origin case (2026-09-08) was a post-merge push on `main`: a run\r\n  belonging to someone else. **Here the starving run is the `pull_request` run of the very PR carrying\r\n  the golden head**, so opening the golden PR arms the starvation of that same head's twohost pair.\r\n  **Consequence for the remedy shape above: any option that only de-conflicts against OTHER lanes'\r\n  runs does not reach this case.** The golden head's own PR has to be excluded from the Windows\r\n  runner for the duration of the golden run (or the pair collapsed into one job, option 1).\r\n- **SECOND-ORDER FACE (deployah, same run): starvation does not merely red B — it desynchronises the\r\n  pair past repair.** twohost-b was TERMINAL at 07:36:16Z; twohost-a did not start until **07:48:07Z**\r\n  — the two halves never overlapped for a single second, so twohost-a's outcome is uninformative\r\n  **whatever it says**, and a red there must not be counted as a second product failure. Recorded\r\n  honestly at deployah's own insistence: **VOID is his SCORING interpretation, not a fact about the\r\n  run** — the release record carries GitHub's raw `conclusion` for both jobs beside the scoring, not\r\n  laundered into it.\r\n- **⚠ ITS WALL CLOCK IS INDISTINGUISHABLE FROM [[IR-89]]'s.** A 900 s twohost red whose panel blames\r\n  pairing is ALSO the exact signature of the banked Windows-firewall hazard. The panel alone cannot\r\n  separate them; **the job TIMELINE can**. Check the schedule before accepting the firewall hazard for\r\n  any 900 s twohost red — this one fit that signature perfectly and was not it.\r\n\r\n### IR-88 — `pool-release` via `cargo run -p xtask` REBUILDS xtask INTO the pool it is releasing, so a reaped pool regrows ~2.8 GB in silence\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-08 from hertz's reap report (20:00Z) during the #272\r\n  golden r2 repair. · **Origin:** hertz reaped hertz-lane4 / hertz-repin / hertz-percell-id target\r\n  subtrees (Length-sum upper bounds 68.16 / 47.11 / 8.79 GB) and then ran `cargo run -p xtask --\r\n  pool-release …` from each worktree: cargo rebuilt xtask into the just-reaped `target/` (2.8 GB\r\n  back in lane4, partial in repin), nothing printed said so, and the descendancy stopper killed\r\n  the second before it finished. Removed by hand afterwards; the post-reap free reading on the\r\n  record (275.95 GiB at 19:55:51Z) predates the regrowth.\r\n- **Mechanism:** the documented verb (AGENTS.md: \"drop it with `pool-release`\") is a `cargo run`,\r\n  and cargo's default target for that run IS the pool being released. The verb's own success path\r\n  recreates the state the operator just measured away; a teardown step that runs it AFTER a reap\r\n  undoes part of the reap and leaves the recorded free reading stale.\r\n- **Remedy shape:** either (a) `pool-release` documented and scripted as a PREBUILT `xtask.exe`\r\n  invoked against `--pool <dir>` from another pool, or (b) the verb refuses when its own\r\n  `CARGO_TARGET_DIR`/default target equals `--pool` and prints the prebuilt form, or (c) the reap\r\n  recipe orders release BEFORE the subtree delete. Memory banked 2026-09-08\r\n  (`pool-release-rebuilds-xtask-into-the-pool-you-just-reaped`); this entry is the durable home.\r\n- **POSITIVE CONTROL (hertz, 2026-09-09, ruling-3 gate-r3 teardown):** the same release run\r\n  from a PREBUILT `xtask.exe` invoked from outside the pool regrew NOTHING — the pool's own\r\n  `xtask.exe` still carried its original 21:00:42 mtime afterwards, and the reap that followed\r\n  reclaimed 63.71 GiB (132.03 -> 195.74 GiB free) against a 64.88 GiB Length-sum. So the\r\n  regrowth is a property of the `cargo run` VEHICLE, not of the verb, and remedy (a) is proven\r\n  rather than merely proposed.\r\n- **Kin:** [[IR-31]] (pool budgeting), [[IR-56]] (pool-claim identity from CWD — same verb\r\n  family, same \"the tool acts on where it stands\" shape), releases#103.\r\n- **Ripe when:** next xtask pool-verb touch or the teardown runbook edit. · **Size:** tiny —\r\n  one guard or one doc line.\r\n\r\n### IR-89 — hfenduleam's Windows Firewall drops cold inbound UDP to the runner-built test exes, so the two-host rig's first B→A claim (W2 helper) reds for its whole 900 s budget and the panic blames A\r\n\r\n- **Status:** BOX HALF **APPLIED** 2026-09-08; WORKFLOW HALF **BUILT** 2026-09-09 — PR #211\r\n  (`9b96d7e7` + this amendment), **LANDED, exact golden-step acceptance unreconciled**.\r\n  Subsequent goldens have run: \"until the next golden\" is no longer a future trigger.\r\n  This sweep does not infer probe execution from a run's existence or overall conclusion;\r\n  retain the step-specific exercised/skipped/failed evidence before closing. Filed by doyle 2026-09-08\r\n  at the #272 golden r2 terminal triage; the operator-blocked flag is retired here, because\r\n  the operator acted.\r\n  The operator applied BOTH layers that evening — the Windows inbound rule (~23:41Z) and the\r\n  tailnet ACL grant (~23:56Z) — and the re-probe with the same rule-less pwsh listener read\r\n  **3/3 over Tailscale on 7483 AND 3/3 on 7489 at 23:57:50Z** from `100.98.197.12`, with a\r\n  post-terminal probe 3/3 on both ports at attempt 4. v0.68.0 then shipped at `a2f335f8` with\r\n  both two-host legs GREEN on golden r4, so the box half is closed by measurement and not by\r\n  assertion. **Durable half BUILT, acceptance reconciliation OPEN:** the pre-ceremony B→A\r\n  probe and its corrections are documented below. Do not redispatch a workflow guard that\r\n  already landed, or reopen the spent operator permission. The next box/ACL reset remains a\r\n  recheck trigger. · **Origin:** run 34262154550 @ `25e60015`, twohost-a 102229928746\r\n  (`two_host_web_helper_role_a`, :968, 900.40 s) and twohost-b 102229928689\r\n  (`two_host_web_role_b`, :559, 910.20 s): B logged 75 × \"A not ready … broker QUIC op exceeded\r\n  the 10s bound (peer unresponsive)\" from 20:49:49Z to 21:04:37Z and was never ADMITTED. Ladder\r\n  green both sides; both halves started 20:41:23Z on their own runners (not IR-87's starvation).\r\n- **Mechanism (MEASURED 21:11Z):** the box's firewall policy is `BlockInbound,AllowOutbound` on\r\n  all three profiles (Ethernet and Tailscale both Private). Inbound allow rules exist only for\r\n  exes under `Documents\\projects\\spt-core\\target` (interactive Allow clicks) and under the DEAD\r\n  pre-rename runner path `_work\\spt-core\\spt-core`; exactly ONE under `_work\\spt-bs-core` (its\r\n  `target\\debug\\spt.exe`, the CLI, not the binder — deployah's count, mine had said zero), none for\r\n  any `twohost_web-*.exe`. `Get-NetFirewallProfile` shows `DefaultInboundAction = NotConfigured`,\r\n  whose effective default IS block: the block is Windows' default, not a configured policy, so there\r\n  is no policy to \"restore\". The runner is a service (`.\\decid`), so the Allow dialog that minted the\r\n  old rules cannot appear. A's helper cell 3 bound `broker udp 7483` inside\r\n  `_work\\spt-bs-core\\spt-bs-core\\target\\debug\\deps\\twohost_web-f73bc44be13353fb.exe`; B dialled\r\n  `100.68.35.65:7483` cold. Probe: a rule-less pwsh UDP listener on hfenduleam:7483 received 0 of\r\n  3 datagrams from kitsubito `100.98.197.12`; the reverse control (python listener on\r\n  kitsubito:7483) received 3 of 3 from hfenduleam.\r\n- **Why three faces from one cause:** the shared-key rig (pre-`e4444413`) reached A only through\r\n  holes A's OUT-dialling cells (7480–7482) had opened for `id_a` — six 10 s bounds until B's\r\n  magicsock fell onto one of those paths, then ADMITTED (the 63 s stall, helper-stall memory), or\r\n  onto a live same-key sibling that never replied (the 21 min hang in 34239258523). Per-cell A\r\n  identity (`id_a_for`, `e4444413`) removed the accidental route by construction, leaving only\r\n  the cold path, which the firewall drops. hertz's one-box discriminator \"vanishes\" was true on\r\n  one box because one box never crosses the firewall. Product and rig are both exonerated; the\r\n  rig's `a_addr` comment already names W2 as the first A-ward claim.\r\n- **Remedy (two halves):** (1) BOX, operator-owned, elevated on hfenduleam:\r\n  `New-NetFirewallRule -DisplayName \"spt-ci two-host rig UDP-In (kitsubito only)\" -Direction Inbound -Action Allow -Protocol UDP -LocalPort 7460-7499 -RemoteAddress 100.98.197.12 -Profile Any`\r\n  (rig ports at the sha: ladder 7460/7461; web `PORT_OFFSET` 20 → A cells 7480–7483, B 7481; the\r\n  A-ward surface today is exactly UDP 7480–7483 — deployah's tighter range — and the whole range\r\n  moves with any `SPT_TWO_HOST_PORT_A` override, so the rule must move with it);\r\n  program-path rules are the wrong shape because the exe hash changes per build. Verify with the\r\n  same probe (3/3) before any rerun. (2) WORKFLOW, hertz: a B→A UDP probe step in the twohost\r\n  jobs before the ceremony, so this reds in 10 s with its own name instead of 900 s blaming\r\n  pairing; and retire the dead `_work\\spt-core` rules note in the runner runbook.\r\n- **Kin:** [[IR-83]] (the tailnet-ACL face of a cross-box inbound block — KIN, **NOT the same\r\n  finding**: that entry is the tailnet policy layer, this one is the Windows firewall layer, and\r\n  the SECOND LAYER note below is exactly the measurement that separates them), [[IR-87]] (the\r\n  other way a half waits 900 s on a partner), [[IR-76]] (golden runner\r\n  is the operator's box), [[IR-64]] (box-level facts only the operator can move),\r\n  `twohost-web-helper-stall-shared-a-identity-stale-path` (memory; its CONFIRMED arm is re-read\r\n  by this entry).\r\n- **AMENDMENT 2026-09-09 — the WORKFLOW half is BUILT and FIELD-MEASURED; it is LANDED-pending-golden\r\n  (hertz).** The guard is two cells in `twohost_web.rs` plus a step per half in `golden.yml`, and it\r\n  grew four design corrections that are worth more than the guard itself, because each one is a way a\r\n  probe can certify the fault it exists to catch.\r\n  1. **A FIXED SYMMETRIC WINDOW ADDS A THIRD CAUSE THAT LOOKS LIKE THE OTHER TWO.** The step boundary\r\n     orders the probe on ONE host; it does not align two, and after the ladder each half pays its own\r\n     wrapper and `cargo test` (on Windows a fingerprint scan plus Defender's first touch of a fresh\r\n     exe). MEASURED: the first hand-run in the A=kitsubito direction (13:14:13 → 13:14:51Z) redded\r\n     `INBOUND_BLOCKED` at 10.24 s with text asserting \"a BOX rule, not a product or rig fault\" — and\r\n     the cause was `cargo`'s start-up on the SENDER putting its first datagram after the receiver's\r\n     10 s window closed. An innocent box, the guard's own words against it. What stopped it being\r\n     filed as a kitsubito block was that the box facts contradicted the text (`tailscale debug\r\n     netmap` on kitsubito lists `100.68.35.65/32` among its permitted inbound sources, and `ufw` is\r\n     inactive) — a failure text that contradicts a measured box is the text's defect. So the\r\n     rendezvous is DATA: A listens up to the rig budget and beacons once a second; B binds first,\r\n     waits for a beacon, and only then starts a ten-second clock, so B's red has already excluded\r\n     \"A is not up\". That is a FOURTH outcome with its own name, `PROBE_NO_BEACON`, never\r\n     `INBOUND_BLOCKED`.\r\n  2. **THE LISTENING SOCKET MUST NEVER SEND.** Any outbound datagram from the measured port opens\r\n     stateful return state for it, so B's probe then arrives SOLICITED and crosses under both layers\r\n     — this entry's own \"solicited return traffic works under either fault\" applied to the guard\r\n     rather than to the ceremony. MEASURED: with the beacon sharing A's listening socket, the\r\n     out-of-grant control went **GREEN at 13:28Z** on a port a listen-only run had measured BLOCKED\r\n     at 13:20Z; a further green at 13:31Z with the beacon moved but the ack still leaving that socket\r\n     was residual state from 13:28 — true BY ELIMINATION rather than by assertion: nothing in the\r\n     13:31 run sent from 7509 before the first arrival, so the only outbound that could have opened\r\n     that port's return state belongs to the previous run. Beacon and ack both leave an ephemeral socket now, and B sends\r\n     from an ephemeral port too, so no run repeats a 4-tuple a previous run opened.\r\n  3. **THE ACK IS ADDRESSED TO B'S RIG PORT, not to the probe's source port.** MEASURED: acking to\r\n     `from` produced a run that CONTRADICTED ITSELF — A said `INBOUND OK` and B said\r\n     `INBOUND_BLOCKED`, same run, 13:41:33 → 13:41:50Z — because A's ack leaves its ephemeral\r\n     socket, is therefore not return traffic of the flow B opened, and a receiver whose inbound rule\r\n     is a port RANGE drops it. The rig port is the only address either host is reachable on cold.\r\n  4. **THE FALSIFIER, and it is the operator's own rule used as an instrument.** Forcing the probe\r\n     port to **7509** (`SPT_TWO_HOST_PORT_A=7480`), one port outside the granted udp 7460-7499, reds\r\n     the guard on demand with no elevation and no policy edit. Run TWICE BACK TO BACK at the final\r\n     code, 13:43:41 → 13:44:23Z and 13:44:25 → 13:45:07Z: **RED, RED** — A after 40 s having sent\r\n     39 beacons, B in its ten seconds having sent 48 and 47 datagrams with no ack, both exit 101.\r\n     One red would only prove a state timeout expired; two consecutive reds prove the design writes\r\n     none. The grant boundary is therefore measured from inside the test binary: 7489 crosses, 7509\r\n     does not, same hosts, same binary, one env var apart.\r\n  5. **ONE ACK IS NOT ENOUGH — the same split verdict arrives by packet loss** (doyle, reviewing the\r\n     built lane). A acking ONCE and breaking leaves B's red resting on a single unrepeated UDP\r\n     datagram: lose it and A prints `INBOUND OK` while B reds `INBOUND_BLOCKED`, blaming a firewall\r\n     for ordinary loss — correction 3's defect reached by a different road. A now keeps draining for\r\n     a short window after its own verdict is already settled and acks EVERY probe in it, while B\r\n     stops on the first ack. The A-side assertion is unchanged: it was decided by the first datagram.\r\n  6. **THE PROBE STEPS CARRY THEIR OWN BUDGET, 300 s, set EXPLICITLY** beside ceremony steps that say\r\n     900. It bounds RENDEZVOUS skew, not pairing, so a blocked link costs 300 s ONCE instead of 900\r\n     per cell per half. Left unset it would have been `from_env`'s invisible default sitting next to\r\n     a visible 900 on the step below — a number the next reader would have inferred wrongly, which is\r\n     this entry's whole failure mode in miniature.\r\n- **FIELD PROOF, 2026-09-09, and it is the ONLY proof this guard has:** `dir 1` (A=hfenduleam,\r\n  B=kitsubito) 13:45:14 → 13:45:18Z and `dir 2` (A=kitsubito, B=hfenduleam) 13:45:41 → 13:45:58Z,\r\n  both GREEN with the ack after ONE datagram, both exits 0, both hosts running byte-identical source\r\n  (md5 `f31779339266f8034dcd72917c56a37e`, checked on both sides). Free space 174.38 GiB, flat across\r\n  all four arms.\r\n  ⚠ **THE `golden.yml` STEPS THEMSELVES ARE UNEXERCISED UNTIL THE NEXT GOLDEN RUN.** Thin CI\r\n  compiles the cells and SKIPS them — `Rig::from_env` returns `None` without `SPT_TWO_HOST`, so a\r\n  green thin run says the code builds and nothing about the steps. The wall times above are the field\r\n  proof; treat the workflow half as landed-pending-golden and not as verified by its own PR.\r\n- **Ripe when:** the next GOLDEN run, which is the first thing that exercises the steps — the\r\n  code half is built and field-measured (PR #211). (The box half was ripe \"now\" against\r\n  `25e60015` and is done; #272 golden acceptance is no longer blocked by it.) · **Size:** one\r\n  workflow step remaining; the elevated command is spent.\r\n- **SECOND LAYER (measured 23:41–23:50Z, after the operator applied the Windows rule exactly as\r\n  asked and the re-probe STILL read 0/3):** the tailnet ACL. The same `python.exe` listener (own\r\n  program rule) received 3/3 from kitsubito over the LAN (`192.168.1.168 → 192.168.1.81:7483`) and\r\n  0/3 over Tailscale (`100.98.197.12 → 100.68.35.65`), TCP connect over Tailscale times out too,\r\n  solicited return over Tailscale works, ShieldsUp false both ends. `tailscale debug netmap` on\r\n  hfenduleam: one PacketFilter rule, 18 permitted inbound sources, kitsubito ABSENT; kitsubito is\r\n  `tag:eye-tracking-resource` owned by a different tailnet user, and its own filter DOES permit\r\n  hfenduleam. Asymmetric policy: member device → tagged resource allowed, reverse denied. The\r\n  Windows rule was NECESSARY (rule-less exe, LAN probe 0/2 earlier) and NOT SUFFICIENT. Remedy\r\n  half (1) gains an ACL grant, operator-owned in the admin console:\r\n  `{\"action\":\"accept\",\"src\":[\"tag:eye-tracking-resource\"],\"dst\":[\"hfenduleam:7460-7499\"],\"proto\":\"udp\"}`.\r\n  Rider 4's failure text names both layers and the LAN-vs-Tailscale probe as the discriminator.\r\n  Lesson for the entry: a cross-box \"unresponsive\" has at least THREE layers (Windows rule, tailnet\r\n  policy, the exe's own bind); probe through the SAME path the rig uses, and re-probe after every\r\n  single change — the first fix reading as \"applied\" is not the probe reading 3/3.\r\n- **Corroboration + reading traps (deployah 23:50Z, from the box):** Windows rule found present by\r\n  FILTER search (`netsh advfirewall firewall show rule name=all dir=in verbose`), not by name — the\r\n  operator's name is hyphenated \"two-host\" and a `twohost` grep reads it ABSENT. Netmap: the single\r\n  filter permits ALL ports and ALL protocols from its 18 sources, so the grant is SOURCE-scoped, not\r\n  port-scoped — \"this peer is not a permitted source at all\", which is why TCP timed out beside UDP.\r\n  Two permitted sources (100.98.213.33, 100.98.214.87) share kitsubito's 100.98/16 and read as hits\r\n  to an eyeball scan for \"100.98.\"; test membership of the full /32, never a prefix. His first netmap\r\n  read extracted a non-existent field (`SrcIPs`; the real key is `Srcs`), printed an empty list and\r\n  minted a confident \"ABSENT\" — an empty extraction cannot witness absence; the 18-count is from the\r\n  corrected read. Prefs on the box: ShieldsUp false, NoStatefulFiltering true, RouteAll true,\r\n  NetfilterMode 2 — nothing there explains the drop.\r\n- **Probe-rider design rule (hertz, d882297f):** the pre-ceremony probe reds `INBOUND_BLOCKED` for\r\n  EITHER layer and does not pretend to know which — its job is \"the box cannot receive, stop triaging\r\n  the product\"; the layer is named only by the one measurement that decides it (same listener, LAN\r\n  vs Tailscale), which the failure text prints as a recipe. A guard that names a cause it did not\r\n  measure is the defect class this whole entry documents.\r\n\r\n### IR-90 — a full disk on the self-hosted box reds a rig as a PRODUCT refusal, not a build error, and no rig or gate records the free space that would falsify it\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-09 from the disk-full incident on hfenduleam. ·\r\n  **Origin:** the IR-85 discriminator lane's head arm, killed by the volume rather than by the code\r\n  under test.\r\n- **Symptom:** `spt-daemon::sync concurrent_writes_reconcile_on_elected_node_and_converge` FAILED at\r\n  67.588 s with a panic in our own test at `crates\\spt-daemon\\tests\\sync.rs:198`:\r\n  `pull: Custom { kind: Other, error: \"sync refused: bundle failed: git -C <tmp>\\tracked-b\\.seed.git\r\n  bundle create <tmp>\\scratch\\serve\\serve-pull-6.bundle ^d12a7134... a-doyle failed (exit Some(1)):\r\n  fatal: sha1 file '<stdout>' write error. Out of diskspace\\nerror: pack-objects died\" }`, then a\r\n  second panic at `:213` (`pull thread: Any { .. }`) as the harness thread unwound.\r\n- **Cause:** `C:` was at **0.018 GiB free of 1862.02 GiB (0.00%)** at that instant\r\n  (`Win32_LogicalDisk`, 10:57Z). `git bundle create` could not write; the daemon's serve path turned\r\n  that into its real product refusal string `sync refused: bundle failed`; the test asserted on the\r\n  refusal. **Every layer behaved correctly, and the report reads as a sync regression at the sha\r\n  under test.**\r\n- **Why it is worse than the disk faces already known:** the two banked faces\r\n  (`disk-full-reds-as-lnk1318-pdb-error`) are TOOLCHAIN costumes — `LNK1318` at link, and rustc\r\n  I/O before any link — and both route a reader to \"the box is sick\". This one routes to a CODE\r\n  OWNER: it names our file, our line and our refusal string, and the disk word sits in the FOURTH\r\n  nested clause behind a git exit code. It arrived mid-discriminator with an old sha and a new sha\r\n  side by side, where the cheapest reading — \"the head arm failed, the old arm passed\" — is a\r\n  head regression that does not exist.\r\n- **Blast radius, same incident:** the volume also carried a live `unit (self-hosted, Windows,\r\n  hfenduleam)` job (run 34341010297) compiling into it, which completed FAILURE on its own and was\r\n  ruled VOID after the fact. doyle's cancel of THAT run returned `Cannot cancel a workflow run that\r\n  is completed` — recorded because a register that credits a controlled action nobody performed\r\n  teaches the next reader that the box was under control. (The earlier run 34337797758, in\r\n  **IR-85**'s amendment, is a different run with a different ending: CANCELLED at the job wall. One\r\n  register putting one cancel string on the wrong run is the same defect, one run over.) `spt daemon status` went to peer pump last tick 185 s with 24 brain\r\n  subscribers stall-evicted (last evict 10:51:22Z, inside the disk window), with an operator restart\r\n  under consideration — a restart that risks the releases#287 shell stranding and that, had it\r\n  appeared to help, would have taught everyone the wrong cause.\r\n- **⚠ Two things that looked like disk fallout and are NOT**, recorded so this entry does not\r\n  overclaim. (a) `serve list` returning `SERVE_UNCONFIRMED`: doyle read it from source —\r\n  `servehost.rs` and `KIND_SERVE_REQUEST` are ABSENT at 0.67.0/0.67.1 and were minted by 0.68.0, and\r\n  the resident broker is still the 0.67.0 image after the brain-only flip, so the CLI's 10 s bound\r\n  times out **by design** against an older daemon. (b) `peer reachability: DEGRADED, 4 of 7 peers\r\n  unreachable for 882775 s` — 10.2 days, predating the incident entirely. Even the pump term is\r\n  claimed as CONCURRENT, not caused: hertz called the pump recovered off ONE post-reclaim sample\r\n  (54 s) and doyle falsified it two minutes later (133 s), because a single reading of a monotonic\r\n  \"last tick N s ago\" counter cannot separate STILL TICKING from TICKED ONCE, and a fresh project\r\n  index proves the coordinator loop, not the pump.\r\n- **Remedy — one guard, two placements, and it REFUSES rather than runs:**\r\n  1. **Rig start.** For the two-host rig and any test rig that shells out to `git bundle` or writes a\r\n     store: read free space on the volume holding the rig's temp root and `target`, and under a floor\r\n     fail immediately with a message that says DISK and prints the number — never enter the\r\n     ceremony. Floor: start at **10 GiB**, above the largest single artifact these rigs write and far\r\n     below any healthy state of this box; tune only with a measurement.\r\n  2. **Failure text**, for the case where space runs out MID-run and no start check can catch it:\r\n     when a shelled-out git/store operation fails, append the current free space to the error before\r\n     it becomes a product refusal string, so the panic that reaches a human already carries the\r\n     falsifier.\r\n- **WHY BOTH, measured rather than argued (hertz, 2026-09-09, the #209 lane):** a floor read ONCE at\r\n  rig start would have PASSED that run and the run still ended nearly empty — `cargo check` started\r\n  at **136.32 GiB** free, the test-profile build of 221 binaries took it to **40.18 GiB in ten\r\n  minutes**, the legs finished at **16.24 GiB**, and it read **12.27 GiB** ninety seconds later. A\r\n  start-only guard is a guard against yesterday's disk. That last ~4 GiB fell with those legs already\r\n  terminal; the candidates are the runner's CI job and its `_work` tree, unsampled and therefore\r\n  UNATTRIBUTED.\r\n- **The record itself, and the only one that caught the dip (hertz, 2026-09-09):**\r\n  `.spt/preserved/hertz-leak-670-legs/disk-full-trace.log` — **139 samples, 11:52:46Z–13:57:07Z, one\r\n  per minute**, max **238.41 GiB** @12:45:20Z, min **12.53 GiB** @12:12:45Z. Two samples fall under\r\n  15 GiB — **14.85** @12:12:11Z and **12.53** @12:12:45Z — both inside the #209 leak lane's\r\n  build-and-teardown window, i.e. AFTER a start floor would have passed the run at **136.15 GiB**\r\n  (the window's first sample). Two caveats, both binding on any reading of it: **the true minimum is\r\n  unbounded below 12.53 — the sampler cannot see between its samples**, and **it attributes nothing:\r\n  hertz's own legs and the runner's CI job are indistinguishable in it.** It is the SECOND instrument\r\n  on this incident and the only one covering the dip: doyle's 30 s trace, preserved at\r\n  `.spt/preserved/ir90-free-space-trace-2026-09-09/free-sampler-12-13Z-to-12-28Z.txt`, runs\r\n  12:15:37Z–12:31:10Z and so begins after hertz's reap — it records the RECOVERY, this one records\r\n  the FALL. sha256 `d58ce838b677e62d4a017e77524f899fda81e7bacf73a0e2a05a1192e60abaf2`\r\n  (doyle's, `8bdae01bc151597070d7011443a2cdc74614232dbc962faec1b1b1833c71f22a`).\r\n- **Explicitly NOT the remedy:** a bigger disk, or a reap schedule. ~195 GiB of headroom was consumed\r\n  by ordinary work, ACCRUED across a ~45-minute build phase; **no reading bounds a rate** — the\r\n  free-space observations either side are endpoints of an accrual, and a rate derived from them\r\n  retargets a hunt (deployah's went to runaway logs, VSS and torrent preallocation on the strength of\r\n  a `>150 MB/s` derived that way, while the measured live box-wide write rate was ~1.5 MB/s). What\r\n  consumed it: two `cargo nextest run -E <5-test filter>` lanes at **82.88** and **64.44 GiB** — a\r\n  filter narrows the RUN, never the BUILD, and both built 221 test binaries under the `test` profile\r\n  — plus 40.93 GiB of `C:\\actions-runner\\_work` and 9.8 GiB of `%TEMP%`. Any headroom this box\r\n  has is two cold pools away from gone, so the guard must be a REFUSAL, not a budget.\r\n- **Kin:** **IR-85** (the same box's fs-heavy slowdown; a near-full volume is now a named environment\r\n  term there), **IR-86** (a start floor that passes a box which cannot finish — the same defect one\r\n  layer up, and this entry is its mid-run half), **IR-76** (the golden runner is the operator's\r\n  desktop), `disk-full-reds-as-lnk1318-pdb-error` (memory; this is its third face and its standing\r\n  gap), `test-profile-pool-outgrows-the-disk-floor`, `free-space-floor-blocks-golden`.\r\n- **Ripe when:** now. · **Size:** one assertion plus one error-context append, both test-side.\r\n\r\n### IR-91 — 561 untracked files sat at the repo root, 18 of them cited by tracked files, and the census that classified them used a corpus that made the discriminator invisible\r\n\r\n- **Status:** CLOSED by the lane that filed it (the root-scratch classify PR), hertz 2026-09-09 on\r\n  doyle's census and rulings. · **Origin:** the `.spt/` ignore lane (PR #212) named 561 untracked\r\n  root files as explicitly out of scope; this is that half.\r\n- **The population, measured at `2037bcb8`:** `git status --porcelain --untracked-files=all` = **561\r\n  `??` rows, all at the repo root, zero in subdirectories**, 50,034,994 bytes (47.7 MiB). By\r\n  extension: 268 `.raw`, 184 `.exit`, 87 `.md`, 7 `.out`, 4 `.log`, 4 `.done`, 2 `.txt`,\r\n  2 `.stackdump`, 2 `.sh`, 1 `.py`. **A `git add -A` at the root staged every one of them**, which\r\n  is the same landmine `.spt/` carried before #212 and the reason this is one arc in two lanes.\r\n- **⚠ THE FINDING, and it is about the CENSUS, not the files:** the first classification put two\r\n  cited files in the \"bury\" class. `W3-196-CENSUS.md` and `WEBSERVE-272-JIT.md` were recorded as\r\n  \"cited only from other root scratch\" — citing files `W3-196-JIT.md` and `W3-272-MEASUREMENTS.md`,\r\n  which are **TRACKED**. The census corpus was tracked-only, so **every hit it produced was a\r\n  tracked citation by construction**; the two were then relabelled by their PATH, because a `.md`\r\n  sitting at the repo root reads as scratch. **The discriminator is TRACKED-OR-NOT, never\r\n  ROOT-OR-NOT** — and a corpus that can only return tracked hits cannot tell you which of its own\r\n  hits are tracked, because it has already thrown away the distinction. Burying those two would have\r\n  left two tracked files citing paths that no longer existed: the `launch-battery.py` mechanism from\r\n  **IR-90**'s sibling lane with the sides swapped, caught here only because the burial list was\r\n  re-verified against the corpus a second time by a different reader.\r\n- **The second finding, which withdrew the lane's own destinations:** the repo root **already holds\r\n  140 tracked files, 134 of them `.md`, 25 with `JIT` in the name** — `IDLE-EDGE-JIT.md`,\r\n  `W3-196-JIT.md`, `WEBSERVE-272-W2-JIT.md`, every `M*-PLAN.md`, `MESH-D*-PLAN.md`,\r\n  `RESTORATION-D*-PLAN.md`. **The house convention is measured, not assumed: a plan or record lives\r\n  at the repo root and is TRACKED.** The first ruling would have relocated the cited files into\r\n  `docs/intake/`, `docs/design/` and `docs/gate-records/` — splitting siblings across two homes\r\n  (`WEBSERVE-272-W2-JIT.md` at root, `WEBSERVE-272-W3-DRIFT-RIDERS.md` in `docs/intake/`) and\r\n  repointing 18 citation lines to buy that split. **Destinations withdrawn; the 18 are tracked where\r\n  they are.** Zero moves, zero repoints, zero sha-transfer risk. A lane that tidies against a\r\n  measured convention is not tidying.\r\n- **THE RULE, which is what this entry is for:** *a plan or record cited from a tracked file is\r\n  itself tracked, at the path the citation already names.* The root is a legal home. What decides a\r\n  file's fate is whether the repo points at it — not where it sits, not what it is called, and not\r\n  whether it looks like scratch.\r\n- **What the lane did:** **18 Class A** files `git add`ed in place. **473 Class B** gate legs\r\n  (`.raw`/`.exit`/`.done`/`.log`/`.out`/`.stackdump`/`.sh`/`.txt`, zero tracked citations, each\r\n  word-bounded against the whole 911-file tracked corpus) **MOVED — not deleted** — to\r\n  `.spt/preserved/root-gate-legs-2026-09-09/` with a sha256 manifest, every file hashed before and\r\n  after the move. **70 Class C** uncited `.md` likewise to `.spt/preserved/root-md-2026-09-09/`.\r\n  Then five **root-anchored** ignore lines: `/*.raw` `/*.exit` `/*.done` `/*.out` `/*.stackdump`.\r\n- **Why those five and not more.** Legs are the one class whose FUTURE instances are scratch **by\r\n  construction**, so ignoring them institutionalizes no loss. `/*.md`, `/*.log`, `/*.sh` and\r\n  `/*.txt` are deliberately NOT ignored: a plan or script dropped at the root must keep showing as\r\n  `??` so the next census classifies it — **that is exactly the pattern that produced this repo's\r\n  140-file tracked root corpus**, and an ignore line there would hide the next one. The anchoring is\r\n  load-bearing and was proved with a negative control: `crates/probe.raw` is **not** ignored, which\r\n  an unanchored `*.raw` would have swallowed.\r\n- **Kin:** the `.spt/` ignore lane (PR #212 — same arc, and its `launch-battery.py` case is why\r\n  nothing here was deleted), **IR-90** (a citation into `.spt/preserved/` is machine-bound evidence,\r\n  never a repo path), `ignoring-a-directory-buries-what-the-repo-cites-in-it` (memory).\r\n- **Ripe when:** landed with this entry. · **Size:** one `.gitignore` stanza, 18 adds, 543\r\n  preserved files, no deletions.\r\n\r\n### IR-92 — the message that WAKES an idle spt-hosted endpoint rides a delivery leg that never publishes MSG_IN, so a woken agent's own funnel holds none of the messages that woke it\r\n\r\n- **Status:** OPEN — filed doyle 2026-09-09 from hertz's census, probe and proposed text (his by\r","truncated":true,"truncatedBy":"lines","totalLines":914,"totalBytes":38259,"outputLines":421,"outputBytes":38259,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":5900,"displayContent":{"text":"### IR-86 — golden's 32 GiB floor is BELOW the measured 67.4 GiB Windows suite footprint, so a start floor passes a box that cannot finish\n…\n- **Status:** OPEN, filed by doyle 2026-09-08 at the #272/v0.68.0 golden r2 triage. · **Origin:**\r\n  run 34262154550 @ `25e60015` (shaped on `e4444413`), Windows test job 102182665033: every product\r\n  step green (Phase A 3346/3346, Phase B 234/234, Summary 2, FAIL 0), the ONLY reds were the two\r\n  in-job floor gates. `FLOOR_START` 97,649,786,880 B PASS at 18:47:23Z -> `FLOOR_DOCS`\r\n  25,284,501,504 B RED at 19:31:55Z -> `FLOOR_END` RED. Consumed in-job: 67.4 GiB.\r\n- **Mechanism:** `golden.yml` derives 32 GiB as \"the observed tens-of-GB full-suite footprint\r\n  rounded up to the next binary boundary, preserving headroom for one complete run\" (comment\r\n  above the Windows start floor). The measured footprint is 67.4 GiB, so a start reading anywhere\r\n  in [32, ~100) GiB passes and the job then walks under the floor by construction: box baseline\r\n  91 GiB minus 67.4 = 23.5 < 32. This is a shortfall of the DERIVATION, not a rate, not a product\r\n  red, and not the instant-vs-sustained face IR-46 files (that face is fixed by the FLOOR_DOCS\r\n  re-read, which is what caught it). The start floor must be footprint + end-floor (~100 GiB) or\r\n  it asserts nothing about finishing.\r\n- **Coverage consequence (the load-bearing part):** the Windows `Docs drift gate (CLI ref + llms\r\n  links)` step is sequenced BEHIND `FLOOR_DOCS`, so it SKIPPED and r2 held NO Windows CLI-ref\r\n  axis at that sha until the rerun. A floor red that skips a gate is a coverage hole wearing a\r\n  disk red.\r\n- **Kin:** [[IR-46]] (a floor asserts an instant), [[IR-59]] (pool arithmetic, LNK-class reds\r\n  that name no disk), [[IR-64]] (the operator-payload reservoir that sets the box baseline; its\r\n  ripe-when arm — a golden that dies at the floor despite adopted pool discipline — FIRED here\r\n  in the in-job form), [[IR-73]] (second half BUILT: the within-job re-read exists and is what\r\n  produced the FLOOR_DOCS reading), REQ-CI-FREE-SPACE-PREFLIGHT.\r\n- **Coupling (deployah 23:54Z, from `golden.yml` at `25e60015`):** the Windows `DISK docs floor`\r\n  (:616) and `Docs drift gate — windows` (:629) carry only `if: runner.os == 'Windows'`, no\r\n  `always()`, while `DISK end floor` does (`always() && runner.os == 'Windows'`, ~:705). Actions'\r\n  default is \"previous steps succeeded\", so ANY Phase B red skips the docs axis by construction —\r\n  observed three times at this sha (floor red, ttl cell, ttl cell). The docs gate is therefore never\r\n  independent evidence: it can only be banked when Phase B is green in the same job. Remedy line:\r\n  gate the two docs steps on `!cancelled()` plus the success of the steps they actually depend on\r\n  (checkout/build), not on Phase B — a rig change, new sha, hertz workflow rider slot.\r\n- **Remedy shape:** re-derive the start floor from the measured footprint (67.4 GiB Windows,\r\n  Linux to be measured) plus the 32 GiB end floor, print the footprint (start minus end free)\r\n  on every run so the number re-measures itself, and keep the 32 GiB literal only for\r\n  `FLOOR_END`.\r\n- **Ripe when:** next `golden.yml` touch (hertz workflow rider slot). · **Size:** small — one\r\n  literal per start-floor site + one printed subtraction.\r\n\r\n### IR-87 — two-host ceremony halves are INDEPENDENT jobs on DIFFERENT runners (A Windows/hfenduleam, B Linux/kitsubito); B's 900 s budget runs on B's own clock, so any older queued Windows job starves A and reds B deterministically, and the panic text blames pairing\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-08 at the #272 golden r2 triage. · **Origin:**\r\n  run 34262154550, twohost-b job 102207296960 (log 81,692 B, sha256 67403f04…8030): role B built,\r\n  rostered, polled PAIR_MEET_UP every 30 s from 19:34:30Z, and hit the rig_wait barrier\r\n  \"pairing: A rostered via the daemon-hosted responder\" at its 900 s deadline 19:49:17Z\r\n  (`crates/spt-daemon/tests/twohost.rs`, exit 101, 2 passed 1 failed). twohost-a (102207296985)\r\n  was QUEUED from 19:32:13Z with no runner: the Windows runner went to thin ci run 34261096301\r\n  (post-merge on main @ `e4444413`) the second the golden test job released it at 19:31:56Z.\r\n- **Mechanism:** `golden.yml` sequences twohost-a and twohost-b after `test`, but they are two\r\n  jobs on two runners (measured 2026-09-08 20:56Z via the jobs API `runner_name`: twohost-a on\r\n  hfenduleam, twohost-b on kitsubito), and GitHub's queue does not honour a workflow's intra-run\r\n  job ordering against a FOREIGN run on either runner. B starts, its whole budget ticks against a partner that has not been\r\n  scheduled, and `rig_wait` panics `never converged on the rig: {what}` — a text that reads as a\r\n  pairing defect. The lanes were not at fault, and twohost-a's outcome was predetermined once B\r\n  exited (a later A pass would be vacuous).\r\n- **Kin:** [[IR-76]] (hfenduleam is golden runner AND builders' box; the job-start census cannot\r\n  see a competing GitHub run either), [[IR-62]] (rig collisions on shared runners), the W1 two-host\r\n  rig, `a-barrier-cannot-ride-a-carrier-its-sender-outlives` (memory, same family: a barrier needs\r\n  the receiver's own answer).\r\n- **Remedy shape (pick at rider time):** (1) start barrier on B keyed to A's job having STARTED\r\n  (a run-scoped artifact or a `needs`+matrix collapse into ONE job that spawns both roles), or\r\n  (2) B's deadline clock starts at first A-rostered signal with a separate, longer \"A never\r\n  appeared\" budget, or (3) the panic names the missing partner's job state so triage does not\r\n  chase pairing. Any option: the two-host halves must never share a runner queue with a foreign\r\n  run while one half waits.\r\n- **Ripe when:** next `golden.yml`/twohost rig touch. · **Size:** small-medium (job shape or\r\n  barrier rework + panic text).\r\n\r\n- **AMENDMENT 2026-09-10 (releases#294, golden 34445961595 att1 @ `a9e786b2`) — THE STARVING RUN CAN\r\n  BE GOLDEN'S OWN PR, which makes this self-inflicted and recurrent on every golden run with a PR\r\n  open.** Measured timeline: **07:18:59Z** golden `test (Windows)` completes and releases hfenduleam;\r\n  **07:18:59Z** twohost-a queued; **07:19:01Z** PR run **34446095808** job `unit (Windows,\r\n  hfenduleam)` SEIZES the runner; **07:19:02Z** twohost-b starts on the free kitsubito; **07:36:16Z**\r\n  twohost-b fails at **900.41s** — `never converged on the rig: pairing: A rostered via the\r\n  daemon-hosted responder`. The origin case (2026-09-08) was a post-merge push on `main`: a run\r\n  belonging to someone else. **Here the starving run is the `pull_request` run of the very PR carrying\r\n  the golden head**, so opening the golden PR arms the starvation of that same head's twohost pair.\r\n  **Consequence for the remedy shape above: any option that only de-conflicts against OTHER lanes'\r\n  runs does not reach this case.** The golden head's own PR has to be excluded from the Windows\r\n  runner for the duration of the golden run (or the pair collapsed into one job, option 1).\r\n- **SECOND-ORDER FACE (deployah, same run): starvation does not merely red B — it desynchronises the\r\n  pair past repair.** twohost-b was TERMINAL at 07:36:16Z; twohost-a did not start until **07:48:07Z**\r\n  — the two halves never overlapped for a single second, so twohost-a's outcome is uninformative\r\n  **whatever it says**, and a red there must not be counted as a second product failure. Recorded\r\n  honestly at deployah's own insistence: **VOID is his SCORING interpretation, not a fact about the\r\n  run** — the release record carries GitHub's raw `conclusion` for both jobs beside the scoring, not\r\n  laundered into it.\r\n- **⚠ ITS WALL CLOCK IS INDISTINGUISHABLE FROM [[IR-89]]'s.** A 900 s twohost red whose panel blames\r\n  pairing is ALSO the exact signature of the banked Windows-firewall hazard. The panel alone cannot\r\n  separate them; **the job TIMELINE can**. Check the schedule before accepting the firewall hazard for\r\n  any 900 s twohost red — this one fit that signature perfectly and was not it.\r\n\r\n### IR-88 — `pool-release` via `cargo run -p xtask` REBUILDS xtask INTO the pool it is releasing, so a reaped pool regrows ~2.8 GB in silence\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-08 from hertz's reap report (20:00Z) during the #272\r\n  golden r2 repair. · **Origin:** hertz reaped hertz-lane4 / hertz-repin / hertz-percell-id target\r\n  subtrees (Length-sum upper bounds 68.16 / 47.11 / 8.79 GB) and then ran `cargo run -p xtask --\r\n  pool-release …` from each worktree: cargo rebuilt xtask into the just-reaped `target/` (2.8 GB\r\n  back in lane4, partial in repin), nothing printed said so, and the descendancy stopper killed\r\n  the second before it finished. Removed by hand afterwards; the post-reap free reading on the\r\n  record (275.95 GiB at 19:55:51Z) predates the regrowth.\r\n- **Mechanism:** the documented verb (AGENTS.md: \"drop it with `pool-release`\") is a `cargo run`,\r\n  and cargo's default target for that run IS the pool being released. The verb's own success path\r\n  recreates the state the operator just measured away; a teardown step that runs it AFTER a reap\r\n  undoes part of the reap and leaves the recorded free reading stale.\r\n- **Remedy shape:** either (a) `pool-release` documented and scripted as a PREBUILT `xtask.exe`\r\n  invoked against `--pool <dir>` from another pool, or (b) the verb refuses when its own\r\n  `CARGO_TARGET_DIR`/default target equals `--pool` and prints the prebuilt form, or (c) the reap\r\n  recipe orders release BEFORE the subtree delete. Memory banked 2026-09-08\r\n  (`pool-release-rebuilds-xtask-into-the-pool-you-just-reaped`); this entry is the durable home.\r\n- **POSITIVE CONTROL (hertz, 2026-09-09, ruling-3 gate-r3 teardown):** the same release run\r\n  from a PREBUILT `xtask.exe` invoked from outside the pool regrew NOTHING — the pool's own\r\n  `xtask.exe` still carried its original 21:00:42 mtime afterwards, and the reap that followed\r\n  reclaimed 63.71 GiB (132.03 -> 195.74 GiB free) against a 64.88 GiB Length-sum. So the\r\n  regrowth is a property of the `cargo run` VEHICLE, not of the verb, and remedy (a) is proven\r\n  rather than merely proposed.\r\n- **Kin:** [[IR-31]] (pool budgeting), [[IR-56]] (pool-claim identity from CWD — same verb\r\n  family, same \"the tool acts on where it stands\" shape), releases#103.\r\n- **Ripe when:** next xtask pool-verb touch or the teardown runbook edit. · **Size:** tiny —\r\n  one guard or one doc line.\r\n\r\n### IR-89 — hfenduleam's Windows Firewall drops cold inbound UDP to the runner-built test exes, so the two-host rig's first B→A claim (W2 helper) reds for its whole 900 s budget and the panic blames A\r\n\r\n- **Status:** BOX HALF **APPLIED** 2026-09-08; WORKFLOW HALF **BUILT** 2026-09-09 — PR #211\r\n  (`9b96d7e7` + this amendment), **LANDED, exact golden-step acceptance unreconciled**.\r\n  Subsequent goldens have run: \"until the next golden\" is no longer a future trigger.\r\n  This sweep does not infer probe execution from a run's existence or overall conclusion;\r\n  retain the step-specific exercised/skipped/failed evidence before closing. Filed by doyle 2026-09-08\r\n  at the #272 golden r2 terminal triage; the operator-blocked flag is retired here, because\r\n  the operator acted.\r\n  The operator applied BOTH layers that evening — the Windows inbound rule (~23:41Z) and the\r\n  tailnet ACL grant (~23:56Z) — and the re-probe with the same rule-less pwsh listener read\r\n  **3/3 over Tailscale on 7483 AND 3/3 on 7489 at 23:57:50Z** from `100.98.197.12`, with a\r\n  post-terminal probe 3/3 on both ports at attempt 4. v0.68.0 then shipped at `a2f335f8` with\r\n  both two-host legs GREEN on golden r4, so the box half is closed by measurement and not by\r\n  assertion. **Durable half BUILT, acceptance reconciliation OPEN:** the pre-ceremony B→A\r\n  probe and its corrections are documented below. Do not redispatch a workflow guard that\r\n  already landed, or reopen the spent operator permission. The next box/ACL reset remains a\r\n  recheck trigger. · **Origin:** run 34262154550 @ `25e60015`, twohost-a 102229928746\r\n  (`two_host_web_helper_role_a`, :968, 900.40 s) and twohost-b 102229928689\r\n  (`two_host_web_role_b`, :559, 910.20 s): B logged 75 × \"A not ready … broker QUIC op exceeded\r\n  the 10s bound (peer unresponsive)\" from 20:49:49Z to 21:04:37Z and was never ADMITTED. Ladder\r\n  green both sides; both halves started 20:41:23Z on their own runners (not IR-87's starvation).\r\n- **Mechanism (MEASURED 21:11Z):** the box's firewall policy is `BlockInbound,AllowOutbound` on\r\n  all three profiles (Ethernet and Tailscale both Private). Inbound allow rules exist only for\r\n  exes under `Documents\\projects\\spt-core\\target` (interactive Allow clicks) and under the DEAD\r\n  pre-rename runner path `_work\\spt-core\\spt-core`; exactly ONE under `_work\\spt-bs-core` (its\r\n  `target\\debug\\spt.exe`, the CLI, not the binder — deployah's count, mine had said zero), none for\r\n  any `twohost_web-*.exe`. `Get-NetFirewallProfile` shows `DefaultInboundAction = NotConfigured`,\r\n  whose effective default IS block: the block is Windows' default, not a configured policy, so there\r\n  is no policy to \"restore\". The runner is a service (`.\\decid`), so the Allow dialog that minted the\r\n  old rules cannot appear. A's helper cell 3 bound `broker udp 7483` inside\r\n  `_work\\spt-bs-core\\spt-bs-core\\target\\debug\\deps\\twohost_web-f73bc44be13353fb.exe`; B dialled\r\n  `100.68.35.65:7483` cold. Probe: a rule-less pwsh UDP listener on hfenduleam:7483 received 0 of\r\n  3 datagrams from kitsubito `100.98.197.12`; the reverse control (python listener on\r\n  kitsubito:7483) received 3 of 3 from hfenduleam.\r\n- **Why three faces from one cause:** the shared-key rig (pre-`e4444413`) reached A only through\r\n  holes A's OUT-dialling cells (7480–7482) had opened for `id_a` — six 10 s bounds until B's\r\n  magicsock fell onto one of those paths, then ADMITTED (the 63 s stall, helper-stall memory), or\r\n  onto a live same-key sibling that never replied (the 21 min hang in 34239258523). Per-cell A\r\n  identity (`id_a_for`, `e4444413`) removed the accidental route by construction, leaving only\r\n  the cold path, which the firewall drops. hertz's one-box discriminator \"vanishes\" was true on\r\n  one box because one box never crosses the firewall. Product and rig are both exonerated; the\r\n  rig's `a_addr` comment already names W2 as the first A-ward claim.\r\n- **Remedy (two halves):** (1) BOX, operator-owned, elevated on hfenduleam:\r\n  `New-NetFirewallRule -DisplayName \"spt-ci two-host rig UDP-In (kitsubito only)\" -Direction Inbound -Action Allow -Protocol UDP -LocalPort 7460-7499 -RemoteAddress 100.98.197.12 -Profile Any`\r\n  (rig ports at the sha: ladder 7460/7461; web `PORT_OFFSET` 20 → A cells 7480–7483, B 7481; the\r\n  A-ward surface today is exactly UDP 7480–7483 — deployah's tighter range — and the whole range\r\n  moves with any `SPT_TWO_HOST_PORT_A` override, so the rule must move with it);\r\n  program-path rules are the wrong shape because the exe hash changes per build. Verify with the\r\n  same probe (3/3) before any rerun. (2) WORKFLOW, hertz: a B→A UDP probe step in the twohost\r\n  jobs before the ceremony, so this reds in 10 s with its own name instead of 900 s blaming\r\n  pairing; and retire the dead `_work\\spt-core` rules note in the runner runbook.\r\n- **Kin:** [[IR-83]] (the tailnet-ACL face of a cross-box inbound block — KIN, **NOT the same\r\n  finding**: that entry is the tailnet policy layer, this one is the Windows firewall layer, and\r\n  the SECOND LAYER note below is exactly the measurement that separates them), [[IR-87]] (the\r\n  other way a half waits 900 s on a partner), [[IR-76]] (golden runner\r\n  is the operator's box), [[IR-64]] (box-level facts only the operator can move),\r\n  `twohost-web-helper-stall-shared-a-identity-stale-path` (memory; its CONFIRMED arm is re-read\r\n  by this entry).\r\n- **AMENDMENT 2026-09-09 — the WORKFLOW half is BUILT and FIELD-MEASURED; it is LANDED-pending-golden\r\n  (hertz).** The guard is two cells in `twohost_web.rs` plus a step per half in `golden.yml`, and it\r\n  grew four design corrections that are worth more than the guard itself, because each one is a way a\r\n  probe can certify the fault it exists to catch.\r\n  1. **A FIXED SYMMETRIC WINDOW ADDS A THIRD CAUSE THAT LOOKS LIKE THE OTHER TWO.** The step boundary\r\n     orders the probe on ONE host; it does not align two, and after the ladder each half pays its own\r\n     wrapper and `cargo test` (on Windows a fingerprint scan plus Defender's first touch of a fresh\r\n     exe). MEASURED: the first hand-run in the A=kitsubito direction (13:14:13 → 13:14:51Z) redded\r\n     `INBOUND_BLOCKED` at 10.24 s with text asserting \"a BOX rule, not a product or rig fault\" — and\r\n     the cause was `cargo`'s start-up on the SENDER putting its first datagram after the receiver's\r\n     10 s window closed. An innocent box, the guard's own words against it. What stopped it being\r\n     filed as a kitsubito block was that the box facts contradicted the text (`tailscale debug\r\n     netmap` on kitsubito lists `100.68.35.65/32` among its permitted inbound sources, and `ufw` is\r\n     inactive) — a failure text that contradicts a measured box is the text's defect. So the\r\n     rendezvous is DATA: A listens up to the rig budget and beacons once a second; B binds first,\r\n     waits for a beacon, and only then starts a ten-second clock, so B's red has already excluded\r\n     \"A is not up\". That is a FOURTH outcome with its own name, `PROBE_NO_BEACON`, never\r\n     `INBOUND_BLOCKED`.\r\n  2. **THE LISTENING SOCKET MUST NEVER SEND.** Any outbound datagram from the measured port opens\r\n     stateful return state for it, so B's probe then arrives SOLICITED and crosses under both layers\r\n     — this entry's own \"solicited return traffic works under either fault\" applied to the guard\r\n     rather than to the ceremony. MEASURED: with the beacon sharing A's listening socket, the\r\n     out-of-grant control went **GREEN at 13:28Z** on a port a listen-only run had measured BLOCKED\r\n     at 13:20Z; a further green at 13:31Z with the beacon moved but the ack still leaving that socket\r\n     was residual state from 13:28 — true BY ELIMINATION rather than by assertion: nothing in the\r\n     13:31 run sent from 7509 before the first arrival, so the only outbound that could have opened\r\n     that port's return state belongs to the previous run. Beacon and ack both leave an ephemeral socket now, and B sends\r\n     from an ephemeral port too, so no run repeats a 4-tuple a previous run opened.\r\n  3. **THE ACK IS ADDRESSED TO B'S RIG PORT, not to the probe's source port.** MEASURED: acking to\r\n     `from` produced a run that CONTRADICTED ITSELF — A said `INBOUND OK` and B said\r\n     `INBOUND_BLOCKED`, same run, 13:41:33 → 13:41:50Z — because A's ack leaves its ephemeral\r\n     socket, is therefore not return traffic of the flow B opened, and a receiver whose inbound rule\r\n     is a port RANGE drops it. The rig port is the only address either host is reachable on cold.\r\n  4. **THE FALSIFIER, and it is the operator's own rule used as an instrument.** Forcing the probe\r\n     port to **7509** (`SPT_TWO_HOST_PORT_A=7480`), one port outside the granted udp 7460-7499, reds\r\n     the guard on demand with no elevation and no policy edit. Run TWICE BACK TO BACK at the final\r\n     code, 13:43:41 → 13:44:23Z and 13:44:25 → 13:45:07Z: **RED, RED** — A after 40 s having sent\r\n     39 beacons, B in its ten seconds having sent 48 and 47 datagrams with no ack, both exit 101.\r\n     One red would only prove a state timeout expired; two consecutive reds prove the design writes\r\n     none. The grant boundary is therefore measured from inside the test binary: 7489 crosses, 7509\r\n     does not, same hosts, same binary, one env var apart.\r\n  5. **ONE ACK IS NOT ENOUGH — the same split verdict arrives by packet loss** (doyle, reviewing the\r\n     built lane). A acking ONCE and breaking leaves B's red resting on a single unrepeated UDP\r\n     datagram: lose it and A prints `INBOUND OK` while B reds `INBOUND_BLOCKED`, blaming a firewall\r\n     for ordinary loss — correction 3's defect reached by a different road. A now keeps draining for\r\n     a short window after its own verdict is already settled and acks EVERY probe in it, while B\r\n     stops on the first ack. The A-side assertion is unchanged: it was decided by the first datagram.\r\n  6. **THE PROBE STEPS CARRY THEIR OWN BUDGET, 300 s, set EXPLICITLY** beside ceremony steps that say\r\n     900. It bounds RENDEZVOUS skew, not pairing, so a blocked link costs 300 s ONCE instead of 900\r\n     per cell per half. Left unset it would have been `from_env`'s invisible default sitting next to\r\n     a visible 900 on the step below — a number the next reader would have inferred wrongly, which is\r\n     this entry's whole failure mode in miniature.\r\n- **FIELD PROOF, 2026-09-09, and it is the ONLY proof this guard has:** `dir 1` (A=hfenduleam,\r\n  B=kitsubito) 13:45:14 → 13:45:18Z and `dir 2` (A=kitsubito, B=hfenduleam) 13:45:41 → 13:45:58Z,\r\n  both GREEN with the ack after ONE datagram, both exits 0, both hosts running byte-identical source\r\n  (md5 `f31779339266f8034dcd72917c56a37e`, checked on both sides). Free space 174.38 GiB, flat across\r\n  all four arms.\r\n  ⚠ **THE `golden.yml` STEPS THEMSELVES ARE UNEXERCISED UNTIL THE NEXT GOLDEN RUN.** Thin CI\r\n  compiles the cells and SKIPS them — `Rig::from_env` returns `None` without `SPT_TWO_HOST`, so a\r\n  green thin run says the code builds and nothing about the steps. The wall times above are the field\r\n  proof; treat the workflow half as landed-pending-golden and not as verified by its own PR.\r\n- **Ripe when:** the next GOLDEN run, which is the first thing that exercises the steps — the\r\n  code half is built and field-measured (PR #211). (The box half was ripe \"now\" against\r\n  `25e60015` and is done; #272 golden acceptance is no longer blocked by it.) · **Size:** one\r\n  workflow step remaining; the elevated command is spent.\r\n- **SECOND LAYER (measured 23:41–23:50Z, after the operator applied the Windows rule exactly as\r\n  asked and the re-probe STILL read 0/3):** the tailnet ACL. The same `python.exe` listener (own\r\n  program rule) received 3/3 from kitsubito over the LAN (`192.168.1.168 → 192.168.1.81:7483`) and\r\n  0/3 over Tailscale (`100.98.197.12 → 100.68.35.65`), TCP connect over Tailscale times out too,\r\n  solicited return over Tailscale works, ShieldsUp false both ends. `tailscale debug netmap` on\r\n  hfenduleam: one PacketFilter rule, 18 permitted inbound sources, kitsubito ABSENT; kitsubito is\r\n  `tag:eye-tracking-resource` owned by a different tailnet user, and its own filter DOES permit\r\n  hfenduleam. Asymmetric policy: member device → tagged resource allowed, reverse denied. The\r\n  Windows rule was NECESSARY (rule-less exe, LAN probe 0/2 earlier) and NOT SUFFICIENT. Remedy\r\n  half (1) gains an ACL grant, operator-owned in the admin console:\r\n  `{\"action\":\"accept\",\"src\":[\"tag:eye-tracking-resource\"],\"dst\":[\"hfenduleam:7460-7499\"],\"proto\":\"udp\"}`.\r\n  Rider 4's failure text names both layers and the LAN-vs-Tailscale probe as the discriminator.\r\n  Lesson for the entry: a cross-box \"unresponsive\" has at least THREE layers (Windows rule, tailnet\r\n  policy, the exe's own bind); probe through the SAME path the rig uses, and re-probe after every\r\n  single change — the first fix reading as \"applied\" is not the probe reading 3/3.\r\n- **Corroboration + reading traps (deployah 23:50Z, from the box):** Windows rule found present by\r\n  FILTER search (`netsh advfirewall firewall show rule name=all dir=in verbose`), not by name — the\r\n  operator's name is hyphenated \"two-host\" and a `twohost` grep reads it ABSENT. Netmap: the single\r\n  filter permits ALL ports and ALL protocols from its 18 sources, so the grant is SOURCE-scoped, not\r\n  port-scoped — \"this peer is not a permitted source at all\", which is why TCP timed out beside UDP.\r\n  Two permitted sources (100.98.213.33, 100.98.214.87) share kitsubito's 100.98/16 and read as hits\r\n  to an eyeball scan for \"100.98.\"; test membership of the full /32, never a prefix. His first netmap\r\n  read extracted a non-existent field (`SrcIPs`; the real key is `Srcs`), printed an empty list and\r\n  minted a confident \"ABSENT\" — an empty extraction cannot witness absence; the 18-count is from the\r\n  corrected read. Prefs on the box: ShieldsUp false, NoStatefulFiltering true, RouteAll true,\r\n  NetfilterMode 2 — nothing there explains the drop.\r\n- **Probe-rider design rule (hertz, d882297f):** the pre-ceremony probe reds `INBOUND_BLOCKED` for\r\n  EITHER layer and does not pretend to know which — its job is \"the box cannot receive, stop triaging\r\n  the product\"; the layer is named only by the one measurement that decides it (same listener, LAN\r\n  vs Tailscale), which the failure text prints as a recipe. A guard that names a cause it did not\r\n  measure is the defect class this whole entry documents.\r\n\r\n### IR-90 — a full disk on the self-hosted box reds a rig as a PRODUCT refusal, not a build error, and no rig or gate records the free space that would falsify it\r\n\r\n- **Status:** OPEN, filed by hertz 2026-09-09 from the disk-full incident on hfenduleam. ·\r\n  **Origin:** the IR-85 discriminator lane's head arm, killed by the volume rather than by the code\r\n  under test.\r\n- **Symptom:** `spt-daemon::sync concurrent_writes_reconcile_on_elected_node_and_converge` FAILED at\r\n  67.588 s with a panic in our own test at `crates\\spt-daemon\\tests\\sync.rs:198`:\r\n  `pull: Custom { kind: Other, error: \"sync refused: bundle failed: git -C <tmp>\\tracked-b\\.seed.git\r\n  bundle create <tmp>\\scratch\\serve\\serve-pull-6.bundle ^d12a7134... a-doyle failed (exit Some(1)):\r\n  fatal: sha1 file '<stdout>' write error. Out of diskspace\\nerror: pack-objects died\" }`, then a\r\n  second panic at `:213` (`pull thread: Any { .. }`) as the harness thread unwound.\r\n- **Cause:** `C:` was at **0.018 GiB free of 1862.02 GiB (0.00%)** at that instant\r\n  (`Win32_LogicalDisk`, 10:57Z). `git bundle create` could not write; the daemon's serve path turned\r\n  that into its real product refusal string `sync refused: bundle failed`; the test asserted on the\r\n  refusal. **Every layer behaved correctly, and the report reads as a sync regression at the sha\r\n  under test.**\r\n- **Why it is worse than the disk faces already known:** the two banked faces\r\n  (`disk-full-reds-as-lnk1318-pdb-error`) are TOOLCHAIN costumes — `LNK1318` at link, and rustc\r\n  I/O before any link — and both route a reader to \"the box is sick\". This one routes to a CODE\r\n  OWNER: it names our file, our line and our refusal string, and the disk word sits in the FOURTH\r\n  nested clause behind a git exit code. It arrived mid-discriminator with an old sha and a new sha\r\n  side by side, where the cheapest reading — \"the head arm failed, the old arm passed\" — is a\r\n  head regression that does not exist.\r\n- **Blast radius, same incident:** the volume also carried a live `unit (self-hosted, Windows,\r\n  hfenduleam)` job (run 34341010297) compiling into it, which completed FAILURE on its own and was\r\n  ruled VOID after the fact. doyle's cancel of THAT run returned `Cannot cancel a workflow run that\r\n  is completed` — recorded because a register that credits a controlled action nobody performed\r\n  teaches the next reader that the box was under control. (The earlier run 34337797758, in\r\n  **IR-85**'s amendment, is a different run with a different ending: CANCELLED at the job wall. One\r\n  register putting one cancel string on the wrong run is the same defect, one run over.) `spt daemon status` went to peer pump last tick 185 s with 24 brain\r\n  subscribers stall-evicted (last evict 10:51:22Z, inside the disk window), with an operator restart\r\n  under consideration — a restart that risks the releases#287 shell stranding and that, had it\r\n  appeared to help, would have taught everyone the wrong cause.\r\n- **⚠ Two things that looked like disk fallout and are NOT**, recorded so this entry does not\r\n  overclaim. (a) `serve list` returning `SERVE_UNCONFIRMED`: doyle read it from source —\r\n  `servehost.rs` and `KIND_SERVE_REQUEST` are ABSENT at 0.67.0/0.67.1 and were minted by 0.68.0, and\r\n  the resident broker is still the 0.67.0 image after the brain-only flip, so the CLI's 10 s bound\r\n  times out **by design** against an older daemon. (b) `peer reachability: DEGRADED, 4 of 7 peers\r\n  unreachable for 882775 s` — 10.2 days, predating the incident entirely. Even the pump term is\r\n  claimed as CONCURRENT, not caused: hertz called the pump recovered off ONE post-reclaim sample\r\n  (54 s) and doyle falsified it two minutes later (133 s), because a single reading of a monotonic\r\n  \"last tick N s ago\" counter cannot separate STILL TICKING from TICKED ONCE, and a fresh project\r\n  index proves the coordinator loop, not the pump.\r\n- **Remedy — one guard, two placements, and it REFUSES rather than runs:**\r\n  1. **Rig start.** For the two-host rig and any test rig that shells out to `git bundle` or writes a\r\n     store: read free space on the volume holding the rig's temp root and `target`, and under a floor\r\n     fail immediately with a message that says DISK and prints the number — never enter the\r\n     ceremony. Floor: start at **10 GiB**, above the largest single artifact these rigs write and far\r\n     below any healthy state of this box; tune only with a measurement.\r\n  2. **Failure text**, for the case where space runs out MID-run and no start check can catch it:\r\n     when a shelled-out git/store operation fails, append the current free space to the error before\r\n     it becomes a product refusal string, so the panic that reaches a human already carries the\r\n     falsifier.\r\n- **WHY BOTH, measured rather than argued (hertz, 2026-09-09, the #209 lane):** a floor read ONCE at\r\n  rig start would have PASSED that run and the run still ended nearly empty — `cargo check` started\r\n  at **136.32 GiB** free, the test-profile build of 221 binaries took it to **40.18 GiB in ten\r\n  minutes**, the legs finished at **16.24 GiB**, and it read **12.27 GiB** ninety seconds later. A\r\n  start-only guard is a guard against yesterday's disk. That last ~4 GiB fell with those legs already\r\n  terminal; the candidates are the runner's CI job and its `_work` tree, unsampled and therefore\r\n  UNATTRIBUTED.\r\n- **The record itself, and the only one that caught the dip (hertz, 2026-09-09):**\r\n  `.spt/preserved/hertz-leak-670-legs/disk-full-trace.log` — **139 samples, 11:52:46Z–13:57:07Z, one\r\n  per minute**, max **238.41 GiB** @12:45:20Z, min **12.53 GiB** @12:12:45Z. Two samples fall under\r\n  15 GiB — **14.85** @12:12:11Z and **12.53** @12:12:45Z — both inside the #209 leak lane's\r\n  build-and-teardown window, i.e. AFTER a start floor would have passed the run at **136.15 GiB**\r\n  (the window's first sample). Two caveats, both binding on any reading of it: **the true minimum is\r\n  unbounded below 12.53 — the sampler cannot see between its samples**, and **it attributes nothing:\r\n  hertz's own legs and the runner's CI job are indistinguishable in it.** It is the SECOND instrument\r\n  on this incident and the only one covering the dip: doyle's 30 s trace, preserved at\r\n  `.spt/preserved/ir90-free-space-trace-2026-09-09/free-sampler-12-13Z-to-12-28Z.txt`, runs\r\n  12:15:37Z–12:31:10Z and so begins after hertz's reap — it records the RECOVERY, this one records\r\n  the FALL. sha256 `d58ce838b677e62d4a017e77524f899fda81e7bacf73a0e2a05a1192e60abaf2`\r\n  (doyle's, `8bdae01bc151597070d7011443a2cdc74614232dbc962faec1b1b1833c71f22a`).\r\n- **Explicitly NOT the remedy:** a bigger disk, or a reap schedule. ~195 GiB of headroom was consumed\r\n  by ordinary work, ACCRUED across a ~45-minute build phase; **no reading bounds a rate** — the\r\n  free-space observations either side are endpoints of an accrual, and a rate derived from them\r\n  retargets a hunt (deployah's went to runaway logs, VSS and torrent preallocation on the strength of\r\n  a `>150 MB/s` derived that way, while the measured live box-wide write rate was ~1.5 MB/s). What\r\n  consumed it: two `cargo nextest run -E <5-test filter>` lanes at **82.88** and **64.44 GiB** — a\r\n  filter narrows the RUN, never the BUILD, and both built 221 test binaries under the `test` profile\r\n  — plus 40.93 GiB of `C:\\actions-runner\\_work` and 9.8 GiB of `%TEMP%`. Any headroom this box\r\n  has is two cold pools away from gone, so the guard must be a REFUSAL, not a budget.\r\n- **Kin:** **IR-85** (the same box's fs-heavy slowdown; a near-full volume is now a named environment\r\n  term there), **IR-86** (a start floor that passes a box which cannot finish — the same defect one\r\n  layer up, and this entry is its mid-run half), **IR-76** (the golden runner is the operator's\r\n  desktop), `disk-full-reds-as-lnk1318-pdb-error` (memory; this is its third face and its standing\r\n  gap), `test-profile-pool-outgrows-the-disk-floor`, `free-space-floor-blocks-golden`.\r\n- **Ripe when:** now. · **Size:** one assertion plus one error-context append, both test-side.\r\n\r\n### IR-91 — 561 untracked files sat at the repo root, 18 of them cited by tracked files, and the census that classified them used a corpus that made the discriminator invisible\r\n\r\n- **Status:** CLOSED by the lane that filed it (the root-scratch classify PR), hertz 2026-09-09 on\r\n  doyle's census and rulings. · **Origin:** the `.spt/` ignore lane (PR #212) named 561 untracked\r\n  root files as explicitly out of scope; this is that half.\r\n- **The population, measured at `2037bcb8`:** `git status --porcelain --untracked-files=all` = **561\r\n  `??` rows, all at the repo root, zero in subdirectories**, 50,034,994 bytes (47.7 MiB). By\r\n  extension: 268 `.raw`, 184 `.exit`, 87 `.md`, 7 `.out`, 4 `.log`, 4 `.done`, 2 `.txt`,\r\n  2 `.stackdump`, 2 `.sh`, 1 `.py`. **A `git add -A` at the root staged every one of them**, which\r\n  is the same landmine `.spt/` carried before #212 and the reason this is one arc in two lanes.\r\n- **⚠ THE FINDING, and it is about the CENSUS, not the files:** the first classification put two\r\n  cited files in the \"bury\" class. `W3-196-CENSUS.md` and `WEBSERVE-272-JIT.md` were recorded as\r\n  \"cited only from other root scratch\" — citing files `W3-196-JIT.md` and `W3-272-MEASUREMENTS.md`,\r\n  which are **TRACKED**. The census corpus was tracked-only, so **every hit it produced was a\r\n  tracked citation by construction**; the two were then relabelled by their PATH, because a `.md`\r\n  sitting at the repo root reads as scratch. **The discriminator is TRACKED-OR-NOT, never\r\n  ROOT-OR-NOT** — and a corpus that can only return tracked hits cannot tell you which of its own\r\n  hits are tracked, because it has already thrown away the distinction. Burying those two would have\r\n  left two tracked files citing paths that no longer existed: the `launch-battery.py` mechanism from\r\n  **IR-90**'s sibling lane with the sides swapped, caught here only because the burial list was\r\n  re-verified against the corpus a second time by a different reader.\r\n- **The second finding, which withdrew the lane's own destinations:** the repo root **already holds\r\n  140 tracked files, 134 of them `.md`, 25 with `JIT` in the name** — `IDLE-EDGE-JIT.md`,\r\n  `W3-196-JIT.md`, `WEBSERVE-272-W2-JIT.md`, every `M*-PLAN.md`, `MESH-D*-PLAN.md`,\r\n  `RESTORATION-D*-PLAN.md`. **The house convention is measured, not assumed: a plan or record lives\r\n  at the repo root and is TRACKED.** The first ruling would have relocated the cited files into\r\n  `docs/intake/`, `docs/design/` and `docs/gate-records/` — splitting siblings across two homes\r\n  (`WEBSERVE-272-W2-JIT.md` at root, `WEBSERVE-272-W3-DRIFT-RIDERS.md` in `docs/intake/`) and\r\n  repointing 18 citation lines to buy that split. **Destinations withdrawn; the 18 are tracked where\r\n  they are.** Zero moves, zero repoints, zero sha-transfer risk. A lane that tidies against a\r\n  measured convention is not tidying.\r\n- **THE RULE, which is what this entry is for:** *a plan or record cited from a tracked file is\r\n  itself tracked, at the path the citation already names.* The root is a legal home. What decides a\r\n  file's fate is whether the repo points at it — not where it sits, not what it is called, and not\r\n  whether it looks like scratch.\r\n- **What the lane did:** **18 Class A** files `git add`ed in place. **473 Class B** gate legs\r\n  (`.raw`/`.exit`/`.done`/`.log`/`.out`/`.stackdump`/`.sh`/`.txt`, zero tracked citations, each\r\n  word-bounded against the whole 911-file tracked corpus) **MOVED — not deleted** — to\r\n  `.spt/preserved/root-gate-legs-2026-09-09/` with a sha256 manifest, every file hashed before and\r\n  after the move. **70 Class C** uncited `.md` likewise to `.spt/preserved/root-md-2026-09-09/`.\r\n  Then five **root-anchored** ignore lines: `/*.raw` `/*.exit` `/*.done` `/*.out` `/*.stackdump`.\r\n- **Why those five and not more.** Legs are the one class whose FUTURE instances are scratch **by\r\n  construction**, so ignoring them institutionalizes no loss. `/*.md`, `/*.log`, `/*.sh` and\r\n  `/*.txt` are deliberately NOT ignored: a plan or script dropped at the root must keep showing as\r\n  `??` so the next census classifies it — **that is exactly the pattern that produced this repo's\r\n  140-file tracked root corpus**, and an ignore line there would hide the next one. The anchoring is\r\n  load-bearing and was proved with a negative control: `crates/probe.raw` is **not** ignored, which\r\n  an unanchored `*.raw` would have swallowed.\r\n- **Kin:** the `.spt/` ignore lane (PR #212 — same arc, and its `launch-battery.py` case is why\r\n  nothing here was deleted), **IR-90** (a citation into `.spt/preserved/` is machine-bound evidence,\r\n  never a repo path), `ignoring-a-directory-buries-what-the-repo-cites-in-it` (memory).\r\n- **Ripe when:** landed with this entry. · **Size:** one `.gitignore` stanza, 18 adds, 543\r\n  preserved files, no deletions.\r\n\r\n### IR-92 — the message that WAKES an idle spt-hosted endpoint rides a delivery leg that never publishes MSG_IN, so a woken agent's own funnel holds none of the messages that woke it\r\n\r\n- **Status:** OPEN — filed doyle 2026-09-09 from hertz's census, probe and proposed text (his by\r\n…\n  the chase exposed that neither agent's io-events log held the messages that woke it.\n…\n","startLine":4985,"lineNumbers":[4985,null,4987,4988,4989,4990,4991,4992,4993,4994,4995,4996,4997,4998,4999,5000,5001,5002,5003,5004,5005,5006,5007,5008,5009,5010,5011,5012,5013,5014,5015,5016,5017,5018,5019,5020,5021,5022,5023,5024,5025,5026,5027,5028,5029,5030,5031,5032,5033,5034,5035,5036,5037,5038,5039,5040,5041,5042,5043,5044,5045,5046,5047,5048,5049,5050,5051,5052,5053,5054,5055,5056,5057,5058,5059,5060,5061,5062,5063,5064,5065,5066,5067,5068,5069,5070,5071,5072,5073,5074,5075,5076,5077,5078,5079,5080,5081,5082,5083,5084,5085,5086,5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102,5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,5113,5114,5115,5116,5117,5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133,5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149,5150,5151,5152,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164,5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,5176,5177,5178,5179,5180,5181,5182,5183,5184,5185,5186,5187,5188,5189,5190,5191,5192,5193,5194,5195,5196,5197,5198,5199,5200,5201,5202,5203,5204,5205,5206,5207,5208,5209,5210,5211,5212,5213,5214,5215,5216,5217,5218,5219,5220,5221,5222,5223,5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,5237,5238,5239,5240,5241,5242,5243,5244,5245,5246,5247,5248,5249,5250,5251,5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267,5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283,5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299,5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315,5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331,5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347,5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363,5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379,5380,5381,5382,5383,5384,5385,5386,5387,5388,5389,5390,5391,5392,5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,null,5411,null,5536]},"fileSize":512411,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\INFRA-REGISTER.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":5900,"totalBytes":38259,"outputLines":421,"outputBytes":38259,"shownRange":{"start":4987,"end":5407},"nextOffset":5408}}},"isError":false,"timestamp":1789107062044}}
{"type":"message","id":"046b9e09","parentId":"e5085ead","timestamp":"2026-09-11T06:11:02.049Z","message":{"role":"toolResult","toolCallId":"call_hTpV277YoFnrWGHlQnPcKk7N|fc_0330c101aa2c61dc016aa39b739b9887d1bc614f18aaedb9e8","toolName":"read","content":[{"type":"text","text":"# Infra register — CI / build-pipeline debt\n…\n## BUILT / RETIRED\n…\n### IR-91 — 561 untracked files sat at the repo root, 18 of them cited by tracked files, and the census that classified them used a corpus that made the discriminator invisible\n…\n- **Status:** CLOSED by the lane that filed it (the root-scratch classify PR), hertz 2026-09-09 on\n…\n- **Ripe when:** landed with this entry. · **Size:** one `.gitignore` stanza, 18 adds, 543\n…\n\n### IR-92 — the message that WAKES an idle spt-hosted endpoint rides a delivery leg that never publishes MSG_IN, so a woken agent's own funnel holds none of the messages that woke it\n\n- **Status:** OPEN — filed doyle 2026-09-09 from hertz's census, probe and proposed text (his by\n  role; the recorder read and the REQ reading are doyle's). Fix lane unassigned: product change in\n  `spt-daemon` (todlando), test-side legs (hertz). · **Origin:** a 22:35Z empty `<msg from=\"hertz\"/>`\n  turn trigger after the #292 daemon restart, chased for its body; the body was in a spill file, and\n  the chase exposed that neither agent's io-events log held the messages that woke it.\n- **Release reconciliation, 2026-09-11 (source read at `e5a2fed9`):** core PR **#215 is\n  DOCS-ONLY**. Its merge and v0.69.0 ship-fact record (comment 5628532753) discharge the\n  **register rider**, not this product remedy. Core #217 is the separate #293 brain-read\n  census, not an inject-edge fix. `try_spt_hosted_inject` still returns the result of\n  `brain.inject_endpoint` without publishing `MSG_IN`. **IR-92 stays OPEN.** Carry the\n  observation-only chokepoint remedy into the next product intake (todlando product ownership,\n  hertz test ownership); neither offline owner's execution is implied by that assignment.\n- **THE TWO PUBLISH SITES ORDER THEMSELVES OPPOSITELY — read at `de5a44bc`, 2026-09-10, from the\n  bare-baseline red on `io_events_undriven_kinds_e2e` (golden 34467873057, Linux Phase A).** The\n  count below is right and the ORDERING is what this entry was missing:\n  · **PATH A, hook poll** (`delivery.rs`): `poll_drain()` publishes EVERY delivered row (`:757`) and\n    RETURNS them; its only caller `cmd_poll` (`:660`) then loops `emit_event` over the returned rows.\n    **Publication happens-before presentation**, strictly. An immediate log read after observed\n    presentation is CONTRACT-CORRECT here, and a bounded retry on this path WOULD conceal a real\n    violation. **Leave Path A alone.**\n  · **PATH B, the relay** (`startup.rs:1057`, the `deliver` closure): `emit(id, from, body)` — the\n    presentation — runs, and `publish_msg_io(...MSG_IN...)` runs AFTER it, per message, in the same\n    closure; the closure's own comment records that \"Both backlog (after notif validity) and live TCP\n    reach this edge.\" **Presentation happens-before publication.**\n  A test that detects presentation by reading the listener child's STDOUT through a pipe and then\n  reads the io-events log immediately is therefore **racy BY CONTRACT on Path B** — publication for\n  that message runs after its emit, in the child, and the pipe read can win. A bounded wait on the\n  log is permitted on Path B: **it does not weaken any publication-before-presentation guarantee\n  there, because there is none** (hertz's and todlando's narrowing — NOT \"conceals nothing\": the\n  wait still DEFINES WHICH PUBLICATION DELAYS THE TEST ACCEPTS, and it does not establish why any\n  given execution missed a row). A timeout would establish \"not published within the bound\", never\n  \"never publishes\", and cannot alone identify this entry's defect.\n- **A SECOND, INDEPENDENT DEFECT IN THAT CELL'S ASSERTION, true regardless of the above.**\n  `io_events_undriven_kinds_e2e.rs:818` asserts exact-once as\n  `vec![(\"MSG_IN\", Some(AUTHOR)), (\"MSG_IN\", Some(AUTHOR))]` — a `(kind, author)` pair per row, and\n  **both rows are identical**, so the assertion cannot tell the backlog row from the live row and\n  **two BACKLOG rows would satisfy it**. The identities exist and are already stamped:\n  `publish_msg_io_local` carries `.with_msg_id(msg_id_of(body))` — the short ID the failing panel\n  itself printed. Exact-once belongs per MESSAGE ID, not per author.\n  **AND IT CUTS BACKWARDS, WEAKENING EVERY GREEN THIS CELL HAS EVER RETURNED (deployah, on\n  arm-comparability grounds — the point nobody else had drawn):** the three PASSING executions of\n  this cell in the instrumented pair (base linux 3.612 s, head linux 2.343 s, head windows 16.411 s)\n  did **NOT** establish that both relay arms published. They established that two rows matching\n  `(MSG_IN, alice)` were present at read time. A green here is a WEAKER fact than it reads as — the\n  verdict stands in for a measurement the assertion never made. So \"both Linux legs were green\n  across the instrumented pair\" does not become FALSE, it becomes NARROWER than it was being used\n  for: it is a statement about the ASSERTION's outcome, not about publication. It does **not** make\n  the bare red likelier to be a product defect, does not classify anything, and does not separate\n  the race from non-publication — it removes a comparison the RCA was implicitly leaning on.\n  (Raised independently by hertz and todlando as an assertion defect; its backwards consequence for\n  the greens is deployah's.)\n- **Status of that red: UNEXPLAINED between DELAYED and ABSENT publication.** Path B makes the race\n  MECHANICALLY AVAILABLE, which is more than \"not excluded\" — but availability is not occurrence,\n  and one observation does not separate them. Kinship to this entry stays a HYPOTHESIS. The cell is\n  in neither `docs/FLAKE-LEDGER.md` nor this register (0 hits each): an unregistered signature.\n- **The mechanism, read at `de5a44bc`:** `MSG_IN` has exactly two publish sites in the tree —\n  `crates/spt/src/api/delivery.rs:757` (`publish_msg_io_local`, reached only from `poll_drain`, the\n  hook-poll leg, `TakerLeg::HookPoll`) and `crates/spt/src/api/startup.rs:1064` (`publish_msg_io`\n  inside the `api listen` relay's `deliver` sink — the Monitor-stream surface a hook-hosted session\n  never uses). **The spt-hosted inject leg reaches neither.** `crates/spt-daemon/src/inject.rs:75`\n  `try_spt_hosted_inject` renders the envelope and hands it to `brain.inject_endpoint`; the file has\n  zero `publish_msg_io` / `iobus` / `IO_KIND_MSG_IN` references in 343 lines (control: `TakerAudit`\n  / `claim_idle_edge_at` hit, so the grep is live). Every caller delivers through it unobserved:\n  `cli.rs:11739` send-time direct inject when the broker reports the target IDLE (the sender is\n  answered `SENT`), `cli.rs:11684` `--force-native`, `inject.rs:168` `drain_spool_offering` (the\n  idle-EDGE drain `delivery.rs:801`, the send-time already-idle re-offer, the pulse-tick belt, and the\n  native ER-briefing arm), and `wan.rs:822` / `:1173` WAN ingress. Two more drain edges are silent by\n  the same shape and did not fire here: `cmd_poll_shell` (`delivery.rs:705`, shell surface) and\n  `cmd_worker_poll` (`worker.rs:138`, worker surface). A call-site grep would have marked `relay.rs`\n  silent too — it publishes through its sink one crate up — so \"does this edge observe\" is answered\n  by following the row to a bus, never by grepping the edge.\n- **The rule it produces (hertz's refinement, measured across both logs):** for a hook-hosted live\n  agent (`is_spt_hosted_no_relay`), **`SENT` to an idle peer → direct inject → NEVER recorded on\n  the peer** (deterministic). **`QUEUED` → recorded IFF the hook poll takes the row.** One stamped\n  census, **as of 23:04Z 2026-09-09** (the counts grow with every message, so an unstamped figure is\n  stale on arrival): SENT-to-idle unrecorded on the receiver **12/12** (hertz’s five to doyle, doyle’s\n  seven to hertz — the seventh being the message that announced this filing, delivered by the defect\n  it named); QUEUED recorded **8/8**, every one drained mid-tool. Each side’s absence census matched\n  the other side’s verdict log without either seeing the other’s data.\n  by the caller census a spooled row can also be taken by the send-time already-idle re-offer or the\n  pulse-tick belt (`inject.rs:168`, unrecorded), so a `QUEUED` row’s fate is decided by the TAKER,\n  not the verdict — that arm was not observed tonight and stays a prediction.\n- **Measured, hfenduleam 2026-09-09, both full streams read end to end, same 23:04Z stamp:** hertz’s\n  log (through seq 1812): the messages that arrived as turn triggers (`UserPromptSubmit`, idle) — **7/7\n  unlogged**; those that arrived mid-tool (`PreToolUse`, busy) — **4/4 logged**, msg-id present,\n  `<LAST_MSGS>` clock moved (doyle's 22:55Z probe was `QUEUED`, drained mid-Bash, logged as 1804).\n  His \"zero `MSG_IN` since 14:02:34Z\" was **not a state change**: 1633 at 14:02 was the last message\n  that happened to catch him inside a tool call; everything after found him idle. doyle's log (1,121\n  events): PACER-0 **7 received / 6 logged**, the missing one `G4NK5FFT` being the row that woke the\n  session; hertz’s five `SENT` wake messages **absent entirely** and his four `QUEUED` ones **present\n  4/4**, each drained mid-tool; riders in the same spill (1856/1857 beside the promoted 1855;\n  `3NGTHQHN` beside a task-notification trigger) logged. One variable moved.\n- **Scope, corrected once (hertz struck his own \"bilateral\" clause on doyle's control):**\n  receiver-side only. The sender's `MSG_OUT` rows are intact on both sides, so an exchange IS\n  reconstructible from the **peer's** log — but not from the woken agent's own, which is the surface\n  a post-reset agent reads. hertz re-grounded his 22:36 session off seq 1786 of a log that holds his\n  half of every exchange since 14:02 and none of doyle's; a replay of an idle-woken agent shows its\n  own outbound answering nothing, and the last-received clock skips exactly the moments the peer was\n  talking, which reads as \"peer gone quiet\".\n- **Against the requirement's own words:** `REQ-IO-MSG-EDGES` (activated, `doc`/`impl`/`unit`)\n  states that \"MSG_IN publishes where core **delivers or injects** an inbound one, so the funnel\n  observes the edges rather than growing a parallel notion of what a message is\". This is not a case\n  the requirement failed to anticipate: **its own second clause is unimplemented** while `impl` and\n  `unit` read green on the first. The inject edge was never given a publisher when F-023 (idle-edge\n  drain), W5 (parked re-offer) and the WAN ingress added takers; the unit cell at `delivery.rs:1251`\n  pins the poll leg only, so the coverage the registry reports is green on two edges and vacuous on\n  the one the requirement names by verb.\n- **Remedy, and where it must sit:** publish `MSG_IN` **inside `try_spt_hosted_inject` on\n  `Some((true, _))`** — the one chokepoint all four callers share — so no caller can deliver\n  unobserved; a fix placed in `drain_spool_offering` would leave the send-time direct inject and WAN\n  ingress silent. Keep it observation-only (REQ-IO-EVENT-BUS): the inject verdict must not depend on\n  the bus. The unit cell to add mirrors `delivery.rs:1251`: an injected row owes exactly one\n  `MSG_IN`, a refused inject owes none. Post-hoc census of what was lost: spooled rows carry\n  `TakerLeg::IdleInject` / `NativeInject` in the audit column (REQ-SPOOL-TAKE-AUDIT); direct injects\n  never spooled and are enumerable only from the sender's `MSG_OUT`.\n- **OPEN, unranked, not smoothed:** doyle's pre-clear 1855 got a **bodiless** `USER_INPUT msg\n  from=\"hertz\"` row (the `api state busy` payload path, `delivery.rs:115` `state_io_kind`) while his\n  post-clear five got **no row at all**. Both are wake-delivered; the difference is downstream of\n  this gap, in what the adapter passed as the state payload, and is not this entry's mechanism.\n  Also out of scope, perri's surface: the claude-spt overflow notice names spills of the CURRENT\n  session id only, so the last spill before a `/clear` is never named again (how the 22:35Z body\n  went unread in the first place).\n- **Kin:** `REQ-IO-MSG-EDGES`, `REQ-MSG-IDLE-EDGE-DRAIN`, `REQ-IDLE-PARKED-DELIVERY`,\n  `REQ-SPOOL-TAKE-AUDIT`, **IR-84** (the arm the rigs fire was the only one without a clock — same\n  shape: the leg that fires most is the one the instrument never covered), releases#287 (shells after\n  a restart), memory `an-empty-msg-from-tag-is-a-turn-trigger-whose-body-lives-in-the-spill`.\n- **Ripe when:** any lane touches `spt-daemon::inject` or the IO funnel; small enough to ride the\n  next product batch. · **Size:** one publish call at one chokepoint, one unit cell, one `int` leg\n  (a hook-hosted receiver woken by a `SENT`, then `io-events` replayed for the msg-id).\n\n### IR-93 — no PDB ships beside the installed `spt` binary, so the one non-invasive read of a wedged production daemon comes back without a single named frame\n\n- **Status:** OPEN, filed by doyle 2026-09-10. **The number was reserved by NAME on 2026-09-09** at\n  the #293 mechanism read (\"PDB ask -> IR-93 at next sweep\") and this entry closes that claim — a\n  name-only IR with no entry text is the exact gap [[IR-85]]'s status line had to spend a paragraph\n  explaining about IR-84, and it is not being left open a second time. · **Origin:** the #293 pump\n  wedge on hfenduleam.\n- **What was actually paid.** With the daemon wedged and unrecoverable, hertz's `cdb -pv -p 31856`\n  dump (2026-09-09 23:23:26-31Z, 4.79 s suspend, 35 threads, preserved at\n  `.spt/preserved/293-brain-stacks-20260909T232326Z/`) was the ONLY direct observation available of\n  the live wedged process — the pump had already stopped, so the suspend cost the fleet nothing it\n  still had. It came back **with NO SYMBOLS: there is no PDB beside the installed exe.** Both\n  pump-ipc-reader threads were visible in `SleepEx` and all 32 brain threads in Wait, but the frames\n  are addresses.\n- **The cost, stated at the strength it holds.** The mechanism was named anyway — from SOURCE reading\n  (`Brain::read_event()` unbounded at `brain.rs:1025-1027`, 17 in-brain loopers), not from the dump.\n  What the dump could not do is say **WHICH call site parked THAT instance**, and that remains NOT\n  ESTABLISHED. A symbolised dump is the one artifact that answers it directly, and the next wedge\n  will present the same choice with the same empty answer.\n- **Remedy:** retain and ship the PDB beside the installed binary (or publish a symbol store the\n  debugger can resolve against) so a production dump names frames. **Weigh it honestly at rider\n  time:** this is a packaging/size decision, and a release profile that emits no debug info is a\n  deliberate choice someone made — this entry is the bill for it, not a claim it was wrong.\n- **Kin:** [[IR-82]] (a daemon death leaves no record of who died — same family: the corpse is the\n  evidence and nothing preserves it), [[IR-84]] (the arm with no clock), [[IR-95]] (a budget that\n  cannot say how much it burned).\n- **Ripe when:** next installer / release-packaging touch. · **Size:** packaging (profile + install\n  layout), no product code.\n\n### IR-94 — xtask's brainread deadline gate cannot SEE `serve_sync`: its registry is three hand-listed files and its predicate is a name shape, so a stream server outside both got the reply form and the gate stayed green\n\n- **Status:** OPEN, filed by doyle 2026-09-10 at the releases#294 / v0.69.0 golden RED triage. **This\n  is an INDEPENDENT gate finding, not the cause of that red** — it was found while reading the\n  milestone's diff and stands whatever Finding 1 turns out to be. · **Origin:**\n  `xtask/src/brainread.rs`, new this milestone (the #293 fix's zero-call-site guard).\n- **Mechanism, read at source.** The gate's REACH is two hand-authored narrowings stacked:\n  **registry = exactly three files** (`dispatch.rs`, `attach.rs`, `brain.rs`) and **predicate = a name\n  shape** (`starts_with(\"serve_\") && ends_with(\"_feed\")` or `== \"serve_attach\"`). `serve_sync` is a\n  stream server that lives in **no registry file** and whose name **escapes the pattern**, so it is\n  invisible on both axes at once. It therefore carries the **REPLY form — the exact form this gate\n  REJECTS for every stream server it can see — and the gate is GREEN.** An enforcement whose\n  population is enumerated by hand reports compliance over the set it can see, which is not the set\n  that matters.\n- **Why it is inert TODAY and why that is not reassuring.** The production carrier is unbounded:\n  `dispatch::connect()` (`dispatch.rs:898`) uses `Brain::cold_start` with `io_timeout: None`, so\n  `call_deadline()` is `None` and the read is unbounded regardless of which form the server carries.\n  **It becomes LATENT the day `serve_sync` rides a pump carrier** — which is precisely the direction\n  the #293 fix is moving the codebase. The guard will still be green on that day.\n- **Owned:** todlando has taken that his migration/census missed `serve_sync`'s lifetime semantics.\n  Recorded because the entry is about the GATE's reach, not about who missed it.\n- **Remedy shape:** derive the population from the **behaviour** (a fn that serves a stream) rather\n  than from the file it sits in or the name it happens to carry, and make the gate **FAIL on a server\n  it cannot classify instead of skipping it**. Add a census leg that PRINTS the population checked —\n  a count is what would have exposed a three-file registry at a glance.\n- **Kin:** [[IR-84]], `unbounded-brain-carrier-cannot-be-bounded` (memory — the carrier question that\n  makes this inert today), `REQ-BRAIN-READ-BOUNDED-PER-CALL`.\n- **Ripe when:** next `brainread`/xtask touch, **and mandatorily BEFORE `serve_sync` is migrated to a\n  bounded carrier.** · **Size:** small.\n\n### IR-95 — a burned polling budget names WHAT it wanted and never HOW LONG it waited, so no run, green or red, can say how close it came\n\n- **Status:** OPEN, filed by doyle 2026-09-10 at the releases#294 golden RED, where it cost this\n  triage most of a morning and four agents. · **Origin:** the two Windows Phase A failures at\n  `a9e786b2`, both polling budgets burned rather than value mismatches.\n- **The two sites, read at source.** They are not even the same KIND of budget, which is the first\n  thing no reader can tell from the panel:\n  · `crates/spt/tests/contract_e2e.rs:393-407` — a **WALL** deadline,\n  `let deadline = Instant::now() + Duration::from_secs(30)`, panicking\n  `\"the brain pulse must ingest the commune into the live context tier\"`. **No elapsed.**\n  · `crates/spt-daemon/tests/sync.rs:98-110` — an **ITERATION** budget, `for _ in 0..400 {\n  net_streams(); sleep(25ms) }`, panicking `\"sync stream never appeared at the responder's broker\"`.\n  **No elapsed, no iteration count** — and its own comment calls it a \"10s budget\", which is a\n  NOMINAL sum of sleeps, not a wall bound: each `net_streams()` IPC call adds to it (hertz), so on a\n  loaded box the wall it grants is unknown and larger.\n- **Four costs MEASURED in this one triage, each traceable to the missing clock:**\n  1. **The panic reads as a CONTENT claim.** `contract_e2e.rs:403`'s message is what a 30 s DEADLINE\n     EXPIRY prints, and doyle relayed it to three peers as \"a clean content assert, not a stall\"\n     before opening the source.\n  2. **History cannot supply margins at all.** nextest suppresses passing output by default, so\n     **eight consecutive goldens** of this cell's Windows durations exist and **not one carries an\n     internal margin**. (`--success-output immediate` retains it — so this is recoverable going\n     forward, and was not, going back.)\n  3. **A whole-test total cannot locate the poll inside the test.** This conflation was committed\n     **five times in forty minutes by three different agents** — deployah twice (retracted both),\n     doyle once *in the message correcting deployah for it*, and it was caught each time by todlando\n     and hertz. A defect that costs three careful agents five errors in one morning is not a people\n     problem; the number they needed was not printed anywhere.\n  4. **A FAIL and a PASS are not the same quantity.** `wait_for_stream_except` is called at\n     `sync.rs:201`, with `serve_sync`, the puller join and every assertion AFTER it — so a failing\n     run **truncates** there. This cell FAILED at 58.77 s and PASSED at 61.304 s, and that 2.5 s gap\n     carries no information in either direction. It was read as an anomaly (\"it took LESS time and\n     still failed\") until the call site was opened.\n- **Remedy:** on expiry, print **elapsed, the budget, and iterations consumed**; where the poll waits\n  on another party, print that party's **PRODUCER PROGRESS** too — a watcher's own timings cannot\n  separate a slow watcher from a slow producer (hertz, todlando), which is the single fact this\n  triage most needed and could not get. Keep the content sentence; it is the panic's `{what}`, not\n  its whole body.\n- **Population CENSUSED 2026-09-10 (doyle), discharging the census this entry declared OWED — 323\n  poll sites detected, 304 of them classified blind. SUPERSEDED 2026-09-10 by the validation\n  below: 317 blind of a 321-site population, and the census's own coverage measured.** Read-only, run beside golden diagnostic 34458491560\n  without dispatching anything to either runner. Preserved with its method, its raw classification\n  and its discarded first attempt at `.spt/preserved/ir95-poll-census-20260910/`.\n- **Method, deliberately WORDING-INDEPENDENT.** Over the 212 tracked `*.rs` files under\n  `**/tests/**` plus `xtask/`, take every loop by SHAPE — `for _ in 0..N`, `while Instant::now() <\n  deadline`, `while <x>.elapsed() < budget`, bare `loop {` — keep it only if it SLEEPS (a poll, not\n  a spin) and can FAIL (`panic!`/`assert!`/`expect(`/`bail!` on its exit path), then ask whether its\n  failure path emits a MEASURED VALUE (`.elapsed()`, `.as_millis()`, an iteration counter). **String\n  literals are stripped before that question is asked**, so the word \"budget\" inside a panic message\n  cannot credit itself with a clock. **Result: 323 sites, 19 apparently clocked, 304 blind.**\n- **304 of 323 DETECTED CANDIDATES CLASSIFIED BLIND — a classifier count, NOT a proven floor.**\n  Stated at that strength on hertz's and todlando's correction of a stronger form this entry\n  briefly carried. What was actually spot-checked is the CLOCK bucket, and both errors found there\n  ran the same direction, undercounting blindness: `brain_read_deadline.rs:87` was credited from\n  elsewhere in the read window while its real failure path is `panic!(\"whole-carrier brain never\n  connected to {name}\")`, carrying no clock at all; `er_briefing_presented_e2e.rs:310` returns\n  `Some(started.elapsed())` on SUCCESS and a bare `None` on expiry.\n- **What that does NOT license.** Finding only false-CLOCK errors does not exclude false-BLIND ones,\n  and nothing here establishes POPULATION COVERAGE — whether the four loop shapes catch every poll\n  in the corpus is unvalidated, so a poll expressed as a helper, a retry combinator or an iterator\n  chain is uncounted and unmeasured. **No repository-wide `>= 94%` claim is made and none should be\n  repeated from this entry.** The honest sentence is: 304 classified BLIND among 323 detected\n  candidates, with the checked errors so far undercounting blindness. Validating both buckets and\n  the population is owed before any bound is asserted.\n- **VALIDATED 2026-09-10 (doyle) — all three owed checks discharged; the headline figure MOVES to\n  317 blind of 321.** Preserved as `VALIDATION.md` beside the census (machine-bound per [[IR-90]]).\n  (1) **The CLOCK bucket is now adjudicated EXHAUSTIVELY, not spot-checked**: of 19, only **4** emit\n  a measured value on their own expiry path, **13 were FALSE CLOCKs** and move to BLIND, and **2 are\n  not poll-failure sites at all**. Two mechanisms cover all 13, neither of them a wording problem:\n  **window bleed** (7 — four credited by a `const CONVERGE_BUDGET: Duration = …as_millis()…`\n  *declaration* 20-25 lines BELOW a bare `panic!(\"brain could not connect\")`, one by a different\n  loop 57 lines away, two by an unrelated `now_ms()` helper) and **condition-use, not emission** (6 —\n  `assert!(started.elapsed() < Duration::from_secs(30), \"…viewer_count={count:?}\")` reads the clock\n  in the PREDICATE and omits it from the MESSAGE). Stripping string literals stopped a message\n  crediting itself; it does not stop CODE crediting a site whose message stays silent.\n  (2) **False-BLINDs checked at last — a seeded 30-site random sample of the BLIND bucket\n  (`random.seed(95)`), hand-adjudicated: 30 of 30 confirm BLIND, zero false-BLIND.** By the rule of\n  three that bounds the false-BLIND rate at **<= ~10%, at 95% confidence** — a binomial upper bound\n  assuming the 30 are a simple random sample of the 304 and each site's adjudication is independent;\n  it is **not a deterministic guarantee**, and zero errors in 30 excludes nothing outright (hertz).\n  This is the FIRST check run in the\n  direction that would REDUCE the blind count and it found nothing; every error found in either\n  bucket still runs the other way.\n  (3) **Population coverage, measured against every `sleep` in the corpus** — 472 call-sites, 349\n  inside a detected window, 75 one-shot settles in no loop. The remaining 48 dedup to 47 loop\n  headers and **every one is explained, 0 unexplained**: **32** matched a census shape but cannot\n  FAIL within 60 lines (excluded BY DESIGN — the census counts loops that wait AND can fail), and\n  **15 are the detector's true false negatives**, a fixed nameable set:\n  `while std::time::Instant::now() < deadline` (the PATH-QUALIFIED spelling — the regex demands a\n  bare `Instant::now()`; `broker.rs:389`, `shellchan.rs:114`), `while !stop.load(Ordering::Relaxed)`,\n  `while <predicate>(…)` (`shell_relink_force_e2e.rs:194/241`, `shell_stale_online_e2e.rs:146`,\n  `redispatch.rs:269`), and one `for (a, b) in [...]`. Those 15 stay UNCLASSIFIED.\n  **The 32 change how this census may be QUOTED:** \"323 poll loops that wait and can fail\" silently\n  excludes 32 loops that wait and CANNOT fail at the poll — a defensible scope, but a scope, and the\n  sentence must carry it.\n- **Restated census, and the form to quote.** **321** sites in the adjudicated population (323 minus\n  2 membership errors from the CLOCK bucket; a 3rd — `net_worker_starve.rs:99`, a fixed-window\n  SAMPLER that always runs its window and has no expiry failure — turned up in the BLIND sample, so\n  3 errors in 49 hand-adjudicated sites means the population carries ~6% slop and **321 is not\n  exact**). **317** classified BLIND. **4** report a measurement. **15** poll loops outside the\n  detector's reach, unclassified. **Still not established, and still not to be written: that 317 is\n  a FLOOR, or any repository-wide rate.** One direction is now exhaustive, the other bounded at\n  <=10% by a 30-site sample — a bounded estimate, never a floor, and silent about the 15.\n- **A distinction this validation surfaced, and the remedy above should carry: \"emits a clock\" is\n  TWO different things.** `transport_death_eof.rs:540` prints the OBSERVED quantity\n  (`{canary_after}ms`); `er_brief_once_per_session_e2e.rs:288` prints the MARGIN (`elapsed=`). Only\n  the second tells a reader how close the budget came. 3 of the 4 surviving CLOCK sites report a\n  margin, 1 reports an observation — and **a binary CLOCK/BLIND classifier cannot see that\n  difference**, which is a limit of the census, not of the sites.\n- **One edit to preserved evidence, DECLARED.** `census.py` printed `<-- IR-95 population (a FLOOR)`\n  on its blind line. That sentence was retracted the day it was written, but the retraction never\n  reached the SCRIPT, so re-running the preserved artifact reprinted the withdrawn claim at whoever\n  ran it — a retraction does not propagate to the next reader on its own. The LABEL, and only the\n  label, is corrected in place; the computation is untouched and **still reproduces 323 / 19 / 304**,\n  which is what makes this validation checkable against it. The old line is quoted verbatim in\n  `VALIDATION.md`.\n- **A FIRST detector was discarded, and its failure is itself evidence for cost 1 above.** Keying on\n  expiry VOCABULARY (\"never\", \"timed out\", \"did not appear\") found 53 sites and **missed\n  `contract_e2e.rs:393` entirely — the very site this entry was filed from** — because its panic\n  message is a CONTENT sentence. A wording-keyed census is structurally blind to exactly the sites\n  whose messages mislead. Recorded so no one re-runs the cheap version and reports 53 as the answer.\n- **Positive control passes, and it found siblings.** Both originating sites appear, both BLIND:\n  `sync.rs:102` and `contract_e2e.rs:395`. The census also surfaced **two fixed budgets nobody had\n  noticed** — `sync.rs:89` (`0..300`, beside the `0..400` at :102) and `contract_e2e.rs:51`\n  (`0..400`, beside the wall deadline at :393). Concentration: `inject_control_wedge.rs` 18,\n  `broker.rs` 10, `endpoint_lifecycle.rs` 9, `dispatch.rs` 7, `twohost.rs` 7.\n- **PRODUCER-PROGRESS INSTRUMENT — SPEC, 2026-09-10, and the three readings it does NOT support.**\n  The remedy above asks for the waited-on party's progress because a watcher's own timings cannot\n  separate a slow watcher from a slow producer. `last_streams_seen=0` throughout is equally\n  consistent with \"the producer never produced\" and \"the watcher never saw it\", and neither arm of\n  the releases#294 pair can tell those apart. **Design (doyle), narrowed by hertz and todlando, who\n  independently found the same three defects in the first form of it.**\n  **INSTRUMENT** — rides the IPC the poll ALREADY makes, so it adds no channel and no budget: the\n  responder's broker surfaces, alongside `net_streams`, a monotonic `streams_created_total` AND a\n  monotonic `streams_retired_total` for the session, the sequence and age of its last transition,\n  and the STREAM IDS of the most recent transitions so the watcher can correlate them against the\n  ids it sees and skips. The watcher prints the producer's counters beside its own observation.\n  **SEMANTICS THAT MUST BE DECLARED BEFORE A SINGLE READING IS TAKEN** — a bare count is not a\n  measurement until these are fixed: WHICH HOOK \"created\" fires at (broker stream-table\n  registration? wire acceptance?), WHICH KEY the counter is scoped to and what a session rotation\n  does to it, the COUNTER LIFETIME and reset behaviour (process lifetime, per session, what a broker\n  restart does), and WHICH CLOCK the age is measured against and whether it is comparable to the\n  watcher's.\n  **WHAT EACH READING LICENSES, and what it does NOT** (the first form of this table asserted three\n  causal conclusions it had not earned):\n  · `created=0` at expiry means **no creation was RECORDED AT THAT HOOK, in that counter's scope,\n    for that session key**. It does **NOT** establish that the requester never produced, and it does\n    **NOT** exonerate the watcher — the hook may sit downstream of the real production, or be scoped\n    to a different key.\n  · `created>0` with every snapshot empty is **CONSISTENT WITH a visibility/registration defect AND\n    with a stream being created and retired entirely between two 25 ms polls**. On its own it\n    establishes neither; the retire counter and the ids are what separate them.\n  · **Creation AFTER expiry cannot be observed by a poll that has already stopped.** A last-change\n    age cannot supply it. That needs either a separately bounded, separately declared post-expiry\n    observation, or a retained producer event trace with timestamps.\n  **Process constraints:** separately versioned and announced, never slipped between arms of a\n  comparison, and the existing diagnostic patch and every budget stay UNCHANGED. Widening a budget\n  to make a red go green remains refused.\n- **`last_streams_seen` IS A FILTERED-VIEW COUNT — the sharpest narrowing this field has had, and it\n  applies to all three expiries in the releases#294 pair.** The poll calls `net_streams`; the broker\n  answers at `broker.rs:9546` `dispatch_net_streams` -> `host.dispatch_stream_infos()`\n  (`nethost.rs:1952`) -> `stream_infos_filtered(FALSE)`, and that filter drops TWO classes\n  SERVER-SIDE, before serialization (ADR-0040 decision 2, `REQ-STREAM-INFOS-SERVER-FILTER`):\n  `!e.retired.load(SeqCst)` and `!e.initiated_locally`. So `last_streams_seen=0` does **NOT** mean\n  the broker held no streams. It means **zero NON-RETIRED, NON-LOCALLY-INITIATED rows at that\n  instant** — a row that exists and is retired is invisible to the poll BY DESIGN. That is narrower\n  than the corrected form the RCA had settled on (\"the final snapshot was empty\"), and it is a\n  hook-scope fact of exactly the kind the preconditions above demand be pinned before any reading.\n- **A \"reuse it, no product change\" stage-1 design WAS PROPOSED AND IS WITHDRAWN — recorded because\n  the reason generalises.** `NetHost::stream_counts()` (`nethost.rs:1980`) is already surfaced as\n  `NetStatusReply.streams_held` (`broker.rs:9002`, `msg.rs:874`) and documents itself as\n  \"retirement-blind ON PURPOSE ... the resource truth the eligibility view hides\". Reading it beside\n  `net_streams` looked like it would separate \"filtered out\" from \"absent\" for free. It does not,\n  for four reasons, and hertz and todlando raised them independently:\n  · **Two IPC replies are not an atomic snapshot.** `filtered=0` then `held>0` is equally consistent\n    with a row ARRIVING BETWEEN THE TWO CALLS. Such a pair must never be labelled proof of filtering,\n    and needs call order and timestamps recorded if it is read at all.\n  · **`streams_held` is HOST-SCOPED, not exchange-scoped.** It counts unrelated and locally-initiated\n    rows the filtered view drops, so it cannot speak to the exchange under investigation without\n    stream-ID correlation; any conclusion from it stays aggregate.\n  · **It adds UNMEASURED perturbation** — a second IPC per iteration changes the 400-iteration\n    window's wall duration by an amount nobody has measured. **CORRECTED 2026-09-10 (hertz,\n    todlando), because the first form of this bullet was itself an overclaim in two ways and both\n    are instructive:** (a) it called perturbation DISQUALIFYING, and it is not — instrumentation\n    that perturbs timing can still be useful; the objection is ADDED, UNMEASURED perturbation, not\n    perturbation as such. (b) It SIZED that perturbation from two figures that cannot carry it: the\n    measured `net_streams` cost (60,295 us / 400 = 0.151 ms per iteration) does **not** estimate the\n    `net-status` cost — different call, different work — and the **0.29% expiry difference between\n    the two arms is NOT an established causal effect size**, only an unexplained gap between two n=1\n    observations. Sizing an observer effect against it treats an open question as a known\n    quantity.\n  · A single POST-EXPIRY sample avoids perturbing the poll but then describes LATER state, not\n    expiry state, and is still host-scoped.\n- **THE INSTRUMENT THAT SURVIVES REVIEW: a retained, EXCHANGE-CORRELATED create/retire TRACE**\n  (hertz and todlando, converged independently). Recorded per stream lifecycle transition on the\n  producer side — stream id, conn id, remote id, transition, `initiated_locally`, a monotonic\n  sequence and a timestamp on a NAMED clock — retained and read AFTER the fact rather than sampled\n  by the watcher, so it adds **NO POLL CALLS**. Say that, and not \"adds nothing\" (hertz): it still\n  adds PRODUCER-SIDE work that may affect arrival timing and resource contention, and **that effect\n  is unmeasured too**. The trace is preferable for having no watcher IPC, not for being free. It captures between-poll transitions,\n  which neither a gauge nor an in-loop counter can: **a gauge reads 0 for a stream created and\n  retired between two 25 ms polls exactly as it does for one never created.** Correlation to the\n  exchange is by stream id against the ids the watcher saw and skipped.\n  **MEASURED: it does not exist today** — zero stream-lifetime log lines in `nethost.rs`. So this is\n  a PRODUCT change, not a reuse, and it stays unbuilt while the product is frozen. Its preconditions\n  are the ones above, unchanged. Production AFTER the trace's retention window remains outside it.\n- **THE FIRST MARGINS THIS ENTRY PRODUCED UNDER CI / GOLDEN CONDITIONS — instrumented run\n  34458491560, 2026-09-10\n  (hertz's patch; deployah's lane; read independently by doyle).** The remedy above was argued for\n  on the ground that a poll which prints nothing cannot say how close it came. It has now printed\n  on a runner. **NOT the first margins overall** — the earlier local 12-leg run already reported\n  them, including a 392/400 (hertz, todlando). **The genuinely novel quantity is narrower and\n  sharper than \"CI margins\" (deployah): it is a FAILING poll's margin, which no local leg could\n  produce because all 12 of them PASSED.** A budget's behaviour at expiry is the one thing a green\n  run structurally cannot report, and it is the case the remedy exists for.\n  **The figure is the MAXIMUM AMONG SUCCESSFUL polls in this run — explicitly NOT a ceiling, and not\n  a bound on observations**: the poll that EXPIRED in this same run consumed 400/400 = 100%. So:\n  among the polls that PASSED on hfenduleam, both instrumented sites peak at ~63% of budget. The\n  seven successful\n  `[IR95-SYNC]` waits in that run are 92, 19, 72, 254, 21, 21 and 20 iterations — **worst 254/400 =\n  63.5%** (6.449393 s) — and the `[IR95-CONTRACT]` success consumed **18.857089 s of its 30.000 s\n  wall = 62.9%**. Two independent sites, two different budget KINDS, the same maximum-among-passes.\n  Headroom at that worst SUCCESSFUL case ~37%; the failing case had none left. **n=7 and n=1, one\n  box, one run: a first CI measurement, not a stability claim, and NO budget change is proposed on\n  it.**\n- **The iteration budget's WALL EQUIVALENT, also measured for the first time.** The expiring poll's\n  400 iterations cost **10.199907 s against 400 × 25 ms = 10.000 s nominal — 2.0% over**, with\n  per-iteration overhead ~0.5 ms against a 25 ms sleep (IPC 60.295 ms total, 0.151 ms per iteration,\n  **0.59% of elapsed**; sleep is 99.4%). So on this box in this run a \"400 iteration\" budget and a\n  \"~10.2 s wall\" are nearly the same object — the iteration budget did NOT silently become a\n  different budget under load. That bounds one standing worry about blind iteration counts, and it\n  is precisely the class of thing that stops being guessable the moment a clock prints. Box-local\n  and run-local; it is not a general result.\n- **A scope limit the instrumentation itself imposes, and a smaller ask than it first looks.**\n  `last_streams_seen` is an ASSIGNMENT per iteration (`sync.rs:111`), not an accumulator, so\n  `last_streams_seen=0` at expiry describes the FINAL iteration only — not all 400 (todlando's\n  correction; deployah withdrew the aggregate reading, doyle confirmed it at source). But the loop's\n  CONTROL FLOW already proves the interesting half for free: the `find()` at `:113` returns the\n  instant a non-skipped stream appears, so **reaching the expiry print IS proof that no non-skipped\n  stream was seen in any of the 400 SNAPSHOTS** — no aggregate trace required. **It does NOT mean\n  no stream EXISTED between snapshots** (hertz): the poll samples at 25 ms, and nothing here\n  observes the gaps. What is genuinely\n  unmeasured is only whether a SKIPPED stream was ever present, and `skip` is empty on that call.\n  An aggregate/per-iteration trace therefore buys less here than the gap first suggests.\n- **NOT ESTABLISHED: that all 304 deserve a clock.** The census SIZES the problem; it does not\n  schedule it, and it does not pre-judge which sites are worth the edit. Remedy triage is owed\n  separately and is the larger half.\n- **Kin:** [[IR-84]] (the one `PUMP_PEER_FAIL` arm the rigs fire was the only one carrying no clock —\n  **the same class in product code**; this entry is its test-corpus face), [[IR-85]] (budgets sized\n  against a box whose speed moved), [[IR-77]] (nothing stamps the spawn-to-first-log interval, so a\n  readiness red cannot say where the time went), [[IR-90]].\n- **Ripe when:** with the releases#294 instrumented base-vs-head comparison, which **cannot be run\n  without it** — the experiment's whole output is the margins these sites do not print. ·\n  **Size:** small per site; the census is the larger half.\n\n### IR-96 — the `daemon_stop_convoy_e2e` API-storm cell fails 3-of-3 under the HEAVY suite at the diagnostic tree while passing at the candidate in golden CI, and nothing yet separates instrumentation from box from product\n\n- **Status:** OPEN, **cause-unclassified** (todlando's and hertz's stipulation, adopted verbatim — a\n  triage placement here is NOT a finding of non-defect).\n- **Origin:** releases#294 / v0.69.0 Arm B, 2026-09-10, deployah executing at diagnostic tree\n  `ed8ecd94` (= candidate `a9e786b2` + the unlanded sync instrumentation, never merged).\n- **What:** `spt::daemon_stop_convoy_e2e stop_under_an_api_storm_stays_down_then_start_brings_up_exactly_one`\n  FAILED in **all three** Arm B runs, with durations **growing every run: 9.473s · 10.973s ·\n  14.553s**. Different signature from the #294 sync cell; nothing was filed against #294.\n- **THE DIFFERENTIAL that makes it worth an entry rather than a shrug:** the same cell shows **0\n  failures at the candidate** in golden 34481993681 Phase A on this same box — that run's single\n  failure was the sync cell (`3381 tests run: 3380 passed (6 slow, 5 leaky), 1 failed, 1 skipped`).\n  So: 0-of-1 at `a9e786b2` under CI load, 3-of-3 at `ed8ecd94` under local HEAVY load.\n- **WHAT THAT DOES NOT ESTABLISH.** It does **not** isolate the instrumentation or the box as the\n  only candidates — a condition-dependent or intermittent PRODUCT defect remains live, and a single\n  CI pass is not evidence of absence. doyle claimed that elimination on 2026-09-10 and **withdrew\n  it** the same hour under todlando's and hertz's correction; the withdrawal is recorded in\n  `.spt/preserved/gate-r2-34481993681-20260910/CLASSIFICATION-AMENDMENT-2-doyle.md`.\n- **Confounded by IR-97** (below): the three runs were not equivalent conditions.\n- **Ripe when:** any lane touches daemon stop/start convoy behaviour, OR a golden run reds this cell\n  at a candidate, OR someone runs the cell at `a9e786b2` under the same local HEAVY workload — that\n  last one is the cheap discriminator and nobody has run it. · **Size:** one targeted local run to\n  discriminate; unknown beyond that.\n\n### IR-97 — a suite that leaks a fixed cohort of child processes per invocation makes consecutive runs non-comparable, and the between-run accounting the protocol required was not enforced\n\n- **Status:** OPEN. **Protocol deviation** (hertz's framing, and it is stronger than \"confounder\":\n  the protocol ALREADY required between-run accounting — execution did not enforce it, so the fix is\n  enforcement, not a limitations paragraph).\n- **Origin:** releases#294 Arm B, 2026-09-10. Derived by doyle from deployah's preserved\n  `10-residual-births.json` against the run windows.\n- **What:** each Arm B suite leaked **exactly 6** `spt` children that outlived it; all **18** were\n  still alive at the post-B3 census. Because a process alive at census whose OS birth time falls in\n  an earlier window existed continuously through the runs between (pid + birth time is an identity),\n  the carried diag-tree residue was **0 during B1 · 6 during B2 · 12 during B3**. The three\n  \"repetitions\" were therefore not three equivalent conditions, and every cross-run comparison in\n  that arm inherits it.\n- **LIMITS, stated so the entry is not over-read:** process **COUNT** is measured; **LOAD is not** —\n  idle orphans may cost nothing, contention was UNMEASURED (overlap UNVERIFIED all arm), and this is\n  **not** a drift meter. It neither implicates nor excludes residue as a cause of the one expiry, and\n  it does not explain it: B3 carried twice the orphans and **passed**.\n- **Also unestablished, in both directions:** 18 censused against 15 killed shows only that three\n  were absent at the second read. \"Three self-exited\" needs exit evidence; \"I killed 18\" was\n  likewise refused by deployah at the time.\n- **Kin:** the LEAK rows every Arm A/B run reported; `REQ-HAZARD-RESUME-CUSTODY-ABA` (KH 7.51) and\n  KH 7.58 — the cleanup that resolved this was correctly scoped by **pid + image path**, leaving 15\n  unrelated `spt` processes untouched, where a name-based kill would have taken down the live agent\n  fleet including the gater's own session.\n- **Ripe when:** any repeated-run experiment is designed on this box — census BETWEEN runs, not only\n  at the end. · **Size:** a between-run census step plus a scoped reap in the harness."}],"details":{"totalLines":5900,"displayContent":{"text":"# Infra register — CI / build-pipeline debt\n…\n## BUILT / RETIRED\n…\n### IR-91 — 561 untracked files sat at the repo root, 18 of them cited by tracked files, and the census that classified them used a corpus that made the discriminator invisible\n…\n- **Status:** CLOSED by the lane that filed it (the root-scratch classify PR), hertz 2026-09-09 on\n…\n- **Ripe when:** landed with this entry. · **Size:** one `.gitignore` stanza, 18 adds, 543\n…\n\r\n### IR-92 — the message that WAKES an idle spt-hosted endpoint rides a delivery leg that never publishes MSG_IN, so a woken agent's own funnel holds none of the messages that woke it\r\n\r\n- **Status:** OPEN — filed doyle 2026-09-09 from hertz's census, probe and proposed text (his by\r\n  role; the recorder read and the REQ reading are doyle's). Fix lane unassigned: product change in\r\n  `spt-daemon` (todlando), test-side legs (hertz). · **Origin:** a 22:35Z empty `<msg from=\"hertz\"/>`\r\n  turn trigger after the #292 daemon restart, chased for its body; the body was in a spill file, and\r\n  the chase exposed that neither agent's io-events log held the messages that woke it.\r\n- **Release reconciliation, 2026-09-11 (source read at `e5a2fed9`):** core PR **#215 is\r\n  DOCS-ONLY**. Its merge and v0.69.0 ship-fact record (comment 5628532753) discharge the\r\n  **register rider**, not this product remedy. Core #217 is the separate #293 brain-read\r\n  census, not an inject-edge fix. `try_spt_hosted_inject` still returns the result of\r\n  `brain.inject_endpoint` without publishing `MSG_IN`. **IR-92 stays OPEN.** Carry the\r\n  observation-only chokepoint remedy into the next product intake (todlando product ownership,\r\n  hertz test ownership); neither offline owner's execution is implied by that assignment.\r\n- **THE TWO PUBLISH SITES ORDER THEMSELVES OPPOSITELY — read at `de5a44bc`, 2026-09-10, from the\r\n  bare-baseline red on `io_events_undriven_kinds_e2e` (golden 34467873057, Linux Phase A).** The\r\n  count below is right and the ORDERING is what this entry was missing:\r\n  · **PATH A, hook poll** (`delivery.rs`): `poll_drain()` publishes EVERY delivered row (`:757`) and\r\n    RETURNS them; its only caller `cmd_poll` (`:660`) then loops `emit_event` over the returned rows.\r\n    **Publication happens-before presentation**, strictly. An immediate log read after observed\r\n    presentation is CONTRACT-CORRECT here, and a bounded retry on this path WOULD conceal a real\r\n    violation. **Leave Path A alone.**\r\n  · **PATH B, the relay** (`startup.rs:1057`, the `deliver` closure): `emit(id, from, body)` — the\r\n    presentation — runs, and `publish_msg_io(...MSG_IN...)` runs AFTER it, per message, in the same\r\n    closure; the closure's own comment records that \"Both backlog (after notif validity) and live TCP\r\n    reach this edge.\" **Presentation happens-before publication.**\r\n  A test that detects presentation by reading the listener child's STDOUT through a pipe and then\r\n  reads the io-events log immediately is therefore **racy BY CONTRACT on Path B** — publication for\r\n  that message runs after its emit, in the child, and the pipe read can win. A bounded wait on the\r\n  log is permitted on Path B: **it does not weaken any publication-before-presentation guarantee\r\n  there, because there is none** (hertz's and todlando's narrowing — NOT \"conceals nothing\": the\r\n  wait still DEFINES WHICH PUBLICATION DELAYS THE TEST ACCEPTS, and it does not establish why any\r\n  given execution missed a row). A timeout would establish \"not published within the bound\", never\r\n  \"never publishes\", and cannot alone identify this entry's defect.\r\n- **A SECOND, INDEPENDENT DEFECT IN THAT CELL'S ASSERTION, true regardless of the above.**\r\n  `io_events_undriven_kinds_e2e.rs:818` asserts exact-once as\r\n  `vec![(\"MSG_IN\", Some(AUTHOR)), (\"MSG_IN\", Some(AUTHOR))]` — a `(kind, author)` pair per row, and\r\n  **both rows are identical**, so the assertion cannot tell the backlog row from the live row and\r\n  **two BACKLOG rows would satisfy it**. The identities exist and are already stamped:\r\n  `publish_msg_io_local` carries `.with_msg_id(msg_id_of(body))` — the short ID the failing panel\r\n  itself printed. Exact-once belongs per MESSAGE ID, not per author.\r\n  **AND IT CUTS BACKWARDS, WEAKENING EVERY GREEN THIS CELL HAS EVER RETURNED (deployah, on\r\n  arm-comparability grounds — the point nobody else had drawn):** the three PASSING executions of\r\n  this cell in the instrumented pair (base linux 3.612 s, head linux 2.343 s, head windows 16.411 s)\r\n  did **NOT** establish that both relay arms published. They established that two rows matching\r\n  `(MSG_IN, alice)` were present at read time. A green here is a WEAKER fact than it reads as — the\r\n  verdict stands in for a measurement the assertion never made. So \"both Linux legs were green\r\n  across the instrumented pair\" does not become FALSE, it becomes NARROWER than it was being used\r\n  for: it is a statement about the ASSERTION's outcome, not about publication. It does **not** make\r\n  the bare red likelier to be a product defect, does not classify anything, and does not separate\r\n  the race from non-publication — it removes a comparison the RCA was implicitly leaning on.\r\n  (Raised independently by hertz and todlando as an assertion defect; its backwards consequence for\r\n  the greens is deployah's.)\r\n- **Status of that red: UNEXPLAINED between DELAYED and ABSENT publication.** Path B makes the race\r\n  MECHANICALLY AVAILABLE, which is more than \"not excluded\" — but availability is not occurrence,\r\n  and one observation does not separate them. Kinship to this entry stays a HYPOTHESIS. The cell is\r\n  in neither `docs/FLAKE-LEDGER.md` nor this register (0 hits each): an unregistered signature.\r\n- **The mechanism, read at `de5a44bc`:** `MSG_IN` has exactly two publish sites in the tree —\r\n  `crates/spt/src/api/delivery.rs:757` (`publish_msg_io_local`, reached only from `poll_drain`, the\r\n  hook-poll leg, `TakerLeg::HookPoll`) and `crates/spt/src/api/startup.rs:1064` (`publish_msg_io`\r\n  inside the `api listen` relay's `deliver` sink — the Monitor-stream surface a hook-hosted session\r\n  never uses). **The spt-hosted inject leg reaches neither.** `crates/spt-daemon/src/inject.rs:75`\r\n  `try_spt_hosted_inject` renders the envelope and hands it to `brain.inject_endpoint`; the file has\r\n  zero `publish_msg_io` / `iobus` / `IO_KIND_MSG_IN` references in 343 lines (control: `TakerAudit`\r\n  / `claim_idle_edge_at` hit, so the grep is live). Every caller delivers through it unobserved:\r\n  `cli.rs:11739` send-time direct inject when the broker reports the target IDLE (the sender is\r\n  answered `SENT`), `cli.rs:11684` `--force-native`, `inject.rs:168` `drain_spool_offering` (the\r\n  idle-EDGE drain `delivery.rs:801`, the send-time already-idle re-offer, the pulse-tick belt, and the\r\n  native ER-briefing arm), and `wan.rs:822` / `:1173` WAN ingress. Two more drain edges are silent by\r\n  the same shape and did not fire here: `cmd_poll_shell` (`delivery.rs:705`, shell surface) and\r\n  `cmd_worker_poll` (`worker.rs:138`, worker surface). A call-site grep would have marked `relay.rs`\r\n  silent too — it publishes through its sink one crate up — so \"does this edge observe\" is answered\r\n  by following the row to a bus, never by grepping the edge.\r\n- **The rule it produces (hertz's refinement, measured across both logs):** for a hook-hosted live\r\n  agent (`is_spt_hosted_no_relay`), **`SENT` to an idle peer → direct inject → NEVER recorded on\r\n  the peer** (deterministic). **`QUEUED` → recorded IFF the hook poll takes the row.** One stamped\r\n  census, **as of 23:04Z 2026-09-09** (the counts grow with every message, so an unstamped figure is\r\n  stale on arrival): SENT-to-idle unrecorded on the receiver **12/12** (hertz’s five to doyle, doyle’s\r\n  seven to hertz — the seventh being the message that announced this filing, delivered by the defect\r\n  it named); QUEUED recorded **8/8**, every one drained mid-tool. Each side’s absence census matched\r\n  the other side’s verdict log without either seeing the other’s data.\r\n  by the caller census a spooled row can also be taken by the send-time already-idle re-offer or the\r\n  pulse-tick belt (`inject.rs:168`, unrecorded), so a `QUEUED` row’s fate is decided by the TAKER,\r\n  not the verdict — that arm was not observed tonight and stays a prediction.\r\n- **Measured, hfenduleam 2026-09-09, both full streams read end to end, same 23:04Z stamp:** hertz’s\r\n  log (through seq 1812): the messages that arrived as turn triggers (`UserPromptSubmit`, idle) — **7/7\r\n  unlogged**; those that arrived mid-tool (`PreToolUse`, busy) — **4/4 logged**, msg-id present,\r\n  `<LAST_MSGS>` clock moved (doyle's 22:55Z probe was `QUEUED`, drained mid-Bash, logged as 1804).\r\n  His \"zero `MSG_IN` since 14:02:34Z\" was **not a state change**: 1633 at 14:02 was the last message\r\n  that happened to catch him inside a tool call; everything after found him idle. doyle's log (1,121\r\n  events): PACER-0 **7 received / 6 logged**, the missing one `G4NK5FFT` being the row that woke the\r\n  session; hertz’s five `SENT` wake messages **absent entirely** and his four `QUEUED` ones **present\r\n  4/4**, each drained mid-tool; riders in the same spill (1856/1857 beside the promoted 1855;\r\n  `3NGTHQHN` beside a task-notification trigger) logged. One variable moved.\r\n- **Scope, corrected once (hertz struck his own \"bilateral\" clause on doyle's control):**\r\n  receiver-side only. The sender's `MSG_OUT` rows are intact on both sides, so an exchange IS\r\n  reconstructible from the **peer's** log — but not from the woken agent's own, which is the surface\r\n  a post-reset agent reads. hertz re-grounded his 22:36 session off seq 1786 of a log that holds his\r\n  half of every exchange since 14:02 and none of doyle's; a replay of an idle-woken agent shows its\r\n  own outbound answering nothing, and the last-received clock skips exactly the moments the peer was\r\n  talking, which reads as \"peer gone quiet\".\r\n- **Against the requirement's own words:** `REQ-IO-MSG-EDGES` (activated, `doc`/`impl`/`unit`)\r\n  states that \"MSG_IN publishes where core **delivers or injects** an inbound one, so the funnel\r\n  observes the edges rather than growing a parallel notion of what a message is\". This is not a case\r\n  the requirement failed to anticipate: **its own second clause is unimplemented** while `impl` and\r\n  `unit` read green on the first. The inject edge was never given a publisher when F-023 (idle-edge\r\n  drain), W5 (parked re-offer) and the WAN ingress added takers; the unit cell at `delivery.rs:1251`\r\n  pins the poll leg only, so the coverage the registry reports is green on two edges and vacuous on\r\n  the one the requirement names by verb.\r\n- **Remedy, and where it must sit:** publish `MSG_IN` **inside `try_spt_hosted_inject` on\r\n  `Some((true, _))`** — the one chokepoint all four callers share — so no caller can deliver\r\n  unobserved; a fix placed in `drain_spool_offering` would leave the send-time direct inject and WAN\r\n  ingress silent. Keep it observation-only (REQ-IO-EVENT-BUS): the inject verdict must not depend on\r\n  the bus. The unit cell to add mirrors `delivery.rs:1251`: an injected row owes exactly one\r\n  `MSG_IN`, a refused inject owes none. Post-hoc census of what was lost: spooled rows carry\r\n  `TakerLeg::IdleInject` / `NativeInject` in the audit column (REQ-SPOOL-TAKE-AUDIT); direct injects\r\n  never spooled and are enumerable only from the sender's `MSG_OUT`.\r\n- **OPEN, unranked, not smoothed:** doyle's pre-clear 1855 got a **bodiless** `USER_INPUT msg\r\n  from=\"hertz\"` row (the `api state busy` payload path, `delivery.rs:115` `state_io_kind`) while his\r\n  post-clear five got **no row at all**. Both are wake-delivered; the difference is downstream of\r\n  this gap, in what the adapter passed as the state payload, and is not this entry's mechanism.\r\n  Also out of scope, perri's surface: the claude-spt overflow notice names spills of the CURRENT\r\n  session id only, so the last spill before a `/clear` is never named again (how the 22:35Z body\r\n  went unread in the first place).\r\n- **Kin:** `REQ-IO-MSG-EDGES`, `REQ-MSG-IDLE-EDGE-DRAIN`, `REQ-IDLE-PARKED-DELIVERY`,\r\n  `REQ-SPOOL-TAKE-AUDIT`, **IR-84** (the arm the rigs fire was the only one without a clock — same\r\n  shape: the leg that fires most is the one the instrument never covered), releases#287 (shells after\r\n  a restart), memory `an-empty-msg-from-tag-is-a-turn-trigger-whose-body-lives-in-the-spill`.\r\n- **Ripe when:** any lane touches `spt-daemon::inject` or the IO funnel; small enough to ride the\r\n  next product batch. · **Size:** one publish call at one chokepoint, one unit cell, one `int` leg\r\n  (a hook-hosted receiver woken by a `SENT`, then `io-events` replayed for the msg-id).\r\n\r\n### IR-93 — no PDB ships beside the installed `spt` binary, so the one non-invasive read of a wedged production daemon comes back without a single named frame\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-10. **The number was reserved by NAME on 2026-09-09** at\r\n  the #293 mechanism read (\"PDB ask -> IR-93 at next sweep\") and this entry closes that claim — a\r\n  name-only IR with no entry text is the exact gap [[IR-85]]'s status line had to spend a paragraph\r\n  explaining about IR-84, and it is not being left open a second time. · **Origin:** the #293 pump\r\n  wedge on hfenduleam.\r\n- **What was actually paid.** With the daemon wedged and unrecoverable, hertz's `cdb -pv -p 31856`\r\n  dump (2026-09-09 23:23:26-31Z, 4.79 s suspend, 35 threads, preserved at\r\n  `.spt/preserved/293-brain-stacks-20260909T232326Z/`) was the ONLY direct observation available of\r\n  the live wedged process — the pump had already stopped, so the suspend cost the fleet nothing it\r\n  still had. It came back **with NO SYMBOLS: there is no PDB beside the installed exe.** Both\r\n  pump-ipc-reader threads were visible in `SleepEx` and all 32 brain threads in Wait, but the frames\r\n  are addresses.\r\n- **The cost, stated at the strength it holds.** The mechanism was named anyway — from SOURCE reading\r\n  (`Brain::read_event()` unbounded at `brain.rs:1025-1027`, 17 in-brain loopers), not from the dump.\r\n  What the dump could not do is say **WHICH call site parked THAT instance**, and that remains NOT\r\n  ESTABLISHED. A symbolised dump is the one artifact that answers it directly, and the next wedge\r\n  will present the same choice with the same empty answer.\r\n- **Remedy:** retain and ship the PDB beside the installed binary (or publish a symbol store the\r\n  debugger can resolve against) so a production dump names frames. **Weigh it honestly at rider\r\n  time:** this is a packaging/size decision, and a release profile that emits no debug info is a\r\n  deliberate choice someone made — this entry is the bill for it, not a claim it was wrong.\r\n- **Kin:** [[IR-82]] (a daemon death leaves no record of who died — same family: the corpse is the\r\n  evidence and nothing preserves it), [[IR-84]] (the arm with no clock), [[IR-95]] (a budget that\r\n  cannot say how much it burned).\r\n- **Ripe when:** next installer / release-packaging touch. · **Size:** packaging (profile + install\r\n  layout), no product code.\r\n\r\n### IR-94 — xtask's brainread deadline gate cannot SEE `serve_sync`: its registry is three hand-listed files and its predicate is a name shape, so a stream server outside both got the reply form and the gate stayed green\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-10 at the releases#294 / v0.69.0 golden RED triage. **This\r\n  is an INDEPENDENT gate finding, not the cause of that red** — it was found while reading the\r\n  milestone's diff and stands whatever Finding 1 turns out to be. · **Origin:**\r\n  `xtask/src/brainread.rs`, new this milestone (the #293 fix's zero-call-site guard).\r\n- **Mechanism, read at source.** The gate's REACH is two hand-authored narrowings stacked:\r\n  **registry = exactly three files** (`dispatch.rs`, `attach.rs`, `brain.rs`) and **predicate = a name\r\n  shape** (`starts_with(\"serve_\") && ends_with(\"_feed\")` or `== \"serve_attach\"`). `serve_sync` is a\r\n  stream server that lives in **no registry file** and whose name **escapes the pattern**, so it is\r\n  invisible on both axes at once. It therefore carries the **REPLY form — the exact form this gate\r\n  REJECTS for every stream server it can see — and the gate is GREEN.** An enforcement whose\r\n  population is enumerated by hand reports compliance over the set it can see, which is not the set\r\n  that matters.\r\n- **Why it is inert TODAY and why that is not reassuring.** The production carrier is unbounded:\r\n  `dispatch::connect()` (`dispatch.rs:898`) uses `Brain::cold_start` with `io_timeout: None`, so\r\n  `call_deadline()` is `None` and the read is unbounded regardless of which form the server carries.\r\n  **It becomes LATENT the day `serve_sync` rides a pump carrier** — which is precisely the direction\r\n  the #293 fix is moving the codebase. The guard will still be green on that day.\r\n- **Owned:** todlando has taken that his migration/census missed `serve_sync`'s lifetime semantics.\r\n  Recorded because the entry is about the GATE's reach, not about who missed it.\r\n- **Remedy shape:** derive the population from the **behaviour** (a fn that serves a stream) rather\r\n  than from the file it sits in or the name it happens to carry, and make the gate **FAIL on a server\r\n  it cannot classify instead of skipping it**. Add a census leg that PRINTS the population checked —\r\n  a count is what would have exposed a three-file registry at a glance.\r\n- **Kin:** [[IR-84]], `unbounded-brain-carrier-cannot-be-bounded` (memory — the carrier question that\r\n  makes this inert today), `REQ-BRAIN-READ-BOUNDED-PER-CALL`.\r\n- **Ripe when:** next `brainread`/xtask touch, **and mandatorily BEFORE `serve_sync` is migrated to a\r\n  bounded carrier.** · **Size:** small.\r\n\r\n### IR-95 — a burned polling budget names WHAT it wanted and never HOW LONG it waited, so no run, green or red, can say how close it came\r\n\r\n- **Status:** OPEN, filed by doyle 2026-09-10 at the releases#294 golden RED, where it cost this\r\n  triage most of a morning and four agents. · **Origin:** the two Windows Phase A failures at\r\n  `a9e786b2`, both polling budgets burned rather than value mismatches.\r\n- **The two sites, read at source.** They are not even the same KIND of budget, which is the first\r\n  thing no reader can tell from the panel:\r\n  · `crates/spt/tests/contract_e2e.rs:393-407` — a **WALL** deadline,\r\n  `let deadline = Instant::now() + Duration::from_secs(30)`, panicking\r\n  `\"the brain pulse must ingest the commune into the live context tier\"`. **No elapsed.**\r\n  · `crates/spt-daemon/tests/sync.rs:98-110` — an **ITERATION** budget, `for _ in 0..400 {\r\n  net_streams(); sleep(25ms) }`, panicking `\"sync stream never appeared at the responder's broker\"`.\r\n  **No elapsed, no iteration count** — and its own comment calls it a \"10s budget\", which is a\r\n  NOMINAL sum of sleeps, not a wall bound: each `net_streams()` IPC call adds to it (hertz), so on a\r\n  loaded box the wall it grants is unknown and larger.\r\n- **Four costs MEASURED in this one triage, each traceable to the missing clock:**\r\n  1. **The panic reads as a CONTENT claim.** `contract_e2e.rs:403`'s message is what a 30 s DEADLINE\r\n     EXPIRY prints, and doyle relayed it to three peers as \"a clean content assert, not a stall\"\r\n     before opening the source.\r\n  2. **History cannot supply margins at all.** nextest suppresses passing output by default, so\r\n     **eight consecutive goldens** of this cell's Windows durations exist and **not one carries an\r\n     internal margin**. (`--success-output immediate` retains it — so this is recoverable going\r\n     forward, and was not, going back.)\r\n  3. **A whole-test total cannot locate the poll inside the test.** This conflation was committed\r\n     **five times in forty minutes by three different agents** — deployah twice (retracted both),\r\n     doyle once *in the message correcting deployah for it*, and it was caught each time by todlando\r\n     and hertz. A defect that costs three careful agents five errors in one morning is not a people\r\n     problem; the number they needed was not printed anywhere.\r\n  4. **A FAIL and a PASS are not the same quantity.** `wait_for_stream_except` is called at\r\n     `sync.rs:201`, with `serve_sync`, the puller join and every assertion AFTER it — so a failing\r\n     run **truncates** there. This cell FAILED at 58.77 s and PASSED at 61.304 s, and that 2.5 s gap\r\n     carries no information in either direction. It was read as an anomaly (\"it took LESS time and\r\n     still failed\") until the call site was opened.\r\n- **Remedy:** on expiry, print **elapsed, the budget, and iterations consumed**; where the poll waits\r\n  on another party, print that party's **PRODUCER PROGRESS** too — a watcher's own timings cannot\r\n  separate a slow watcher from a slow producer (hertz, todlando), which is the single fact this\r\n  triage most needed and could not get. Keep the content sentence; it is the panic's `{what}`, not\r\n  its whole body.\r\n- **Population CENSUSED 2026-09-10 (doyle), discharging the census this entry declared OWED — 323\r\n  poll sites detected, 304 of them classified blind. SUPERSEDED 2026-09-10 by the validation\r\n  below: 317 blind of a 321-site population, and the census's own coverage measured.** Read-only, run beside golden diagnostic 34458491560\r\n  without dispatching anything to either runner. Preserved with its method, its raw classification\r\n  and its discarded first attempt at `.spt/preserved/ir95-poll-census-20260910/`.\r\n- **Method, deliberately WORDING-INDEPENDENT.** Over the 212 tracked `*.rs` files under\r\n  `**/tests/**` plus `xtask/`, take every loop by SHAPE — `for _ in 0..N`, `while Instant::now() <\r\n  deadline`, `while <x>.elapsed() < budget`, bare `loop {` — keep it only if it SLEEPS (a poll, not\r\n  a spin) and can FAIL (`panic!`/`assert!`/`expect(`/`bail!` on its exit path), then ask whether its\r\n  failure path emits a MEASURED VALUE (`.elapsed()`, `.as_millis()`, an iteration counter). **String\r\n  literals are stripped before that question is asked**, so the word \"budget\" inside a panic message\r\n  cannot credit itself with a clock. **Result: 323 sites, 19 apparently clocked, 304 blind.**\r\n- **304 of 323 DETECTED CANDIDATES CLASSIFIED BLIND — a classifier count, NOT a proven floor.**\r\n  Stated at that strength on hertz's and todlando's correction of a stronger form this entry\r\n  briefly carried. What was actually spot-checked is the CLOCK bucket, and both errors found there\r\n  ran the same direction, undercounting blindness: `brain_read_deadline.rs:87` was credited from\r\n  elsewhere in the read window while its real failure path is `panic!(\"whole-carrier brain never\r\n  connected to {name}\")`, carrying no clock at all; `er_briefing_presented_e2e.rs:310` returns\r\n  `Some(started.elapsed())` on SUCCESS and a bare `None` on expiry.\r\n- **What that does NOT license.** Finding only false-CLOCK errors does not exclude false-BLIND ones,\r\n  and nothing here establishes POPULATION COVERAGE — whether the four loop shapes catch every poll\r\n  in the corpus is unvalidated, so a poll expressed as a helper, a retry combinator or an iterator\r\n  chain is uncounted and unmeasured. **No repository-wide `>= 94%` claim is made and none should be\r\n  repeated from this entry.** The honest sentence is: 304 classified BLIND among 323 detected\r\n  candidates, with the checked errors so far undercounting blindness. Validating both buckets and\r\n  the population is owed before any bound is asserted.\r\n- **VALIDATED 2026-09-10 (doyle) — all three owed checks discharged; the headline figure MOVES to\r\n  317 blind of 321.** Preserved as `VALIDATION.md` beside the census (machine-bound per [[IR-90]]).\r\n  (1) **The CLOCK bucket is now adjudicated EXHAUSTIVELY, not spot-checked**: of 19, only **4** emit\r\n  a measured value on their own expiry path, **13 were FALSE CLOCKs** and move to BLIND, and **2 are\r\n  not poll-failure sites at all**. Two mechanisms cover all 13, neither of them a wording problem:\r\n  **window bleed** (7 — four credited by a `const CONVERGE_BUDGET: Duration = …as_millis()…`\r\n  *declaration* 20-25 lines BELOW a bare `panic!(\"brain could not connect\")`, one by a different\r\n  loop 57 lines away, two by an unrelated `now_ms()` helper) and **condition-use, not emission** (6 —\r\n  `assert!(started.elapsed() < Duration::from_secs(30), \"…viewer_count={count:?}\")` reads the clock\r\n  in the PREDICATE and omits it from the MESSAGE). Stripping string literals stopped a message\r\n  crediting itself; it does not stop CODE crediting a site whose message stays silent.\r\n  (2) **False-BLINDs checked at last — a seeded 30-site random sample of the BLIND bucket\r\n  (`random.seed(95)`), hand-adjudicated: 30 of 30 confirm BLIND, zero false-BLIND.** By the rule of\r\n  three that bounds the false-BLIND rate at **<= ~10%, at 95% confidence** — a binomial upper bound\r\n  assuming the 30 are a simple random sample of the 304 and each site's adjudication is independent;\r\n  it is **not a deterministic guarantee**, and zero errors in 30 excludes nothing outright (hertz).\r\n  This is the FIRST check run in the\r\n  direction that would REDUCE the blind count and it found nothing; every error found in either\r\n  bucket still runs the other way.\r\n  (3) **Population coverage, measured against every `sleep` in the corpus** — 472 call-sites, 349\r\n  inside a detected window, 75 one-shot settles in no loop. The remaining 48 dedup to 47 loop\r\n  headers and **every one is explained, 0 unexplained**: **32** matched a census shape but cannot\r\n  FAIL within 60 lines (excluded BY DESIGN — the census counts loops that wait AND can fail), and\r\n  **15 are the detector's true false negatives**, a fixed nameable set:\r\n  `while std::time::Instant::now() < deadline` (the PATH-QUALIFIED spelling — the regex demands a\r\n  bare `Instant::now()`; `broker.rs:389`, `shellchan.rs:114`), `while !stop.load(Ordering::Relaxed)`,\r\n  `while <predicate>(…)` (`shell_relink_force_e2e.rs:194/241`, `shell_stale_online_e2e.rs:146`,\r\n  `redispatch.rs:269`), and one `for (a, b) in [...]`. Those 15 stay UNCLASSIFIED.\r\n  **The 32 change how this census may be QUOTED:** \"323 poll loops that wait and can fail\" silently\r\n  excludes 32 loops that wait and CANNOT fail at the poll — a defensible scope, but a scope, and the\r\n  sentence must carry it.\r\n- **Restated census, and the form to quote.** **321** sites in the adjudicated population (323 minus\r\n  2 membership errors from the CLOCK bucket; a 3rd — `net_worker_starve.rs:99`, a fixed-window\r\n  SAMPLER that always runs its window and has no expiry failure — turned up in the BLIND sample, so\r\n  3 errors in 49 hand-adjudicated sites means the population carries ~6% slop and **321 is not\r\n  exact**). **317** classified BLIND. **4** report a measurement. **15** poll loops outside the\r\n  detector's reach, unclassified. **Still not established, and still not to be written: that 317 is\r\n  a FLOOR, or any repository-wide rate.** One direction is now exhaustive, the other bounded at\r\n  <=10% by a 30-site sample — a bounded estimate, never a floor, and silent about the 15.\r\n- **A distinction this validation surfaced, and the remedy above should carry: \"emits a clock\" is\r\n  TWO different things.** `transport_death_eof.rs:540` prints the OBSERVED quantity\r\n  (`{canary_after}ms`); `er_brief_once_per_session_e2e.rs:288` prints the MARGIN (`elapsed=`). Only\r\n  the second tells a reader how close the budget came. 3 of the 4 surviving CLOCK sites report a\r\n  margin, 1 reports an observation — and **a binary CLOCK/BLIND classifier cannot see that\r\n  difference**, which is a limit of the census, not of the sites.\r\n- **One edit to preserved evidence, DECLARED.** `census.py` printed `<-- IR-95 population (a FLOOR)`\r\n  on its blind line. That sentence was retracted the day it was written, but the retraction never\r\n  reached the SCRIPT, so re-running the preserved artifact reprinted the withdrawn claim at whoever\r\n  ran it — a retraction does not propagate to the next reader on its own. The LABEL, and only the\r\n  label, is corrected in place; the computation is untouched and **still reproduces 323 / 19 / 304**,\r\n  which is what makes this validation checkable against it. The old line is quoted verbatim in\r\n  `VALIDATION.md`.\r\n- **A FIRST detector was discarded, and its failure is itself evidence for cost 1 above.** Keying on\r\n  expiry VOCABULARY (\"never\", \"timed out\", \"did not appear\") found 53 sites and **missed\r\n  `contract_e2e.rs:393` entirely — the very site this entry was filed from** — because its panic\r\n  message is a CONTENT sentence. A wording-keyed census is structurally blind to exactly the sites\r\n  whose messages mislead. Recorded so no one re-runs the cheap version and reports 53 as the answer.\r\n- **Positive control passes, and it found siblings.** Both originating sites appear, both BLIND:\r\n  `sync.rs:102` and `contract_e2e.rs:395`. The census also surfaced **two fixed budgets nobody had\r\n  noticed** — `sync.rs:89` (`0..300`, beside the `0..400` at :102) and `contract_e2e.rs:51`\r\n  (`0..400`, beside the wall deadline at :393). Concentration: `inject_control_wedge.rs` 18,\r\n  `broker.rs` 10, `endpoint_lifecycle.rs` 9, `dispatch.rs` 7, `twohost.rs` 7.\r\n- **PRODUCER-PROGRESS INSTRUMENT — SPEC, 2026-09-10, and the three readings it does NOT support.**\r\n  The remedy above asks for the waited-on party's progress because a watcher's own timings cannot\r\n  separate a slow watcher from a slow producer. `last_streams_seen=0` throughout is equally\r\n  consistent with \"the producer never produced\" and \"the watcher never saw it\", and neither arm of\r\n  the releases#294 pair can tell those apart. **Design (doyle), narrowed by hertz and todlando, who\r\n  independently found the same three defects in the first form of it.**\r\n  **INSTRUMENT** — rides the IPC the poll ALREADY makes, so it adds no channel and no budget: the\r\n  responder's broker surfaces, alongside `net_streams`, a monotonic `streams_created_total` AND a\r\n  monotonic `streams_retired_total` for the session, the sequence and age of its last transition,\r\n  and the STREAM IDS of the most recent transitions so the watcher can correlate them against the\r\n  ids it sees and skips. The watcher prints the producer's counters beside its own observation.\r\n  **SEMANTICS THAT MUST BE DECLARED BEFORE A SINGLE READING IS TAKEN** — a bare count is not a\r\n  measurement until these are fixed: WHICH HOOK \"created\" fires at (broker stream-table\r\n  registration? wire acceptance?), WHICH KEY the counter is scoped to and what a session rotation\r\n  does to it, the COUNTER LIFETIME and reset behaviour (process lifetime, per session, what a broker\r\n  restart does), and WHICH CLOCK the age is measured against and whether it is comparable to the\r\n  watcher's.\r\n  **WHAT EACH READING LICENSES, and what it does NOT** (the first form of this table asserted three\r\n  causal conclusions it had not earned):\r\n  · `created=0` at expiry means **no creation was RECORDED AT THAT HOOK, in that counter's scope,\r\n    for that session key**. It does **NOT** establish that the requester never produced, and it does\r\n    **NOT** exonerate the watcher — the hook may sit downstream of the real production, or be scoped\r\n    to a different key.\r\n  · `created>0` with every snapshot empty is **CONSISTENT WITH a visibility/registration defect AND\r\n    with a stream being created and retired entirely between two 25 ms polls**. On its own it\r\n    establishes neither; the retire counter and the ids are what separate them.\r\n  · **Creation AFTER expiry cannot be observed by a poll that has already stopped.** A last-change\r\n    age cannot supply it. That needs either a separately bounded, separately declared post-expiry\r\n    observation, or a retained producer event trace with timestamps.\r\n  **Process constraints:** separately versioned and announced, never slipped between arms of a\r\n  comparison, and the existing diagnostic patch and every budget stay UNCHANGED. Widening a budget\r\n  to make a red go green remains refused.\r\n- **`last_streams_seen` IS A FILTERED-VIEW COUNT — the sharpest narrowing this field has had, and it\r\n  applies to all three expiries in the releases#294 pair.** The poll calls `net_streams`; the broker\r\n  answers at `broker.rs:9546` `dispatch_net_streams` -> `host.dispatch_stream_infos()`\r\n  (`nethost.rs:1952`) -> `stream_infos_filtered(FALSE)`, and that filter drops TWO classes\r\n  SERVER-SIDE, before serialization (ADR-0040 decision 2, `REQ-STREAM-INFOS-SERVER-FILTER`):\r\n  `!e.retired.load(SeqCst)` and `!e.initiated_locally`. So `last_streams_seen=0` does **NOT** mean\r\n  the broker held no streams. It means **zero NON-RETIRED, NON-LOCALLY-INITIATED rows at that\r\n  instant** — a row that exists and is retired is invisible to the poll BY DESIGN. That is narrower\r\n  than the corrected form the RCA had settled on (\"the final snapshot was empty\"), and it is a\r\n  hook-scope fact of exactly the kind the preconditions above demand be pinned before any reading.\r\n- **A \"reuse it, no product change\" stage-1 design WAS PROPOSED AND IS WITHDRAWN — recorded because\r\n  the reason generalises.** `NetHost::stream_counts()` (`nethost.rs:1980`) is already surfaced as\r\n  `NetStatusReply.streams_held` (`broker.rs:9002`, `msg.rs:874`) and documents itself as\r\n  \"retirement-blind ON PURPOSE ... the resource truth the eligibility view hides\". Reading it beside\r\n  `net_streams` looked like it would separate \"filtered out\" from \"absent\" for free. It does not,\r\n  for four reasons, and hertz and todlando raised them independently:\r\n  · **Two IPC replies are not an atomic snapshot.** `filtered=0` then `held>0` is equally consistent\r\n    with a row ARRIVING BETWEEN THE TWO CALLS. Such a pair must never be labelled proof of filtering,\r\n    and needs call order and timestamps recorded if it is read at all.\r\n  · **`streams_held` is HOST-SCOPED, not exchange-scoped.** It counts unrelated and locally-initiated\r\n    rows the filtered view drops, so it cannot speak to the exchange under investigation without\r\n    stream-ID correlation; any conclusion from it stays aggregate.\r\n  · **It adds UNMEASURED perturbation** — a second IPC per iteration changes the 400-iteration\r\n    window's wall duration by an amount nobody has measured. **CORRECTED 2026-09-10 (hertz,\r\n    todlando), because the first form of this bullet was itself an overclaim in two ways and both\r\n    are instructive:** (a) it called perturbation DISQUALIFYING, and it is not — instrumentation\r\n    that perturbs timing can still be useful; the objection is ADDED, UNMEASURED perturbation, not\r\n    perturbation as such. (b) It SIZED that perturbation from two figures that cannot carry it: the\r\n    measured `net_streams` cost (60,295 us / 400 = 0.151 ms per iteration) does **not** estimate the\r\n    `net-status` cost — different call, different work — and the **0.29% expiry difference between\r\n    the two arms is NOT an established causal effect size**, only an unexplained gap between two n=1\r\n    observations. Sizing an observer effect against it treats an open question as a known\r\n    quantity.\r\n  · A single POST-EXPIRY sample avoids perturbing the poll but then describes LATER state, not\r\n    expiry state, and is still host-scoped.\r\n- **THE INSTRUMENT THAT SURVIVES REVIEW: a retained, EXCHANGE-CORRELATED create/retire TRACE**\r\n  (hertz and todlando, converged independently). Recorded per stream lifecycle transition on the\r\n  producer side — stream id, conn id, remote id, transition, `initiated_locally`, a monotonic\r\n  sequence and a timestamp on a NAMED clock — retained and read AFTER the fact rather than sampled\r\n  by the watcher, so it adds **NO POLL CALLS**. Say that, and not \"adds nothing\" (hertz): it still\r\n  adds PRODUCER-SIDE work that may affect arrival timing and resource contention, and **that effect\r\n  is unmeasured too**. The trace is preferable for having no watcher IPC, not for being free. It captures between-poll transitions,\r\n  which neither a gauge nor an in-loop counter can: **a gauge reads 0 for a stream created and\r\n  retired between two 25 ms polls exactly as it does for one never created.** Correlation to the\r\n  exchange is by stream id against the ids the watcher saw and skipped.\r\n  **MEASURED: it does not exist today** — zero stream-lifetime log lines in `nethost.rs`. So this is\r\n  a PRODUCT change, not a reuse, and it stays unbuilt while the product is frozen. Its preconditions\r\n  are the ones above, unchanged. Production AFTER the trace's retention window remains outside it.\r\n- **THE FIRST MARGINS THIS ENTRY PRODUCED UNDER CI / GOLDEN CONDITIONS — instrumented run\r\n  34458491560, 2026-09-10\r\n  (hertz's patch; deployah's lane; read independently by doyle).** The remedy above was argued for\r\n  on the ground that a poll which prints nothing cannot say how close it came. It has now printed\r\n  on a runner. **NOT the first margins overall** — the earlier local 12-leg run already reported\r\n  them, including a 392/400 (hertz, todlando). **The genuinely novel quantity is narrower and\r\n  sharper than \"CI margins\" (deployah): it is a FAILING poll's margin, which no local leg could\r\n  produce because all 12 of them PASSED.** A budget's behaviour at expiry is the one thing a green\r\n  run structurally cannot report, and it is the case the remedy exists for.\r\n  **The figure is the MAXIMUM AMONG SUCCESSFUL polls in this run — explicitly NOT a ceiling, and not\r\n  a bound on observations**: the poll that EXPIRED in this same run consumed 400/400 = 100%. So:\r\n  among the polls that PASSED on hfenduleam, both instrumented sites peak at ~63% of budget. The\r\n  seven successful\r\n  `[IR95-SYNC]` waits in that run are 92, 19, 72, 254, 21, 21 and 20 iterations — **worst 254/400 =\r\n  63.5%** (6.449393 s) — and the `[IR95-CONTRACT]` success consumed **18.857089 s of its 30.000 s\r\n  wall = 62.9%**. Two independent sites, two different budget KINDS, the same maximum-among-passes.\r\n  Headroom at that worst SUCCESSFUL case ~37%; the failing case had none left. **n=7 and n=1, one\r\n  box, one run: a first CI measurement, not a stability claim, and NO budget change is proposed on\r\n  it.**\r\n- **The iteration budget's WALL EQUIVALENT, also measured for the first time.** The expiring poll's\r\n  400 iterations cost **10.199907 s against 400 × 25 ms = 10.000 s nominal — 2.0% over**, with\r\n  per-iteration overhead ~0.5 ms against a 25 ms sleep (IPC 60.295 ms total, 0.151 ms per iteration,\r\n  **0.59% of elapsed**; sleep is 99.4%). So on this box in this run a \"400 iteration\" budget and a\r\n  \"~10.2 s wall\" are nearly the same object — the iteration budget did NOT silently become a\r\n  different budget under load. That bounds one standing worry about blind iteration counts, and it\r\n  is precisely the class of thing that stops being guessable the moment a clock prints. Box-local\r\n  and run-local; it is not a general result.\r\n- **A scope limit the instrumentation itself imposes, and a smaller ask than it first looks.**\r\n  `last_streams_seen` is an ASSIGNMENT per iteration (`sync.rs:111`), not an accumulator, so\r\n  `last_streams_seen=0` at expiry describes the FINAL iteration only — not all 400 (todlando's\r\n  correction; deployah withdrew the aggregate reading, doyle confirmed it at source). But the loop's\r\n  CONTROL FLOW already proves the interesting half for free: the `find()` at `:113` returns the\r\n  instant a non-skipped stream appears, so **reaching the expiry print IS proof that no non-skipped\r\n  stream was seen in any of the 400 SNAPSHOTS** — no aggregate trace required. **It does NOT mean\r\n  no stream EXISTED between snapshots** (hertz): the poll samples at 25 ms, and nothing here\r\n  observes the gaps. What is genuinely\r\n  unmeasured is only whether a SKIPPED stream was ever present, and `skip` is empty on that call.\r\n  An aggregate/per-iteration trace therefore buys less here than the gap first suggests.\r\n- **NOT ESTABLISHED: that all 304 deserve a clock.** The census SIZES the problem; it does not\r\n  schedule it, and it does not pre-judge which sites are worth the edit. Remedy triage is owed\r\n  separately and is the larger half.\r\n- **Kin:** [[IR-84]] (the one `PUMP_PEER_FAIL` arm the rigs fire was the only one carrying no clock —\r\n  **the same class in product code**; this entry is its test-corpus face), [[IR-85]] (budgets sized\r\n  against a box whose speed moved), [[IR-77]] (nothing stamps the spawn-to-first-log interval, so a\r\n  readiness red cannot say where the time went), [[IR-90]].\r\n- **Ripe when:** with the releases#294 instrumented base-vs-head comparison, which **cannot be run\r\n  without it** — the experiment's whole output is the margins these sites do not print. ·\r\n  **Size:** small per site; the census is the larger half.\r\n\r\n### IR-96 — the `daemon_stop_convoy_e2e` API-storm cell fails 3-of-3 under the HEAVY suite at the diagnostic tree while passing at the candidate in golden CI, and nothing yet separates instrumentation from box from product\r\n\r\n- **Status:** OPEN, **cause-unclassified** (todlando's and hertz's stipulation, adopted verbatim — a\r\n  triage placement here is NOT a finding of non-defect).\r\n- **Origin:** releases#294 / v0.69.0 Arm B, 2026-09-10, deployah executing at diagnostic tree\r\n  `ed8ecd94` (= candidate `a9e786b2` + the unlanded sync instrumentation, never merged).\r\n- **What:** `spt::daemon_stop_convoy_e2e stop_under_an_api_storm_stays_down_then_start_brings_up_exactly_one`\r\n  FAILED in **all three** Arm B runs, with durations **growing every run: 9.473s · 10.973s ·\r\n  14.553s**. Different signature from the #294 sync cell; nothing was filed against #294.\r\n- **THE DIFFERENTIAL that makes it worth an entry rather than a shrug:** the same cell shows **0\r\n  failures at the candidate** in golden 34481993681 Phase A on this same box — that run's single\r\n  failure was the sync cell (`3381 tests run: 3380 passed (6 slow, 5 leaky), 1 failed, 1 skipped`).\r\n  So: 0-of-1 at `a9e786b2` under CI load, 3-of-3 at `ed8ecd94` under local HEAVY load.\r\n- **WHAT THAT DOES NOT ESTABLISH.** It does **not** isolate the instrumentation or the box as the\r\n  only candidates — a condition-dependent or intermittent PRODUCT defect remains live, and a single\r\n  CI pass is not evidence of absence. doyle claimed that elimination on 2026-09-10 and **withdrew\r\n  it** the same hour under todlando's and hertz's correction; the withdrawal is recorded in\r\n  `.spt/preserved/gate-r2-34481993681-20260910/CLASSIFICATION-AMENDMENT-2-doyle.md`.\r\n- **Confounded by IR-97** (below): the three runs were not equivalent conditions.\r\n- **Ripe when:** any lane touches daemon stop/start convoy behaviour, OR a golden run reds this cell\r\n  at a candidate, OR someone runs the cell at `a9e786b2` under the same local HEAVY workload — that\r\n  last one is the cheap discriminator and nobody has run it. · **Size:** one targeted local run to\r\n  discriminate; unknown beyond that.\r\n\r\n### IR-97 — a suite that leaks a fixed cohort of child processes per invocation makes consecutive runs non-comparable, and the between-run accounting the protocol required was not enforced\r\n\r\n- **Status:** OPEN. **Protocol deviation** (hertz's framing, and it is stronger than \"confounder\":\r\n  the protocol ALREADY required between-run accounting — execution did not enforce it, so the fix is\r\n  enforcement, not a limitations paragraph).\r\n- **Origin:** releases#294 Arm B, 2026-09-10. Derived by doyle from deployah's preserved\r\n  `10-residual-births.json` against the run windows.\r\n- **What:** each Arm B suite leaked **exactly 6** `spt` children that outlived it; all **18** were\r\n  still alive at the post-B3 census. Because a process alive at census whose OS birth time falls in\r\n  an earlier window existed continuously through the runs between (pid + birth time is an identity),\r\n  the carried diag-tree residue was **0 during B1 · 6 during B2 · 12 during B3**. The three\r\n  \"repetitions\" were therefore not three equivalent conditions, and every cross-run comparison in\r\n  that arm inherits it.\r\n- **LIMITS, stated so the entry is not over-read:** process **COUNT** is measured; **LOAD is not** —\r\n  idle orphans may cost nothing, contention was UNMEASURED (overlap UNVERIFIED all arm), and this is\r\n  **not** a drift meter. It neither implicates nor excludes residue as a cause of the one expiry, and\r\n  it does not explain it: B3 carried twice the orphans and **passed**.\r\n- **Also unestablished, in both directions:** 18 censused against 15 killed shows only that three\r\n  were absent at the second read. \"Three self-exited\" needs exit evidence; \"I killed 18\" was\r\n  likewise refused by deployah at the time.\r\n- **Kin:** the LEAK rows every Arm A/B run reported; `REQ-HAZARD-RESUME-CUSTODY-ABA` (KH 7.51) and\r\n  KH 7.58 — the cleanup that resolved this was correctly scoped by **pid + image path**, leaving 15\r\n  unrelated `spt` processes untouched, where a name-based kill would have taken down the live agent\r\n  fleet including the gater's own session.\r\n- **Ripe when:** any repeated-run experiment is designed on this box — census BETWEEN runs, not only\r\n  at the end. · **Size:** a between-run census step plus a scoped reap in the harness.\r","startLine":1,"lineNumbers":[1,null,1216,null,5351,null,5353,null,5402,null,5404,5405,5406,5407,5408,5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424,5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440,5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456,5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472,5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488,5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504,5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520,5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536,5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552,5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568,5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584,5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600,5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616,5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632,5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648,5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664,5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680,5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696,5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712,5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728,5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744,5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760,5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776,5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792,5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808,5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824,5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840,5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856,5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872,5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888,5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900]},"fileSize":512411,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\INFRA-REGISTER.md"}}},"isError":false,"timestamp":1789107062049}}
{"type":"message","id":"dd4c65af","parentId":"046b9e09","timestamp":"2026-09-11T06:11:02.051Z","message":{"role":"toolResult","toolCallId":"call_ApWKh6YJsHgT9hQLqIqfuYLr|fc_0330c101aa2c61dc016aa39b739ba887d1aca38b69832057d1","toolName":"read","content":[{"type":"text","text":"# spt-core\n\n**Platform scope:** Windows + Linux for v1. macOS is out (no test machine available) but kept structurally easy — `portable-pty` and Iroh both support it, so macOS is a later test/CI-budget decision, not a re-architecture.\n\n**Legacy migration:** it should be possible — ideally *automatic* — for a user to migrate an existing `claude_skill_owl` (modern SPT) install to spt-core (identity, agents, tracked Psyche context). Exact mechanism deferred to design; the commitment is that migration is a first-class supported path, not a manual rebuild.\n\nHarness-independent core for the SPT ecosystem. Provides inter-agent messaging, live-agent lifecycle, terminal wrapping, self-update, and networking primitives — as both a Rust library workspace and a canonical reference binary. Designed so any agent runtime (Claude Code, Codex, Cursor, headless, future harnesses) can interface with the SPT ecosystem either by shelling out to the binary or by linking the crates directly.\n\nSuccessor to `claude_skill_owl` (today's \"modern SPT\"), which is being rebuilt as `spt-core` to untether the system from Claude Code and lift it to a general-purpose agent-ecosystem core.\n\n## Language\n\n**spt-core**:\nThe system. Canonical name. The Rust workspace and the umbrella project.\n\n**spt.exe / spt** (canonical binary):\nThe reference binary built from the workspace. Replaces today's `owl.exe`. Most external integrations (plugins, hooks, scripts in other harnesses) interact with spt-core *only* through this binary — fire-and-forget subcommands, long-running listeners under a parent harness's process supervisor, etc. Unix builds use the same name without `.exe`.\n\n**library workspace**:\nThe set of Rust crates that compose spt-core. Consumers that want a deeper integration than shelling out to `spt.exe` link these crates directly. The reference binary is itself a consumer of the workspace. The expected non-binary consumers are future first-party services that link Rust directly.\n\n**spt plugin** (separate downstream project — NOT an spt-core deliverable):\nA rebuilt version of today's Claude Code `spt` plugin. It is the **first consumer** built *atop* spt-core and the **acceptance proof** of spt-core v1 (it reaches feature parity with modern SPT while delegating all core functionality to spt-core, primarily via `spt.exe`, with deeper hooks where useful) — but it **lives and builds in its own repository, outside spt-core**. It is a Claude-Code-specific *adapter*: it holds the Claude Code conventions (hooks, slash-commands, skill/plugin layout, `claude` session-invocation). **spt-core itself contains zero Claude Code conventions** — only the harness-agnostic contract the plugin binds to. The only adapter-shaped artifact ever in this repo is a generic mock/test adapter exercising the manifest + `api` contract (PR…\n\n**Pi** (disambiguation — two meanings, never conflate):\n(1) **Pi, the coding agent/harness** (`badlogic/pi-mono`) — a harness example alongside Claude Code and Codex; this is the meaning in user-facing harness lists. (2) **Pi-class node** — Raspberry-Pi-class low-power hardware hosting a Shell-only or headless SPT node; an incidental hardware descriptor, never an explicit product example. Public-facing docs must disambiguate or avoid the bare word.\n_Avoid_: bare \"Pi node\" when the harness is meant.\n\n**spt-daemon** (per-machine supervisor):\nThe single always-on, one-per-machine logical supervisor. Owns the PTYs for all hosted sessions, the node's network identity + WAN endpoint, the subnet registry, all spools, **all poll-listener logic, and all Psyche/pulse loops** — everything is consolidated here (no separate poll-listener or Psyche-wrapper processes; listeners already touch sessions directly under capsule/idle, and Psyche wrappers already invoke harness binaries directly, so they belong in the one supervisor). Collapses what the sister project planned as a separate `spt-node` daemon into one process — see Networking. The `spt-node` separate-deliverable concept is retired.\n\n<!-- [doc->REQ-CLI-NODE-VERB-PRIMARY] -->\n**`spt node` (the CLI verb) is NOT the retired `spt-node` (the process)** — the two are different kinds of thing and must never be conflated. What is retired above is a separate *process* deliverable: a second daemon alongside `spt-daemon`, which this project collapsed into one supervisor. What `spt node` names is the *CLI verb* an operator types to run, stop, or read the state of that one supervisor on their machine (releases#112) — a vocabulary choice on the command surface, with no second process behind it. `spt daemon` remains a full alias of that verb, subcommand for subcommand, and is documented as deprecated rather than removed: installed OS service units and scheduled-task rungs already carry `spt daemon run`, and renaming a verb does not rewrite art…\n\nInternally the logical daemon is split into two implementation layers for seamless self-update (see Self-update):\n- **broker** (stable \"kernel\") — holds *only* the un-transferable, must-not-die resources: PTY master fds, the spawned harness child processes, and listening network sockets. Minimal, dumb, versioned local IPC. Almost never updates.\n- **daemon brain** (\"userspace\") — all logic (routing, registry, pulse/psyche loops, manifest parsing, update orchestration). Restarts freely on update; rehydrates from disk state and re-attaches to the broker's held handles.\n\nLogical addressing is unchanged — still one per-machine `spt-daemon`; the broker is an internal layer, not separately addressable. There is exactly **one broker per machine** (per `SPT_HOME`) — *not* one per endpoint: a single broker holds every hosted endpoint's resources, and it is present whenever the daemon runs, even with zero endpoints online (the bare-daemon case). It is therefore the always-present per-machine layer, which is why the single-daemon lock + liveness anchor belong to it.\n\n**in-session relay**:\nA thin, stateless `spt.exe` task that exists only in **harness-hosted** sessions (where the agent harness is the parent process and spt cannot reach into its process tree — today's Monitor model). It streams the daemon brain's events into the session's stdout. All *stateful* listener logic lives in the daemon; the relay is a dumb pipe, freely killable and respawnable. **spt-hosted** sessions need no separate harness-owned relay — the daemon owns the PTY and consumes the same poll feed itself. Idle delivery into an spt-hosted PTY goes through an opt-in adapter **translation binary** (`[message-idle-translation-binary]`, ADR-0022): a pure stdin→stdout filter spt-core lifecycle-manages — it reads the `<EVENT>` feed on stdin, emits keystroke-commands (`{key}`/`{…\n\n### Deliverable shape\n\nspt-core ships **both** a library workspace and a canonical binary:\n\n- **Library crates** — the deeper integration path. Used by future first-party services that link Rust directly.\n- **`spt.exe` / `spt`** — the canonical binary, built from the workspace. The primary integration path for harness plugins and external tooling, which mostly fire it as a subprocess at various surfaces (one-shot commands, poll listeners under a Monitor-tool-equivalent, hook tap-ins).\n\nBoth surfaces are first-class. Wire-protocol parity between them is a versioning concern from day one (a non-Rust client speaking to `spt.exe` and a Rust client linking the crates must see the same observable behavior).\n\n## Runtime model\n\nspt-core is harness-independent: it does not know about Claude Code, Codex, Cursor, or any other agent runtime. All harness-specific surfaces (how to invoke an agent session, fetch conversation history for an echo commune, detect activity/idleness, etc.) are abstracted behind a runtime layer that consumers supply.\n\n**AgentRuntime** (Rust trait, implementation detail):\nThe internal Rust abstraction over a harness. Anything spt-core needs to do *to* or *with* an agent goes through this trait. Most consumers never see it directly — they configure spt-core via a manifest, and spt-core's default `ManifestRuntime` implementation executes against the manifest.\n\n**harness contract** (umbrella term):\nThe full surface a harness binds to in order to participate in the spt-core ecosystem. Has two equally-important halves: the **runtime manifest** (outbound — how spt-core drives the harness) and the **subcommand surface** (inbound — how the harness reports events back to spt-core). A harness implementation is one TOML/YAML manifest + a binding from the harness's own hook system into `spt.exe <subcommand>` calls.\n\n**runtime manifest** (outbound half of the harness contract):\nA declarative configuration file (TOML/YAML — schema TBD) that tells spt-core how to drive a specific harness. Declares: how to invoke an agent session, how to look up conversation history for an echo commune, how to spawn/resume a Psyche-equivalent, which binary or command implements each harness-side operation, and which endpoint types this harness supports. spt-core is the actor for each of these; the manifest tells it what to do.\n\nExample shape (illustrative): `spt.exe --manifest spt-plugin.toml live start <id>`. A harness like the planned spt plugin wraps this invocation into the `$LIVE` / `$OWL` environment variables it injects into its sessions, so harness-internal callers continue to invoke `$LIVE` / `$OWL` unchanged.\n\n**subcommand surface** (inbound half of the harness contract):\nThe stable set of `spt.exe <subcommand>` entry points that harnesses bind their own hook systems to. When the harness's runtime emits an event (subagent started, tool just invoked, user typed `/clear`, session crashed), the harness's hook fires a short-lived `spt.exe <subcommand>` invocation that mutates on-disk SPT state (perch registry, spool, etc.). spt-core publishes this surface; harnesses author the bindings.\n\n**Naming convention:** these inbound, machinery-facing commands are prefixed **`api `/`api-`** (e.g. `spt api bind`, `spt api state`) to distinguish them from the agent-facing verbs an agent invokes directly (`send`, `ring`, `ready`, …). The `api` namespace is the harness/adapter commands-API; the unprefixed namespace is the agent surface.\n\nTogether: manifest + subcommand surface = the complete harness API. A sidecar-style long-running adapter process speaking a wire protocol is explicitly **deferred** as a possible v2 alternative for harnesses that outgrow the manifest+hooks shape (e.g. need streaming or in-memory state across events). Not built day-one.\n\n**adapter manifest header** (`adapter_name` + version compat):\nEvery manifest declares a unified **`adapter_name`** (e.g. `claude-spt`), carried on every `api` invocation too. It is load-bearing: one daemon hosts endpoints from multiple adapters, so it resolves an endpoint's manifest + seams by `adapter_name`; adapter-update ripples target by it; capability/manifest lookup and telemetry key on it. The header also declares the adapter's own version and a **`min_spt_core_version`** — the minimum spt-core the adapter requires. This declaration must be **readable before an adapter update is applied** (it lives in the manifest header / a small metadata file fetched first), so spt-core can verify compatibility / expected supported features *before* committing the update. If spt-core is below the adapter's `min_spt_core_versio…\n\n<!-- [doc->REQ-MANIFEST-2] -->\n**adapter profile** (ratified 2026-06-11, Gateway grill; future spt-core milestone — first beneficiaries `spt-claude-code` and the usbip shell):\nA named **sparse overlay** on its parent adapter manifest. Merge semantics are **leaf-replace**: a profile key replaces the whole value at that path (arrays included — never spliced or appended). The merged result is a complete manifest, and the profile behaves as a distinct adapter option everywhere: canonical addressing is the composite **`<adapter>:<profile>`** (`claude-spt:work`, `spt-usbip-driver:hid-only`) in every place a bare `adapter_name` rides today (perch `info.json`, capability resolution, `api` invocations, `spt adapter list`); the bare name = the parent unmodified. **Two sources, one semantics:** a **shipped profile** is declared inside the parent manifest by the adapter dev and updates as one unit with it; a **local profile** is a node-local …\n_Avoid_: \"manifest fork\", \"child adapter\", per-profile versioning.\n\n**adapter strings** (ratified 2026-06-11, Gateway grill):\n<!-- [doc->REQ-MANIFEST-3] -->\nA `[strings]` manifest section — an adapter-authored JSON/TOML KV tree, dot-path-readable by anything on the node via `spt adapter get-string <adapter-option> <key.path>` (e.g. a harness hook fetching per-profile `additionalContext` — one hook script serves every profile, only the data differs). Resolution rides the **same leaf-replace profile overlay** as the rest of the manifest: a shipped or local profile may override base strings; `get-string` returns the merged view for the named adapter option. **Strings are data only** — nothing in spt-core ever executes a string (command templates live in manifest sections behind registration, never in the KV). Node-local like the registration itself; no cross-node sync. `set-string` is sugar that edits a **local** p…\n<!-- [doc->REQ-MANIFEST-5] -->\n**File-backed strings** (M12-W3): a `[strings]` value MAY be a **file pointer** instead of an inline literal — a value-position table with **exactly one** key `file`: `skill = { file = \"skill.md\" }`. `get-string` resolves it to the file's **contents** (so large bodies — skill-instructions, hint text — stay out of the manifest). The exactly-one-key rule is the disambiguation: any other table shape stays an opaque nested strings tree (existing trees untouched), and `{ file = … }` is reserved as the pointer form (it can't double as inline data). Files live in the adapter's per-adapter aux dir **`adapters/<adapter>/strings/`** (sibling of `profiles/`), referenced by a path relative to it that **must stay inside that dir** (HAZARD-class containment: `..` traversa…\n_Avoid_: treating strings as config knobs for spt-core itself (those are global settings); \"adapter KV store\" as a separate registry; putting user files in the adapter-shipped `strings/` dir (clobbered by updates — use a local profile).\n\n**manifest substitution in `[strings]`** (ratified 2026-06-25, v0.16.0 update-arc grill):\n`get-string` resolves a set of **adapter-static** substitution keys inside a returned string value at **read time** (lazily, like file-backed strings): **`{adapter_dir}`** — the registry record's precise `source_dir` (the install dir; survives updates; the same dir bare-program resolution already uses) — and **`{adapter_name}`**. Session-scoped keys (`{id}`/`{session_id}`/…) are **not** available: `get-string` carries no session context today, and a `get-string --session-id` for session-scoped substitution is a deferred, larger change. The load-bearing invariant is preserved: **spt-core still never executes a string** — it substitutes and returns; the *adapter's own wrapper* executes the result. Canonical use: a harness hook dispatcher resolves its own packe…\n_Avoid_: session-scoped substitution through bare `get-string`; reading this as spt-core executing a string (it never does — the adapter wrapper executes the resolved value).\n\n**keyword hints** (ratified 2026-06-12 — core milestone A):\n<!-- [doc->REQ-MANIFEST-4] -->\nOnce-per-session usage/syntax hints, a first-class adapter feature: the manifest's `[hints]` section declares entries of `{keywords (literal default, regex opt-in), text}`; the adapter's user-prompt hook pipes the **full user message** to `spt api hint --session <id>` (stdin) and receives matched hint lines (`keyword hint for SPT adapter <name>: \"<kw>\"-->{text}`) for its context-injection channel. The daemon keeps a per-session seen-set — each hint fires **once per session** (a `/clear` mints a new session, naturally re-arming) — and emits at most **one hint per message PER SOURCE**. **The per-source cap AMENDS BY REPLACEMENT the original global one-per-message clause (releases#133, gater-ruled 2026-08-30), and the authority chain is this:** the global claus…\n_Avoid_: unconditional static context (that's the adapter's own preamble); firing per-message.\n\n**shell keyword hints** (releases#133, operator-GREENLIT; shape ruled 2026-08-30):\n<!-- [doc->REQ-SHELL-HINTS] -->\n`[[hints]]` was never harness-only — it is a top-level manifest section with no kind gate, so a `kind = \"shell\"` adapter has always been able to declare hints; what was missing was a reader, because the only reader resolved the endpoint-bound manifest. The now-signal **HINTS** category now also reads the shell adapters an endpoint can see, one line each under the per-source cap above. **Two arms, decided by INSTANTIATION and never by link state:** an adapter this owner holds an instance of surfaces the **full** hint text — whether that instance is online or offline — and an adapter with no instance surfaces only a **teaser** naming the trigger keyword and the command that shows the text (`spt adapter hints <adapter[:profile]>`, which resolves the merged view…\n_Avoid_: gating the shell arm on the harness manifest (an endpoint with no bound manifest still owns shells); filtering the full arm on online/offline; naming a surfacing command that does not exist at the shipping head.\n\n…\n\n…\nThe CLI sibling of the frontend's guided resume — one command that lists endpoints **grouped by locality, most-recently-used within each group**: `on-node / current-project → on-node / other-project → off-node`, mirroring the *resolution policy*'s local-first preference. Selection **chains conditionally**: a **running** instance → attach/tap-in (no adapter step — already live under one); a **non-running** endpoint → into the **adapter selector** (*adapter selection*: history head = default → prior adapters → \"choose a different adapter\") → *anchor subnet* / other creation prompts as needed → launch; a **\"+ new endpoint\"** entry → the full creation flow. Off-node picks respect the reach + consent gates (remote-drive of your own running instance is ungated; a …\n\n[Showing lines 1-103 of 1267. Use :104 to continue. Some lines truncated to 768 chars]"}],"details":{"truncation":{"content":"# spt-core\r\n\r\n**Platform scope:** Windows + Linux for v1. macOS is out (no test machine available) but kept structurally easy — `portable-pty` and Iroh both support it, so macOS is a later test/CI-budget decision, not a re-architecture.\r\n\r\n**Legacy migration:** it should be possible — ideally *automatic* — for a user to migrate an existing `claude_skill_owl` (modern SPT) install to spt-core (identity, agents, tracked Psyche context). Exact mechanism deferred to design; the commitment is that migration is a first-class supported path, not a manual rebuild.\r\n\r\nHarness-independent core for the SPT ecosystem. Provides inter-agent messaging, live-agent lifecycle, terminal wrapping, self-update, and networking primitives — as both a Rust library workspace and a canonical reference binary. Designed so any agent runtime (Claude Code, Codex, Cursor, headless, future harnesses) can interface with the SPT ecosystem either by shelling out to the binary or by linking the crates directly.\r\n\r\nSuccessor to `claude_skill_owl` (today's \"modern SPT\"), which is being rebuilt as `spt-core` to untether the system from Claude Code and lift it to a general-purpose agent-ecosystem core.\r\n\r\n## Language\r\n\r\n**spt-core**:\r\nThe system. Canonical name. The Rust workspace and the umbrella project.\r\n\r\n**spt.exe / spt** (canonical binary):\r\nThe reference binary built from the workspace. Replaces today's `owl.exe`. Most external integrations (plugins, hooks, scripts in other harnesses) interact with spt-core *only* through this binary — fire-and-forget subcommands, long-running listeners under a parent harness's process supervisor, etc. Unix builds use the same name without `.exe`.\r\n\r\n**library workspace**:\r\nThe set of Rust crates that compose spt-core. Consumers that want a deeper integration than shelling out to `spt.exe` link these crates directly. The reference binary is itself a consumer of the workspace. The expected non-binary consumers are future first-party services that link Rust directly.\r\n\r\n**spt plugin** (separate downstream project — NOT an spt-core deliverable):\r\nA rebuilt version of today's Claude Code `spt` plugin. It is the **first consumer** built *atop* spt-core and the **acceptance proof** of spt-core v1 (it reaches feature parity with modern SPT while delegating all core functionality to spt-core, primarily via `spt.exe`, with deeper hooks where useful) — but it **lives and builds in its own repository, outside spt-core**. It is a Claude-Code-specific *adapter*: it holds the Claude Code conventions (hooks, slash-commands, skill/plugin layout, `claude` session-invocation). **spt-core itself contains zero Claude Code conventions** — only the harness-agnostic contract the plugin binds to. The only adapter-shaped artifact ever in this repo is a generic mock/test adapter exercising the manifest + `api` contract (PR…\n\r\n**Pi** (disambiguation — two meanings, never conflate):\r\n(1) **Pi, the coding agent/harness** (`badlogic/pi-mono`) — a harness example alongside Claude Code and Codex; this is the meaning in user-facing harness lists. (2) **Pi-class node** — Raspberry-Pi-class low-power hardware hosting a Shell-only or headless SPT node; an incidental hardware descriptor, never an explicit product example. Public-facing docs must disambiguate or avoid the bare word.\r\n_Avoid_: bare \"Pi node\" when the harness is meant.\r\n\r\n**spt-daemon** (per-machine supervisor):\r\nThe single always-on, one-per-machine logical supervisor. Owns the PTYs for all hosted sessions, the node's network identity + WAN endpoint, the subnet registry, all spools, **all poll-listener logic, and all Psyche/pulse loops** — everything is consolidated here (no separate poll-listener or Psyche-wrapper processes; listeners already touch sessions directly under capsule/idle, and Psyche wrappers already invoke harness binaries directly, so they belong in the one supervisor). Collapses what the sister project planned as a separate `spt-node` daemon into one process — see Networking. The `spt-node` separate-deliverable concept is retired.\r\n\r\n<!-- [doc->REQ-CLI-NODE-VERB-PRIMARY] -->\r\n**`spt node` (the CLI verb) is NOT the retired `spt-node` (the process)** — the two are different kinds of thing and must never be conflated. What is retired above is a separate *process* deliverable: a second daemon alongside `spt-daemon`, which this project collapsed into one supervisor. What `spt node` names is the *CLI verb* an operator types to run, stop, or read the state of that one supervisor on their machine (releases#112) — a vocabulary choice on the command surface, with no second process behind it. `spt daemon` remains a full alias of that verb, subcommand for subcommand, and is documented as deprecated rather than removed: installed OS service units and scheduled-task rungs already carry `spt daemon run`, and renaming a verb does not rewrite art…\n\r\nInternally the logical daemon is split into two implementation layers for seamless self-update (see Self-update):\r\n- **broker** (stable \"kernel\") — holds *only* the un-transferable, must-not-die resources: PTY master fds, the spawned harness child processes, and listening network sockets. Minimal, dumb, versioned local IPC. Almost never updates.\r\n- **daemon brain** (\"userspace\") — all logic (routing, registry, pulse/psyche loops, manifest parsing, update orchestration). Restarts freely on update; rehydrates from disk state and re-attaches to the broker's held handles.\r\n\r\nLogical addressing is unchanged — still one per-machine `spt-daemon`; the broker is an internal layer, not separately addressable. There is exactly **one broker per machine** (per `SPT_HOME`) — *not* one per endpoint: a single broker holds every hosted endpoint's resources, and it is present whenever the daemon runs, even with zero endpoints online (the bare-daemon case). It is therefore the always-present per-machine layer, which is why the single-daemon lock + liveness anchor belong to it.\r\n\r\n**in-session relay**:\r\nA thin, stateless `spt.exe` task that exists only in **harness-hosted** sessions (where the agent harness is the parent process and spt cannot reach into its process tree — today's Monitor model). It streams the daemon brain's events into the session's stdout. All *stateful* listener logic lives in the daemon; the relay is a dumb pipe, freely killable and respawnable. **spt-hosted** sessions need no separate harness-owned relay — the daemon owns the PTY and consumes the same poll feed itself. Idle delivery into an spt-hosted PTY goes through an opt-in adapter **translation binary** (`[message-idle-translation-binary]`, ADR-0022): a pure stdin→stdout filter spt-core lifecycle-manages — it reads the `<EVENT>` feed on stdin, emits keystroke-commands (`{key}`/`{…\n\r\n### Deliverable shape\r\n\r\nspt-core ships **both** a library workspace and a canonical binary:\r\n\r\n- **Library crates** — the deeper integration path. Used by future first-party services that link Rust directly.\r\n- **`spt.exe` / `spt`** — the canonical binary, built from the workspace. The primary integration path for harness plugins and external tooling, which mostly fire it as a subprocess at various surfaces (one-shot commands, poll listeners under a Monitor-tool-equivalent, hook tap-ins).\r\n\r\nBoth surfaces are first-class. Wire-protocol parity between them is a versioning concern from day one (a non-Rust client speaking to `spt.exe` and a Rust client linking the crates must see the same observable behavior).\r\n\r\n## Runtime model\r\n\r\nspt-core is harness-independent: it does not know about Claude Code, Codex, Cursor, or any other agent runtime. All harness-specific surfaces (how to invoke an agent session, fetch conversation history for an echo commune, detect activity/idleness, etc.) are abstracted behind a runtime layer that consumers supply.\r\n\r\n**AgentRuntime** (Rust trait, implementation detail):\r\nThe internal Rust abstraction over a harness. Anything spt-core needs to do *to* or *with* an agent goes through this trait. Most consumers never see it directly — they configure spt-core via a manifest, and spt-core's default `ManifestRuntime` implementation executes against the manifest.\r\n\r\n**harness contract** (umbrella term):\r\nThe full surface a harness binds to in order to participate in the spt-core ecosystem. Has two equally-important halves: the **runtime manifest** (outbound — how spt-core drives the harness) and the **subcommand surface** (inbound — how the harness reports events back to spt-core). A harness implementation is one TOML/YAML manifest + a binding from the harness's own hook system into `spt.exe <subcommand>` calls.\r\n\r\n**runtime manifest** (outbound half of the harness contract):\r\nA declarative configuration file (TOML/YAML — schema TBD) that tells spt-core how to drive a specific harness. Declares: how to invoke an agent session, how to look up conversation history for an echo commune, how to spawn/resume a Psyche-equivalent, which binary or command implements each harness-side operation, and which endpoint types this harness supports. spt-core is the actor for each of these; the manifest tells it what to do.\r\n\r\nExample shape (illustrative): `spt.exe --manifest spt-plugin.toml live start <id>`. A harness like the planned spt plugin wraps this invocation into the `$LIVE` / `$OWL` environment variables it injects into its sessions, so harness-internal callers continue to invoke `$LIVE` / `$OWL` unchanged.\r\n\r\n**subcommand surface** (inbound half of the harness contract):\r\nThe stable set of `spt.exe <subcommand>` entry points that harnesses bind their own hook systems to. When the harness's runtime emits an event (subagent started, tool just invoked, user typed `/clear`, session crashed), the harness's hook fires a short-lived `spt.exe <subcommand>` invocation that mutates on-disk SPT state (perch registry, spool, etc.). spt-core publishes this surface; harnesses author the bindings.\r\n\r\n**Naming convention:** these inbound, machinery-facing commands are prefixed **`api `/`api-`** (e.g. `spt api bind`, `spt api state`) to distinguish them from the agent-facing verbs an agent invokes directly (`send`, `ring`, `ready`, …). The `api` namespace is the harness/adapter commands-API; the unprefixed namespace is the agent surface.\r\n\r\nTogether: manifest + subcommand surface = the complete harness API. A sidecar-style long-running adapter process speaking a wire protocol is explicitly **deferred** as a possible v2 alternative for harnesses that outgrow the manifest+hooks shape (e.g. need streaming or in-memory state across events). Not built day-one.\r\n\r\n**adapter manifest header** (`adapter_name` + version compat):\r\nEvery manifest declares a unified **`adapter_name`** (e.g. `claude-spt`), carried on every `api` invocation too. It is load-bearing: one daemon hosts endpoints from multiple adapters, so it resolves an endpoint's manifest + seams by `adapter_name`; adapter-update ripples target by it; capability/manifest lookup and telemetry key on it. The header also declares the adapter's own version and a **`min_spt_core_version`** — the minimum spt-core the adapter requires. This declaration must be **readable before an adapter update is applied** (it lives in the manifest header / a small metadata file fetched first), so spt-core can verify compatibility / expected supported features *before* committing the update. If spt-core is below the adapter's `min_spt_core_versio…\n\r\n<!-- [doc->REQ-MANIFEST-2] -->\r\n**adapter profile** (ratified 2026-06-11, Gateway grill; future spt-core milestone — first beneficiaries `spt-claude-code` and the usbip shell):\r\nA named **sparse overlay** on its parent adapter manifest. Merge semantics are **leaf-replace**: a profile key replaces the whole value at that path (arrays included — never spliced or appended). The merged result is a complete manifest, and the profile behaves as a distinct adapter option everywhere: canonical addressing is the composite **`<adapter>:<profile>`** (`claude-spt:work`, `spt-usbip-driver:hid-only`) in every place a bare `adapter_name` rides today (perch `info.json`, capability resolution, `api` invocations, `spt adapter list`); the bare name = the parent unmodified. **Two sources, one semantics:** a **shipped profile** is declared inside the parent manifest by the adapter dev and updates as one unit with it; a **local profile** is a node-local …\n_Avoid_: \"manifest fork\", \"child adapter\", per-profile versioning.\r\n\r\n**adapter strings** (ratified 2026-06-11, Gateway grill):\r\n<!-- [doc->REQ-MANIFEST-3] -->\r\nA `[strings]` manifest section — an adapter-authored JSON/TOML KV tree, dot-path-readable by anything on the node via `spt adapter get-string <adapter-option> <key.path>` (e.g. a harness hook fetching per-profile `additionalContext` — one hook script serves every profile, only the data differs). Resolution rides the **same leaf-replace profile overlay** as the rest of the manifest: a shipped or local profile may override base strings; `get-string` returns the merged view for the named adapter option. **Strings are data only** — nothing in spt-core ever executes a string (command templates live in manifest sections behind registration, never in the KV). Node-local like the registration itself; no cross-node sync. `set-string` is sugar that edits a **local** p…\n<!-- [doc->REQ-MANIFEST-5] -->\r\n**File-backed strings** (M12-W3): a `[strings]` value MAY be a **file pointer** instead of an inline literal — a value-position table with **exactly one** key `file`: `skill = { file = \"skill.md\" }`. `get-string` resolves it to the file's **contents** (so large bodies — skill-instructions, hint text — stay out of the manifest). The exactly-one-key rule is the disambiguation: any other table shape stays an opaque nested strings tree (existing trees untouched), and `{ file = … }` is reserved as the pointer form (it can't double as inline data). Files live in the adapter's per-adapter aux dir **`adapters/<adapter>/strings/`** (sibling of `profiles/`), referenced by a path relative to it that **must stay inside that dir** (HAZARD-class containment: `..` traversa…\n_Avoid_: treating strings as config knobs for spt-core itself (those are global settings); \"adapter KV store\" as a separate registry; putting user files in the adapter-shipped `strings/` dir (clobbered by updates — use a local profile).\r\n\r\n**manifest substitution in `[strings]`** (ratified 2026-06-25, v0.16.0 update-arc grill):\r\n`get-string` resolves a set of **adapter-static** substitution keys inside a returned string value at **read time** (lazily, like file-backed strings): **`{adapter_dir}`** — the registry record's precise `source_dir` (the install dir; survives updates; the same dir bare-program resolution already uses) — and **`{adapter_name}`**. Session-scoped keys (`{id}`/`{session_id}`/…) are **not** available: `get-string` carries no session context today, and a `get-string --session-id` for session-scoped substitution is a deferred, larger change. The load-bearing invariant is preserved: **spt-core still never executes a string** — it substitutes and returns; the *adapter's own wrapper* executes the result. Canonical use: a harness hook dispatcher resolves its own packe…\n_Avoid_: session-scoped substitution through bare `get-string`; reading this as spt-core executing a string (it never does — the adapter wrapper executes the resolved value).\r\n\r\n**keyword hints** (ratified 2026-06-12 — core milestone A):\r\n<!-- [doc->REQ-MANIFEST-4] -->\r\nOnce-per-session usage/syntax hints, a first-class adapter feature: the manifest's `[hints]` section declares entries of `{keywords (literal default, regex opt-in), text}`; the adapter's user-prompt hook pipes the **full user message** to `spt api hint --session <id>` (stdin) and receives matched hint lines (`keyword hint for SPT adapter <name>: \"<kw>\"-->{text}`) for its context-injection channel. The daemon keeps a per-session seen-set — each hint fires **once per session** (a `/clear` mints a new session, naturally re-arming) — and emits at most **one hint per message PER SOURCE**. **The per-source cap AMENDS BY REPLACEMENT the original global one-per-message clause (releases#133, gater-ruled 2026-08-30), and the authority chain is this:** the global claus…\n_Avoid_: unconditional static context (that's the adapter's own preamble); firing per-message.\r\n\r\n**shell keyword hints** (releases#133, operator-GREENLIT; shape ruled 2026-08-30):\r\n<!-- [doc->REQ-SHELL-HINTS] -->\r\n`[[hints]]` was never harness-only — it is a top-level manifest section with no kind gate, so a `kind = \"shell\"` adapter has always been able to declare hints; what was missing was a reader, because the only reader resolved the endpoint-bound manifest. The now-signal **HINTS** category now also reads the shell adapters an endpoint can see, one line each under the per-source cap above. **Two arms, decided by INSTANTIATION and never by link state:** an adapter this owner holds an instance of surfaces the **full** hint text — whether that instance is online or offline — and an adapter with no instance surfaces only a **teaser** naming the trigger keyword and the command that shows the text (`spt adapter hints <adapter[:profile]>`, which resolves the merged view…\n_Avoid_: gating the shell arm on the harness manifest (an endpoint with no bound manifest still owns shells); filtering the full arm on online/offline; naming a surfacing command that does not exist at the shipping head.\r\n\r","truncated":true,"truncatedBy":"lines","totalLines":1267,"totalBytes":22739,"outputLines":103,"outputBytes":22739,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":1267,"displayContent":{"text":"# spt-core\r\n\r\n**Platform scope:** Windows + Linux for v1. macOS is out (no test machine available) but kept structurally easy — `portable-pty` and Iroh both support it, so macOS is a later test/CI-budget decision, not a re-architecture.\r\n\r\n**Legacy migration:** it should be possible — ideally *automatic* — for a user to migrate an existing `claude_skill_owl` (modern SPT) install to spt-core (identity, agents, tracked Psyche context). Exact mechanism deferred to design; the commitment is that migration is a first-class supported path, not a manual rebuild.\r\n\r\nHarness-independent core for the SPT ecosystem. Provides inter-agent messaging, live-agent lifecycle, terminal wrapping, self-update, and networking primitives — as both a Rust library workspace and a canonical reference binary. Designed so any agent runtime (Claude Code, Codex, Cursor, headless, future harnesses) can interface with the SPT ecosystem either by shelling out to the binary or by linking the crates directly.\r\n\r\nSuccessor to `claude_skill_owl` (today's \"modern SPT\"), which is being rebuilt as `spt-core` to untether the system from Claude Code and lift it to a general-purpose agent-ecosystem core.\r\n\r\n## Language\r\n\r\n**spt-core**:\r\nThe system. Canonical name. The Rust workspace and the umbrella project.\r\n\r\n**spt.exe / spt** (canonical binary):\r\nThe reference binary built from the workspace. Replaces today's `owl.exe`. Most external integrations (plugins, hooks, scripts in other harnesses) interact with spt-core *only* through this binary — fire-and-forget subcommands, long-running listeners under a parent harness's process supervisor, etc. Unix builds use the same name without `.exe`.\r\n\r\n**library workspace**:\r\nThe set of Rust crates that compose spt-core. Consumers that want a deeper integration than shelling out to `spt.exe` link these crates directly. The reference binary is itself a consumer of the workspace. The expected non-binary consumers are future first-party services that link Rust directly.\r\n\r\n**spt plugin** (separate downstream project — NOT an spt-core deliverable):\r\nA rebuilt version of today's Claude Code `spt` plugin. It is the **first consumer** built *atop* spt-core and the **acceptance proof** of spt-core v1 (it reaches feature parity with modern SPT while delegating all core functionality to spt-core, primarily via `spt.exe`, with deeper hooks where useful) — but it **lives and builds in its own repository, outside spt-core**. It is a Claude-Code-specific *adapter*: it holds the Claude Code conventions (hooks, slash-commands, skill/plugin layout, `claude` session-invocation). **spt-core itself contains zero Claude Code conventions** — only the harness-agnostic contract the plugin binds to. The only adapter-shaped artifact ever in this repo is a generic mock/test adapter exercising the manifest + `api` contract (PR…\n\r\n**Pi** (disambiguation — two meanings, never conflate):\r\n(1) **Pi, the coding agent/harness** (`badlogic/pi-mono`) — a harness example alongside Claude Code and Codex; this is the meaning in user-facing harness lists. (2) **Pi-class node** — Raspberry-Pi-class low-power hardware hosting a Shell-only or headless SPT node; an incidental hardware descriptor, never an explicit product example. Public-facing docs must disambiguate or avoid the bare word.\r\n_Avoid_: bare \"Pi node\" when the harness is meant.\r\n\r\n**spt-daemon** (per-machine supervisor):\r\nThe single always-on, one-per-machine logical supervisor. Owns the PTYs for all hosted sessions, the node's network identity + WAN endpoint, the subnet registry, all spools, **all poll-listener logic, and all Psyche/pulse loops** — everything is consolidated here (no separate poll-listener or Psyche-wrapper processes; listeners already touch sessions directly under capsule/idle, and Psyche wrappers already invoke harness binaries directly, so they belong in the one supervisor). Collapses what the sister project planned as a separate `spt-node` daemon into one process — see Networking. The `spt-node` separate-deliverable concept is retired.\r\n\r\n<!-- [doc->REQ-CLI-NODE-VERB-PRIMARY] -->\r\n**`spt node` (the CLI verb) is NOT the retired `spt-node` (the process)** — the two are different kinds of thing and must never be conflated. What is retired above is a separate *process* deliverable: a second daemon alongside `spt-daemon`, which this project collapsed into one supervisor. What `spt node` names is the *CLI verb* an operator types to run, stop, or read the state of that one supervisor on their machine (releases#112) — a vocabulary choice on the command surface, with no second process behind it. `spt daemon` remains a full alias of that verb, subcommand for subcommand, and is documented as deprecated rather than removed: installed OS service units and scheduled-task rungs already carry `spt daemon run`, and renaming a verb does not rewrite art…\n\r\nInternally the logical daemon is split into two implementation layers for seamless self-update (see Self-update):\r\n- **broker** (stable \"kernel\") — holds *only* the un-transferable, must-not-die resources: PTY master fds, the spawned harness child processes, and listening network sockets. Minimal, dumb, versioned local IPC. Almost never updates.\r\n- **daemon brain** (\"userspace\") — all logic (routing, registry, pulse/psyche loops, manifest parsing, update orchestration). Restarts freely on update; rehydrates from disk state and re-attaches to the broker's held handles.\r\n\r\nLogical addressing is unchanged — still one per-machine `spt-daemon`; the broker is an internal layer, not separately addressable. There is exactly **one broker per machine** (per `SPT_HOME`) — *not* one per endpoint: a single broker holds every hosted endpoint's resources, and it is present whenever the daemon runs, even with zero endpoints online (the bare-daemon case). It is therefore the always-present per-machine layer, which is why the single-daemon lock + liveness anchor belong to it.\r\n\r\n**in-session relay**:\r\nA thin, stateless `spt.exe` task that exists only in **harness-hosted** sessions (where the agent harness is the parent process and spt cannot reach into its process tree — today's Monitor model). It streams the daemon brain's events into the session's stdout. All *stateful* listener logic lives in the daemon; the relay is a dumb pipe, freely killable and respawnable. **spt-hosted** sessions need no separate harness-owned relay — the daemon owns the PTY and consumes the same poll feed itself. Idle delivery into an spt-hosted PTY goes through an opt-in adapter **translation binary** (`[message-idle-translation-binary]`, ADR-0022): a pure stdin→stdout filter spt-core lifecycle-manages — it reads the `<EVENT>` feed on stdin, emits keystroke-commands (`{key}`/`{…\n\r\n### Deliverable shape\r\n\r\nspt-core ships **both** a library workspace and a canonical binary:\r\n\r\n- **Library crates** — the deeper integration path. Used by future first-party services that link Rust directly.\r\n- **`spt.exe` / `spt`** — the canonical binary, built from the workspace. The primary integration path for harness plugins and external tooling, which mostly fire it as a subprocess at various surfaces (one-shot commands, poll listeners under a Monitor-tool-equivalent, hook tap-ins).\r\n\r\nBoth surfaces are first-class. Wire-protocol parity between them is a versioning concern from day one (a non-Rust client speaking to `spt.exe` and a Rust client linking the crates must see the same observable behavior).\r\n\r\n## Runtime model\r\n\r\nspt-core is harness-independent: it does not know about Claude Code, Codex, Cursor, or any other agent runtime. All harness-specific surfaces (how to invoke an agent session, fetch conversation history for an echo commune, detect activity/idleness, etc.) are abstracted behind a runtime layer that consumers supply.\r\n\r\n**AgentRuntime** (Rust trait, implementation detail):\r\nThe internal Rust abstraction over a harness. Anything spt-core needs to do *to* or *with* an agent goes through this trait. Most consumers never see it directly — they configure spt-core via a manifest, and spt-core's default `ManifestRuntime` implementation executes against the manifest.\r\n\r\n**harness contract** (umbrella term):\r\nThe full surface a harness binds to in order to participate in the spt-core ecosystem. Has two equally-important halves: the **runtime manifest** (outbound — how spt-core drives the harness) and the **subcommand surface** (inbound — how the harness reports events back to spt-core). A harness implementation is one TOML/YAML manifest + a binding from the harness's own hook system into `spt.exe <subcommand>` calls.\r\n\r\n**runtime manifest** (outbound half of the harness contract):\r\nA declarative configuration file (TOML/YAML — schema TBD) that tells spt-core how to drive a specific harness. Declares: how to invoke an agent session, how to look up conversation history for an echo commune, how to spawn/resume a Psyche-equivalent, which binary or command implements each harness-side operation, and which endpoint types this harness supports. spt-core is the actor for each of these; the manifest tells it what to do.\r\n\r\nExample shape (illustrative): `spt.exe --manifest spt-plugin.toml live start <id>`. A harness like the planned spt plugin wraps this invocation into the `$LIVE` / `$OWL` environment variables it injects into its sessions, so harness-internal callers continue to invoke `$LIVE` / `$OWL` unchanged.\r\n\r\n**subcommand surface** (inbound half of the harness contract):\r\nThe stable set of `spt.exe <subcommand>` entry points that harnesses bind their own hook systems to. When the harness's runtime emits an event (subagent started, tool just invoked, user typed `/clear`, session crashed), the harness's hook fires a short-lived `spt.exe <subcommand>` invocation that mutates on-disk SPT state (perch registry, spool, etc.). spt-core publishes this surface; harnesses author the bindings.\r\n\r\n**Naming convention:** these inbound, machinery-facing commands are prefixed **`api `/`api-`** (e.g. `spt api bind`, `spt api state`) to distinguish them from the agent-facing verbs an agent invokes directly (`send`, `ring`, `ready`, …). The `api` namespace is the harness/adapter commands-API; the unprefixed namespace is the agent surface.\r\n\r\nTogether: manifest + subcommand surface = the complete harness API. A sidecar-style long-running adapter process speaking a wire protocol is explicitly **deferred** as a possible v2 alternative for harnesses that outgrow the manifest+hooks shape (e.g. need streaming or in-memory state across events). Not built day-one.\r\n\r\n**adapter manifest header** (`adapter_name` + version compat):\r\nEvery manifest declares a unified **`adapter_name`** (e.g. `claude-spt`), carried on every `api` invocation too. It is load-bearing: one daemon hosts endpoints from multiple adapters, so it resolves an endpoint's manifest + seams by `adapter_name`; adapter-update ripples target by it; capability/manifest lookup and telemetry key on it. The header also declares the adapter's own version and a **`min_spt_core_version`** — the minimum spt-core the adapter requires. This declaration must be **readable before an adapter update is applied** (it lives in the manifest header / a small metadata file fetched first), so spt-core can verify compatibility / expected supported features *before* committing the update. If spt-core is below the adapter's `min_spt_core_versio…\n\r\n<!-- [doc->REQ-MANIFEST-2] -->\r\n**adapter profile** (ratified 2026-06-11, Gateway grill; future spt-core milestone — first beneficiaries `spt-claude-code` and the usbip shell):\r\nA named **sparse overlay** on its parent adapter manifest. Merge semantics are **leaf-replace**: a profile key replaces the whole value at that path (arrays included — never spliced or appended). The merged result is a complete manifest, and the profile behaves as a distinct adapter option everywhere: canonical addressing is the composite **`<adapter>:<profile>`** (`claude-spt:work`, `spt-usbip-driver:hid-only`) in every place a bare `adapter_name` rides today (perch `info.json`, capability resolution, `api` invocations, `spt adapter list`); the bare name = the parent unmodified. **Two sources, one semantics:** a **shipped profile** is declared inside the parent manifest by the adapter dev and updates as one unit with it; a **local profile** is a node-local …\n_Avoid_: \"manifest fork\", \"child adapter\", per-profile versioning.\r\n\r\n**adapter strings** (ratified 2026-06-11, Gateway grill):\r\n<!-- [doc->REQ-MANIFEST-3] -->\r\nA `[strings]` manifest section — an adapter-authored JSON/TOML KV tree, dot-path-readable by anything on the node via `spt adapter get-string <adapter-option> <key.path>` (e.g. a harness hook fetching per-profile `additionalContext` — one hook script serves every profile, only the data differs). Resolution rides the **same leaf-replace profile overlay** as the rest of the manifest: a shipped or local profile may override base strings; `get-string` returns the merged view for the named adapter option. **Strings are data only** — nothing in spt-core ever executes a string (command templates live in manifest sections behind registration, never in the KV). Node-local like the registration itself; no cross-node sync. `set-string` is sugar that edits a **local** p…\n<!-- [doc->REQ-MANIFEST-5] -->\r\n**File-backed strings** (M12-W3): a `[strings]` value MAY be a **file pointer** instead of an inline literal — a value-position table with **exactly one** key `file`: `skill = { file = \"skill.md\" }`. `get-string` resolves it to the file's **contents** (so large bodies — skill-instructions, hint text — stay out of the manifest). The exactly-one-key rule is the disambiguation: any other table shape stays an opaque nested strings tree (existing trees untouched), and `{ file = … }` is reserved as the pointer form (it can't double as inline data). Files live in the adapter's per-adapter aux dir **`adapters/<adapter>/strings/`** (sibling of `profiles/`), referenced by a path relative to it that **must stay inside that dir** (HAZARD-class containment: `..` traversa…\n_Avoid_: treating strings as config knobs for spt-core itself (those are global settings); \"adapter KV store\" as a separate registry; putting user files in the adapter-shipped `strings/` dir (clobbered by updates — use a local profile).\r\n\r\n**manifest substitution in `[strings]`** (ratified 2026-06-25, v0.16.0 update-arc grill):\r\n`get-string` resolves a set of **adapter-static** substitution keys inside a returned string value at **read time** (lazily, like file-backed strings): **`{adapter_dir}`** — the registry record's precise `source_dir` (the install dir; survives updates; the same dir bare-program resolution already uses) — and **`{adapter_name}`**. Session-scoped keys (`{id}`/`{session_id}`/…) are **not** available: `get-string` carries no session context today, and a `get-string --session-id` for session-scoped substitution is a deferred, larger change. The load-bearing invariant is preserved: **spt-core still never executes a string** — it substitutes and returns; the *adapter's own wrapper* executes the result. Canonical use: a harness hook dispatcher resolves its own packe…\n_Avoid_: session-scoped substitution through bare `get-string`; reading this as spt-core executing a string (it never does — the adapter wrapper executes the resolved value).\r\n\r\n**keyword hints** (ratified 2026-06-12 — core milestone A):\r\n<!-- [doc->REQ-MANIFEST-4] -->\r\nOnce-per-session usage/syntax hints, a first-class adapter feature: the manifest's `[hints]` section declares entries of `{keywords (literal default, regex opt-in), text}`; the adapter's user-prompt hook pipes the **full user message** to `spt api hint --session <id>` (stdin) and receives matched hint lines (`keyword hint for SPT adapter <name>: \"<kw>\"-->{text}`) for its context-injection channel. The daemon keeps a per-session seen-set — each hint fires **once per session** (a `/clear` mints a new session, naturally re-arming) — and emits at most **one hint per message PER SOURCE**. **The per-source cap AMENDS BY REPLACEMENT the original global one-per-message clause (releases#133, gater-ruled 2026-08-30), and the authority chain is this:** the global claus…\n_Avoid_: unconditional static context (that's the adapter's own preamble); firing per-message.\r\n\r\n**shell keyword hints** (releases#133, operator-GREENLIT; shape ruled 2026-08-30):\r\n<!-- [doc->REQ-SHELL-HINTS] -->\r\n`[[hints]]` was never harness-only — it is a top-level manifest section with no kind gate, so a `kind = \"shell\"` adapter has always been able to declare hints; what was missing was a reader, because the only reader resolved the endpoint-bound manifest. The now-signal **HINTS** category now also reads the shell adapters an endpoint can see, one line each under the per-source cap above. **Two arms, decided by INSTANTIATION and never by link state:** an adapter this owner holds an instance of surfaces the **full** hint text — whether that instance is online or offline — and an adapter with no instance surfaces only a **teaser** naming the trigger keyword and the command that shows the text (`spt adapter hints <adapter[:profile]>`, which resolves the merged view…\n_Avoid_: gating the shell arm on the harness manifest (an endpoint with no bound manifest still owns shells); filtering the full arm on online/offline; naming a surfacing command that does not exist at the shipping head.\r\n\r\n…\n\n…\nThe CLI sibling of the frontend's guided resume — one command that lists endpoints **grouped by locality, most-recently-used within each group**: `on-node / current-project → on-node / other-project → off-node`, mirroring the *resolution policy*'s local-first preference. Selection **chains conditionally**: a **running** instance → attach/tap-in (no adapter step — already live under one); a **non-running** endpoint → into the **adapter selector** (*adapter selection*: history head = default → prior adapters → \"choose a different adapter\") → *anchor subnet* / other creation prompts as needed → launch; a **\"+ new endpoint\"** entry → the full creation flow. Off-node picks respect the reach + consent gates (remote-drive of your own running instance is ungated; a …","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,null,528,null,1267]},"fileSize":351501,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\CONTEXT.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":1267,"totalBytes":22739,"outputLines":103,"outputBytes":22739,"shownRange":{"start":1,"end":103},"nextOffset":104},"limits":{"columnTruncated":{"maxColumn":768}}}},"isError":false,"timestamp":1789107062051}}
{"type":"message","id":"f0112690","parentId":"dd4c65af","timestamp":"2026-09-11T06:11:02.239Z","message":{"role":"toolResult","toolCallId":"call_q80EtOd43vcv1eFRkV85eAEP|fc_0330c101aa2c61dc016aa39b739ba487d1b53655ebed36d720","toolName":"grep","content":[{"type":"text","text":"# docs/\n## INFRA-REGISTER.md\n 33|  rung faces remain; IR-33's 16 MiB CLI stack exists, acceptance/margin reconciliation remains.\n*34|  IR-57 `pick-audit`, IR-59 `disk-floor`, and IR-46 workflow floor tokens exist; residual adoption\n 35|  and receipt reconciliation are the work. IR-69's original product lane landed; #243 residuals\n*36|  remain. IR-83's universal LAN-only prescription is superseded by IR-89's layer-specific box\n*37|  proof. IR-89's next-golden trigger has fired; exact step acceptance still needs reconciliation,\n 38|  not a second guard implementation or renewed operator permission.\n 39|- **IR-92 stays OPEN:** core#215 shipped the documentation/register rider, NOT the product\n 40|  remedy; core#217 is the separate brainread audit. `try_spt_hosted_inject` still lacks the\n...\n 50|  IR-85/95/96 are scoped diagnostic continuation, NOT budget widening or a load/disk diagnosis.\n*51|  Todlando owns product-side IR-81/82/92 composition; #285's completion did not build IR-82's\n 52|  predecessor record. Both builders are offline: existing briefs are delivered, unacknowledged,\n 53|  and **not executing**. No board mutation or new run authorization is implied.\n 54|- **Small seam riders remain explicit:** next tooling intake weighs IR-5/6/10/11/32/37/47/58/94\n 55|  (IR-37 upstream release is not downstream adoption: golden still requests 0.2.0).\n*56|  IR-93 remains a separate symbol-packaging decision before a release-workflow rider, not a\n 57|  property proven by a successful release build. All other open entries retain their recorded\n 58|  trigger, residual, and owner where named; the complete audit records each, not a sampled set.\n 59|- **Cleanup is mitigation, not closure:** 38 clean merged worktrees and classified obsolete\n...\n 73|respin edit under a pre-registered hard stop is not a remedy window, so the entry gains that datum\n*74|and is COMPOSED forward. **Composed: the floor trio IR-46 + IR-59 (log-the-floor half) + IR-73\n 75|(8 literal-first sites) as ONE hertz workflow rider on WEBSERVE** (`ci.yml`/`golden.yml`/\n 76|`release.yml`, thin PR off the golden path, before the WEBSERVE golden head so that head runs\n*77|under it); **IR-59's log-the-floor line ALSO rides IR-76's three-arm pre-flight on W0's driver\n 78|template** (todlando authors; free space recorded beside the floor check). **IR-66 residual (two\n 79|first-chunk-needle members) = hertz WEBSERVE test rider** (two one-line edits). **IR-12 residual =\n 80|W3 drift-gate rider** (hertz already holds W3's drift-gate riders). IR-67 satisfied at this intake\n...\n 95|IR-34/35 cluster strengthened). Same-day second sweep, so most composition state is the\n*96|morning's; deltas only: IR-59 gained the SEVENTH face (parallel-lane fill rate: 236.6 GB /\n 97|3.5 h across four wave pools drove the box to 0.01 GB mid-close; per-wave pool reaping rule).\n 98|IR-12 gained the stale-binary kin note (xtask reference-drift arm reads the ON-DISK spt binary;\n 99|structural remedy = the now-mandatory workspace-bins prebuild leg, adopted this arc after it\n*100|also caught W2's spacerun red). IR-63's conhost litter REPRODUCED on cue: 14 fresh CWD pins on\n 101|the four party trees at the same `crates/spt-daemon` relative path, killed by pid via the PEB\n 102|probe, all four worktrees then removed FIRST TRY — the pin-check-first party rule held\n 103|(+58.2 GB; earlier emergency reap of the same wave's finished-lane targets +186.6 GB).\n...\n 122|IR-7/17/20/34/35/63 LANE-LINKED to hertz's queued fixup lane (briefs in his spool cite the entry\n*123|ids). IR-57 first-real-assembly use appended (ASM-241: 6 picks, 5 MATCH / 1 LOSS reconciled\n 124|byte-for-byte to the deliberate resolution; its earlier \"figure correction rides next batch\"\n 125|note was STALE — the correction landed inline 2026-08-29, retired here). IR-46 gained the #242\n 126|golden additions (per-job floor instants; the `/runs/<id>/jobs` run_attempt trap with\n 127|`started_at` discriminator + `/attempts/N/jobs` authority; raw-bytes rerun preflight;\n*128|non-vacuous rerun check). IR-59 gained the SIXTH face (r4 LNK1318 at the job's internal\n 129|low-water; within-job floor re-read rides the next workflow commit; box ~51 GB non-recovering\n 130|consumption → audit slot). FILED: IR-73 (ci.yml/release.yml literal-first floor sites off the\n 131|golden path, 8 sites), IR-74 (kitsubito 21,643 /tmp endpoint homes, hertz's measurement), IR-75\n...\n 133|surface). Composed: IR-14/26/27/49 as ONE between-milestone pool/worktree audit slot (window\n*134|open now); IR-11 + IR-33(a) as next-intake small riders; IR-59's log-the-floor half + IR-57's\n 135|scripted audit stand as the next intake's tooling pair. IR-54 evidence noted: the #242 cut's\n 136|unshaped-head intake miss (self-caught by deployah, shape-on-top `e4f52047`, 8th consecutive\n 137|shape-inside-candidate) is another construction-not-discipline datum. No entries retired.\n...\n 642|  and TWO content-bearing checkout remnants (gate-signet-w1 10.8MB, gate-w1-a8f04aff 27MB) =\n*643|  registry-pruned dirs held by the conhost CWD pins IR-63's third face names. **Sweep\n 644|  executed on the gater's own rigs:** evidence preserved FIRST\n 645|  (`spt-preserve\\audit-2026-08-30\\`: gate-w1-a8f04aff's 229 non-HEAD files as a verified\n 646|  tarball; er-instrument's 115-line UNCOMMITTED instrument diff as a patch — that worktree\n...\n 665|  realised). Lane close-out = `git worktree remove` + prune + the conhost CWD-pin check\n*666|  ([[IR-63]] third face) when removal refuses; a registry-pruned dir left behind is a defect\n 667|  to sweep, not a norm.\n 668|- **Ripe when:** between-milestone idle window (it is a dev-box chore, zero product risk) — but the\n 669|  class-A pool findings are armed hazards and do not wait for it.\n...\n 2708|\n*2709|- **2026-09-06 addendum (doyle, v0.67.1 close sweep): trigger FIRED at `04e32c8c` — `golden.yml` touched (2-line HEAVY reclass of `brain_resume_conn_deadlock` on the respin) with no remedy weighed. Not a drive-by by choice: the touch rode a respin under a pre-registered hard stop, which is no remedy window. COMPOSED with IR-59 (log-the-floor) + IR-73 (literal-first sites) as one hertz workflow rider on WEBSERVE #272; the remedy weighing happens on THAT lane, before the WEBSERVE golden head.**\n 2710|\n 2711|<!-- [doc->REQ-CI-FREE-SPACE-PREFLIGHT] -->\n 2712|- **2026-09-06 remedy ruling (doyle, WEBSERVE rider):** retain 32 GiB; record raw-byte\n...\n 3188|\n*3189|### IR-57 — an assembly pick's conflict resolution can silently DROP lines, and every gate run at assembly time is blind to it\n 3190|\n 3191|- **Status:** OPEN, owned by **doyle** (gater craft, not a code defect — no lane to dispatch).\n 3192|  Filed 2026-08-22 from doyle's own defect on the TURNKEY #212 assembly head.\n...\n 3232|  repaired file**, which is not necessarily the suite the head gate runs.\n*3233|- **FIRST LIVE CATCH, and it was the author's own resolution (2026-08-29, one hour after the verb landed):** rebasing the IR-59 rider over the IR-57 rider produced four conflicts — three additive keep-both, one usage line both sides had edited. `xtask pick-audit` read the rebase as **LOSS, 282 lane / 280 pick**. The two missing lines were a `[[requirements]]` header and its blank line in `traceable-reqs.toml`, so `id = REQ-DISK-FLOOR-PREFLIGHT` landed INSIDE the previous table as a duplicate key: **`tr...\n 3234|- **FIRST REAL-ASSEMBLY USE (2026-08-29, #241 emission head, ASM-241-GATE-VERDICT.md):** `xtask\n 3235|  pick-audit --range 57a0d27c..HEAD --lane 4d6007ac..d0fdd58d` over 6 picks — **5 MATCH\n 3236|  (digest-identical), 1 LOSS, 0 drift, 0 unclassified**, exit 1 forcing the accounting. The LOSS\n...\n 3282|\n*3283|### IR-59 — pool arithmetic: this box holds TWO cold pools, not four; and a build that exhausts the volume reds as a LINKER defect that names no disk\n 3284|\n 3285|- **Status:** OPEN, unowned — it is arithmetic and discipline, not a code lane. Filed by doyle\n 3286|  2026-08-22 from a live disk-floor abort during the TURNKEY #212 W4 gate; footprint figures measured\n...\n 3321|  (2) **The remedy itself arrived garbled through relay:** the golden push was held \"waiting on the\n*3322|  IR-59 reboot\" when this entry prescribes no reboot anywhere — tens of releases have shipped without\n 3323|  one; the operator refused the premise and the register's own recorded remedy (reap finished-lane\n 3324|  pools) cleared it in ten minutes. A remedy relayed as a DIFFERENT remedy is the relay trap wearing\n 3325|  infra clothes: the entry is the author — read it before adopting a hold. Recovery measured: five\n...\n 3410|- **Composed for next intake (doyle, v0.65.0 close):** the still-open log-the-floor build half\n*3411|  rides with [[IR-57]]'s scripted pick-fidelity audit as the next milestone's two tooling riders.\n 3412|- **Trigger condition:** ripe now for the log-the-floor half (it rides any gate-script or CI touch);\n 3413|  the arithmetic is discipline and applies immediately.\n 3414|- **Size guess:** small — one line in each rig/gate preflight to record free space alongside the\n\n## instruments/\n\n### ir57/\n#### STATUS.md\n 2|\n*3|# IR-57 instrument — `xtask pick-audit`, the scripted pick-fidelity audit\n 4|\n*5|The instrument behind [[IR-57]] in `docs/INFRA-REGISTER.md`. Run it at every assembly, over the\n 6|whole pick chain, before the head is handed anywhere.\n 7|\n 8|```\n\n### ir59/\n#### STATUS.md\n 2|\n*3|# IR-59 instrument — `xtask disk-floor`, the run-start free-space reading\n 4|\n*5|The log-the-floor half of [[IR-59]] in `docs/INFRA-REGISTER.md`. Call it as the FIRST step of any\n 6|rig or gate script, before the first cargo invocation.\n 7|\n 8|```\n\n[Some lines truncated to 512 chars]"}],"details":{"scopePath":"docs","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":24,"fileCount":3,"files":["docs/INFRA-REGISTER.md","docs/instruments/ir57/STATUS.md","docs/instruments/ir59/STATUS.md"],"fileMatches":[{"path":"docs/INFRA-REGISTER.md","count":20},{"path":"docs/instruments/ir57/STATUS.md","count":2},{"path":"docs/instruments/ir59/STATUS.md","count":2}],"truncated":true,"perFileLimitReached":20,"displayContent":"# docs/\n## INFRA-REGISTER.md\n   33│  rung faces remain; IR-33's 16 MiB CLI stack exists, acceptance/margin reconciliation remains.\n  *34│  IR-57 `pick-audit`, IR-59 `disk-floor`, and IR-46 workflow floor tokens exist; residual adoption\n   35│  and receipt reconciliation are the work. IR-69's original product lane landed; #243 residuals\n  *36│  remain. IR-83's universal LAN-only prescription is superseded by IR-89's layer-specific box\n  *37│  proof. IR-89's next-golden trigger has fired; exact step acceptance still needs reconciliation,\n   38│  not a second guard implementation or renewed operator permission.\n   39│- **IR-92 stays OPEN:** core#215 shipped the documentation/register rider, NOT the product\n   40│  remedy; core#217 is the separate brainread audit. `try_spt_hosted_inject` still lacks the\n     │...\n   50│  IR-85/95/96 are scoped diagnostic continuation, NOT budget widening or a load/disk diagnosis.\n  *51│  Todlando owns product-side IR-81/82/92 composition; #285's completion did not build IR-82's\n   52│  predecessor record. Both builders are offline: existing briefs are delivered, unacknowledged,\n   53│  and **not executing**. No board mutation or new run authorization is implied.\n   54│- **Small seam riders remain explicit:** next tooling intake weighs IR-5/6/10/11/32/37/47/58/94\n   55│  (IR-37 upstream release is not downstream adoption: golden still requests 0.2.0).\n  *56│  IR-93 remains a separate symbol-packaging decision before a release-workflow rider, not a\n   57│  property proven by a successful release build. All other open entries retain their recorded\n   58│  trigger, residual, and owner where named; the complete audit records each, not a sampled set.\n   59│- **Cleanup is mitigation, not closure:** 38 clean merged worktrees and classified obsolete\n     │...\n   73│respin edit under a pre-registered hard stop is not a remedy window, so the entry gains that datum\n  *74│and is COMPOSED forward. **Composed: the floor trio IR-46 + IR-59 (log-the-floor half) + IR-73\n   75│(8 literal-first sites) as ONE hertz workflow rider on WEBSERVE** (`ci.yml`/`golden.yml`/\n   76│`release.yml`, thin PR off the golden path, before the WEBSERVE golden head so that head runs\n  *77│under it); **IR-59's log-the-floor line ALSO rides IR-76's three-arm pre-flight on W0's driver\n   78│template** (todlando authors; free space recorded beside the floor check). **IR-66 residual (two\n   79│first-chunk-needle members) = hertz WEBSERVE test rider** (two one-line edits). **IR-12 residual =\n   80│W3 drift-gate rider** (hertz already holds W3's drift-gate riders). IR-67 satisfied at this intake\n     │...\n   95│IR-34/35 cluster strengthened). Same-day second sweep, so most composition state is the\n  *96│morning's; deltas only: IR-59 gained the SEVENTH face (parallel-lane fill rate: 236.6 GB /\n   97│3.5 h across four wave pools drove the box to 0.01 GB mid-close; per-wave pool reaping rule).\n   98│IR-12 gained the stale-binary kin note (xtask reference-drift arm reads the ON-DISK spt binary;\n   99│structural remedy = the now-mandatory workspace-bins prebuild leg, adopted this arc after it\n *100│also caught W2's spacerun red). IR-63's conhost litter REPRODUCED on cue: 14 fresh CWD pins on\n  101│the four party trees at the same `crates/spt-daemon` relative path, killed by pid via the PEB\n  102│probe, all four worktrees then removed FIRST TRY — the pin-check-first party rule held\n  103│(+58.2 GB; earlier emergency reap of the same wave's finished-lane targets +186.6 GB).\n     │...\n  122│IR-7/17/20/34/35/63 LANE-LINKED to hertz's queued fixup lane (briefs in his spool cite the entry\n *123│ids). IR-57 first-real-assembly use appended (ASM-241: 6 picks, 5 MATCH / 1 LOSS reconciled\n  124│byte-for-byte to the deliberate resolution; its earlier \"figure correction rides next batch\"\n  125│note was STALE — the correction landed inline 2026-08-29, retired here). IR-46 gained the #242\n  126│golden additions (per-job floor instants; the `/runs/<id>/jobs` run_attempt trap with\n  127│`started_at` discriminator + `/attempts/N/jobs` authority; raw-bytes rerun preflight;\n *128│non-vacuous rerun check). IR-59 gained the SIXTH face (r4 LNK1318 at the job's internal\n  129│low-water; within-job floor re-read rides the next workflow commit; box ~51 GB non-recovering\n  130│consumption → audit slot). FILED: IR-73 (ci.yml/release.yml literal-first floor sites off the\n  131│golden path, 8 sites), IR-74 (kitsubito 21,643 /tmp endpoint homes, hertz's measurement), IR-75\n     │...\n  133│surface). Composed: IR-14/26/27/49 as ONE between-milestone pool/worktree audit slot (window\n *134│open now); IR-11 + IR-33(a) as next-intake small riders; IR-59's log-the-floor half + IR-57's\n  135│scripted audit stand as the next intake's tooling pair. IR-54 evidence noted: the #242 cut's\n  136│unshaped-head intake miss (self-caught by deployah, shape-on-top `e4f52047`, 8th consecutive\n  137│shape-inside-candidate) is another construction-not-discipline datum. No entries retired.\n     │...\n  642│  and TWO content-bearing checkout remnants (gate-signet-w1 10.8MB, gate-w1-a8f04aff 27MB) =\n *643│  registry-pruned dirs held by the conhost CWD pins IR-63's third face names. **Sweep\n  644│  executed on the gater's own rigs:** evidence preserved FIRST\n  645│  (`spt-preserve\\audit-2026-08-30\\`: gate-w1-a8f04aff's 229 non-HEAD files as a verified\n  646│  tarball; er-instrument's 115-line UNCOMMITTED instrument diff as a patch — that worktree\n     │...\n  665│  realised). Lane close-out = `git worktree remove` + prune + the conhost CWD-pin check\n *666│  ([[IR-63]] third face) when removal refuses; a registry-pruned dir left behind is a defect\n  667│  to sweep, not a norm.\n  668│- **Ripe when:** between-milestone idle window (it is a dev-box chore, zero product risk) — but the\n  669│  class-A pool findings are armed hazards and do not wait for it.\n     │...\n 2708│\n*2709│- **2026-09-06 addendum (doyle, v0.67.1 close sweep): trigger FIRED at `04e32c8c` — `golden.yml` touched (2-line HEAVY reclass of `brain_resume_conn_deadlock` on the respin) with no remedy weighed. Not a drive-by by choice: the touch rode a respin under a pre-registered hard stop, which is no remedy window. COMPOSED with IR-59 (log-the-floor) + IR-73 (literal-first sites) as one hertz workflow rider on WEBSERVE #272; the remedy weighing happens on THAT lane, before the WEBSERVE golden head.**\n 2710│\n 2711│<!-- [doc->REQ-CI-FREE-SPACE-PREFLIGHT] -->\n 2712│- **2026-09-06 remedy ruling (doyle, WEBSERVE rider):** retain 32 GiB; record raw-byte\n     │...\n 3188│\n*3189│### IR-57 — an assembly pick's conflict resolution can silently DROP lines, and every gate run at assembly time is blind to it\n 3190│\n 3191│- **Status:** OPEN, owned by **doyle** (gater craft, not a code defect — no lane to dispatch).\n 3192│  Filed 2026-08-22 from doyle's own defect on the TURNKEY #212 assembly head.\n     │...\n 3232│  repaired file**, which is not necessarily the suite the head gate runs.\n*3233│- **FIRST LIVE CATCH, and it was the author's own resolution (2026-08-29, one hour after the verb landed):** rebasing the IR-59 rider over the IR-57 rider produced four conflicts — three additive keep-both, one usage line both sides had edited. `xtask pick-audit` read the rebase as **LOSS, 282 lane / 280 pick**. The two missing lines were a `[[requirements]]` header and its blank line in `traceable-reqs.toml`, so `id = REQ-DISK-FLOOR-PREFLIGHT` landed INSIDE the previous table as a duplicate key: **`tr...\n 3234│- **FIRST REAL-ASSEMBLY USE (2026-08-29, #241 emission head, ASM-241-GATE-VERDICT.md):** `xtask\n 3235│  pick-audit --range 57a0d27c..HEAD --lane 4d6007ac..d0fdd58d` over 6 picks — **5 MATCH\n 3236│  (digest-identical), 1 LOSS, 0 drift, 0 unclassified**, exit 1 forcing the accounting. The LOSS\n     │...\n 3282│\n*3283│### IR-59 — pool arithmetic: this box holds TWO cold pools, not four; and a build that exhausts the volume reds as a LINKER defect that names no disk\n 3284│\n 3285│- **Status:** OPEN, unowned — it is arithmetic and discipline, not a code lane. Filed by doyle\n 3286│  2026-08-22 from a live disk-floor abort during the TURNKEY #212 W4 gate; footprint figures measured\n     │...\n 3321│  (2) **The remedy itself arrived garbled through relay:** the golden push was held \"waiting on the\n*3322│  IR-59 reboot\" when this entry prescribes no reboot anywhere — tens of releases have shipped without\n 3323│  one; the operator refused the premise and the register's own recorded remedy (reap finished-lane\n 3324│  pools) cleared it in ten minutes. A remedy relayed as a DIFFERENT remedy is the relay trap wearing\n 3325│  infra clothes: the entry is the author — read it before adopting a hold. Recovery measured: five\n     │...\n 3410│- **Composed for next intake (doyle, v0.65.0 close):** the still-open log-the-floor build half\n*3411│  rides with [[IR-57]]'s scripted pick-fidelity audit as the next milestone's two tooling riders.\n 3412│- **Trigger condition:** ripe now for the log-the-floor half (it rides any gate-script or CI touch);\n 3413│  the arithmetic is discipline and applies immediately.\n 3414│- **Size guess:** small — one line in each rig/gate preflight to record free space alongside the\n\n## instruments/\n\n### ir57/\n#### STATUS.md\n 2│\n*3│# IR-57 instrument — `xtask pick-audit`, the scripted pick-fidelity audit\n 4│\n*5│The instrument behind [[IR-57]] in `docs/INFRA-REGISTER.md`. Run it at every assembly, over the\n 6│whole pick chain, before the head is handed anywhere.\n 7│\n 8│```\n\n### ir59/\n#### STATUS.md\n 2│\n*3│# IR-59 instrument — `xtask disk-floor`, the run-start free-space reading\n 4│\n*5│The log-the-floor half of [[IR-59]] in `docs/INFRA-REGISTER.md`. Call it as the FIRST step of any\n 6│rig or gate script, before the first cargo invocation.\n 7│\n 8│```","linesTruncated":true,"meta":{"limits":{"columnTruncated":{"maxColumn":512}}}},"isError":false,"timestamp":1789107062238}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_luTGlLGYzBqbijqQsOXiR3pc|fc_0330c101aa2c61dc016aa39b8363a487d190d9d879b3ac465f","toolName":"read","startedAt":"2026-09-11T06:11:17.792Z","args":{"path":"docs/INFRA-REGISTER.md:1-61"},"intent":"Reading release close governing findings"},"id":"015f0af2","parentId":"f0112690","timestamp":"2026-09-11T06:11:17.792Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_Z7opTUUeNl8tK13hdxXqD8Sb|fc_0330c101aa2c61dc016aa39b8363b887d1b51cdee0a1a31f5f","toolName":"read","startedAt":"2026-09-11T06:11:17.792Z","args":{"path":"docs/instruments/ir59/STATUS.md"},"intent":"Reading built disk instrument contract"},"id":"9edd5684","parentId":"015f0af2","timestamp":"2026-09-11T06:11:17.792Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_CRO2WfK85bmooOJJgQnT64ih|fc_0330c101aa2c61dc016aa39b8363c087d19008b3ed7be73bc7","toolName":"grep","startedAt":"2026-09-11T06:11:17.793Z","args":{"path":"crates/spt/tests/common;crates/spt-daemon/src/daemon.rs;crates/spt-store/src/proc.rs;crates/xtask/src; .github/bench"},"intent":"Checking implemented infra substrate"},"id":"97d3d513","parentId":"9edd5684","timestamp":"2026-09-11T06:11:17.793Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_iGAJFshVAIPR888rRwQMSeZA|fc_0330c101aa2c61dc016aa39b8363c887d19cb3425863ac2a17","toolName":"glob","startedAt":"2026-09-11T06:11:17.793Z","args":{"path":"*294*;*304*;*JIT*;docs/adr/*;PRD.md;ROADMAP.md;docs/KNOWN-HAZARDS.md;docs/STORAGE.md;docs/MANIFEST.md;docs/CONTEXT-MEMORY.md;docs/DOCS-STRATEGY.md;docs/TRACEABILITY.md"},"intent":"Locating intake and orientation sections"},"id":"61d87159","parentId":"97d3d513","timestamp":"2026-09-11T06:11:17.793Z"}
{"type":"message","id":"4ce0aa83","parentId":"61d87159","timestamp":"2026-09-11T06:11:17.793Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Surveying source sections**"},{"type":"toolCall","id":"call_luTGlLGYzBqbijqQsOXiR3pc|fc_0330c101aa2c61dc016aa39b8363a487d190d9d879b3ac465f","name":"read","arguments":{"i":"Reading release close governing findings","path":"docs/INFRA-REGISTER.md:1-61"},"intent":"Reading release close governing findings"},{"type":"toolCall","id":"call_Z7opTUUeNl8tK13hdxXqD8Sb|fc_0330c101aa2c61dc016aa39b8363b887d1b51cdee0a1a31f5f","name":"read","arguments":{"i":"Reading built disk instrument contract","path":"docs/instruments/ir59/STATUS.md"},"intent":"Reading built disk instrument contract"},{"type":"toolCall","id":"call_CRO2WfK85bmooOJJgQnT64ih|fc_0330c101aa2c61dc016aa39b8363c087d19008b3ed7be73bc7","name":"grep","arguments":{"i":"Checking implemented infra substrate","pattern":"DaemonReaper|struct .*Guard|DAEMON_SUCCEEDS_PID|daemon.pid.prev|IR-81|expected_identity|kill_pid_tree\\(|IR-90|disk.floor|IR95|IR-95","path":"crates/spt/tests/common;crates/spt-daemon/src/daemon.rs;crates/spt-store/src/proc.rs;crates/xtask/src; .github/bench","case":false,"gitignore":true,"skip":null},"intent":"Checking implemented infra substrate"},{"type":"toolCall","id":"call_iGAJFshVAIPR888rRwQMSeZA|fc_0330c101aa2c61dc016aa39b8363c887d19cb3425863ac2a17","name":"glob","arguments":{"i":"Locating intake and orientation sections","path":"*294*;*304*;*JIT*;docs/adr/*;PRD.md;ROADMAP.md;docs/KNOWN-HAZARDS.md;docs/STORAGE.md;docs/MANIFEST.md;docs/CONTEXT-MEMORY.md;docs/DOCS-STRATEGY.md;docs/TRACEABILITY.md","hidden":true,"gitignore":true,"limit":90},"intent":"Locating intake and orientation sections"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":29949,"output":331,"cacheRead":65536,"cacheWrite":0,"totalTokens":95816,"reasoningTokens":26,"cost":{"input":0.29949000000000003,"output":0.016550000000000002,"cacheRead":0.065536,"cacheWrite":0,"total":0.381576}},"stopReason":"toolUse","timestamp":1789107062285,"responseId":"resp_0330c101aa2c61dc016aa39b745ba087d1bf2d517518b22347","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0330c101aa2c61dc016aa39b797f7487d1835500588e64c596","type":"reasoning","content":[],"encrypted_content":"gAAAAABqo5uDS6YqA-2a_GqnHt2o4hSmWBT_hmVNHkuI1o91K70zi6wEHNtnVsXHiQOX5QuZvWyoeuuz4vdVxo6RWrsWHdqjDrluvdf1h-WlbV7tmvi-3MHE_EP0qJcG5_JgQCHZOdCakyaD5iNNKSoUJ3r5wyyjsiO_qCozmV9euAPE3hHSmEq52B7qiiZjufR3Rn7vpMzoKPEE4wgAPmohfnJxKjlZFoOB8Mj7VBRJdzxwymEh-yVTgZNedxAjrheViZfFC2oZYrd2hoYqSWEMgil6ps_9zF57wFEWwKXqbqJYFnn4MolwU7MJOP0FtkOmyE9mEskOIusAHf00PnaASfiFGBicoA2kI024e6861LXhbobQtzGMuqjyMGpjPK3Z23wEdZ1kuRjVd6g6xXLo5dukzIBWv5BH0FG72PAULxNXhN6JCPUmhq029-bsobYV-wwMrUEE9ab5xqFsr9u6GX_FTGaJFgl1iPmvYlxxF-DvbPsz17ZdavFSkKTSdAZNo5nXqWhzL5kXeAQV3VZpSqdqq3p9VKG_ZC-Wnx_S2og1L0VRYjvtISEIe2oylLI2RuJ8WDKqR4ryy-I-7uafgi9cUasyv9ZEiZlm9-oDouevtNM3ewhJkw09IbEjMHY47S2yli7hbWMxXcrAPpY1C7IlHq6f3YXJlsdSr1nlsd5s0NafHqxpzUO9iXh_YcbzS_bnhLMVP6G498tjGKkMxmJGw7c6P6DtLK0iR3H3hTUQYunXh7jzmDQ5KKQ9Q1hJojs5MKoglz669D0vUqy60aLGXAAa3WGKZ-JhYR2ZBKNummArsQD5uQ3_jBXLKE5SRv2dVHJrmZ8jt0rvgCplwgMiiVUUgG43rbU49PJqgUtdrKE5e1aB7p-nnTBn_mKKWYP9H9VC1AJLrtdhX4VlLVyH7iWFMnrI_Kp7EYP2nTdmWQU1KLmv_OgDk-BP-3PYf9druXd1jx268nbPUHQa6n412qd3f-7ljoakpzd0sjLPfcQt_iJTy3zBNja5iTJzaT97thRMRm7tbxttvVJl1PHOvMKIutowuQd1IGHS1Pv22-Vrsq2aqayUF7XTuXoIPTBs9h6smxtgsAi9yYqtBUbPtXTiBXk-aFSCrjX_00ZsMJt0-yOgLGCTvQi1TGY17xv_sKWnIqsTqaixRfZpYr9KUZtbkoqlbnFBylHA3NSwHQeJWemQ24t9jV8ezf12Zfvs7RLO_r0WFUxNHlYAwOq66hTK6tlz4PjFr3xXIbNuD7PSoQX1dE-guDHYvIOOh8_fOBDXRWN1o0_s7S1hoSWHcSK3CZ5O2ET0okUn7lWmxQQF50833b3t4QJgit-sJATemqJiQEIQ-c_hoPPY1RH6bDYKKUeNuEQJdzm2RIzZy_QMjmTHfwsMs3TIpoenGVpWbtdTjecqq2_HBSpPPEidXHASLJ2IS8-XNCTY-vUirzA-p_iNrSRcWyU5Ts5h0udFlMlu","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"summary":[{"type":"summary_text","text":"**Surveying source sections**"}],"metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b8363a487d190d9d879b3ac465f","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading release close governing findings\",\"path\":\"docs/INFRA-REGISTER.md:1-61\"}","call_id":"call_luTGlLGYzBqbijqQsOXiR3pc","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b8363b887d1b51cdee0a1a31f5f","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading built disk instrument contract\",\"path\":\"docs/instruments/ir59/STATUS.md\"}","call_id":"call_Z7opTUUeNl8tK13hdxXqD8Sb","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"read","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b8363c087d19008b3ed7be73bc7","type":"function_call","status":"completed","arguments":"{\"i\":\"Checking implemented infra substrate\",\"pattern\":\"DaemonReaper|struct .*Guard|DAEMON_SUCCEEDS_PID|daemon.pid.prev|IR-81|expected_identity|kill_pid_tree\\\\(|IR-90|disk.floor|IR95|IR-95\",\"path\":\"crates/spt/tests/common;crates/spt-daemon/src/daemon.rs;crates/spt-store/src/proc.rs;crates/xtask/src; .github/bench\",\"case\":false,\"gitignore\":true,\"skip\":null}","call_id":"call_CRO2WfK85bmooOJJgQnT64ih","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"grep","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}},{"id":"fc_0330c101aa2c61dc016aa39b8363c887d19cb3425863ac2a17","type":"function_call","status":"completed","arguments":"{\"i\":\"Locating intake and orientation sections\",\"path\":\"*294*;*304*;*JIT*;docs/adr/*;PRD.md;ROADMAP.md;docs/KNOWN-HAZARDS.md;docs/STORAGE.md;docs/MANIFEST.md;docs/CONTEXT-MEMORY.md;docs/DOCS-STRATEGY.md;docs/TRACEABILITY.md\",\"hidden\":true,\"gitignore\":true,\"limit\":90}","call_id":"call_iGAJFshVAIPR888rRwQMSeZA","internal_chat_message_metadata_passthrough":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"},"name":"glob","metadata":{"turn_id":"51a995e7-8541-4ad0-8d27-364d2fd547bf"}}]},"duration":15506.176900000311,"ttft":5562.386900000274,"completedAt":1789107077791,"contextSnapshot":{"promptTokens":95485,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"message","id":"95910095","parentId":"4ce0aa83","timestamp":"2026-09-11T06:11:17.804Z","message":{"role":"toolResult","toolCallId":"call_Z7opTUUeNl8tK13hdxXqD8Sb|fc_0330c101aa2c61dc016aa39b8363b887d1b51cdee0a1a31f5f","toolName":"read","content":[{"type":"text","text":"<!-- [doc->REQ-DISK-FLOOR-PREFLIGHT] -->\n\n# IR-59 instrument — `xtask disk-floor`, the run-start free-space reading\n\nThe log-the-floor half of [[IR-59]] in `docs/INFRA-REGISTER.md`. Call it as the FIRST step of any\nrig or gate script, before the first cargo invocation.\n\n```\ncargo run -p xtask -- disk-floor --label <lane>\n```\n\nIt prints one line whether it passes or fails:\n\n```\ndisk preflight: drive=C:\\ free_bytes=155184713728 floor_bytes=34359738368 label=gate-w2\n```\n\n## Why a verb and not a line in a script\n\nThe entry asks for the reading in \"the rig/gate preflight path\". There is no such path in this tree\nto amend — the gate legs that hit this ran as **plain per-run scripts**, which is the entry's own\nsecond face. There was nothing to add a line to, so the verb is the template: one command, carrying\nthe floor with it, that a rig script calls at run start.\n\n## Flags\n\n| Flag | Default | Means |\n| --- | --- | --- |\n| `--path <dir>` | cwd | the volume to read |\n| `--floor-gb <n>` | `32` | refuse below this; **`0` is print-only and never refuses** |\n| `--label <lane>` | none | attributes the reading on a box carrying several lanes |\n\n`32` is the golden runner's number, so a local rig and a golden leg refuse at one floor rather than\nat two. The keys are the golden runner's too (`disk preflight: drive= free_bytes= floor_bytes=`, and\n`RESOURCE=disk` on refusal), so one grep reads a local rig log and a CI log alike.\n\n## What it is answering\n\nA full volume **reds as a linker defect that names no disk**: `LNK1318: Unexpected PDB error` (the\nparenthesised code varies — do not key recognition on it), often beside `LNK4209: debugging\ninformation corrupt`. It has also arrived as a `traceable-reqs check` PANIC carrying `os error 112`,\nso even a registry red can be the disk's. Nothing in those texts says \"disk\". Two agents spent hours\non a mechanism for one of them and neither read free space.\n\n**A run that starts under the floor produces reds that belong to nothing. They are re-run, never\nre-read.**\n\n## The limit, and it is the important sentence\n\n**One reading is an INSTANT, not headroom** (IR-46). The danger window is the TAIL of a cold build,\nnot a steady state you can check once: the measured instance died linking the last and largest\nartifact of a 74 GB pool while that same build was draining the volume out from under itself, and a\nreading taken before it started looked fine. A green preflight says the run was allowed to start. It\nis not a guarantee about the run.\n\nThe lever this leaves alone is pool accumulation — a pool re-accumulated to 152–169 GB within one\nday of a clean, and a reap is an instant too. Free space at run start is the falsifier for a red in\nhand; `xtask pool-sweep` is what keeps the number healthy."}],"details":{"totalLines":58,"displayContent":{"text":"<!-- [doc->REQ-DISK-FLOOR-PREFLIGHT] -->\r\n\r\n# IR-59 instrument — `xtask disk-floor`, the run-start free-space reading\r\n\r\nThe log-the-floor half of [[IR-59]] in `docs/INFRA-REGISTER.md`. Call it as the FIRST step of any\r\nrig or gate script, before the first cargo invocation.\r\n\r\n```\r\ncargo run -p xtask -- disk-floor --label <lane>\r\n```\r\n\r\nIt prints one line whether it passes or fails:\r\n\r\n```\r\ndisk preflight: drive=C:\\ free_bytes=155184713728 floor_bytes=34359738368 label=gate-w2\r\n```\r\n\r\n## Why a verb and not a line in a script\r\n\r\nThe entry asks for the reading in \"the rig/gate preflight path\". There is no such path in this tree\r\nto amend — the gate legs that hit this ran as **plain per-run scripts**, which is the entry's own\r\nsecond face. There was nothing to add a line to, so the verb is the template: one command, carrying\r\nthe floor with it, that a rig script calls at run start.\r\n\r\n## Flags\r\n\r\n| Flag | Default | Means |\r\n| --- | --- | --- |\r\n| `--path <dir>` | cwd | the volume to read |\r\n| `--floor-gb <n>` | `32` | refuse below this; **`0` is print-only and never refuses** |\r\n| `--label <lane>` | none | attributes the reading on a box carrying several lanes |\r\n\r\n`32` is the golden runner's number, so a local rig and a golden leg refuse at one floor rather than\r\nat two. The keys are the golden runner's too (`disk preflight: drive= free_bytes= floor_bytes=`, and\r\n`RESOURCE=disk` on refusal), so one grep reads a local rig log and a CI log alike.\r\n\r\n## What it is answering\r\n\r\nA full volume **reds as a linker defect that names no disk**: `LNK1318: Unexpected PDB error` (the\r\nparenthesised code varies — do not key recognition on it), often beside `LNK4209: debugging\r\ninformation corrupt`. It has also arrived as a `traceable-reqs check` PANIC carrying `os error 112`,\r\nso even a registry red can be the disk's. Nothing in those texts says \"disk\". Two agents spent hours\r\non a mechanism for one of them and neither read free space.\r\n\r\n**A run that starts under the floor produces reds that belong to nothing. They are re-run, never\r\nre-read.**\r\n\r\n## The limit, and it is the important sentence\r\n\r\n**One reading is an INSTANT, not headroom** (IR-46). The danger window is the TAIL of a cold build,\r\nnot a steady state you can check once: the measured instance died linking the last and largest\r\nartifact of a 74 GB pool while that same build was draining the volume out from under itself, and a\r\nreading taken before it started looked fine. A green preflight says the run was allowed to start. It\r\nis not a guarantee about the run.\r\n\r\nThe lever this leaves alone is pool accumulation — a pool re-accumulated to 152–169 GB within one\r\nday of a clean, and a reap is an instant too. Free space at run start is the falsifier for a red in\r\nhand; `xtask pool-sweep` is what keeps the number healthy.\r","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58]},"fileSize":2826,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\instruments\\ir59\\STATUS.md"}}},"isError":false,"timestamp":1789107077804}}
{"type":"message","id":"a43e8ae4","parentId":"95910095","timestamp":"2026-09-11T06:11:17.806Z","message":{"role":"toolResult","toolCallId":"call_luTGlLGYzBqbijqQsOXiR3pc|fc_0330c101aa2c61dc016aa39b8363a487d190d9d879b3ac465f","toolName":"read","content":[{"type":"text","text":"# Infra register — CI / build-pipeline debt\n\nOperator-ruled 2026-08-02: infrastructure and CI-pipeline work items live HERE, not on the\n`spt-bs-releases` board. The board carries product surface the operator triages; this register\ncarries what the gater triages. **Mandate: doyle sweeps this file at every milestone intake and\nevery release close, and composes ripe entries into waves/milestone riders.** An entry leaves\nthis file only by being built (link the lane) or being retired with a stated reason.\n\nEntry format: status · origin · what/why · trigger condition (what makes it ripe) · size guess.\n\nLast sweep: **2026-09-11, v0.69.0 RELEASE CLOSE — FULL REGISTER**, source `e5a2fed9`.\nAll **97 entries (IR-1–97, including headingless IR-31)** read in two disjoint ranges; audit\npopulation checked for missing/duplicate IDs (97 rows, 97 unique, zero missing). Per-entry\ntrigger and disposition evidence: `.spt/preserved/infra-close069-20260911/audit.json`.\nUNKNOWN means no qualifying event established, not a disproved trigger or a discharged debt.\n\n- **Release facts, not a blanket green:** v0.69.0 at `16df0e41`, counter **105**, Latest,\n  11 assets; #294 and all eight members DONE. Explicit operator SHIP overrode the known\n  sync-cell red at candidate `a9e786b2`; the release neither classifies nor closes that defect.\n  Source closeout: releases#294 comment **5628538587**. The scoped four-package `--lib` battery\n  passed **121/121**; push CI **34550282074** passed **3167 Windows units**, then failed the\n  END disk floor (**15,360,114,688 < 34,359,738,368 bytes**). Release build **34550300527**\n  succeeded. Earlier PR unit-red logs remain unavailable/cause-unclassified. These are separate\n  verdict objects; no pass substitutes for a red, missing specimen, or unexecuted acceptance.\n- **Close already-built work, retain residuals:** IR-1/4 stale unlanded headers reconciled to\n  their landed rider and recorded golden exercise. IR-66 CLOSED using its existing two-platform\n  gates and WEBSERVE satisfaction ruling. IR-73 CLOSED: eight post-checkout sites plus both\n  docs-floor rereads are present; IR-86 retains sizing/dependency debt. Other established\n  BUILT/RETIRED decisions stand. IR-18's deferred consolidation and IR-53/62's narrower\n  touch-triggered siblings remain carried; closing their built halves does not erase those.\n- **Do not redispatch existing implementations:** IR-26 build-side identity is committed,\n  but claim-time observation and old-reader issues remain; IR-29's first fix landed, later\n  rung faces remain; IR-33's 16 MiB CLI stack exists, acceptance/margin reconciliation remains.\n  IR-57 `pick-audit`, IR-59 `disk-floor`, and IR-46 workflow floor tokens exist; residual adoption\n  and receipt reconciliation are the work. IR-69's original product lane landed; #243 residuals\n  remain. IR-83's universal LAN-only prescription is superseded by IR-89's layer-specific box\n  proof. IR-89's next-golden trigger has fired; exact step acceptance still needs reconciliation,\n  not a second guard implementation or renewed operator permission.\n- **IR-92 stays OPEN:** core#215 shipped the documentation/register rider, NOT the product\n  remedy; core#217 is the separate brainread audit. `try_spt_hosted_inject` still lacks the\n  MSG_IN publisher. Deployah corrected comment **5628532753** in place and confirmed readback.\n  Inject coverage, relay publication ordering and per-msg-id exact-once are distinct obligations.\n- **Next-intake composition, owned by doyle until accepted:** hertz's driver/workflow package\n  takes IR-31/46/59/60/76/86/87/90/97: aggregate capacity, truthful producer status, existing\n  quiet-window contract, independent rendezvous clocks, and mandatory between-run identity\n  census. IR-88 adopts the already-proven prebuilt release-before-delete recipe; IR-64 remains\n  a separate operator capacity decision. No new loaded comparison before these prerequisites.\n  Hertz's lifecycle package retains IR-7/17/20/22/25/34/35/55/63/79/80; guard adoption must\n  distinguish unwinding from hard process death. IR-74/75 ride the next Linux box audit.\n  IR-85/95/96 are scoped diagnostic continuation, NOT budget widening or a load/disk diagnosis.\n  Todlando owns product-side IR-81/82/92 composition; #285's completion did not build IR-82's\n  predecessor record. Both builders are offline: existing briefs are delivered, unacknowledged,\n  and **not executing**. No board mutation or new run authorization is implied.\n- **Small seam riders remain explicit:** next tooling intake weighs IR-5/6/10/11/32/37/47/58/94\n  (IR-37 upstream release is not downstream adoption: golden still requests 0.2.0).\n  IR-93 remains a separate symbol-packaging decision before a release-workflow rider, not a\n  property proven by a successful release build. All other open entries retain their recorded\n  trigger, residual, and owner where named; the complete audit records each, not a sampled set.\n- **Cleanup is mitigation, not closure:** 38 clean merged worktrees and classified obsolete\n  artifacts removed; dirty/unmerged/retained evidence preserved. Net free-space change\n  **4,532,350,976 bytes**, ending **83,382,472,704 bytes** (concurrent-activity caveat).\n  `.spt/cleanup-20260911.json` is the receipt. Root-target and CI-debug reclaims are separate\n  earlier measurements, not additions to that net. IR-14/26/27/49 remain structurally OPEN.\n\n…\n  at the end. · **Size:** a between-run census step plus a scoped reap in the harness.\n\n[Showing lines 1-64 of 5900. Use :65 to continue]"}],"details":{"truncation":{"content":"# Infra register — CI / build-pipeline debt\r\n\r\nOperator-ruled 2026-08-02: infrastructure and CI-pipeline work items live HERE, not on the\r\n`spt-bs-releases` board. The board carries product surface the operator triages; this register\r\ncarries what the gater triages. **Mandate: doyle sweeps this file at every milestone intake and\r\nevery release close, and composes ripe entries into waves/milestone riders.** An entry leaves\r\nthis file only by being built (link the lane) or being retired with a stated reason.\r\n\r\nEntry format: status · origin · what/why · trigger condition (what makes it ripe) · size guess.\r\n\r\nLast sweep: **2026-09-11, v0.69.0 RELEASE CLOSE — FULL REGISTER**, source `e5a2fed9`.\r\nAll **97 entries (IR-1–97, including headingless IR-31)** read in two disjoint ranges; audit\r\npopulation checked for missing/duplicate IDs (97 rows, 97 unique, zero missing). Per-entry\r\ntrigger and disposition evidence: `.spt/preserved/infra-close069-20260911/audit.json`.\r\nUNKNOWN means no qualifying event established, not a disproved trigger or a discharged debt.\r\n\r\n- **Release facts, not a blanket green:** v0.69.0 at `16df0e41`, counter **105**, Latest,\r\n  11 assets; #294 and all eight members DONE. Explicit operator SHIP overrode the known\r\n  sync-cell red at candidate `a9e786b2`; the release neither classifies nor closes that defect.\r\n  Source closeout: releases#294 comment **5628538587**. The scoped four-package `--lib` battery\r\n  passed **121/121**; push CI **34550282074** passed **3167 Windows units**, then failed the\r\n  END disk floor (**15,360,114,688 < 34,359,738,368 bytes**). Release build **34550300527**\r\n  succeeded. Earlier PR unit-red logs remain unavailable/cause-unclassified. These are separate\r\n  verdict objects; no pass substitutes for a red, missing specimen, or unexecuted acceptance.\r\n- **Close already-built work, retain residuals:** IR-1/4 stale unlanded headers reconciled to\r\n  their landed rider and recorded golden exercise. IR-66 CLOSED using its existing two-platform\r\n  gates and WEBSERVE satisfaction ruling. IR-73 CLOSED: eight post-checkout sites plus both\r\n  docs-floor rereads are present; IR-86 retains sizing/dependency debt. Other established\r\n  BUILT/RETIRED decisions stand. IR-18's deferred consolidation and IR-53/62's narrower\r\n  touch-triggered siblings remain carried; closing their built halves does not erase those.\r\n- **Do not redispatch existing implementations:** IR-26 build-side identity is committed,\r\n  but claim-time observation and old-reader issues remain; IR-29's first fix landed, later\r\n  rung faces remain; IR-33's 16 MiB CLI stack exists, acceptance/margin reconciliation remains.\r\n  IR-57 `pick-audit`, IR-59 `disk-floor`, and IR-46 workflow floor tokens exist; residual adoption\r\n  and receipt reconciliation are the work. IR-69's original product lane landed; #243 residuals\r\n  remain. IR-83's universal LAN-only prescription is superseded by IR-89's layer-specific box\r\n  proof. IR-89's next-golden trigger has fired; exact step acceptance still needs reconciliation,\r\n  not a second guard implementation or renewed operator permission.\r\n- **IR-92 stays OPEN:** core#215 shipped the documentation/register rider, NOT the product\r\n  remedy; core#217 is the separate brainread audit. `try_spt_hosted_inject` still lacks the\r\n  MSG_IN publisher. Deployah corrected comment **5628532753** in place and confirmed readback.\r\n  Inject coverage, relay publication ordering and per-msg-id exact-once are distinct obligations.\r\n- **Next-intake composition, owned by doyle until accepted:** hertz's driver/workflow package\r\n  takes IR-31/46/59/60/76/86/87/90/97: aggregate capacity, truthful producer status, existing\r\n  quiet-window contract, independent rendezvous clocks, and mandatory between-run identity\r\n  census. IR-88 adopts the already-proven prebuilt release-before-delete recipe; IR-64 remains\r\n  a separate operator capacity decision. No new loaded comparison before these prerequisites.\r\n  Hertz's lifecycle package retains IR-7/17/20/22/25/34/35/55/63/79/80; guard adoption must\r\n  distinguish unwinding from hard process death. IR-74/75 ride the next Linux box audit.\r\n  IR-85/95/96 are scoped diagnostic continuation, NOT budget widening or a load/disk diagnosis.\r\n  Todlando owns product-side IR-81/82/92 composition; #285's completion did not build IR-82's\r\n  predecessor record. Both builders are offline: existing briefs are delivered, unacknowledged,\r\n  and **not executing**. No board mutation or new run authorization is implied.\r\n- **Small seam riders remain explicit:** next tooling intake weighs IR-5/6/10/11/32/37/47/58/94\r\n  (IR-37 upstream release is not downstream adoption: golden still requests 0.2.0).\r\n  IR-93 remains a separate symbol-packaging decision before a release-workflow rider, not a\r\n  property proven by a successful release build. All other open entries retain their recorded\r\n  trigger, residual, and owner where named; the complete audit records each, not a sampled set.\r\n- **Cleanup is mitigation, not closure:** 38 clean merged worktrees and classified obsolete\r\n  artifacts removed; dirty/unmerged/retained evidence preserved. Net free-space change\r\n  **4,532,350,976 bytes**, ending **83,382,472,704 bytes** (concurrent-activity caveat).\r\n  `.spt/cleanup-20260911.json` is the receipt. Root-target and CI-debug reclaims are separate\r\n  earlier measurements, not additions to that net. IR-14/26/27/49 remain structurally OPEN.\r\n\r","truncated":true,"truncatedBy":"lines","totalLines":5900,"totalBytes":5465,"outputLines":64,"outputBytes":5465,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":5900,"displayContent":{"text":"# Infra register — CI / build-pipeline debt\r\n\r\nOperator-ruled 2026-08-02: infrastructure and CI-pipeline work items live HERE, not on the\r\n`spt-bs-releases` board. The board carries product surface the operator triages; this register\r\ncarries what the gater triages. **Mandate: doyle sweeps this file at every milestone intake and\r\nevery release close, and composes ripe entries into waves/milestone riders.** An entry leaves\r\nthis file only by being built (link the lane) or being retired with a stated reason.\r\n\r\nEntry format: status · origin · what/why · trigger condition (what makes it ripe) · size guess.\r\n\r\nLast sweep: **2026-09-11, v0.69.0 RELEASE CLOSE — FULL REGISTER**, source `e5a2fed9`.\r\nAll **97 entries (IR-1–97, including headingless IR-31)** read in two disjoint ranges; audit\r\npopulation checked for missing/duplicate IDs (97 rows, 97 unique, zero missing). Per-entry\r\ntrigger and disposition evidence: `.spt/preserved/infra-close069-20260911/audit.json`.\r\nUNKNOWN means no qualifying event established, not a disproved trigger or a discharged debt.\r\n\r\n- **Release facts, not a blanket green:** v0.69.0 at `16df0e41`, counter **105**, Latest,\r\n  11 assets; #294 and all eight members DONE. Explicit operator SHIP overrode the known\r\n  sync-cell red at candidate `a9e786b2`; the release neither classifies nor closes that defect.\r\n  Source closeout: releases#294 comment **5628538587**. The scoped four-package `--lib` battery\r\n  passed **121/121**; push CI **34550282074** passed **3167 Windows units**, then failed the\r\n  END disk floor (**15,360,114,688 < 34,359,738,368 bytes**). Release build **34550300527**\r\n  succeeded. Earlier PR unit-red logs remain unavailable/cause-unclassified. These are separate\r\n  verdict objects; no pass substitutes for a red, missing specimen, or unexecuted acceptance.\r\n- **Close already-built work, retain residuals:** IR-1/4 stale unlanded headers reconciled to\r\n  their landed rider and recorded golden exercise. IR-66 CLOSED using its existing two-platform\r\n  gates and WEBSERVE satisfaction ruling. IR-73 CLOSED: eight post-checkout sites plus both\r\n  docs-floor rereads are present; IR-86 retains sizing/dependency debt. Other established\r\n  BUILT/RETIRED decisions stand. IR-18's deferred consolidation and IR-53/62's narrower\r\n  touch-triggered siblings remain carried; closing their built halves does not erase those.\r\n- **Do not redispatch existing implementations:** IR-26 build-side identity is committed,\r\n  but claim-time observation and old-reader issues remain; IR-29's first fix landed, later\r\n  rung faces remain; IR-33's 16 MiB CLI stack exists, acceptance/margin reconciliation remains.\r\n  IR-57 `pick-audit`, IR-59 `disk-floor`, and IR-46 workflow floor tokens exist; residual adoption\r\n  and receipt reconciliation are the work. IR-69's original product lane landed; #243 residuals\r\n  remain. IR-83's universal LAN-only prescription is superseded by IR-89's layer-specific box\r\n  proof. IR-89's next-golden trigger has fired; exact step acceptance still needs reconciliation,\r\n  not a second guard implementation or renewed operator permission.\r\n- **IR-92 stays OPEN:** core#215 shipped the documentation/register rider, NOT the product\r\n  remedy; core#217 is the separate brainread audit. `try_spt_hosted_inject` still lacks the\r\n  MSG_IN publisher. Deployah corrected comment **5628532753** in place and confirmed readback.\r\n  Inject coverage, relay publication ordering and per-msg-id exact-once are distinct obligations.\r\n- **Next-intake composition, owned by doyle until accepted:** hertz's driver/workflow package\r\n  takes IR-31/46/59/60/76/86/87/90/97: aggregate capacity, truthful producer status, existing\r\n  quiet-window contract, independent rendezvous clocks, and mandatory between-run identity\r\n  census. IR-88 adopts the already-proven prebuilt release-before-delete recipe; IR-64 remains\r\n  a separate operator capacity decision. No new loaded comparison before these prerequisites.\r\n  Hertz's lifecycle package retains IR-7/17/20/22/25/34/35/55/63/79/80; guard adoption must\r\n  distinguish unwinding from hard process death. IR-74/75 ride the next Linux box audit.\r\n  IR-85/95/96 are scoped diagnostic continuation, NOT budget widening or a load/disk diagnosis.\r\n  Todlando owns product-side IR-81/82/92 composition; #285's completion did not build IR-82's\r\n  predecessor record. Both builders are offline: existing briefs are delivered, unacknowledged,\r\n  and **not executing**. No board mutation or new run authorization is implied.\r\n- **Small seam riders remain explicit:** next tooling intake weighs IR-5/6/10/11/32/37/47/58/94\r\n  (IR-37 upstream release is not downstream adoption: golden still requests 0.2.0).\r\n  IR-93 remains a separate symbol-packaging decision before a release-workflow rider, not a\r\n  property proven by a successful release build. All other open entries retain their recorded\r\n  trigger, residual, and owner where named; the complete audit records each, not a sampled set.\r\n- **Cleanup is mitigation, not closure:** 38 clean merged worktrees and classified obsolete\r\n  artifacts removed; dirty/unmerged/retained evidence preserved. Net free-space change\r\n  **4,532,350,976 bytes**, ending **83,382,472,704 bytes** (concurrent-activity caveat).\r\n  `.spt/cleanup-20260911.json` is the receipt. Root-target and CI-debug reclaims are separate\r\n  earlier measurements, not additions to that net. IR-14/26/27/49 remain structurally OPEN.\r\n\r\n…\n  at the end. · **Size:** a between-run census step plus a scoped reap in the harness.","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,null,5900]},"fileSize":512411,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\INFRA-REGISTER.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":5900,"totalBytes":5465,"outputLines":64,"outputBytes":5465,"shownRange":{"start":1,"end":64},"nextOffset":65}}},"isError":false,"timestamp":1789107077806}}
{"type":"message","id":"6b141d71","parentId":"a43e8ae4","timestamp":"2026-09-11T06:11:17.809Z","message":{"role":"toolResult","toolCallId":"call_iGAJFshVAIPR888rRwQMSeZA|fc_0330c101aa2c61dc016aa39b8363c887d19cb3425863ac2a17","toolName":"glob","content":[{"type":"text","text":"WEBSERVE-272-W2-JIT.md\nWEBSERVE-272-JIT.md\nIO-PARSER-22-JIT.md\nFIELD-SEAL-63-JIT.md\nSIGNET-218-JIT.md\nWAX-SEAL-21-JIT.md\nWAX-SEAL-W3-JIT.md\nW1-209-JIT.md\nW3-67-JIT.md\nW3-196-JIT.md\nW3-186-JIT.md\nW3-172-JIT.md\nPRD.md\nCONCIERGE-183-JIT.md\nKEYSTONE-182-JIT.md\nW1-TRANCHE2-JIT.md\nU3-VERB-SURFACE-JIT.md\nINBOUND-FIREWALL-JIT.md\nRESIDENT-SERVICE-JIT.md\nIDLE-EDGE-JIT.md\nW2-JIT.md\nW3-BISECT-JIT.md\nV0.17.0-ROBUST-JOIN-AND-PRESENCE-JIT.md\nV0.16.0-UPDATE-ARC-AND-CLI-JIT.md\nROADMAP.md\nV0.14.0-ENDPOINT-CREATION-FLOW-JIT.md\nV0.13.2-ADAPTER-PACKAGING-JIT.md\nV0.13.0-VIEWER-RING-ROLL-SNAP-JIT.md\nV0.13.0-VIEWER-DRAIN-DECOUPLE-JIT.md\nV0.13.0-SKIP-TO-LIVE-JIT.md\nV0.13.0-P0-JIT-PLAN.md\nV0.13.0-DELIVERY-CONTROL-JIT.md\nV0.12.1-LIFECYCLE-JIT.md\nM9-WAVE3-JIT.md\n# docs/\nKNOWN-HAZARDS.md\nSTORAGE.md\nMANIFEST.md\nTRACEABILITY.md\nCONTEXT-MEMORY.md\nDOCS-STRATEGY.md\n## adr/\n0041-endpoint-lifecycle-truth.md\n0060-mint-web-surface-retire-xfer.md\n0061-message-short-id-is-node-scoped.md\n0059-lan-exposure-only-for-the-bootstrap-surface.md\n0058-attachments-are-pull-model.md\n0057-serving-registry-is-the-primitive.md\n0056-node-prefixed-url-namespace.md\n0019-digest-adapter-declared-extractor-session-spanning.md\n0052-engine-room-endpoint-empower.md\n0010-immutable-home-subnet-fork-not-rehome.md\n0026-multi-subnet-home-at-endpoint-run-creation.md\n0054-sealed-knock-codes.md\n0046-notif-scope-supersession-quiet-delivery.md\n0039-peer-route-resolution-truth.md\n0055-sender-declared-knock-directionality.md\n0050-golden-ci-merge-integration.md\n0051-two-key-subnet-member-admin.md\n0053-access-store-fail-closed.md\n0009-endpoint-access-control-model.md\n0028-activity-gated-delivery-and-send-modifier-axes.md\n0018-broker-brain-process-isolation-restoration.md\n0049-resident-service-substrate.md\n0040-bounded-stream-seat-lifecycle-one-way-terminal.md\n0048-idle-edge-contract.md\n0047-daemon-lifecycle-custody-authority.md\n0031-server-side-screen-grid-render-repaint.md\n0045-endpoint-teardown-authority.md\n0044-controller-lease-truth.md\n0043-terminal-render-lifecycle.md\n0042-rc-attach-truth.md\n0038-broker-stream-lifecycle-truth.md\n0037-materialized-project-index.md\n0036-private-fork-distribution.md\n0005-totp-seeded-spake2-node-pairing.md\n0034-per-minter-op-id-namespacing.md\n0033-wake-resume-via-reconcile-intent.md\n0025-live-daemon-coordinated-adapter-update.md\n0022-spt-hosted-idle-delivery-translation-binary.md\n0032-boundary-rotation-credential.md\n0030-robust-wan-subnet-join.md\n0029-adapter-update-arc-resolve-not-execute.md\n0027-unbound-endpoint-state-and-attach-on-session.md\n0024-multi-platform-adapter-spt-packaging.md\n0023-always-on-endpoints-resident-supervised-binary-sigil-addressing.md\n0021-harness-hosted-adapter-agnostic-seed-and-bind-time-resolution.md\n0020-event-envelope-sole-arriving-format-reply-to-removed.md\n0012-psyche-trust-boundary-stdout-event-outbound.md\n0008-live-activity-buffer-pty-digest.md\n0016-platform-targeted-update-sets.md\n0017-subnet-mesh-membership-seed-proof.md\n\n[90 results limit reached. Use limit=180 for more]"}],"details":{"scopePath":"*294*, *304*, *JIT*, docs/adr/*, PRD.md, ROADMAP.md, docs/KNOWN-HAZARDS.md, docs/STORAGE.md, docs/MANIFEST.md, docs/CONTEXT-MEMORY.md, docs/DOCS-STRATEGY.md, docs/TRACEABILITY.md","fileCount":90,"files":["docs/KNOWN-HAZARDS.md","docs/adr/0041-endpoint-lifecycle-truth.md","docs/STORAGE.md","docs/MANIFEST.md","docs/adr/0060-mint-web-surface-retire-xfer.md","docs/adr/0061-message-short-id-is-node-scoped.md","docs/adr/0059-lan-exposure-only-for-the-bootstrap-surface.md","docs/adr/0058-attachments-are-pull-model.md","docs/adr/0057-serving-registry-is-the-primitive.md","WEBSERVE-272-W2-JIT.md","WEBSERVE-272-JIT.md","docs/adr/0056-node-prefixed-url-namespace.md","docs/adr/0019-digest-adapter-declared-extractor-session-spanning.md","IO-PARSER-22-JIT.md","FIELD-SEAL-63-JIT.md","SIGNET-218-JIT.md","WAX-SEAL-21-JIT.md","WAX-SEAL-W3-JIT.md","docs/adr/0052-engine-room-endpoint-empower.md","W1-209-JIT.md","docs/adr/0010-immutable-home-subnet-fork-not-rehome.md","docs/adr/0026-multi-subnet-home-at-endpoint-run-creation.md","W3-67-JIT.md","W3-196-JIT.md","W3-186-JIT.md","W3-172-JIT.md","PRD.md","CONCIERGE-183-JIT.md","KEYSTONE-182-JIT.md","docs/adr/0054-sealed-knock-codes.md","docs/adr/0046-notif-scope-supersession-quiet-delivery.md","docs/adr/0039-peer-route-resolution-truth.md","W1-TRANCHE2-JIT.md","U3-VERB-SURFACE-JIT.md","docs/adr/0055-sender-declared-knock-directionality.md","docs/adr/0050-golden-ci-merge-integration.md","INBOUND-FIREWALL-JIT.md","docs/TRACEABILITY.md","docs/adr/0051-two-key-subnet-member-admin.md","docs/adr/0053-access-store-fail-closed.md","docs/adr/0009-endpoint-access-control-model.md","docs/adr/0028-activity-gated-delivery-and-send-modifier-axes.md","docs/adr/0018-broker-brain-process-isolation-restoration.md","docs/adr/0049-resident-service-substrate.md","RESIDENT-SERVICE-JIT.md","IDLE-EDGE-JIT.md","docs/adr/0040-bounded-stream-seat-lifecycle-one-way-terminal.md","docs/adr/0048-idle-edge-contract.md","W2-JIT.md","docs/adr/0047-daemon-lifecycle-custody-authority.md","W3-BISECT-JIT.md","docs/adr/0031-server-side-screen-grid-render-repaint.md","docs/adr/0045-endpoint-teardown-authority.md","docs/adr/0044-controller-lease-truth.md","docs/adr/0043-terminal-render-lifecycle.md","docs/adr/0042-rc-attach-truth.md","docs/adr/0038-broker-stream-lifecycle-truth.md","docs/adr/0037-materialized-project-index.md","docs/adr/0036-private-fork-distribution.md","docs/adr/0005-totp-seeded-spake2-node-pairing.md","docs/adr/0034-per-minter-op-id-namespacing.md","docs/adr/0033-wake-resume-via-reconcile-intent.md","docs/adr/0025-live-daemon-coordinated-adapter-update.md","docs/CONTEXT-MEMORY.md","docs/adr/0022-spt-hosted-idle-delivery-translation-binary.md","docs/adr/0032-boundary-rotation-credential.md","V0.17.0-ROBUST-JOIN-AND-PRESENCE-JIT.md","docs/adr/0030-robust-wan-subnet-join.md","V0.16.0-UPDATE-ARC-AND-CLI-JIT.md","docs/adr/0029-adapter-update-arc-resolve-not-execute.md","ROADMAP.md","docs/adr/0027-unbound-endpoint-state-and-attach-on-session.md","V0.14.0-ENDPOINT-CREATION-FLOW-JIT.md","docs/adr/0024-multi-platform-adapter-spt-packaging.md","docs/DOCS-STRATEGY.md","V0.13.2-ADAPTER-PACKAGING-JIT.md","docs/adr/0023-always-on-endpoints-resident-supervised-binary-sigil-addressing.md","V0.13.0-VIEWER-RING-ROLL-SNAP-JIT.md","V0.13.0-VIEWER-DRAIN-DECOUPLE-JIT.md","V0.13.0-SKIP-TO-LIVE-JIT.md","V0.13.0-P0-JIT-PLAN.md","V0.13.0-DELIVERY-CONTROL-JIT.md","V0.12.1-LIFECYCLE-JIT.md","docs/adr/0021-harness-hosted-adapter-agnostic-seed-and-bind-time-resolution.md","docs/adr/0020-event-envelope-sole-arriving-format-reply-to-removed.md","docs/adr/0012-psyche-trust-boundary-stdout-event-outbound.md","docs/adr/0008-live-activity-buffer-pty-digest.md","M9-WAVE3-JIT.md","docs/adr/0016-platform-targeted-update-sets.md","docs/adr/0017-subnet-mesh-membership-seed-proof.md"],"truncated":true,"resultLimitReached":90,"cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","meta":{"limits":{"resultLimit":{"reached":90,"suggestion":180}}}},"isError":false,"timestamp":1789107077809}}
{"type":"message","id":"00a80233","parentId":"6b141d71","timestamp":"2026-09-11T06:11:17.849Z","message":{"role":"toolResult","toolCallId":"call_CRO2WfK85bmooOJJgQnT64ih|fc_0330c101aa2c61dc016aa39b8363c087d19008b3ed7be73bc7","toolName":"grep","content":[{"type":"text","text":"# crates/\n\n## spt-store/src/\n### proc.rs\n 429|// [impl->REQ-PSYCHE-CRASHLOOP-BACKOFF-SHUTDOWN]\n*430|pub fn kill_pid_tree(root: u32) {\n 431|    if root == 0 {\n 432|        return;\n 433|    }\n...\n 943|        if descendants.is_empty() {\n*944|            kill_pid_tree(ppid);\n 945|            let _ = parent.wait();\n 946|            return;\n 947|        }\n...\n 950|\n*951|        kill_pid_tree(ppid);\n 952|        let _ = parent.wait();\n 953|        drop(parent); // release the Windows handle so the root's death is observable\n 954|\n...\n 973|        // pid-0 root is a no-op, never a self-signal.\n*974|        kill_pid_tree(0);\n 975|    }\n 976|}\n\n## xtask/src/\n### diskfloor.rs\n*1|//! `xtask disk-floor` — record free space at run start, and refuse a run that\n 2|//! starts under the floor (IR-59, the log-the-floor half).\n 3|//!\n 4|//! WHY THIS EXISTS: a full volume reds as a LINKER defect that names no disk —\n...\n 22|//! alike. (Cited by text, not by line number — that step moves.)\n*23|// [impl->REQ-DISK-FLOOR-PREFLIGHT]\n 24|\n 25|use std::path::{Path, PathBuf};\n 26|\n...\n 54|/// default floor still refuses, which is golden parity and the\n*55|/// `GATE_ABORTED_DISK_FLOOR` precedent.\n 56|pub fn admits(free_bytes: u64, floor_bytes: u64) -> bool {\n 57|    floor_bytes == 0 || free_bytes >= floor_bytes\n 58|}\n 59|\n*60|/// `xtask disk-floor [--path <dir>] [--floor-gb <n>] [--label <lane>]`\n 61|///\n 62|/// EXIT: 0 when the run may start (always, under `--floor-gb 0`); 1 under the\n 63|/// floor, with the golden runner's `RESOURCE=disk` diagnostic; 2 on usage.\n*64|pub fn disk_floor(args: &[String]) {\n 65|    let path = flag(args, \"--path\")\n 66|        .map(PathBuf::from)\n 67|        .unwrap_or_else(|| std::env::current_dir().expect(\"cwd\"));\n...\n 71|            Err(_) => {\n*72|                eprintln!(\"disk-floor: --floor-gb takes whole GiB, got {v}\");\n 73|                std::process::exit(2);\n 74|            }\n 75|        },\n...\n 82|        Err(e) => {\n*83|            eprintln!(\"disk-floor: cannot read free space at {}: {e}\", path.display());\n 84|            std::process::exit(2);\n 85|        }\n 86|    };\n...\n 140|\n*141|    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 142|    #[test]\n 143|    fn the_line_carries_the_golden_runners_keys() {\n 144|        // Pinned as TEXT because its whole purpose is that one grep reads a\n...\n 156|\n*157|    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 158|    #[test]\n 159|    fn the_floor_refuses_below_and_admits_at_or_above() {\n 160|        let floor = 32 * GIB;\n...\n 167|\n*168|    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 169|    #[test]\n 170|    fn a_zero_floor_is_print_only_and_never_refuses() {\n 171|        assert!(admits(0, 0), \"print-only mode records without owning a refusal\");\n...\n 178|\n*179|    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 180|    #[test]\n 181|    fn the_drive_is_spelled_the_way_the_golden_runner_spells_it() {\n 182|        // Caught live, not in review: the first build printed `drive=\\\\?\\C:\\`\n...\n 200|\n*201|    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 202|    #[test]\n 203|    fn the_reader_returns_a_real_reading_for_a_real_directory() {\n 204|        // An absence is data only if the thing has a way to appear: without\n### main.rs\n 69|        \"pick-audit\" => pickaudit::pick_audit(&args[1..]),\n*70|        \"disk-floor\" => diskfloor::disk_floor(&args[1..]),\n 71|        \"bench-wrap\" => bench_wrap(&args[1..]),\n 72|        \"bench-report\" => bench_report(&args[1..]),\n 73|        \"pool-claim\" => pool_claim(&args[1..]),\n...\n 85|            eprintln!(\n*86|                \"usage: xtask <gen|check|brain-read-check|binedge-check [--no-prebuilds] [--baseline|--write-baseline] [--sites]|perjob-map|pick-audit --range <base>..<head> --lane <base>..<tip> [--lane <base>..<tip>] [--pair <lane-rev>:<pick-rev>] [--repo <dir>]|disk-floor [--path <dir>] [--floor-gb <n>] [--label <lane>]|docs-bundle <out.tar.gz>|bench-wrap --step <name> [--key <k>] -- <cmd...>|bench-report [--top <n>] [--window-hours <h>]|pool-claim --pool <dir> --label <lane> [--holder-pid <pid>] [--fo...\n 87|            );\n 88|            std::process::exit(2);\n 89|        }\n\n# .github/bench/\n## launch-battery.py\n 30|So this tool verifies the child AND its descendants — `a pid is not a tree`\n*31|(IR-80/IR-81) applies to reading an environment exactly as it does to killing.\n 32|The `.env` sidecar records every process actually inspected, by pid, so the\n 33|claim's SCOPE is on disk and not in a sentence.\n 34|\n\n[Some lines truncated to 512 chars]"}],"details":{"scopePath":"crates/spt/tests/common, crates/spt-daemon/src/daemon.rs, crates/spt-store/src/proc.rs, crates/xtask/src, .github/bench","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":19,"fileCount":4,"files":["crates/spt-store/src/proc.rs","crates/xtask/src/diskfloor.rs","crates/xtask/src/main.rs",".github/bench/launch-battery.py"],"fileMatches":[{"path":"crates/spt-store/src/proc.rs","count":4},{"path":"crates/xtask/src/diskfloor.rs","count":12},{"path":"crates/xtask/src/main.rs","count":2},{"path":".github/bench/launch-battery.py","count":1}],"truncated":true,"displayContent":"# crates/\n\n## spt-store/src/\n### proc.rs\n 429│// [impl->REQ-PSYCHE-CRASHLOOP-BACKOFF-SHUTDOWN]\n*430│pub fn kill_pid_tree(root: u32) {\n 431│    if root == 0 {\n 432│        return;\n 433│    }\n    │...\n 943│        if descendants.is_empty() {\n*944│            kill_pid_tree(ppid);\n 945│            let _ = parent.wait();\n 946│            return;\n 947│        }\n    │...\n 950│\n*951│        kill_pid_tree(ppid);\n 952│        let _ = parent.wait();\n 953│        drop(parent); // release the Windows handle so the root's death is observable\n 954│\n    │...\n 973│        // pid-0 root is a no-op, never a self-signal.\n*974│        kill_pid_tree(0);\n 975│    }\n 976│}\n\n## xtask/src/\n### diskfloor.rs\n  *1│//! `xtask disk-floor` — record free space at run start, and refuse a run that\n   2│//! starts under the floor (IR-59, the log-the-floor half).\n   3│//!\n   4│//! WHY THIS EXISTS: a full volume reds as a LINKER defect that names no disk —\n    │...\n  22│//! alike. (Cited by text, not by line number — that step moves.)\n *23│// [impl->REQ-DISK-FLOOR-PREFLIGHT]\n  24│\n  25│use std::path::{Path, PathBuf};\n  26│\n    │...\n  54│/// default floor still refuses, which is golden parity and the\n *55│/// `GATE_ABORTED_DISK_FLOOR` precedent.\n  56│pub fn admits(free_bytes: u64, floor_bytes: u64) -> bool {\n  57│    floor_bytes == 0 || free_bytes >= floor_bytes\n  58│}\n  59│\n *60│/// `xtask disk-floor [--path <dir>] [--floor-gb <n>] [--label <lane>]`\n  61│///\n  62│/// EXIT: 0 when the run may start (always, under `--floor-gb 0`); 1 under the\n  63│/// floor, with the golden runner's `RESOURCE=disk` diagnostic; 2 on usage.\n *64│pub fn disk_floor(args: &[String]) {\n  65│    let path = flag(args, \"--path\")\n  66│        .map(PathBuf::from)\n  67│        .unwrap_or_else(|| std::env::current_dir().expect(\"cwd\"));\n    │...\n  71│            Err(_) => {\n *72│                eprintln!(\"disk-floor: --floor-gb takes whole GiB, got {v}\");\n  73│                std::process::exit(2);\n  74│            }\n  75│        },\n    │...\n  82│        Err(e) => {\n *83│            eprintln!(\"disk-floor: cannot read free space at {}: {e}\", path.display());\n  84│            std::process::exit(2);\n  85│        }\n  86│    };\n    │...\n 140│\n*141│    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 142│    #[test]\n 143│    fn the_line_carries_the_golden_runners_keys() {\n 144│        // Pinned as TEXT because its whole purpose is that one grep reads a\n    │...\n 156│\n*157│    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 158│    #[test]\n 159│    fn the_floor_refuses_below_and_admits_at_or_above() {\n 160│        let floor = 32 * GIB;\n    │...\n 167│\n*168│    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 169│    #[test]\n 170│    fn a_zero_floor_is_print_only_and_never_refuses() {\n 171│        assert!(admits(0, 0), \"print-only mode records without owning a refusal\");\n    │...\n 178│\n*179│    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 180│    #[test]\n 181│    fn the_drive_is_spelled_the_way_the_golden_runner_spells_it() {\n 182│        // Caught live, not in review: the first build printed `drive=\\\\?\\C:\\`\n    │...\n 200│\n*201│    // [unit->REQ-DISK-FLOOR-PREFLIGHT]\n 202│    #[test]\n 203│    fn the_reader_returns_a_real_reading_for_a_real_directory() {\n 204│        // An absence is data only if the thing has a way to appear: without\n### main.rs\n 69│        \"pick-audit\" => pickaudit::pick_audit(&args[1..]),\n*70│        \"disk-floor\" => diskfloor::disk_floor(&args[1..]),\n 71│        \"bench-wrap\" => bench_wrap(&args[1..]),\n 72│        \"bench-report\" => bench_report(&args[1..]),\n 73│        \"pool-claim\" => pool_claim(&args[1..]),\n   │...\n 85│            eprintln!(\n*86│                \"usage: xtask <gen|check|brain-read-check|binedge-check [--no-prebuilds] [--baseline|--write-baseline] [--sites]|perjob-map|pick-audit --range <base>..<head> --lane <base>..<tip> [--lane <base>..<tip>] [--pair <lane-rev>:<pick-rev>] [--repo <dir>]|disk-floor [--path <dir>] [--floor-gb <n>] [--label <lane>]|docs-bundle <out.tar.gz>|bench-wrap --step <name> [--key <k>] -- <cmd...>|bench-report [--top <n>] [--window-hours <h>]|pool-claim --pool <dir> --label <lane> [--holder-pid <pid>] [--fo...\n 87│            );\n 88│            std::process::exit(2);\n 89│        }\n\n# .github/bench/\n## launch-battery.py\n 30│So this tool verifies the child AND its descendants — `a pid is not a tree`\n*31│(IR-80/IR-81) applies to reading an environment exactly as it does to killing.\n 32│The `.env` sidecar records every process actually inspected, by pid, so the\n 33│claim's SCOPE is on disk and not in a sentence.\n 34│","linesTruncated":true,"meta":{"limits":{"columnTruncated":{"maxColumn":512}}}},"isError":false,"timestamp":1789107077849}}
{"type":"custom_message","customType":"irc:incoming","content":"<irc>\nIncoming IRC message from agent `InfraFirstHalf`:\n\nAssigned first-range population is all IR-1–54 inclusive (54 exact IDs; IR-31 headingless inside IR-30). No IR split at 3000: only CI-RIDER historical section continues through 3021; IR-55 opens 3022. I read history through 3021 for boundary.\n\nSent while waiting/working. Active interruptible wait stopped early for immediate reading.\n\nIf response expected, reply via `hub` (`op: \"send\"`, `to: \"InfraFirstHalf\"`); may finish current step first. No one replies on your behalf.\n</irc>","display":true,"details":{"id":"157b1333d6ebfa8a","from":"InfraFirstHalf","message":"Assigned first-range population is all IR-1–54 inclusive (54 exact IDs; IR-31 headingless inside IR-30). No IR split at 3000: only CI-RIDER historical section continues through 3021; IR-55 opens 3022. I read history through 3021 for boundary."},"attribution":"agent","id":"eaf59f34","parentId":"00a80233","timestamp":"2026-09-11T06:11:16.955Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_RtmbuzsyOUvRhdZy0UlOAc3Y|fc_0330c101aa2c61dc016aa39b91a14c87d188ef3ea0515815df","toolName":"read","startedAt":"2026-09-11T06:11:32.050Z","args":{"path":".spt/preserved/infra-close069-20260911/audit.json:1-80"},"intent":"Reading prior per-entry audit"},"id":"78e1bd4c","parentId":"eaf59f34","timestamp":"2026-09-11T06:11:32.050Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_RY7T6HYt9UdzSlx0c6KSrR7l|fc_0330c101aa2c61dc016aa39b91a16487d1a7fb513e233beaf7","toolName":"read","startedAt":"2026-09-11T06:11:32.050Z","args":{"path":"PRD.md:1-35"},"intent":"Reading requirement scope orientation"},"id":"5d87903f","parentId":"78e1bd4c","timestamp":"2026-09-11T06:11:32.050Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_HT9JOiFNG0mDlj4M7D79x2J4|fc_0330c101aa2c61dc016aa39b91a16c87d1899bceec2dd22ca8","toolName":"read","startedAt":"2026-09-11T06:11:32.050Z","args":{"path":"ROADMAP.md:1-30"},"intent":"Reading delivery path orientation"},"id":"35278d9d","parentId":"5d87903f","timestamp":"2026-09-11T06:11:32.050Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_TltIlR9hv3bQA8P6Cu31qq3X|fc_0330c101aa2c61dc016aa39b91a17487d1b7a3238cfc0984f8","toolName":"read","startedAt":"2026-09-11T06:11:32.050Z","args":{"path":"docs/KNOWN-HAZARDS.md:1-35"},"intent":"Reading hazard scope orientation"},"id":"1b8ed001","parentId":"35278d9d","timestamp":"2026-09-11T06:11:32.050Z"}
{"type":"message","id":"1cbbda1d","parentId":"1b8ed001","timestamp":"2026-09-11T06:11:32.050Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Auditing prior trigger JSON**"},{"type":"toolCall","id":"call_RtmbuzsyOUvRhdZy0UlOAc3Y|fc_0330c101aa2c61dc016aa39b91a14c87d188ef3ea0515815df","name":"read","arguments":{"i":"Reading prior per-entry audit","path":".spt/preserved/infra-close069-20260911/audit.json:1-80"},"intent":"Reading prior per-entry audit"},{"type":"toolCall","id":"call_RY7T6HYt9UdzSlx0c6KSrR7l|fc_0330c101aa2c61dc016aa39b91a16487d1a7fb513e233beaf7","name":"read","arguments":{"i":"Reading requirement scope orientation","path":"PRD.md:1-35"},"intent":"Reading requirement scope orientation"},{"type":"toolCall","id":"call_HT9JOiFNG0mDlj4M7D79x2J4|fc_0330c101aa2c61dc016aa39b91a16c87d1899bceec2dd22ca8","name":"read","arguments":{"i":"Reading delivery path orientation","path":"ROADMAP.md:1-30"},"intent":"Reading delivery path orientation"},{"type":"toolCall","id":"call_TltIlR9hv3bQA8P6Cu31qq3X|fc_0330c101aa2c61dc016aa39b91a17487d1b7a3238cfc0984f8","name":"read","arguments":{"i":"Reading hazard scope orientation","path":"docs/KNOWN-HAZARDS.md:1-35"},"intent":"Reading hazard scope orientation"},{"type":"toolCall","id":"call_r0SHGZrTU5zC7GvASh2vHzDY|fc_0330c101aa2c61dc016aa39b91a17c87d19a95d99182d47de3","name":"read","arguments":{"i":"Reading storage orientation","path":"docs/STORAGE.md:1-25"},"intent":"Reading storage orientation"},{"type":"toolCall","id":"call_CuME8lwpTSUP149w8xjZtwqu|fc_0330c101aa2c61dc016aa39b91a18487d1a20c6ca7aa94c531","name":"read","arguments":{"i":"Reading manifest orientation","path":"docs/MANIFEST.md:1-25"},"intent":"Reading manifest orientation"},{"type":"toolCall","id":"call_lXruGZI0Kjb6ScADnsADpFhb|fc_0330c101aa2c61dc016aa39b91a18887d1b671708916734e6e","name":"read","arguments":{"i":"Reading memory orientation","path":"docs/CONTEXT-MEMORY.md:1-25"},"intent":"Reading memory orientation"},{"type":"toolCall","id":"call_4YHLPV3LQqPCUFsecbLZ2oW9|fc_0330c101aa2c61dc016aa39b91a18c87d1aa9ce876ee96ebf1","name":"read","arguments":{"i":"Reading documentation audience rules","path":"docs/DOCS-STRATEGY.md:1-30"},"intent":"Reading documentation audience rules"},{"type":"toolCall","id":"call_BZLAIiMxzrNzT7HCmPSuDcjr|fc_0330c101aa2c61dc016aa39b91a19487d1a66b5eae23c7f1c1","name":"read","arguments":{"i":"Reading traceability orientation","path":"docs/TRACEABILITY.md:1-25"},"intent":"Reading traceability orientation"},{"type":"toolCall","id":"call_NhO1SM3Z9tXMJIAGwPK6q8W3|fc_0330c101aa2c61dc016aa39b91a19887d18e32ca2e2d617b18","name":"read","arguments":{"i":"Reading golden workflow decisions","path":"docs/adr/0050-golden-ci-merge-integration.md:1-70"},"intent":"Reading golden workflow decisions"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":5181,"output":339,"cacheRead":95360,"cacheWrite":0,"totalTokens":100880,"reasoningTokens":14,"cost":{"input":0.05181,"output":0.01695,"cacheRead":0.09536,"cacheWrite":0,"total":0.16412}},"stopReason":"toolUse","timestamp":1789107077892,"responseId":"resp_0330c101aa2c61dc016aa39b83de8c87d18db4c42e70b1ab19","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0330c101aa2c61dc016aa39b877dbc87d1bd9c4c6c652f4c6a","type":"reasoning","content":[],"encrypted_content":"gAAAAABqo5uRHi_3hynEW6jkZDNMJ5hxjEN3ZRBK7dEqy20ced32-GKV-YlF55PC4BsNAWSKZqc9mTy2kVw3SjhQMU9eA4pgBWO5PLta2_DpWcZhJIdTVh9UPifVw3V_41UQWe-_VXYSUQusnCUmomVOGFAhixSjWl444722Yyci9GcGWCzve3B0ZroJa9zTdymuyf3nZrGT1qOmDtDWcrrY_pQ7ws_lzg2A4D_U93rq4lqP-EIPbEM0ueod-qHqgkVAR9kZjfYbNW_A9X9uxxzLbQXBxpXgCVFKhZ4qFbRIEWr6F21u3fqrdBbgv_aAgh1T-vzKAeYpiQQoIxwOoCxOirw2I1736UehlG-TEX-GXJBVcG58VOIn8bjtJ0QLy0scRGuUzYtWWiH30ymCxMMzSwCxZlAuM0NJLmbZOwTiqS9Wa8M5m18Quz899l1eVBVfux7QIns4G7dgbFmGZpG1L0v8u0ncKXtWMpaerPxChgaQODI5ljjhNqRdodfpHLc_qWasy871M9LY6iHgbQXHDtfEwNGzna4WjPsMZIHLoa2YudTq0X8mBQ7f4FWAiOiHonUEkJ2ccClf4UcZuhFC799eWdQMjK2Z2W4fExnWWltHTWAfb5JnW8-lJ3bt5Spaxd6hJPDa-npedN0xSvvt5B4Lk4ZmYr8C9ez0LdRxqn876cWw-r1KqYzNA0aHgf0IUsuAywueR9H16pkanL0PxV7UT4qqcjHn6elX_EnQ8iHQwlO-II2xqq0gVUbDcyeWSgkVJEgCSMRHOM_-J1O3WQ-NcuLNRqnubkUdnLxmHzs3cWL2sfGjMumqxQeG8OPsXocsVq0F_GfaEnCXgpYyxKPs5HlDmWrmG4oWGJ6ctWXYvyiIOsuOjdQNfvXgpymmp28hP_aCI9Gof13FhqWggM7NTuijC17gcNcEhyehANwLwdsiE2nGQjDETMVv7vorh3l0BHOc8nVtR8ABHokSZbWQEIiIqJ4C52y_GZvwZ7gklSK2PCcCCNWOqzppbDIGHhXZhSvs_gC7WXV85jcgKib1qStRg8bE_Kw1jiYOPefFewBemWf5QmFSY4rnhGgDKkSUMoEFiKz6M9drAf4bxW4Ow0T_nHUaVK-1kQBK6gbDVAQ5cVnWYkvMKxdfqwBA7lEz23JsHsGtWzr2xhGs5GL9Gw-fkgldrXizh5oW8LtC1maYNKPoGWlyfGbJNZrwuQ2RIAEYWDEkZwL62shSV35eI5a6EUA4qOuETScUvoFjxQi9hwImcT919PQ6QlKOkGYMWw5ObqVfnSZHerV5vfjkvB790W8kBxSqDd1ygUfXRVBxw-1pQL92Tg6-w_0hslXtlXFLQLLc-oMe2EhNtxzvNcZwCg==","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"summary":[{"type":"summary_text","text":"**Auditing prior trigger JSON**"}],"metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a14c87d188ef3ea0515815df","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading prior per-entry audit\",\"path\":\".spt/preserved/infra-close069-20260911/audit.json:1-80\"}","call_id":"call_RtmbuzsyOUvRhdZy0UlOAc3Y","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a16487d1a7fb513e233beaf7","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading requirement scope orientation\",\"path\":\"PRD.md:1-35\"}","call_id":"call_RY7T6HYt9UdzSlx0c6KSrR7l","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a16c87d1899bceec2dd22ca8","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading delivery path orientation\",\"path\":\"ROADMAP.md:1-30\"}","call_id":"call_HT9JOiFNG0mDlj4M7D79x2J4","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a17487d1b7a3238cfc0984f8","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading hazard scope orientation\",\"path\":\"docs/KNOWN-HAZARDS.md:1-35\"}","call_id":"call_TltIlR9hv3bQA8P6Cu31qq3X","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a17c87d19a95d99182d47de3","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading storage orientation\",\"path\":\"docs/STORAGE.md:1-25\"}","call_id":"call_r0SHGZrTU5zC7GvASh2vHzDY","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a18487d1a20c6ca7aa94c531","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading manifest orientation\",\"path\":\"docs/MANIFEST.md:1-25\"}","call_id":"call_CuME8lwpTSUP149w8xjZtwqu","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a18887d1b671708916734e6e","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading memory orientation\",\"path\":\"docs/CONTEXT-MEMORY.md:1-25\"}","call_id":"call_lXruGZI0Kjb6ScADnsADpFhb","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a18c87d1aa9ce876ee96ebf1","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading documentation audience rules\",\"path\":\"docs/DOCS-STRATEGY.md:1-30\"}","call_id":"call_4YHLPV3LQqPCUFsecbLZ2oW9","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a19487d1a66b5eae23c7f1c1","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading traceability orientation\",\"path\":\"docs/TRACEABILITY.md:1-25\"}","call_id":"call_BZLAIiMxzrNzT7HCmPSuDcjr","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39b91a19887d18e32ca2e2d617b18","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading golden workflow decisions\",\"path\":\"docs/adr/0050-golden-ci-merge-integration.md:1-70\"}","call_id":"call_NhO1SM3Z9tXMJIAGwPK6q8W3","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}}]},"duration":14156.108700000681,"ttft":4072.4787000007927,"completedAt":1789107092048,"contextSnapshot":{"promptTokens":100541,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_r0SHGZrTU5zC7GvASh2vHzDY|fc_0330c101aa2c61dc016aa39b91a17c87d19a95d99182d47de3","toolName":"read","startedAt":"2026-09-11T06:11:32.051Z","args":{"path":"docs/STORAGE.md:1-25"},"intent":"Reading storage orientation"},"id":"41991e8e","parentId":"1cbbda1d","timestamp":"2026-09-11T06:11:32.051Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_CuME8lwpTSUP149w8xjZtwqu|fc_0330c101aa2c61dc016aa39b91a18487d1a20c6ca7aa94c531","toolName":"read","startedAt":"2026-09-11T06:11:32.051Z","args":{"path":"docs/MANIFEST.md:1-25"},"intent":"Reading manifest orientation"},"id":"bc16f29f","parentId":"41991e8e","timestamp":"2026-09-11T06:11:32.051Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_lXruGZI0Kjb6ScADnsADpFhb|fc_0330c101aa2c61dc016aa39b91a18887d1b671708916734e6e","toolName":"read","startedAt":"2026-09-11T06:11:32.051Z","args":{"path":"docs/CONTEXT-MEMORY.md:1-25"},"intent":"Reading memory orientation"},"id":"2d7e7be2","parentId":"bc16f29f","timestamp":"2026-09-11T06:11:32.051Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_4YHLPV3LQqPCUFsecbLZ2oW9|fc_0330c101aa2c61dc016aa39b91a18c87d1aa9ce876ee96ebf1","toolName":"read","startedAt":"2026-09-11T06:11:32.051Z","args":{"path":"docs/DOCS-STRATEGY.md:1-30"},"intent":"Reading documentation audience rules"},"id":"8cf4b19e","parentId":"2d7e7be2","timestamp":"2026-09-11T06:11:32.051Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_BZLAIiMxzrNzT7HCmPSuDcjr|fc_0330c101aa2c61dc016aa39b91a19487d1a66b5eae23c7f1c1","toolName":"read","startedAt":"2026-09-11T06:11:32.051Z","args":{"path":"docs/TRACEABILITY.md:1-25"},"intent":"Reading traceability orientation"},"id":"b8de5896","parentId":"8cf4b19e","timestamp":"2026-09-11T06:11:32.051Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_NhO1SM3Z9tXMJIAGwPK6q8W3|fc_0330c101aa2c61dc016aa39b91a19887d18e32ca2e2d617b18","toolName":"read","startedAt":"2026-09-11T06:11:32.051Z","args":{"path":"docs/adr/0050-golden-ci-merge-integration.md:1-70"},"intent":"Reading golden workflow decisions"},"id":"1cb74aa9","parentId":"b8de5896","timestamp":"2026-09-11T06:11:32.051Z"}
{"type":"message","id":"cd307dda","parentId":"1cb74aa9","timestamp":"2026-09-11T06:11:32.063Z","message":{"role":"toolResult","toolCallId":"call_RtmbuzsyOUvRhdZy0UlOAc3Y|fc_0330c101aa2c61dc016aa39b91a14c87d188ef3ea0515815df","toolName":"read","content":[{"type":"text","text":"{\n  \"source_sha\": \"e5a2fed9badcac399e2fb825a1fc035cee981a39\",\n  \"release_sha\": \"16df0e41be04ca4614a792f7e70e4d1bdec60b24\",\n  \"date\": \"2026-09-11\",\n  \"population\": [\n    1,\n    2,\n    3,\n    4,\n    5,\n    6,\n    7,\n    8,\n    9,\n    10,\n    11,\n    12,\n    13,\n    14,\n    15,\n    16,\n    17,\n    18,\n    19,\n    20,\n    21,\n    22,\n    23,\n    24,\n    25,\n    26,\n    27,\n    28,\n    29,\n    30,\n    31,\n    32,\n    33,\n    34,\n    35,\n    36,\n    37,\n    38,\n    39,\n    40,\n    41,\n    42,\n    43,\n    44,\n    45,\n    46,\n    47,\n    48,\n    49,\n    50,\n    51,\n    52,\n    53,\n    54,\n    55,\n    56,\n    57,\n    58,\n    59,\n    60,\n    61,\n    62,\n    63,\n    64,\n    65,\n    66,\n    67,\n    68,\n    69,\n    70,\n    71,\n    72,\n    73,\n    74,\n    75,\n    76,\n    77,\n    78,\n…\n  ],\n…\n}\n\n[Showing lines 1-83 of 204. Use :84 to continue]"}],"details":{"truncation":{"content":"{\n  \"source_sha\": \"e5a2fed9badcac399e2fb825a1fc035cee981a39\",\n  \"release_sha\": \"16df0e41be04ca4614a792f7e70e4d1bdec60b24\",\n  \"date\": \"2026-09-11\",\n  \"population\": [\n    1,\n    2,\n    3,\n    4,\n    5,\n    6,\n    7,\n    8,\n    9,\n    10,\n    11,\n    12,\n    13,\n    14,\n    15,\n    16,\n    17,\n    18,\n    19,\n    20,\n    21,\n    22,\n    23,\n    24,\n    25,\n    26,\n    27,\n    28,\n    29,\n    30,\n    31,\n    32,\n    33,\n    34,\n    35,\n    36,\n    37,\n    38,\n    39,\n    40,\n    41,\n    42,\n    43,\n    44,\n    45,\n    46,\n    47,\n    48,\n    49,\n    50,\n    51,\n    52,\n    53,\n    54,\n    55,\n    56,\n    57,\n    58,\n    59,\n    60,\n    61,\n    62,\n    63,\n    64,\n    65,\n    66,\n    67,\n    68,\n    69,\n    70,\n    71,\n    72,\n    73,\n    74,\n    75,\n    76,\n    77,\n    78,","truncated":true,"truncatedBy":"lines","totalLines":204,"totalBytes":779,"outputLines":83,"outputBytes":779,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":204,"displayContent":{"text":"{\n  \"source_sha\": \"e5a2fed9badcac399e2fb825a1fc035cee981a39\",\n  \"release_sha\": \"16df0e41be04ca4614a792f7e70e4d1bdec60b24\",\n  \"date\": \"2026-09-11\",\n  \"population\": [\n    1,\n    2,\n    3,\n    4,\n    5,\n    6,\n    7,\n    8,\n    9,\n    10,\n    11,\n    12,\n    13,\n    14,\n    15,\n    16,\n    17,\n    18,\n    19,\n    20,\n    21,\n    22,\n    23,\n    24,\n    25,\n    26,\n    27,\n    28,\n    29,\n    30,\n    31,\n    32,\n    33,\n    34,\n    35,\n    36,\n    37,\n    38,\n    39,\n    40,\n    41,\n    42,\n    43,\n    44,\n    45,\n    46,\n    47,\n    48,\n    49,\n    50,\n    51,\n    52,\n    53,\n    54,\n    55,\n    56,\n    57,\n    58,\n    59,\n    60,\n    61,\n    62,\n    63,\n    64,\n    65,\n    66,\n    67,\n    68,\n    69,\n    70,\n    71,\n    72,\n    73,\n    74,\n    75,\n    76,\n    77,\n    78,\n…\n  ],\n…\n}","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,null,103,null,204]},"fileSize":41129,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.spt\\preserved\\infra-close069-20260911\\audit.json"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":204,"totalBytes":779,"outputLines":83,"outputBytes":779,"shownRange":{"start":1,"end":83},"nextOffset":84}}},"isError":false,"timestamp":1789107092062}}
{"type":"message","id":"818f8eeb","parentId":"cd307dda","timestamp":"2026-09-11T06:11:32.065Z","message":{"role":"toolResult","toolCallId":"call_TltIlR9hv3bQA8P6Cu31qq3X|fc_0330c101aa2c61dc016aa39b91a17487d1b7a3238cfc0984f8","toolName":"read","content":[{"type":"text","text":"# Known Hazards\n\nHard-won edge cases harvested from the sister project (`claude_skill_owl`, ~80 commits / 12+ phases / multiple production incidents). Per ADR-0001, this is a **test checklist for the spt-core rebuild** — the clean-room rebuild must re-satisfy each invariant rather than re-discover the bug.\n\n**Architecture-translation note.** The sister project runs poll listeners and Psyche wrappers as *separate processes*. spt-core consolidates both into the one `spt-daemon` (brain), with a stable broker beneath it (ADR-0004). Many hazards below were inter-process races in the sister project; in spt-core some become intra-daemon concerns (potentially easier) while others move to the daemon↔broker IPC boundary or the network boundary (potentially new failure surface). Each entry notes the mapping where it differs. Citations point at sister-project paths for reference, not at spt-core.\n\n---\n\n## 1. Race conditions & ordering\n\n### 1.1 Phantom INIT_SIGNOFF after grace period\n- **Failure:** orphan teardown enqueues INIT_SIGNOFF before the grace-period recheck; a transient Self recovery (binary handoff, brief stale poll) makes the recheck pass-as-alive, but the signoff was already spooled and drains on the next iteration → teardown despite a live Self.\n- **Invariant:** grace-period wait MUST complete *before* composing/delivering INIT_SIGNOFF; the recheck must bind `still_gone` before any envelope write.\n- **spt-core mapping:** in-daemon now (no separate wrapper), but the ordering invariant is identical — orphan/teardown logic must re-evaluate liveness after the grace wait, not before enqueue.\n- **Sister cite:** `src/live/wrapper/orphan.rs:201-259` (sleep@209 precedes compose@231-251); tests T-grace-recovery:576, T-still-gone-recheck:618.\n\n### 1.2 Poll-rewrite race & info.json mid-write reads\n- **Failure:** `info.json` written by the wrapper mid-iteration while a list/classify command reads it → torn read, misclassification.\n- **Invariant:** consult liveness via the supervisor (`is_wrapper_alive`-equivalent) before any grace gate; reads of state files must tolerate concurrent writes (atomic write + rename, or read-retry).\n- **spt-core mapping:** the daemon owns both writer and reader → use in-process locking/snapshotting instead of racing on disk. Cross-node registry reads remain eventually-consistent and must tolerate staleness.\n- **Sister cite:** `src/common/list_filter.rs:100-150`; `src/owl/poll.rs:141`.\n\n### 1.3 Stale `index.lock` wedge from prior git crash\n- **Failure:** crashed git leaves a 0-byte `index.lock` in a psyche tracked worktree; every later commit blocks forever.\n- **Invariant:** on daemon boot, sweep seed + all agent/project worktrees for stale locks (0 bytes, mtime > 60s) and remove; leave live locks alone.\n- **spt-core mapping:** cross-node Psyche sync (ADR-0002/0003) replaces git-repo sync, so the *git* lock may disappear — but any equivalent lockfile in the new sync mechanism needs the same stale-sweep on boot.\n- **Sister cite:** CHANGELOG v1.11.20 \"Stale `index.lock`\"; `src/common/git.rs`.\n\n### 1.4 Deferred spool rows must not leak to the event stream\n- **Failure:** a hook spools a deferred (spool-only, no TCP wake) notice; startup `drain_all` flushes ALL rows including deferred → event emitted at wrong time/priority.\n- **Invariant:** startup drain (and idle/timeout TCP-wake sites) use `drain_non_deferred` only; deferred rows are picked up by their intended consumer via `peek`. All drain sites must agree on which rows they flush.\n- **spt-core mapping:** carries directly — the daemon's spool-drain has the same deferred-vs-immediate distinction.\n- **Sister cite:** `src/owl/poll.rs:276-316`; `spool::drain_non_deferred_with_metadata`.\n\n### 1.5 Worker (working-perch) lifecycle path consistency\n- **Failure:** subagent-start creates the perch at one path layout; later hooks read it at another → not found; stop-hook scan misses nested perches.\n- **Invariant:** all Worker/Psyche child-perch path composition routes through one central resolver; no divergent path construction across hooks.\n- **spt-core mapping:** `Worker` is a day-one endpoint type; the daemon owns the registry, so perch location is a registry lookup, not ad-hoc path math. Single source of truth for instance→location.\n…\n\n…\n\n…\n<!-- [doc->REQ-HAZARD-EMPOWER-SESSION-RESURRECT] -->\n\n[Showing lines 1-38 of 1132. Use :39 to continue]"}],"details":{"truncation":{"content":"# Known Hazards\r\n\r\nHard-won edge cases harvested from the sister project (`claude_skill_owl`, ~80 commits / 12+ phases / multiple production incidents). Per ADR-0001, this is a **test checklist for the spt-core rebuild** — the clean-room rebuild must re-satisfy each invariant rather than re-discover the bug.\r\n\r\n**Architecture-translation note.** The sister project runs poll listeners and Psyche wrappers as *separate processes*. spt-core consolidates both into the one `spt-daemon` (brain), with a stable broker beneath it (ADR-0004). Many hazards below were inter-process races in the sister project; in spt-core some become intra-daemon concerns (potentially easier) while others move to the daemon↔broker IPC boundary or the network boundary (potentially new failure surface). Each entry notes the mapping where it differs. Citations point at sister-project paths for reference, not at spt-core.\r\n\r\n---\r\n\r\n## 1. Race conditions & ordering\r\n\r\n### 1.1 Phantom INIT_SIGNOFF after grace period\r\n- **Failure:** orphan teardown enqueues INIT_SIGNOFF before the grace-period recheck; a transient Self recovery (binary handoff, brief stale poll) makes the recheck pass-as-alive, but the signoff was already spooled and drains on the next iteration → teardown despite a live Self.\r\n- **Invariant:** grace-period wait MUST complete *before* composing/delivering INIT_SIGNOFF; the recheck must bind `still_gone` before any envelope write.\r\n- **spt-core mapping:** in-daemon now (no separate wrapper), but the ordering invariant is identical — orphan/teardown logic must re-evaluate liveness after the grace wait, not before enqueue.\r\n- **Sister cite:** `src/live/wrapper/orphan.rs:201-259` (sleep@209 precedes compose@231-251); tests T-grace-recovery:576, T-still-gone-recheck:618.\r\n\r\n### 1.2 Poll-rewrite race & info.json mid-write reads\r\n- **Failure:** `info.json` written by the wrapper mid-iteration while a list/classify command reads it → torn read, misclassification.\r\n- **Invariant:** consult liveness via the supervisor (`is_wrapper_alive`-equivalent) before any grace gate; reads of state files must tolerate concurrent writes (atomic write + rename, or read-retry).\r\n- **spt-core mapping:** the daemon owns both writer and reader → use in-process locking/snapshotting instead of racing on disk. Cross-node registry reads remain eventually-consistent and must tolerate staleness.\r\n- **Sister cite:** `src/common/list_filter.rs:100-150`; `src/owl/poll.rs:141`.\r\n\r\n### 1.3 Stale `index.lock` wedge from prior git crash\r\n- **Failure:** crashed git leaves a 0-byte `index.lock` in a psyche tracked worktree; every later commit blocks forever.\r\n- **Invariant:** on daemon boot, sweep seed + all agent/project worktrees for stale locks (0 bytes, mtime > 60s) and remove; leave live locks alone.\r\n- **spt-core mapping:** cross-node Psyche sync (ADR-0002/0003) replaces git-repo sync, so the *git* lock may disappear — but any equivalent lockfile in the new sync mechanism needs the same stale-sweep on boot.\r\n- **Sister cite:** CHANGELOG v1.11.20 \"Stale `index.lock`\"; `src/common/git.rs`.\r\n\r\n### 1.4 Deferred spool rows must not leak to the event stream\r\n- **Failure:** a hook spools a deferred (spool-only, no TCP wake) notice; startup `drain_all` flushes ALL rows including deferred → event emitted at wrong time/priority.\r\n- **Invariant:** startup drain (and idle/timeout TCP-wake sites) use `drain_non_deferred` only; deferred rows are picked up by their intended consumer via `peek`. All drain sites must agree on which rows they flush.\r\n- **spt-core mapping:** carries directly — the daemon's spool-drain has the same deferred-vs-immediate distinction.\r\n- **Sister cite:** `src/owl/poll.rs:276-316`; `spool::drain_non_deferred_with_metadata`.\r\n\r\n### 1.5 Worker (working-perch) lifecycle path consistency\r\n- **Failure:** subagent-start creates the perch at one path layout; later hooks read it at another → not found; stop-hook scan misses nested perches.\r\n- **Invariant:** all Worker/Psyche child-perch path composition routes through one central resolver; no divergent path construction across hooks.\r\n- **spt-core mapping:** `Worker` is a day-one endpoint type; the daemon owns the registry, so perch location is a registry lookup, not ad-hoc path math. Single source of truth for instance→location.\r","truncated":true,"truncatedBy":"lines","totalLines":1132,"totalBytes":4329,"outputLines":38,"outputBytes":4329,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":1132,"displayContent":{"text":"# Known Hazards\r\n\r\nHard-won edge cases harvested from the sister project (`claude_skill_owl`, ~80 commits / 12+ phases / multiple production incidents). Per ADR-0001, this is a **test checklist for the spt-core rebuild** — the clean-room rebuild must re-satisfy each invariant rather than re-discover the bug.\r\n\r\n**Architecture-translation note.** The sister project runs poll listeners and Psyche wrappers as *separate processes*. spt-core consolidates both into the one `spt-daemon` (brain), with a stable broker beneath it (ADR-0004). Many hazards below were inter-process races in the sister project; in spt-core some become intra-daemon concerns (potentially easier) while others move to the daemon↔broker IPC boundary or the network boundary (potentially new failure surface). Each entry notes the mapping where it differs. Citations point at sister-project paths for reference, not at spt-core.\r\n\r\n---\r\n\r\n## 1. Race conditions & ordering\r\n\r\n### 1.1 Phantom INIT_SIGNOFF after grace period\r\n- **Failure:** orphan teardown enqueues INIT_SIGNOFF before the grace-period recheck; a transient Self recovery (binary handoff, brief stale poll) makes the recheck pass-as-alive, but the signoff was already spooled and drains on the next iteration → teardown despite a live Self.\r\n- **Invariant:** grace-period wait MUST complete *before* composing/delivering INIT_SIGNOFF; the recheck must bind `still_gone` before any envelope write.\r\n- **spt-core mapping:** in-daemon now (no separate wrapper), but the ordering invariant is identical — orphan/teardown logic must re-evaluate liveness after the grace wait, not before enqueue.\r\n- **Sister cite:** `src/live/wrapper/orphan.rs:201-259` (sleep@209 precedes compose@231-251); tests T-grace-recovery:576, T-still-gone-recheck:618.\r\n\r\n### 1.2 Poll-rewrite race & info.json mid-write reads\r\n- **Failure:** `info.json` written by the wrapper mid-iteration while a list/classify command reads it → torn read, misclassification.\r\n- **Invariant:** consult liveness via the supervisor (`is_wrapper_alive`-equivalent) before any grace gate; reads of state files must tolerate concurrent writes (atomic write + rename, or read-retry).\r\n- **spt-core mapping:** the daemon owns both writer and reader → use in-process locking/snapshotting instead of racing on disk. Cross-node registry reads remain eventually-consistent and must tolerate staleness.\r\n- **Sister cite:** `src/common/list_filter.rs:100-150`; `src/owl/poll.rs:141`.\r\n\r\n### 1.3 Stale `index.lock` wedge from prior git crash\r\n- **Failure:** crashed git leaves a 0-byte `index.lock` in a psyche tracked worktree; every later commit blocks forever.\r\n- **Invariant:** on daemon boot, sweep seed + all agent/project worktrees for stale locks (0 bytes, mtime > 60s) and remove; leave live locks alone.\r\n- **spt-core mapping:** cross-node Psyche sync (ADR-0002/0003) replaces git-repo sync, so the *git* lock may disappear — but any equivalent lockfile in the new sync mechanism needs the same stale-sweep on boot.\r\n- **Sister cite:** CHANGELOG v1.11.20 \"Stale `index.lock`\"; `src/common/git.rs`.\r\n\r\n### 1.4 Deferred spool rows must not leak to the event stream\r\n- **Failure:** a hook spools a deferred (spool-only, no TCP wake) notice; startup `drain_all` flushes ALL rows including deferred → event emitted at wrong time/priority.\r\n- **Invariant:** startup drain (and idle/timeout TCP-wake sites) use `drain_non_deferred` only; deferred rows are picked up by their intended consumer via `peek`. All drain sites must agree on which rows they flush.\r\n- **spt-core mapping:** carries directly — the daemon's spool-drain has the same deferred-vs-immediate distinction.\r\n- **Sister cite:** `src/owl/poll.rs:276-316`; `spool::drain_non_deferred_with_metadata`.\r\n\r\n### 1.5 Worker (working-perch) lifecycle path consistency\r\n- **Failure:** subagent-start creates the perch at one path layout; later hooks read it at another → not found; stop-hook scan misses nested perches.\r\n- **Invariant:** all Worker/Psyche child-perch path composition routes through one central resolver; no divergent path construction across hooks.\r\n- **spt-core mapping:** `Worker` is a day-one endpoint type; the daemon owns the registry, so perch location is a registry lookup, not ad-hoc path math. Single source of truth for instance→location.\r\n…\n\n…\n\n…\n<!-- [doc->REQ-HAZARD-EMPOWER-SESSION-RESURRECT] -->","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,null,40,null,42,null,1132]},"fileSize":360311,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\KNOWN-HAZARDS.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":1132,"totalBytes":4329,"outputLines":38,"outputBytes":4329,"shownRange":{"start":1,"end":38},"nextOffset":39}}},"isError":false,"timestamp":1789107092064}}
{"type":"message","id":"c8f2265d","parentId":"818f8eeb","timestamp":"2026-09-11T06:11:32.066Z","message":{"role":"toolResult","toolCallId":"call_RY7T6HYt9UdzSlx0c6KSrR7l|fc_0330c101aa2c61dc016aa39b91a16487d1a7fb513e233beaf7","toolName":"read","content":[{"type":"text","text":"# spt-core — Product Requirements Document\n\n> **Status:** draft, 2026-05-30. Synthesized from a grilling session.\n> Canonical detail lives in [`CONTEXT.md`](./CONTEXT.md) (glossary/model) and [`docs/adr/`](./docs/adr/) (decisions). This PRD states *what* and *why*; those state *meaning* and *rationale*. Where they conflict, the ADRs win.\n\n---\n\n## 1. Vision\n\nspt-core is a **harness-independent core for an agent ecosystem**: inter-agent messaging, live-agent lifecycle, terminal hosting, seamless self-update, and zero-config cross-machine networking — shipped as both a Rust library workspace and a single canonical binary (`spt` / `spt.exe`).\n\nIt is the ground-up rebuild of `claude_skill_owl` (\"modern SPT\"), untethering the system from Claude Code so that **any** agent runtime — Claude Code, Codex, Cursor, headless, or novel surfaces — can participate by either shelling out to the binary or linking the crates. The first thing built atop it is a rebuilt `spt` plugin reaching parity with today's system; the networking, terminal-wrapper, and multi-instance capabilities then make an agent reachable and operable across all of a user's machines.\n\n## 2. Problem & motivation\n\n- Today's modern SPT works but is **fragile** — each release introduces 2–5 regressions because it grew rapidly from a narrow starting point and carries the resulting tech debt (ADR-0001).\n- It is **welded to Claude Code**. Other harnesses can't reuse the messaging/lifecycle substrate.\n- Networking, terminal hosting (\"capsule\"), and cross-machine operation were planned piecemeal atop a CC-tied core; they deserve to be first-class in a clean foundation.\n\n## 3. Goals\n\n1. **Harness independence.** Zero knowledge of any specific agent runtime in core; all harness specifics behind a declarative contract (ADR — runtime model).\n2. **Dual deliverable.** First-class library crates *and* a canonical binary, wire-compatible (§Architecture).\n3. **Zero-config cross-machine messaging.** \"Just works\" WAN, baked in day-one (ADR-0002).\n4. **One agent, many machines.** The same agent runs natively on each of a user's machines with a synced mind; reachable and operable from anywhere (ADR-0003).\n5. **Seamless self-update** with a hard no-endpoint-termination invariant (ADR-0004).\n6. **A terminal backbone** that can host sessions headless and headed, locally and over WAN.\n7. **Low-friction, secure onboarding** — accountless node pairing (ADR-0005), one-line install, automatic legacy migration.\n\n## 4. Non-goals (v1)\n\n- **macOS support** — out (no test machine); kept structurally easy, not a re-architecture.\n- **Cross-subnet** (two *different* users' agents communicating) — deferred concept.\n- **Concrete Shells / PresenceChannel implementation / presence gossip** — only the seams ship (§Endpoints).\n- **Remote command execution on another user's node** and **instantiate-anywhere** — seam-compatible, deferred behind a consent/security gate.\n- **Sidecar adapter protocol**, **manifest includes**, **scrollback disk-spillover**, **predictive/state-sync terminal layer** — see [`docs/DEFERRED.md`](./docs/DEFERRED.md).\n- **A model/billing opinion** — SPT is not a harness; model choice is always the adapter's.\n\n…\n- Sister project networking research: `claude_skill_owl/docs/research/SPT Networked Messaging Research Brief.md`.\n\n[Showing lines 1-38 of 229. Use :39 to continue]"}],"details":{"truncation":{"content":"# spt-core — Product Requirements Document\r\n\r\n> **Status:** draft, 2026-05-30. Synthesized from a grilling session.\r\n> Canonical detail lives in [`CONTEXT.md`](./CONTEXT.md) (glossary/model) and [`docs/adr/`](./docs/adr/) (decisions). This PRD states *what* and *why*; those state *meaning* and *rationale*. Where they conflict, the ADRs win.\r\n\r\n---\r\n\r\n## 1. Vision\r\n\r\nspt-core is a **harness-independent core for an agent ecosystem**: inter-agent messaging, live-agent lifecycle, terminal hosting, seamless self-update, and zero-config cross-machine networking — shipped as both a Rust library workspace and a single canonical binary (`spt` / `spt.exe`).\r\n\r\nIt is the ground-up rebuild of `claude_skill_owl` (\"modern SPT\"), untethering the system from Claude Code so that **any** agent runtime — Claude Code, Codex, Cursor, headless, or novel surfaces — can participate by either shelling out to the binary or linking the crates. The first thing built atop it is a rebuilt `spt` plugin reaching parity with today's system; the networking, terminal-wrapper, and multi-instance capabilities then make an agent reachable and operable across all of a user's machines.\r\n\r\n## 2. Problem & motivation\r\n\r\n- Today's modern SPT works but is **fragile** — each release introduces 2–5 regressions because it grew rapidly from a narrow starting point and carries the resulting tech debt (ADR-0001).\r\n- It is **welded to Claude Code**. Other harnesses can't reuse the messaging/lifecycle substrate.\r\n- Networking, terminal hosting (\"capsule\"), and cross-machine operation were planned piecemeal atop a CC-tied core; they deserve to be first-class in a clean foundation.\r\n\r\n## 3. Goals\r\n\r\n1. **Harness independence.** Zero knowledge of any specific agent runtime in core; all harness specifics behind a declarative contract (ADR — runtime model).\r\n2. **Dual deliverable.** First-class library crates *and* a canonical binary, wire-compatible (§Architecture).\r\n3. **Zero-config cross-machine messaging.** \"Just works\" WAN, baked in day-one (ADR-0002).\r\n4. **One agent, many machines.** The same agent runs natively on each of a user's machines with a synced mind; reachable and operable from anywhere (ADR-0003).\r\n5. **Seamless self-update** with a hard no-endpoint-termination invariant (ADR-0004).\r\n6. **A terminal backbone** that can host sessions headless and headed, locally and over WAN.\r\n7. **Low-friction, secure onboarding** — accountless node pairing (ADR-0005), one-line install, automatic legacy migration.\r\n\r\n## 4. Non-goals (v1)\r\n\r\n- **macOS support** — out (no test machine); kept structurally easy, not a re-architecture.\r\n- **Cross-subnet** (two *different* users' agents communicating) — deferred concept.\r\n- **Concrete Shells / PresenceChannel implementation / presence gossip** — only the seams ship (§Endpoints).\r\n- **Remote command execution on another user's node** and **instantiate-anywhere** — seam-compatible, deferred behind a consent/security gate.\r\n- **Sidecar adapter protocol**, **manifest includes**, **scrollback disk-spillover**, **predictive/state-sync terminal layer** — see [`docs/DEFERRED.md`](./docs/DEFERRED.md).\r\n- **A model/billing opinion** — SPT is not a harness; model choice is always the adapter's.\r\n\r","truncated":true,"truncatedBy":"lines","totalLines":229,"totalBytes":3264,"outputLines":38,"outputBytes":3264,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":229,"displayContent":{"text":"# spt-core — Product Requirements Document\r\n\r\n> **Status:** draft, 2026-05-30. Synthesized from a grilling session.\r\n> Canonical detail lives in [`CONTEXT.md`](./CONTEXT.md) (glossary/model) and [`docs/adr/`](./docs/adr/) (decisions). This PRD states *what* and *why*; those state *meaning* and *rationale*. Where they conflict, the ADRs win.\r\n\r\n---\r\n\r\n## 1. Vision\r\n\r\nspt-core is a **harness-independent core for an agent ecosystem**: inter-agent messaging, live-agent lifecycle, terminal hosting, seamless self-update, and zero-config cross-machine networking — shipped as both a Rust library workspace and a single canonical binary (`spt` / `spt.exe`).\r\n\r\nIt is the ground-up rebuild of `claude_skill_owl` (\"modern SPT\"), untethering the system from Claude Code so that **any** agent runtime — Claude Code, Codex, Cursor, headless, or novel surfaces — can participate by either shelling out to the binary or linking the crates. The first thing built atop it is a rebuilt `spt` plugin reaching parity with today's system; the networking, terminal-wrapper, and multi-instance capabilities then make an agent reachable and operable across all of a user's machines.\r\n\r\n## 2. Problem & motivation\r\n\r\n- Today's modern SPT works but is **fragile** — each release introduces 2–5 regressions because it grew rapidly from a narrow starting point and carries the resulting tech debt (ADR-0001).\r\n- It is **welded to Claude Code**. Other harnesses can't reuse the messaging/lifecycle substrate.\r\n- Networking, terminal hosting (\"capsule\"), and cross-machine operation were planned piecemeal atop a CC-tied core; they deserve to be first-class in a clean foundation.\r\n\r\n## 3. Goals\r\n\r\n1. **Harness independence.** Zero knowledge of any specific agent runtime in core; all harness specifics behind a declarative contract (ADR — runtime model).\r\n2. **Dual deliverable.** First-class library crates *and* a canonical binary, wire-compatible (§Architecture).\r\n3. **Zero-config cross-machine messaging.** \"Just works\" WAN, baked in day-one (ADR-0002).\r\n4. **One agent, many machines.** The same agent runs natively on each of a user's machines with a synced mind; reachable and operable from anywhere (ADR-0003).\r\n5. **Seamless self-update** with a hard no-endpoint-termination invariant (ADR-0004).\r\n6. **A terminal backbone** that can host sessions headless and headed, locally and over WAN.\r\n7. **Low-friction, secure onboarding** — accountless node pairing (ADR-0005), one-line install, automatic legacy migration.\r\n\r\n## 4. Non-goals (v1)\r\n\r\n- **macOS support** — out (no test machine); kept structurally easy, not a re-architecture.\r\n- **Cross-subnet** (two *different* users' agents communicating) — deferred concept.\r\n- **Concrete Shells / PresenceChannel implementation / presence gossip** — only the seams ship (§Endpoints).\r\n- **Remote command execution on another user's node** and **instantiate-anywhere** — seam-compatible, deferred behind a consent/security gate.\r\n- **Sidecar adapter protocol**, **manifest includes**, **scrollback disk-spillover**, **predictive/state-sync terminal layer** — see [`docs/DEFERRED.md`](./docs/DEFERRED.md).\r\n- **A model/billing opinion** — SPT is not a harness; model choice is always the adapter's.\r\n\r\n…\n- Sister project networking research: `claude_skill_owl/docs/research/SPT Networked Messaging Research Brief.md`.","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,null,229]},"fileSize":32393,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\PRD.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":229,"totalBytes":3264,"outputLines":38,"outputBytes":3264,"shownRange":{"start":1,"end":38},"nextOffset":39}}},"isError":false,"timestamp":1789107092065}}
{"type":"message","id":"61d877e9","parentId":"c8f2265d","timestamp":"2026-09-11T06:11:32.067Z","message":{"role":"toolResult","toolCallId":"call_HT9JOiFNG0mDlj4M7D79x2J4|fc_0330c101aa2c61dc016aa39b91a16c87d1899bceec2dd22ca8","toolName":"read","content":[{"type":"text","text":"# spt-core Roadmap\n\n> Lightweight-but-structured path from design → fruition. Not a GSD/phase-gated process — a clear sequence with de-risk gates. Planning corpus is complete (PRD + CONTEXT + 5 ADRs + 6 design docs); this is how we build it.\n\n## End goal\n\nA harness-independent core for an agent ecosystem — messaging, live-agent lifecycle, terminal hosting, **first-class P2P networking**, and a runtime-manifest harness contract — shipped as Rust crates + a single `spt` binary. The proof: the same agent runs natively across all of a user's machines with a synced mind, reachable and operable from anywhere, with seamless self-update and zero-config cross-machine messaging. First thing built atop it: a rebuilt `spt` plugin at parity with today's modern SPT.\n\n## Scope decisions (locked)\n\n- **v1 = the full PRD, networking included.** The networked element is the *reason* spt-core exists; it is not deferrable to v1.1.\n- **The hard freeze on `claude_skill_owl` is not a clock.** It works today and delivers value as-is while spt-core is built — no schedule pressure from it.\n- **Process: lightweight but structured.** GSD is too heavy. This roadmap + the design docs are the structure.\n\n## Path to fruition (sequence)\n\n**Stage A — Red-team review (before building).** Pressure-test the design adversarially. Focus on the riskiest architectural decisions, not bikeshedding. Tools: `plan-eng-review` (architecture) + `codex` (adversarial second opinion). Scope-cutting is *not* a goal (v1 is locked as full PRD), but surfacing contradictions / over-engineering / unproven assumptions is.\n\n**Stage B — De-risk spikes.** Throwaway proofs of the load-bearing unknowns — anything that, if it fails, forces a redesign. Do these before committing to the full build. See *De-risk spikes* below.\n\n**Stage C — Walking skeleton.** Build the killer-quickstart slice end-to-end through the real crate boundaries: **two agents exchange a message** (first local; ultimately cross-node — the real proof). Validates the whole stack early; then thicken.\n\n**Stage D — Phased build (M0–M5).** Dependency-ordered, each milestone ships something usable.\n\n## Milestones (all v1)\n\n- **M0 — Workspace + commodity layer.** Cargo workspace; `spt-proto` (wire envelope grammar, endpoint types, framing, Ed25519 identity, typed+binary payloads) + `spt-store` (spool, perch layout, trust store, registry persistence). Copy-verbatim the stable formats from the sister project (ADR-0001).\n- **M1 — Local messaging + binary.** `spt-msg` (delivery TCP+spool, routing, send/ring/ready) + the `spt` binary + CLI. **= the killer quickstart (local): two agents exchange a message.** Task breakdown: [`M1-PLAN.md`](./M1-PLAN.md).\n- **M2 — Harness contract + lifecycle.** **Strictly harness-agnostic — zero Claude Code conventions in this repo.** spt-core defines the adapter contract; the only adapter-shaped artifact in-tree is a generic mock/test adapter (manifest fixture + fake `api` caller) that exercises the contract (PRD R-DOCS-2 dev-agent quickstart). **The rebuilt `spt` plugin (Claude Code) is a SEPARATE downstream project** built atop these crates/binary — spt-core v1's acceptance proof (PRD §\"feature parity\"), not an spt-core deliverable. It lives and builds outside this repo. **Split into two JIT milestones** (decision 2026-06-01):\n  - **M2a — Harness contract. ✅ delivered (2026-06-01).** `spt-runtime` (AgentRuntime, ManifestRuntime, manifest schema) + the `api` subcommand surface (seed/listen/bind/state/echo-gate/poll/worker-*/boundary/session-end/presence/history-log/emit/capability) + the **harness-hosted** startup topology (seed→listen→bind, interim seed-file) + local-api-auth + the generic mock adapter + contract E2E. All M2a reqs activated + green. Task breakdown: [`M2a-PLAN.md`](./M2a-PLAN.md).\n  - **M2b — Live-agent lifecycle. ✅ delivered (2026-06-01).** `spt-live` (fifth layer): history subsystem (fetcher/locate-normalize/native) + spawn-psyche (nested perch, spt-core-owned `$psyche_prompt`) + echo-commune (history brief → single-writer commune drop) + drop-file ingest (single-writer 6.4 + direct-write precedence 6.5) + interim pulse + signoff/boundary ordering invariants (echo-before-signoff 3.3, grace-before-signoff 1.1, stale-signoff sweep 3.2) + resume seam (continue-existing / fresh-with-preload). Hosted by the `api listen` runner + `api shutdown`; mock adapter gained the lifecycle templates; LiveAgent E2E proves spawn→Psyche-perch→commune-ingest→graceful-signoff harness-agnostically. All M2b reqs activated + green. Task breakdown: [`M2b-PLA…\n  - **Interim, no daemon** (like M1): the `api listen` process holds the perch + relays; the seed bridges via a file. **The spt-hosted topology (PTY-launch) + the consolidated `spt-daemon` move to M3** (they need the `spt-term` broker) — this narrows the earlier \"both topologies in M2\" wording.\n- **M3 — Terminal wrapper + daemon + self-update.** `spt-term` (session-surface, PTY, broker) + the consolidated `spt-daemon` (broker/brain split) + peer-propagated signed self-update. Split M3a/M3b/M3c. Scope + carried-forward Spike #1 gaps: [`M3-PLAN.md`](./M3-PLAN.md).\n  - **M3a — `spt-term` session-surface mechanism. ✅ delivered (2026-06-02).** The sixth crate (`…→spt-msg→spt-term`, sibling of spt-runtime): the `SessionSurface` trait + native PTY backends (ConPTY/forkpty via `portable-pty`, REQ-TERM-1) · ConPTY-DSR auto-answer drain pump (REQ-HAZARD-CONPTY-DSR) · send-keys/send-line injection (REQ-TERM-2) · bounded byte-stream (REQ-TERM-3) · the PTY-digest parser primitive (REQ-TERM-4 impl/unit, ADR-0008). OS-neutral per Spike #4/#5 (no OS's stream contract baked in; ANSI-stripped, tail-wins repaint tolerance). Validated on Windows (ConPTY) + Linux (forkpty). All M3a reqs activated + green. Task breakdown: [`M3a-PLAN.md`](./M3a-PLAN.md).\n…\n  - **M3 COMPLETE** (M3a + M3b + M3c all ✅, 2026-06-03): the real ADR-0004 architecture is live — native PTY hosting, the consolidated broker/brain daemon, and seamless signed self-update. Next milestone: M4.\n…\n\n…\n- The dual-audience docs strategy (`docs/DOCS-STRATEGY.md`) governs the *shipped* docs, authored as code lands.\n\n[Showing lines 1-33 of 85. Use :34 to continue. Some lines truncated to 768 chars]"}],"details":{"truncation":{"content":"# spt-core Roadmap\r\n\r\n> Lightweight-but-structured path from design → fruition. Not a GSD/phase-gated process — a clear sequence with de-risk gates. Planning corpus is complete (PRD + CONTEXT + 5 ADRs + 6 design docs); this is how we build it.\r\n\r\n## End goal\r\n\r\nA harness-independent core for an agent ecosystem — messaging, live-agent lifecycle, terminal hosting, **first-class P2P networking**, and a runtime-manifest harness contract — shipped as Rust crates + a single `spt` binary. The proof: the same agent runs natively across all of a user's machines with a synced mind, reachable and operable from anywhere, with seamless self-update and zero-config cross-machine messaging. First thing built atop it: a rebuilt `spt` plugin at parity with today's modern SPT.\r\n\r\n## Scope decisions (locked)\r\n\r\n- **v1 = the full PRD, networking included.** The networked element is the *reason* spt-core exists; it is not deferrable to v1.1.\r\n- **The hard freeze on `claude_skill_owl` is not a clock.** It works today and delivers value as-is while spt-core is built — no schedule pressure from it.\r\n- **Process: lightweight but structured.** GSD is too heavy. This roadmap + the design docs are the structure.\r\n\r\n## Path to fruition (sequence)\r\n\r\n**Stage A — Red-team review (before building).** Pressure-test the design adversarially. Focus on the riskiest architectural decisions, not bikeshedding. Tools: `plan-eng-review` (architecture) + `codex` (adversarial second opinion). Scope-cutting is *not* a goal (v1 is locked as full PRD), but surfacing contradictions / over-engineering / unproven assumptions is.\r\n\r\n**Stage B — De-risk spikes.** Throwaway proofs of the load-bearing unknowns — anything that, if it fails, forces a redesign. Do these before committing to the full build. See *De-risk spikes* below.\r\n\r\n**Stage C — Walking skeleton.** Build the killer-quickstart slice end-to-end through the real crate boundaries: **two agents exchange a message** (first local; ultimately cross-node — the real proof). Validates the whole stack early; then thicken.\r\n\r\n**Stage D — Phased build (M0–M5).** Dependency-ordered, each milestone ships something usable.\r\n\r\n## Milestones (all v1)\r\n\r\n- **M0 — Workspace + commodity layer.** Cargo workspace; `spt-proto` (wire envelope grammar, endpoint types, framing, Ed25519 identity, typed+binary payloads) + `spt-store` (spool, perch layout, trust store, registry persistence). Copy-verbatim the stable formats from the sister project (ADR-0001).\r\n- **M1 — Local messaging + binary.** `spt-msg` (delivery TCP+spool, routing, send/ring/ready) + the `spt` binary + CLI. **= the killer quickstart (local): two agents exchange a message.** Task breakdown: [`M1-PLAN.md`](./M1-PLAN.md).\r\n- **M2 — Harness contract + lifecycle.** **Strictly harness-agnostic — zero Claude Code conventions in this repo.** spt-core defines the adapter contract; the only adapter-shaped artifact in-tree is a generic mock/test adapter (manifest fixture + fake `api` caller) that exercises the contract (PRD R-DOCS-2 dev-agent quickstart). **The rebuilt `spt` plugin (Claude Code) is a SEPARATE downstream project** built atop these crates/binary — spt-core v1's acceptance proof (PRD §\"feature parity\"), not an spt-core deliverable. It lives and builds outside this repo. **Split into two JIT milestones** (decision 2026-06-01):\r\n  - **M2a — Harness contract. ✅ delivered (2026-06-01).** `spt-runtime` (AgentRuntime, ManifestRuntime, manifest schema) + the `api` subcommand surface (seed/listen/bind/state/echo-gate/poll/worker-*/boundary/session-end/presence/history-log/emit/capability) + the **harness-hosted** startup topology (seed→listen→bind, interim seed-file) + local-api-auth + the generic mock adapter + contract E2E. All M2a reqs activated + green. Task breakdown: [`M2a-PLAN.md`](./M2a-PLAN.md).\r\n  - **M2b — Live-agent lifecycle. ✅ delivered (2026-06-01).** `spt-live` (fifth layer): history subsystem (fetcher/locate-normalize/native) + spawn-psyche (nested perch, spt-core-owned `$psyche_prompt`) + echo-commune (history brief → single-writer commune drop) + drop-file ingest (single-writer 6.4 + direct-write precedence 6.5) + interim pulse + signoff/boundary ordering invariants (echo-before-signoff 3.3, grace-before-signoff 1.1, stale-signoff sweep 3.2) + resume seam (continue-existing / fresh-with-preload). Hosted by the `api listen` runner + `api shutdown`; mock adapter gained the lifecycle templates; LiveAgent E2E proves spawn→Psyche-perch→commune-ingest→graceful-signoff harness-agnostically. All M2b reqs activated + green. Task breakdown: [`M2b-PLA…\n  - **Interim, no daemon** (like M1): the `api listen` process holds the perch + relays; the seed bridges via a file. **The spt-hosted topology (PTY-launch) + the consolidated `spt-daemon` move to M3** (they need the `spt-term` broker) — this narrows the earlier \"both topologies in M2\" wording.\r\n- **M3 — Terminal wrapper + daemon + self-update.** `spt-term` (session-surface, PTY, broker) + the consolidated `spt-daemon` (broker/brain split) + peer-propagated signed self-update. Split M3a/M3b/M3c. Scope + carried-forward Spike #1 gaps: [`M3-PLAN.md`](./M3-PLAN.md).\r","truncated":true,"truncatedBy":"lines","totalLines":85,"totalBytes":5246,"outputLines":33,"outputBytes":5246,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":85,"displayContent":{"text":"# spt-core Roadmap\r\n\r\n> Lightweight-but-structured path from design → fruition. Not a GSD/phase-gated process — a clear sequence with de-risk gates. Planning corpus is complete (PRD + CONTEXT + 5 ADRs + 6 design docs); this is how we build it.\r\n\r\n## End goal\r\n\r\nA harness-independent core for an agent ecosystem — messaging, live-agent lifecycle, terminal hosting, **first-class P2P networking**, and a runtime-manifest harness contract — shipped as Rust crates + a single `spt` binary. The proof: the same agent runs natively across all of a user's machines with a synced mind, reachable and operable from anywhere, with seamless self-update and zero-config cross-machine messaging. First thing built atop it: a rebuilt `spt` plugin at parity with today's modern SPT.\r\n\r\n## Scope decisions (locked)\r\n\r\n- **v1 = the full PRD, networking included.** The networked element is the *reason* spt-core exists; it is not deferrable to v1.1.\r\n- **The hard freeze on `claude_skill_owl` is not a clock.** It works today and delivers value as-is while spt-core is built — no schedule pressure from it.\r\n- **Process: lightweight but structured.** GSD is too heavy. This roadmap + the design docs are the structure.\r\n\r\n## Path to fruition (sequence)\r\n\r\n**Stage A — Red-team review (before building).** Pressure-test the design adversarially. Focus on the riskiest architectural decisions, not bikeshedding. Tools: `plan-eng-review` (architecture) + `codex` (adversarial second opinion). Scope-cutting is *not* a goal (v1 is locked as full PRD), but surfacing contradictions / over-engineering / unproven assumptions is.\r\n\r\n**Stage B — De-risk spikes.** Throwaway proofs of the load-bearing unknowns — anything that, if it fails, forces a redesign. Do these before committing to the full build. See *De-risk spikes* below.\r\n\r\n**Stage C — Walking skeleton.** Build the killer-quickstart slice end-to-end through the real crate boundaries: **two agents exchange a message** (first local; ultimately cross-node — the real proof). Validates the whole stack early; then thicken.\r\n\r\n**Stage D — Phased build (M0–M5).** Dependency-ordered, each milestone ships something usable.\r\n\r\n## Milestones (all v1)\r\n\r\n- **M0 — Workspace + commodity layer.** Cargo workspace; `spt-proto` (wire envelope grammar, endpoint types, framing, Ed25519 identity, typed+binary payloads) + `spt-store` (spool, perch layout, trust store, registry persistence). Copy-verbatim the stable formats from the sister project (ADR-0001).\r\n- **M1 — Local messaging + binary.** `spt-msg` (delivery TCP+spool, routing, send/ring/ready) + the `spt` binary + CLI. **= the killer quickstart (local): two agents exchange a message.** Task breakdown: [`M1-PLAN.md`](./M1-PLAN.md).\r\n- **M2 — Harness contract + lifecycle.** **Strictly harness-agnostic — zero Claude Code conventions in this repo.** spt-core defines the adapter contract; the only adapter-shaped artifact in-tree is a generic mock/test adapter (manifest fixture + fake `api` caller) that exercises the contract (PRD R-DOCS-2 dev-agent quickstart). **The rebuilt `spt` plugin (Claude Code) is a SEPARATE downstream project** built atop these crates/binary — spt-core v1's acceptance proof (PRD §\"feature parity\"), not an spt-core deliverable. It lives and builds outside this repo. **Split into two JIT milestones** (decision 2026-06-01):\r\n  - **M2a — Harness contract. ✅ delivered (2026-06-01).** `spt-runtime` (AgentRuntime, ManifestRuntime, manifest schema) + the `api` subcommand surface (seed/listen/bind/state/echo-gate/poll/worker-*/boundary/session-end/presence/history-log/emit/capability) + the **harness-hosted** startup topology (seed→listen→bind, interim seed-file) + local-api-auth + the generic mock adapter + contract E2E. All M2a reqs activated + green. Task breakdown: [`M2a-PLAN.md`](./M2a-PLAN.md).\r\n  - **M2b — Live-agent lifecycle. ✅ delivered (2026-06-01).** `spt-live` (fifth layer): history subsystem (fetcher/locate-normalize/native) + spawn-psyche (nested perch, spt-core-owned `$psyche_prompt`) + echo-commune (history brief → single-writer commune drop) + drop-file ingest (single-writer 6.4 + direct-write precedence 6.5) + interim pulse + signoff/boundary ordering invariants (echo-before-signoff 3.3, grace-before-signoff 1.1, stale-signoff sweep 3.2) + resume seam (continue-existing / fresh-with-preload). Hosted by the `api listen` runner + `api shutdown`; mock adapter gained the lifecycle templates; LiveAgent E2E proves spawn→Psyche-perch→commune-ingest→graceful-signoff harness-agnostically. All M2b reqs activated + green. Task breakdown: [`M2b-PLA…\n  - **Interim, no daemon** (like M1): the `api listen` process holds the perch + relays; the seed bridges via a file. **The spt-hosted topology (PTY-launch) + the consolidated `spt-daemon` move to M3** (they need the `spt-term` broker) — this narrows the earlier \"both topologies in M2\" wording.\r\n- **M3 — Terminal wrapper + daemon + self-update.** `spt-term` (session-surface, PTY, broker) + the consolidated `spt-daemon` (broker/brain split) + peer-propagated signed self-update. Split M3a/M3b/M3c. Scope + carried-forward Spike #1 gaps: [`M3-PLAN.md`](./M3-PLAN.md).\r\n  - **M3a — `spt-term` session-surface mechanism. ✅ delivered (2026-06-02).** The sixth crate (`…→spt-msg→spt-term`, sibling of spt-runtime): the `SessionSurface` trait + native PTY backends (ConPTY/forkpty via `portable-pty`, REQ-TERM-1) · ConPTY-DSR auto-answer drain pump (REQ-HAZARD-CONPTY-DSR) · send-keys/send-line injection (REQ-TERM-2) · bounded byte-stream (REQ-TERM-3) · the PTY-digest parser primitive (REQ-TERM-4 impl/unit, ADR-0008). OS-neutral per Spike #4/#5 (no OS's stream contract baked in; ANSI-stripped, tail-wins repaint tolerance). Validated on Windows (ConPTY) + Linux (forkpty). All M3a reqs activated + green. Task breakdown: [`M3a-PLAN.md`](./M3a-PLAN.md).\n…\n  - **M3 COMPLETE** (M3a + M3b + M3c all ✅, 2026-06-03): the real ADR-0004 architecture is live — native PTY hosting, the consolidated broker/brain daemon, and seamless signed self-update. Next milestone: M4.\n…\n\n…\n- The dual-audience docs strategy (`docs/DOCS-STRATEGY.md`) governs the *shipped* docs, authored as code lands.","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,null,37,null,40,null,85]},"fileSize":30077,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\ROADMAP.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":85,"totalBytes":5246,"outputLines":33,"outputBytes":5246,"shownRange":{"start":1,"end":33},"nextOffset":34},"limits":{"columnTruncated":{"maxColumn":768}}}},"isError":false,"timestamp":1789107092067}}
{"type":"message","id":"df404c9e","parentId":"61d877e9","timestamp":"2026-09-11T06:11:32.068Z","message":{"role":"toolResult","toolCallId":"call_r0SHGZrTU5zC7GvASh2vHzDY|fc_0330c101aa2c61dc016aa39b91a17c87d19a95d99182d47de3","toolName":"read","content":[{"type":"text","text":"# $SPT_HOME on-disk layout\n\n> Draft design doc (2026-05-30). Implementation detail — neither glossary ([`../CONTEXT.md`](../CONTEXT.md)) nor decision ([`adr/`](./adr/)). Resolves PRD §17.1.\n\n## Principles\n\n1. **Single relocatable root.** One `$SPT_HOME` dir holds everything (default `%LOCALAPPDATA%\\spt-core` / `~/.spt-core`; override via `$SPT_HOME`). The `spt-core/` default is deliberately distinct from the modern spt runtime's `spt/` home so a dev build never collides with a running spt-plugin during parity build-out (may stay `spt-core/` for good). One dir to back up, move, or repackage for a marketplace/handheld. No XDG three-way split.\n2. **Endpoint IDs are adapter-agnostic.** `ling` can run under `claude-spt`, then later under `spt-codex` or `spt-pi`. Perches and context key on bare `endpoint_id`; the currently-running `adapter_name` is a *property of the instance* recorded in `info.json`, never a path segment. **At most one instance of an ID per node** — a second attempt (any adapter) is rejected.\n3. **Two separate trees: `tracked/` vs `perches/`.** The synced *mind* (context, a git repo) and the node-local *plumbing* (spool/status/info) are physically separate. Perch runtime is **never** git-tracked — otherwise node-local spools and statuses would clobber across nodes when the context repo syncs.\n4. **Durable vs ephemeral is explicit.** `identity/`, `tracked/`, `history/` are durable (the backup/migrate set). `registry/`, `daemon/`, `updates/` are regenerable. Migration carries the durable set only.\n5. **One path resolver.** A single centralized, idempotent resolver maps `(endpoint_id[, child][, project_id][, kind])` → path. Nothing constructs paths ad-hoc, so any future relayout carries to all dependents (KNOWN-HAZARDS 6.1 — no flat/nested ambiguity).\n\n## Layout\n\n```\n$SPT_HOME/\n  identity/                      ── node-local, durable, NEVER git-tracked ──\n    node.key                     Ed25519 node identity (per-node; must not sync)\n    trust/                       authorized peer pubkeys (trust store)\n    subnet.json                  subnet name + TOTP seed (replicated via pairing, not git)\n  tracked/                       ── git repo; synced across nodes over P2P ──\n    agents/<endpoint_id>/\n      meta.json                  endpoint identity metadata: type, ordered adapter history, created\n      live-context.md            per-agent live context           (branch a-<endpoint_id>)\n    projects/<project_id>/\n      <endpoint_id>/\n        project-context.md       per-(agent,project) context      (branch p-<project_id>)\n  perches/                       ── node-local runtime, NEVER tracked/synced ──\n…\n  serve/registry                 authoritative serving entries + persistent name ownership\n```\n…\n\n…\n- Whether `history/` ever needs cross-node fetch (today node-local; history-lookup over the network would serve remote reads).\n\n[Showing lines 1-28 of 354. Use :29 to continue]"}],"details":{"truncation":{"content":"# $SPT_HOME on-disk layout\r\n\r\n> Draft design doc (2026-05-30). Implementation detail — neither glossary ([`../CONTEXT.md`](../CONTEXT.md)) nor decision ([`adr/`](./adr/)). Resolves PRD §17.1.\r\n\r\n## Principles\r\n\r\n1. **Single relocatable root.** One `$SPT_HOME` dir holds everything (default `%LOCALAPPDATA%\\spt-core` / `~/.spt-core`; override via `$SPT_HOME`). The `spt-core/` default is deliberately distinct from the modern spt runtime's `spt/` home so a dev build never collides with a running spt-plugin during parity build-out (may stay `spt-core/` for good). One dir to back up, move, or repackage for a marketplace/handheld. No XDG three-way split.\r\n2. **Endpoint IDs are adapter-agnostic.** `ling` can run under `claude-spt`, then later under `spt-codex` or `spt-pi`. Perches and context key on bare `endpoint_id`; the currently-running `adapter_name` is a *property of the instance* recorded in `info.json`, never a path segment. **At most one instance of an ID per node** — a second attempt (any adapter) is rejected.\r\n3. **Two separate trees: `tracked/` vs `perches/`.** The synced *mind* (context, a git repo) and the node-local *plumbing* (spool/status/info) are physically separate. Perch runtime is **never** git-tracked — otherwise node-local spools and statuses would clobber across nodes when the context repo syncs.\r\n4. **Durable vs ephemeral is explicit.** `identity/`, `tracked/`, `history/` are durable (the backup/migrate set). `registry/`, `daemon/`, `updates/` are regenerable. Migration carries the durable set only.\r\n5. **One path resolver.** A single centralized, idempotent resolver maps `(endpoint_id[, child][, project_id][, kind])` → path. Nothing constructs paths ad-hoc, so any future relayout carries to all dependents (KNOWN-HAZARDS 6.1 — no flat/nested ambiguity).\r\n\r\n## Layout\r\n\r\n```\r\n$SPT_HOME/\r\n  identity/                      ── node-local, durable, NEVER git-tracked ──\r\n    node.key                     Ed25519 node identity (per-node; must not sync)\r\n    trust/                       authorized peer pubkeys (trust store)\r\n    subnet.json                  subnet name + TOTP seed (replicated via pairing, not git)\r\n  tracked/                       ── git repo; synced across nodes over P2P ──\r\n    agents/<endpoint_id>/\r\n      meta.json                  endpoint identity metadata: type, ordered adapter history, created\r\n      live-context.md            per-agent live context           (branch a-<endpoint_id>)\r\n    projects/<project_id>/\r\n      <endpoint_id>/\r\n        project-context.md       per-(agent,project) context      (branch p-<project_id>)\r\n  perches/                       ── node-local runtime, NEVER tracked/synced ──\r","truncated":true,"truncatedBy":"lines","totalLines":354,"totalBytes":2714,"outputLines":28,"outputBytes":2714,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":354,"displayContent":{"text":"# $SPT_HOME on-disk layout\r\n\r\n> Draft design doc (2026-05-30). Implementation detail — neither glossary ([`../CONTEXT.md`](../CONTEXT.md)) nor decision ([`adr/`](./adr/)). Resolves PRD §17.1.\r\n\r\n## Principles\r\n\r\n1. **Single relocatable root.** One `$SPT_HOME` dir holds everything (default `%LOCALAPPDATA%\\spt-core` / `~/.spt-core`; override via `$SPT_HOME`). The `spt-core/` default is deliberately distinct from the modern spt runtime's `spt/` home so a dev build never collides with a running spt-plugin during parity build-out (may stay `spt-core/` for good). One dir to back up, move, or repackage for a marketplace/handheld. No XDG three-way split.\r\n2. **Endpoint IDs are adapter-agnostic.** `ling` can run under `claude-spt`, then later under `spt-codex` or `spt-pi`. Perches and context key on bare `endpoint_id`; the currently-running `adapter_name` is a *property of the instance* recorded in `info.json`, never a path segment. **At most one instance of an ID per node** — a second attempt (any adapter) is rejected.\r\n3. **Two separate trees: `tracked/` vs `perches/`.** The synced *mind* (context, a git repo) and the node-local *plumbing* (spool/status/info) are physically separate. Perch runtime is **never** git-tracked — otherwise node-local spools and statuses would clobber across nodes when the context repo syncs.\r\n4. **Durable vs ephemeral is explicit.** `identity/`, `tracked/`, `history/` are durable (the backup/migrate set). `registry/`, `daemon/`, `updates/` are regenerable. Migration carries the durable set only.\r\n5. **One path resolver.** A single centralized, idempotent resolver maps `(endpoint_id[, child][, project_id][, kind])` → path. Nothing constructs paths ad-hoc, so any future relayout carries to all dependents (KNOWN-HAZARDS 6.1 — no flat/nested ambiguity).\r\n\r\n## Layout\r\n\r\n```\r\n$SPT_HOME/\r\n  identity/                      ── node-local, durable, NEVER git-tracked ──\r\n    node.key                     Ed25519 node identity (per-node; must not sync)\r\n    trust/                       authorized peer pubkeys (trust store)\r\n    subnet.json                  subnet name + TOTP seed (replicated via pairing, not git)\r\n  tracked/                       ── git repo; synced across nodes over P2P ──\r\n    agents/<endpoint_id>/\r\n      meta.json                  endpoint identity metadata: type, ordered adapter history, created\r\n      live-context.md            per-agent live context           (branch a-<endpoint_id>)\r\n    projects/<project_id>/\r\n      <endpoint_id>/\r\n        project-context.md       per-(agent,project) context      (branch p-<project_id>)\r\n  perches/                       ── node-local runtime, NEVER tracked/synced ──\r\n…\n  serve/registry                 authoritative serving entries + persistent name ownership\n```\n…\n\n…\n- Whether `history/` ever needs cross-node fetch (today node-local; history-lookup over the network would serve remote reads).","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,null,50,51,null,119,null,354]},"fileSize":35259,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\STORAGE.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":354,"totalBytes":2714,"outputLines":28,"outputBytes":2714,"shownRange":{"start":1,"end":28},"nextOffset":29}}},"isError":false,"timestamp":1789107092068}}
{"type":"message","id":"7b0149a6","parentId":"df404c9e","timestamp":"2026-09-11T06:11:32.069Z","message":{"role":"toolResult","toolCallId":"call_lXruGZI0Kjb6ScADnsADpFhb|fc_0330c101aa2c61dc016aa39b91a18887d1b671708916734e6e","toolName":"read","content":[{"type":"text","text":"# Psyche context & memory model\n\n> Draft design doc (2026-05-31). Resolves PRD §17.3 (Psyche live/project authoring directives) and the memformat redesign. Governs how the Psyche authors, structures, syncs, and surfaces an agent's context. On-disk layout: `docs/STORAGE.md`. Several patterns are adapted from `BigscreenVR/pi-agent-memory` (credited inline).\n\n## Two-tier context\n\n- **live context** (per-agent, project-independent — the agent's *mind*): identity/persona, relationship + rapport with the user, the user's cross-project preferences & working style, cross-project life threads, **learnings from work that may apply to other projects**, a thin **project roster** (one line per project the agent works on), the agent's self-model. Synced to **all** instances of the endpoint.\n- **project context** (per-agent-per-project — what the agent is doing *here*): codebase/architecture, decisions made here, **current focus / next steps / todos**, project conventions, build/test commands, blockers. Synced **only** to same-project instances.\n\n(This split independently matches pi-agent-memory's Project Store vs Global Store and its discriminator dialogue — convergent validation.)\n\n### The discriminator (applied per *topic*, not per fragment)\n\n> **\"Would this still be true and relevant if the user opened a *different* project tomorrow?\"** Yes → live. No → project. Equivalently: **WHO the agent is** (live) vs **WHAT it's doing here** (project).\n\n### Anti-leak rules\n\nThe observed failure is project detail leaking *into* live context (which then wrongly syncs everywhere). Countermeasures:\n\n1. **Default-to-project.** A fragment goes to project context unless it *passes the cross-project test* to be promoted to live. Promotion needs justification; demotion is free. The bias points against the leak.\n2. **`current focus / next steps` is project-scoped** — the single biggest leak category. Route it to project unless the focus genuinely spans projects.\n3. **Live holds a thin project roster, never project depth** — cross-project *awareness* travels; depth stays per-project.\n4. **Commune-source asymmetry** (the structural fix): the live signal is strong only from **Self-authored communes**; **echo communes are project-centric** (they synthesize project-heavy session logs). So **echo communes are project-context-primary and live-context-conservative** — they make few/no live edits. This kills the leak at its source. Provenance is recorded on each block (`Source:`).\n\n### Boundary communes are Self-authored (resume Self, not echo)\n\nTo get meaningful **live-context** updates on a consistent basis (the live signal is strong only from Self), three boundaries author their commune by **`--resume`-ing the Self session** (the actual agent), not by a background haiku echo:\n\n…\n\n…\n\n…\npi-agent-memory's **human-in-the-loop approval** (extract → review → approve, max-5-candidates) and **bash-mutation guardrails** fit its \"human curates\" philosophy. SPT's Psyche is **trusted to author its own mind autonomously** — so we adopt pi's *structure* (blocks, INDEX, bounded awareness, provenance, OCC) but **not** its approval gate. Controlled mutation is already covered by the drop-file single-writer rule (KNOWN-HAZARDS 6.4).\n\n[Showing lines 1-28 of 92. Use :29 to continue]"}],"details":{"truncation":{"content":"# Psyche context & memory model\r\n\r\n> Draft design doc (2026-05-31). Resolves PRD §17.3 (Psyche live/project authoring directives) and the memformat redesign. Governs how the Psyche authors, structures, syncs, and surfaces an agent's context. On-disk layout: `docs/STORAGE.md`. Several patterns are adapted from `BigscreenVR/pi-agent-memory` (credited inline).\r\n\r\n## Two-tier context\r\n\r\n- **live context** (per-agent, project-independent — the agent's *mind*): identity/persona, relationship + rapport with the user, the user's cross-project preferences & working style, cross-project life threads, **learnings from work that may apply to other projects**, a thin **project roster** (one line per project the agent works on), the agent's self-model. Synced to **all** instances of the endpoint.\r\n- **project context** (per-agent-per-project — what the agent is doing *here*): codebase/architecture, decisions made here, **current focus / next steps / todos**, project conventions, build/test commands, blockers. Synced **only** to same-project instances.\r\n\r\n(This split independently matches pi-agent-memory's Project Store vs Global Store and its discriminator dialogue — convergent validation.)\r\n\r\n### The discriminator (applied per *topic*, not per fragment)\r\n\r\n> **\"Would this still be true and relevant if the user opened a *different* project tomorrow?\"** Yes → live. No → project. Equivalently: **WHO the agent is** (live) vs **WHAT it's doing here** (project).\r\n\r\n### Anti-leak rules\r\n\r\nThe observed failure is project detail leaking *into* live context (which then wrongly syncs everywhere). Countermeasures:\r\n\r\n1. **Default-to-project.** A fragment goes to project context unless it *passes the cross-project test* to be promoted to live. Promotion needs justification; demotion is free. The bias points against the leak.\r\n2. **`current focus / next steps` is project-scoped** — the single biggest leak category. Route it to project unless the focus genuinely spans projects.\r\n3. **Live holds a thin project roster, never project depth** — cross-project *awareness* travels; depth stays per-project.\r\n4. **Commune-source asymmetry** (the structural fix): the live signal is strong only from **Self-authored communes**; **echo communes are project-centric** (they synthesize project-heavy session logs). So **echo communes are project-context-primary and live-context-conservative** — they make few/no live edits. This kills the leak at its source. Provenance is recorded on each block (`Source:`).\r\n\r\n### Boundary communes are Self-authored (resume Self, not echo)\r\n\r\nTo get meaningful **live-context** updates on a consistent basis (the live signal is strong only from Self), three boundaries author their commune by **`--resume`-ing the Self session** (the actual agent), not by a background haiku echo:\r\n\r","truncated":true,"truncatedBy":"lines","totalLines":92,"totalBytes":2834,"outputLines":28,"outputBytes":2834,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":92,"displayContent":{"text":"# Psyche context & memory model\r\n\r\n> Draft design doc (2026-05-31). Resolves PRD §17.3 (Psyche live/project authoring directives) and the memformat redesign. Governs how the Psyche authors, structures, syncs, and surfaces an agent's context. On-disk layout: `docs/STORAGE.md`. Several patterns are adapted from `BigscreenVR/pi-agent-memory` (credited inline).\r\n\r\n## Two-tier context\r\n\r\n- **live context** (per-agent, project-independent — the agent's *mind*): identity/persona, relationship + rapport with the user, the user's cross-project preferences & working style, cross-project life threads, **learnings from work that may apply to other projects**, a thin **project roster** (one line per project the agent works on), the agent's self-model. Synced to **all** instances of the endpoint.\r\n- **project context** (per-agent-per-project — what the agent is doing *here*): codebase/architecture, decisions made here, **current focus / next steps / todos**, project conventions, build/test commands, blockers. Synced **only** to same-project instances.\r\n\r\n(This split independently matches pi-agent-memory's Project Store vs Global Store and its discriminator dialogue — convergent validation.)\r\n\r\n### The discriminator (applied per *topic*, not per fragment)\r\n\r\n> **\"Would this still be true and relevant if the user opened a *different* project tomorrow?\"** Yes → live. No → project. Equivalently: **WHO the agent is** (live) vs **WHAT it's doing here** (project).\r\n\r\n### Anti-leak rules\r\n\r\nThe observed failure is project detail leaking *into* live context (which then wrongly syncs everywhere). Countermeasures:\r\n\r\n1. **Default-to-project.** A fragment goes to project context unless it *passes the cross-project test* to be promoted to live. Promotion needs justification; demotion is free. The bias points against the leak.\r\n2. **`current focus / next steps` is project-scoped** — the single biggest leak category. Route it to project unless the focus genuinely spans projects.\r\n3. **Live holds a thin project roster, never project depth** — cross-project *awareness* travels; depth stays per-project.\r\n4. **Commune-source asymmetry** (the structural fix): the live signal is strong only from **Self-authored communes**; **echo communes are project-centric** (they synthesize project-heavy session logs). So **echo communes are project-context-primary and live-context-conservative** — they make few/no live edits. This kills the leak at its source. Provenance is recorded on each block (`Source:`).\r\n\r\n### Boundary communes are Self-authored (resume Self, not echo)\r\n\r\nTo get meaningful **live-context** updates on a consistent basis (the live signal is strong only from Self), three boundaries author their commune by **`--resume`-ing the Self session** (the actual agent), not by a background haiku echo:\r\n\r\n…\n\n…\n\n…\npi-agent-memory's **human-in-the-loop approval** (extract → review → approve, max-5-candidates) and **bash-mutation guardrails** fit its \"human curates\" philosophy. SPT's Psyche is **trusted to author its own mind autonomously** — so we adopt pi's *structure* (blocks, INDEX, bounded awareness, provenance, OCC) but **not** its approval gate. Controlled mutation is already covered by the drop-file single-writer rule (KNOWN-HAZARDS 6.4).","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,null,34,null,42,null,92]},"fileSize":9140,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\CONTEXT-MEMORY.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":92,"totalBytes":2834,"outputLines":28,"outputBytes":2834,"shownRange":{"start":1,"end":28},"nextOffset":29}}},"isError":false,"timestamp":1789107092068}}
{"type":"message","id":"6dfe7e27","parentId":"7b0149a6","timestamp":"2026-09-11T06:11:32.070Z","message":{"role":"toolResult","toolCallId":"call_CuME8lwpTSUP149w8xjZtwqu|fc_0330c101aa2c61dc016aa39b91a18487d1a20c6ca7aa94c531","toolName":"read","content":[{"type":"text","text":"# Runtime manifest schema\n\n> Draft design doc (2026-05-31). Resolves PRD §17.2. Implementation detail — see [`../CONTEXT.md`](../CONTEXT.md) for the model. Schema grounded in the sister project's actual functional surface.\n\n## Principle\n\n**SPT is not a harness.** The manifest declares only what *varies per harness*. Command templates are **opaque strings** — spt-core never parses out a model, tool list, or flag; the adapter writes the full command line and spt-core just runs it with substitution keys filled. Anything spt-core owns (sentinels, spool/registry/perch schemas, the event-block vocabulary, the version-trampoline mechanism, config knobs) is **not** in the manifest.\n\n## What is NOT in the manifest (spt-core-owned)\n\n- **Sentinels** (`.idle`-equiv, echo-gate) — managed by `api state`/`api echo-gate`; the adapter only *calls* them.\n- **Spool / registry / perch `info.json` / daemon-state schemas** — core.\n- **Event-block vocabulary** — the XML tags spt-core surfaces to agents (e.g. `<SPT_EVENT>`, `<owl_messages>`-equivalent) are a **fixed, documented constant**, not configurable. Adapters pass spt-core's output through unchanged.\n- **File-drop filenames** — statically `<endpoint_id>-commune.md` / `<endpoint_id>-signoff.md`. Only the *watched directory* is declared (in `[session]`).\n- **Config knobs** (pulse period, echo-commune window, route-guard window, daily-refresh) — spt-core **global settings**, with optional **per-endpoint override** for endpoints with unique needs. Not per-adapter.\n- **Cross-adapter fallback** (psyche/echo invocation falls back to another adapter on rate-limit) — a **node-wide setting**, not a manifest field, because it references *multiple* adapters (under spt-core, `ccs` is its own adapter, not a binary-swap within one). Adapter-agnostic IDs make this safe — an endpoint's Psyche can run under a fallback adapter temporarily.\n- **Plugin-cache / version-trampoline layout** — none of SPT's concern. A CC-plugin adapter updates via `claude plugin update` (delegated command).\n\n<!-- [doc->REQ-MANIFEST-1] The sections below are the authoritative schema; the\ntyped form in `crates/spt-runtime/src/manifest.rs` is kept in lockstep. -->\n\n## Manifest sections\n\n### `[adapter]` — header\n```toml\n[adapter]\nname = \"claude-spt\"\nversion = \"2.0.0\"\n…\nweb_short_path = \"cspt\"            # optional; alias of the core-owned served root\n```\n…\n\n…\n\n…\n- Capability-declaration shape beyond `hostable_types` (per-type operation advertisement).\n\n[Showing lines 1-28 of 825. Use :29 to continue]"}],"details":{"truncation":{"content":"# Runtime manifest schema\r\n\r\n> Draft design doc (2026-05-31). Resolves PRD §17.2. Implementation detail — see [`../CONTEXT.md`](../CONTEXT.md) for the model. Schema grounded in the sister project's actual functional surface.\r\n\r\n## Principle\r\n\r\n**SPT is not a harness.** The manifest declares only what *varies per harness*. Command templates are **opaque strings** — spt-core never parses out a model, tool list, or flag; the adapter writes the full command line and spt-core just runs it with substitution keys filled. Anything spt-core owns (sentinels, spool/registry/perch schemas, the event-block vocabulary, the version-trampoline mechanism, config knobs) is **not** in the manifest.\r\n\r\n## What is NOT in the manifest (spt-core-owned)\r\n\r\n- **Sentinels** (`.idle`-equiv, echo-gate) — managed by `api state`/`api echo-gate`; the adapter only *calls* them.\r\n- **Spool / registry / perch `info.json` / daemon-state schemas** — core.\r\n- **Event-block vocabulary** — the XML tags spt-core surfaces to agents (e.g. `<SPT_EVENT>`, `<owl_messages>`-equivalent) are a **fixed, documented constant**, not configurable. Adapters pass spt-core's output through unchanged.\r\n- **File-drop filenames** — statically `<endpoint_id>-commune.md` / `<endpoint_id>-signoff.md`. Only the *watched directory* is declared (in `[session]`).\r\n- **Config knobs** (pulse period, echo-commune window, route-guard window, daily-refresh) — spt-core **global settings**, with optional **per-endpoint override** for endpoints with unique needs. Not per-adapter.\r\n- **Cross-adapter fallback** (psyche/echo invocation falls back to another adapter on rate-limit) — a **node-wide setting**, not a manifest field, because it references *multiple* adapters (under spt-core, `ccs` is its own adapter, not a binary-swap within one). Adapter-agnostic IDs make this safe — an endpoint's Psyche can run under a fallback adapter temporarily.\r\n- **Plugin-cache / version-trampoline layout** — none of SPT's concern. A CC-plugin adapter updates via `claude plugin update` (delegated command).\r\n\r\n<!-- [doc->REQ-MANIFEST-1] The sections below are the authoritative schema; the\r\ntyped form in `crates/spt-runtime/src/manifest.rs` is kept in lockstep. -->\r\n\r\n## Manifest sections\r\n\r\n### `[adapter]` — header\r\n```toml\r\n[adapter]\r\nname = \"claude-spt\"\r\nversion = \"2.0.0\"\r","truncated":true,"truncatedBy":"lines","totalLines":825,"totalBytes":2346,"outputLines":28,"outputBytes":2346,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":825,"displayContent":{"text":"# Runtime manifest schema\r\n\r\n> Draft design doc (2026-05-31). Resolves PRD §17.2. Implementation detail — see [`../CONTEXT.md`](../CONTEXT.md) for the model. Schema grounded in the sister project's actual functional surface.\r\n\r\n## Principle\r\n\r\n**SPT is not a harness.** The manifest declares only what *varies per harness*. Command templates are **opaque strings** — spt-core never parses out a model, tool list, or flag; the adapter writes the full command line and spt-core just runs it with substitution keys filled. Anything spt-core owns (sentinels, spool/registry/perch schemas, the event-block vocabulary, the version-trampoline mechanism, config knobs) is **not** in the manifest.\r\n\r\n## What is NOT in the manifest (spt-core-owned)\r\n\r\n- **Sentinels** (`.idle`-equiv, echo-gate) — managed by `api state`/`api echo-gate`; the adapter only *calls* them.\r\n- **Spool / registry / perch `info.json` / daemon-state schemas** — core.\r\n- **Event-block vocabulary** — the XML tags spt-core surfaces to agents (e.g. `<SPT_EVENT>`, `<owl_messages>`-equivalent) are a **fixed, documented constant**, not configurable. Adapters pass spt-core's output through unchanged.\r\n- **File-drop filenames** — statically `<endpoint_id>-commune.md` / `<endpoint_id>-signoff.md`. Only the *watched directory* is declared (in `[session]`).\r\n- **Config knobs** (pulse period, echo-commune window, route-guard window, daily-refresh) — spt-core **global settings**, with optional **per-endpoint override** for endpoints with unique needs. Not per-adapter.\r\n- **Cross-adapter fallback** (psyche/echo invocation falls back to another adapter on rate-limit) — a **node-wide setting**, not a manifest field, because it references *multiple* adapters (under spt-core, `ccs` is its own adapter, not a binary-swap within one). Adapter-agnostic IDs make this safe — an endpoint's Psyche can run under a fallback adapter temporarily.\r\n- **Plugin-cache / version-trampoline layout** — none of SPT's concern. A CC-plugin adapter updates via `claude plugin update` (delegated command).\r\n\r\n<!-- [doc->REQ-MANIFEST-1] The sections below are the authoritative schema; the\r\ntyped form in `crates/spt-runtime/src/manifest.rs` is kept in lockstep. -->\r\n\r\n## Manifest sections\r\n\r\n### `[adapter]` — header\r\n```toml\r\n[adapter]\r\nname = \"claude-spt\"\r\nversion = \"2.0.0\"\r\n…\nweb_short_path = \"cspt\"            # optional; alias of the core-owned served root\n```\n…\n\n…\n\n…\n- Capability-declaration shape beyond `hostable_types` (per-type operation advertisement).","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,null,33,34,null,118,null,753,null,825]},"fileSize":72442,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\MANIFEST.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":825,"totalBytes":2346,"outputLines":28,"outputBytes":2346,"shownRange":{"start":1,"end":28},"nextOffset":29}}},"isError":false,"timestamp":1789107092069}}
{"type":"message","id":"6de27c6d","parentId":"6dfe7e27","timestamp":"2026-09-11T06:11:32.070Z","message":{"role":"toolResult","toolCallId":"call_4YHLPV3LQqPCUFsecbLZ2oW9|fc_0330c101aa2c61dc016aa39b91a18c87d1aa9ce876ee96ebf1","toolName":"read","content":[{"type":"text","text":"# Documentation strategy\n\n> Draft (2026-05-31). A **designed-in commitment**, not an afterthought — grounded in research on critically-acclaimed developer docs (Stripe, Twilio, the Rust Book, FastAPI, Cloudflare, Anthropic, Diátaxis, `llms.txt`, Google dev style guide). Governs the **shipped product docs** (authored as code lands); the planning docs (CONTEXT/PRD/ADRs/design docs) are internal and separate.\n\n## The defining constraint: a dual audience\n\nspt-core's docs serve **two readers at once** — human developers *and* the **AI dev-agents that build integrations with it**. This is unusual and it is the design constraint: every artifact is authored **once in clean markdown** and served in **two depths** (human-rendered + agent-export). The agent layer is **first-class, not optional** — the strategic signal (Tailwind's docs traffic fell ~40% because assistants answer for it) is, for spt-core, *the goal*: make the agent layer so good that dev-agents integrate correctly on the first try. There is recursive fit here — the same kind of agent that spt-core *hosts* is the one that *reads its docs*.\n\n## Principles (top techniques, prioritized for spt-core)\n\n1. **Sub-10-minute killer quickstart** — runnable, deterministic, whole-working-thing-first, no placeholders. TTFHW (\"time to first hello world\") is the single most-cited conversion lever (~68% abandon trials over setup time).\n2. **Diátaxis four-mode separation** — tutorial / how-to / reference / explanation, never mixed (mixing is the most-cited cause of confusing docs).\n3. **Deterministic, real, copy-pasteable examples everywhere** — no `<YOUR_VALUE_HERE>` placeholders; real values that run. Serves humans *and* agents.\n4. **Dual-depth agent exports** — `llms.txt` (slim curated index) + `llms-full.txt` (full concatenated export), auto-generated in CI, plus markdown content negotiation (`.md` suffix / `Accept: text/markdown`) which cuts agent token use ~90% vs HTML.\n5. **One canonical way to do X** — explicitly mark deprecated/alternate paths. Non-determinism is fatal for agents.\n6. **Complete reference, auto-generated, all error variants** — rustdoc for the public SDK crates (`spt-proto`, `spt-runtime`, `spt-msg`) + a machine-readable manifest/contract schema. Generic placeholders in reference are a failure mode.\n7. **Consistent conversational voice** — adopt the Google developer style guide: second person (\"you\"), active voice, knowledgeable-friend tone.\n8. **Explain *why*, not just *what*** — conceptual docs + diagrams for the messaging model, the agent lifecycle states, instances/dormancy, and P2P topology.\n9. **Stable, never-renamed anchors/URLs** — agents cache links.\n10. **Docs-as-product, gated in CI** — generation (rustdoc, `llms.txt`, schema, CLI help) is part of the build so docs can never drift from code. Drift is the #1 most-cited docs failure; this kills it structurally.\n\n## Information architecture — by capability vertical\n\nOrganize by capability, each vertical carrying the same four Diátaxis modes internally (the Cloudflare pattern):\n\n**Messaging · Live-agent lifecycle · Terminal hosting · Networking (P2P + pairing) · Harness contract (manifest + `api`) · Instances · Shells · Self-update.**\n\n## Killer quickstart targets (two, one per audience)\n\n- **Human dev:** two agents exchange a message end-to-end in **one command + minimal config**, < 10 min — the core primitive, whole-thing-first, then decomposed.\n- **Dev-agent integrator:** a minimal **adapter** that satisfies the manifest + `api` contract and drives one lifecycle operation — the \"build a harness for spt-core\" hello-world.\n\n## Agent-consumable docs (spt-core specifics)\n…\n\n…\nTop-level `--help` groups by audience (`AGENT COMMANDS` send/ring/ready/poll · `HARNESS COMMANDS` api … · `NODE COMMANDS` pair/subnet/update). Per-command: **USAGE · FLAGS · EXAMPLES (real values) · LEARN MORE**. Beyond gh: a **`spt <cmd> --help --json`** structured-help mode so dev-agents parse the contract without scraping, plus gh's uniform **`--json <fields>` / `--jq` / `--template`** trio on any list command. The `--json` help export is generated + CI-gated alongside rustdoc and the schema.\n\n[Showing lines 1-33 of 147. Use :34 to continue]"}],"details":{"truncation":{"content":"# Documentation strategy\r\n\r\n> Draft (2026-05-31). A **designed-in commitment**, not an afterthought — grounded in research on critically-acclaimed developer docs (Stripe, Twilio, the Rust Book, FastAPI, Cloudflare, Anthropic, Diátaxis, `llms.txt`, Google dev style guide). Governs the **shipped product docs** (authored as code lands); the planning docs (CONTEXT/PRD/ADRs/design docs) are internal and separate.\r\n\r\n## The defining constraint: a dual audience\r\n\r\nspt-core's docs serve **two readers at once** — human developers *and* the **AI dev-agents that build integrations with it**. This is unusual and it is the design constraint: every artifact is authored **once in clean markdown** and served in **two depths** (human-rendered + agent-export). The agent layer is **first-class, not optional** — the strategic signal (Tailwind's docs traffic fell ~40% because assistants answer for it) is, for spt-core, *the goal*: make the agent layer so good that dev-agents integrate correctly on the first try. There is recursive fit here — the same kind of agent that spt-core *hosts* is the one that *reads its docs*.\r\n\r\n## Principles (top techniques, prioritized for spt-core)\r\n\r\n1. **Sub-10-minute killer quickstart** — runnable, deterministic, whole-working-thing-first, no placeholders. TTFHW (\"time to first hello world\") is the single most-cited conversion lever (~68% abandon trials over setup time).\r\n2. **Diátaxis four-mode separation** — tutorial / how-to / reference / explanation, never mixed (mixing is the most-cited cause of confusing docs).\r\n3. **Deterministic, real, copy-pasteable examples everywhere** — no `<YOUR_VALUE_HERE>` placeholders; real values that run. Serves humans *and* agents.\r\n4. **Dual-depth agent exports** — `llms.txt` (slim curated index) + `llms-full.txt` (full concatenated export), auto-generated in CI, plus markdown content negotiation (`.md` suffix / `Accept: text/markdown`) which cuts agent token use ~90% vs HTML.\r\n5. **One canonical way to do X** — explicitly mark deprecated/alternate paths. Non-determinism is fatal for agents.\r\n6. **Complete reference, auto-generated, all error variants** — rustdoc for the public SDK crates (`spt-proto`, `spt-runtime`, `spt-msg`) + a machine-readable manifest/contract schema. Generic placeholders in reference are a failure mode.\r\n7. **Consistent conversational voice** — adopt the Google developer style guide: second person (\"you\"), active voice, knowledgeable-friend tone.\r\n8. **Explain *why*, not just *what*** — conceptual docs + diagrams for the messaging model, the agent lifecycle states, instances/dormancy, and P2P topology.\r\n9. **Stable, never-renamed anchors/URLs** — agents cache links.\r\n10. **Docs-as-product, gated in CI** — generation (rustdoc, `llms.txt`, schema, CLI help) is part of the build so docs can never drift from code. Drift is the #1 most-cited docs failure; this kills it structurally.\r\n\r\n## Information architecture — by capability vertical\r\n\r\nOrganize by capability, each vertical carrying the same four Diátaxis modes internally (the Cloudflare pattern):\r\n\r\n**Messaging · Live-agent lifecycle · Terminal hosting · Networking (P2P + pairing) · Harness contract (manifest + `api`) · Instances · Shells · Self-update.**\r\n\r\n## Killer quickstart targets (two, one per audience)\r\n\r\n- **Human dev:** two agents exchange a message end-to-end in **one command + minimal config**, < 10 min — the core primitive, whole-thing-first, then decomposed.\r\n- **Dev-agent integrator:** a minimal **adapter** that satisfies the manifest + `api` contract and drives one lifecycle operation — the \"build a harness for spt-core\" hello-world.\r\n\r\n## Agent-consumable docs (spt-core specifics)\r","truncated":true,"truncatedBy":"lines","totalLines":147,"totalBytes":3731,"outputLines":33,"outputBytes":3731,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":147,"displayContent":{"text":"# Documentation strategy\r\n\r\n> Draft (2026-05-31). A **designed-in commitment**, not an afterthought — grounded in research on critically-acclaimed developer docs (Stripe, Twilio, the Rust Book, FastAPI, Cloudflare, Anthropic, Diátaxis, `llms.txt`, Google dev style guide). Governs the **shipped product docs** (authored as code lands); the planning docs (CONTEXT/PRD/ADRs/design docs) are internal and separate.\r\n\r\n## The defining constraint: a dual audience\r\n\r\nspt-core's docs serve **two readers at once** — human developers *and* the **AI dev-agents that build integrations with it**. This is unusual and it is the design constraint: every artifact is authored **once in clean markdown** and served in **two depths** (human-rendered + agent-export). The agent layer is **first-class, not optional** — the strategic signal (Tailwind's docs traffic fell ~40% because assistants answer for it) is, for spt-core, *the goal*: make the agent layer so good that dev-agents integrate correctly on the first try. There is recursive fit here — the same kind of agent that spt-core *hosts* is the one that *reads its docs*.\r\n\r\n## Principles (top techniques, prioritized for spt-core)\r\n\r\n1. **Sub-10-minute killer quickstart** — runnable, deterministic, whole-working-thing-first, no placeholders. TTFHW (\"time to first hello world\") is the single most-cited conversion lever (~68% abandon trials over setup time).\r\n2. **Diátaxis four-mode separation** — tutorial / how-to / reference / explanation, never mixed (mixing is the most-cited cause of confusing docs).\r\n3. **Deterministic, real, copy-pasteable examples everywhere** — no `<YOUR_VALUE_HERE>` placeholders; real values that run. Serves humans *and* agents.\r\n4. **Dual-depth agent exports** — `llms.txt` (slim curated index) + `llms-full.txt` (full concatenated export), auto-generated in CI, plus markdown content negotiation (`.md` suffix / `Accept: text/markdown`) which cuts agent token use ~90% vs HTML.\r\n5. **One canonical way to do X** — explicitly mark deprecated/alternate paths. Non-determinism is fatal for agents.\r\n6. **Complete reference, auto-generated, all error variants** — rustdoc for the public SDK crates (`spt-proto`, `spt-runtime`, `spt-msg`) + a machine-readable manifest/contract schema. Generic placeholders in reference are a failure mode.\r\n7. **Consistent conversational voice** — adopt the Google developer style guide: second person (\"you\"), active voice, knowledgeable-friend tone.\r\n8. **Explain *why*, not just *what*** — conceptual docs + diagrams for the messaging model, the agent lifecycle states, instances/dormancy, and P2P topology.\r\n9. **Stable, never-renamed anchors/URLs** — agents cache links.\r\n10. **Docs-as-product, gated in CI** — generation (rustdoc, `llms.txt`, schema, CLI help) is part of the build so docs can never drift from code. Drift is the #1 most-cited docs failure; this kills it structurally.\r\n\r\n## Information architecture — by capability vertical\r\n\r\nOrganize by capability, each vertical carrying the same four Diátaxis modes internally (the Cloudflare pattern):\r\n\r\n**Messaging · Live-agent lifecycle · Terminal hosting · Networking (P2P + pairing) · Harness contract (manifest + `api`) · Instances · Shells · Self-update.**\r\n\r\n## Killer quickstart targets (two, one per audience)\r\n\r\n- **Human dev:** two agents exchange a message end-to-end in **one command + minimal config**, < 10 min — the core primitive, whole-thing-first, then decomposed.\r\n- **Dev-agent integrator:** a minimal **adapter** that satisfies the manifest + `api` contract and drives one lifecycle operation — the \"build a harness for spt-core\" hello-world.\r\n\r\n## Agent-consumable docs (spt-core specifics)\r\n…\n\n…\nTop-level `--help` groups by audience (`AGENT COMMANDS` send/ring/ready/poll · `HARNESS COMMANDS` api … · `NODE COMMANDS` pair/subnet/update). Per-command: **USAGE · FLAGS · EXAMPLES (real values) · LEARN MORE**. Beyond gh: a **`spt <cmd> --help --json`** structured-help mode so dev-agents parse the contract without scraping, plus gh's uniform **`--json <fields>` / `--jq` / `--template`** trio on any list command. The `--json` help export is generated + CI-gated alongside rustdoc and the schema.","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,null,42,null,147]},"fileSize":13143,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\DOCS-STRATEGY.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":147,"totalBytes":3731,"outputLines":33,"outputBytes":3731,"shownRange":{"start":1,"end":33},"nextOffset":34}}},"isError":false,"timestamp":1789107092070}}
{"type":"message","id":"9f58a603","parentId":"6de27c6d","timestamp":"2026-09-11T06:11:32.084Z","message":{"role":"toolResult","toolCallId":"call_NhO1SM3Z9tXMJIAGwPK6q8W3|fc_0330c101aa2c61dc016aa39b91a19887d18e32ca2e2d617b18","toolName":"read","content":[{"type":"text","text":"# Golden CI: milestone-batch integration with fast-forward-only main\n\nStatus: accepted (operator-ruled 2026-07-27, grill session with doyle)\n\nPer-PR full-suite CI on two single-box runners produced eight-hour merge sweeps dominated by queue wait and environmental flakes, and the merge-then-verify gap let a PR merge on a stale green (#106, 2026-07-27 freeze). We decided: PRs run a **thin lane** only (lint, unit, traceability); the full suite runs once per milestone on a **golden branch** — a merge chain of every milestone PR, assembled by a builder and **ruled by the gater** — and on green, main advances by **fast-forward to the exact tested sha**. Nothing else ever moves main; an urgent fix is a golden batch of one.\n\n“Gater-assembled” would have the gater checking his own work, which is the failure this project has already paid for. Milestone A ran the corrected shape in practice: doyle assigned assembly to todlando and retained ruling. A gate loses its independence the moment its author rules it. Drift between documented and practised procedure is a finding to fix, never leave standing.\n\n## Considered options\n\n- **Bisection-first red handling (\"inverse merge pyramid\")** — the original proposal: split the batch in halves until the failure isolates. Rejected as the *primary* mechanism because this repo's measured flake rate (silent-peer: 4/30 on a quiet box before its root fix) makes half-verdicts unreliable, and each level costs a serialized full suite on single-box runners. Kept as the *last resort* behind the red protocol: names first, diagnose-and-fix against the batch, registry-matched flakes get one same-sha rerun.\n- **Green-then-merge-individually** — golden as a gate but PRs merge normally after. Rejected: recreated merge commits mean the final main sha was never tested, which is the exact stale-green class the strategy exists to kill.\n- **GitHub merge queue** — requires branch protection this repo deliberately lacks (agent-watcher enforcement), does rolling batches not milestone batches, cannot express the red protocol.\n- **Eject-and-proceed on conflict** — shipping the batch minus a conflicting PR. Rejected: a milestone ships whole; conflicts bounce to their author and the golden run waits.\n\n## Consequences\n\n- Retired once the pilot proves the mechanics: sacred-baseline runs, merge freezes, the main-run concurrency-cancellation hazard, and per-PR merge choreography.\n- The flake registry (checked-in, test-infra-owned, entries reviewed like code) becomes load-bearing: the red protocol reads it mechanically.\n- A milestone's first full-suite execution of a diff happens at golden time; builders keep local gate rigs for pre-batch confidence.\n- Rollout: pilot on the milestone after FIELD-TRUTH W1, delivered as one CI lane bundle (absorbs the seeded concurrency-exemption + workflow_dispatch fix); old procedures retire only after the pilot's first green fast-forward.\n\n## The silent-skip class\n\n<!-- [doc->REQ-GOLDEN-CI-LANE] -->\n\nMilestone A's golden pilot went green while the milestone's defining seam had never executed. The two-host cross-machine legs came back `skipped`, and a skipped job is **silence about its seam, never evidence**. Six distinct mechanisms produce evidence-shaped silence, and all six were present in the milestone's release path:\n\n- **Face 1 — the marker is absent.** The leg is opt-in on a token (`[twohost]` in the head commit message). Measured: it had executed **zero times across the last 40 runs**, including a release run and every main merge. From inside a run history, *standing design* and *standing oversight are indistinguishable* — the survey that shows a leg never running is the strongest available defence for concluding it was never meant to, which is precisely how the gap survived.\n- **Face 2 — a trigger-impossible expression sits in a GATE position.** `contains(github.event.pull_request.title, …)` in `golden.yml@6bf2bd9`, whose triggers are `push: golden/**` + `workflow_dispatch`: `github.event.pull_request` is always null there, so the clause is unreachable text that *reads* as a live route and invites a probe designed against it. **The defect is the gate position, not the reference.** The identical expression is defensive and correct elsewhere in the same file — `ref: ${{ github.event.pull_request.head.sha || github.sha }}` at `golden.yml@ce4386e:822` resolves correctly on push via its fallback, and `PR_NUMBER: ${{ github.event.pull_request.number }}` at `golden.yml@ce4386e:833` is empty on push and guarded by `[ -n \"$PR_NUMBER\" ]` …\n- **Face 3 — the dependency skips.** A `needs:` upstream that fails, combined with a gate carrying no `always()` / `!cancelled()`. A single *bystander* unit failure on one box would have skipped both two-host legs — manufacturing the exact instrument failure the red protocol classifies as blocking, in the run that was supposed to prove the seam. **Live proof:** on golden run `30501468421`, Windows `test` failed while both `twohost-a` and `twohost-b` still existed as queued job records; `!cancelled()` preserved the seam legs through the exact upstream-red shape this ruling was designed for. Queued existence proves the gate, not the seam—the seam remains unproven until both jobs conclude non-skipped.\n- **Face 4 — the attribution parse finds nothing.** `ci-notify.sh` extracts a line-anchored `Co-authored by:` trailer. A commit body containing literal backslash-`n` characters leaves the apparent trailer mid-line, so the extractor matches nothing and the co-author silently receives no notification. This is the same class: silence that reads as “there was none.” A missing parseable trailer must emit a workflow warning and explicitly report the doyle-only fallback. Notification delivery remains best-effort and cannot change the gate verdict.\n- **Face 5 — the red exits without evidence.** Golden run `30501468421`, Windows job `90742055246`, reported `worker_lifecycle_e2e` as only `running 1 test` followed by exit code 1: every child outcome, assertion, and observability point sat *after* a `taskkill /PID <daemon.pid> /F /T` reaper. A hard-killed harness cannot unwind, so it cannot print a panic or assertion. Emit complete child status/stdout/stderr before any destructive boundary. A breadcrumb pid is not identity: bind the observed daemon to its creation time, then require the live pid to retain that start time and resolve to the exact expected executable; refuse self, ancestors, unreadable identity, or mismatch. A red carrying no reason is closer to silence than evidence.\n- **Face 6 — a competent run measures the wrong tree.** The first reassembled tip `aa487b9` sat on a sibling line from `ce4386e`, omitting the six-commit repair batch—including the `SPT_HOME` isolation repair and the two-host independence workflow that produced the seam evidence. A golden run there would likely have gone green while testing none of the repairs it purported to validate. Every other check verified *what* the run measured; none verified **which tree** it measured. The discrepancy surfaced only because falsifiable source facts disagreed: the requirement seed promised five production `spt_home()` resolutions in `daemon_inhibit`, while the candidate carried the old three-call shape. This is provenance of the subject, not competence of the instrume…\n\n### Rulings\n\n1. **A load-bearing seam is never opt-in on the golden branch.** Golden legs are **default-on**, with an explicit `workflow_dispatch` opt-*out* reserved for intentionally isolating other evidence. Omission must not be able to skip a seam; only a deliberate, recorded act may. The mechanism in force: `if: ${{ !cancelled() && (github.event_name != 'workflow_dispatch' || inputs.twohost) }}` — on a `golden/**` push this reduces to `!cancelled()`, so the legs run unconditionally; on dispatch a typed `twohost: boolean, default: true` governs. This makes face 1 *structurally impossible* rather than merely unlikely.\n2. **A `needs:` used as a rendezvous barrier must say so with `!cancelled()`.** Where a dependency exists only to release coordinated roles together (each self-hosted box has one slot, so an unguarded `needs:` lets one role starve behind the other machine's leg), the gate must make the seam evidence independent of the suite's result. An unrelated red must not be able to erase it.\n3. **A dead clause inside a live gate is a booby trap — delete it, do not leave it.** It documents a route that does not exist and will be designed against.\n4. **Verdicts come from the job list and its conclusions, never from a notification.** An absent or `skipped` job is silence, not a pass. The run-level `success` is compatible with every face above. Missing attribution must likewise be loud even though notification remains best-effort: best-effort delivery is a promise about the channel, never a licence for the producer to fail quietly.\n5. **A milestone's defining seam must have an *executing* leg in the tree that ships.** Prefer probing the tree that ships over a marker-commit probe of an earlier tree: a probe of the pre-repair tree can be skipped by the very defect under repair.\n6. **After anything touches a workflow — including your own fix — re-read every verification procedure written against it.** The repair that closed face 1 retired the marker token as a gate, which silently turned “confirm the token is present” into a check measuring a mechanism that no longer existed. Both the gate's author and its verifier had written procedures against the old instrument. Quote conditions as `<file>@<sha>`, and read both the workflow and requirement registry at the sha under test, never in a working checkout. A stale local ref is a shared instrument, so its staleness is a fleet-wide defect rather than a personal slip; comparing against a branch name hides that defect. Prefer an explicit sha, or verify the ref before using it. Treat a workf…\n7. **Where a gate has several ways to silently not fire, two independent checkers verify it and a DISAGREEMENT between them is itself the finding.** A check with a single owner is not a mechanism.\n8. **Verify the subject before trusting its evidence.** Before pushing a golden candidate, assert the ruled repair tip is an ancestor, then independently assert file-level facts that characterize the intended tree; ancestry alone cannot catch a bad cherry-pick. Use explicit blob hashes for load-bearing files and workflow conditions read at the candidate SHA. Literal source counts must name a fixed-string predicate and its tool—for this incident, `grep -F -c 'spt_home()'`. A regex dialect where `()` is a group would silently match bare `spt_home` and return 10 instead of the intended 5; POSIX BRE treats the parentheses literally and returns 5, so a reported count without its tool and dialect is not reproducible evidence. A falsifiable count or hash can trip; …\n\nA future workflow lint should derive each workflow file's declared trigger set and reject unreachable `github.event.<field>` references in `if:` positions while allowing the same reference behind explicit fallbacks and presence guards. It must inspect the whole workflow after any gate edit, because repairing one instance does not repair sibling instances of the mechanism. The lint remains an inactive requirement seed until its delivery milestone.\n\n## Retired-host side-effect class\n\nThis is distinct from the six silent-evidence faces: **a mechanism was removed and a responsibility it discharged only as a side effect was not re-homed.** The dedicated release PR used to advance `main` when merged. Golden CI correctly retired that PR vehicle, but the original procedure added no explicit replacement because “advance main” had never been written as an obligation. The resulting release sequence could tag and publish the correct signed candidate while `origin/main` silently lagged it, causing the next milestone to branch from stale code.\n\nThe omission became visible because the release driver published his exact commands for review before running them: his first step fast-forwarded only a local branch and no later step pushed `main`. **Retired-host side-effect rule: when you retire a mechanism, enumerate its side effects and re-home each one—the work and the sentence that explains the work.** This retirement lost both in opposite directions: a responsibility vanished with its host (the release-PR merge stopped advancing `main`, and no step named the work), while a by-product outlived the sentence explaining it (the replacement fast-forward push still fires `push:[main]` CI, but the text saying what that run is for disappeared). One stopped happening unnoticed; one kept happening without a kno…\n\nA third paid precedent completes the class in the other direction: the name `docs-publish.yml` outlived the workflow itself after its docs step moved into `release.yml`, so a release driver followed the stale runbook name and waited for a workflow that could never appear (the documentation drift repaired for PR #113). The three failures are distinct consequences of one missing retirement inventory: responsibility vanished with its host, a surviving by-product lost the sentence that gave it meaning, and a name survived the thing it named.\n\n## Release shape under golden CI\n\n<!-- [doc->REQ-GOLDEN-CI-LANE] -->\n\nThe release runbook's dedicated release-PR rule and this ADR's fast-forward-only rule conflict under golden CI. A release PR stacked after the ruled tip would put the tag on a commit no golden run tested: the runbook's own feared unvalidated release commit, reached through the other door. **Tested SHA equals shipped SHA outranks bump-in-PR.** The version bump, lockfile, generated docs, and changelog ride the milestone batch and are tested with it.\n\nMain advances only to a SHA whose golden run is **green**. “Tested” means the suite passed; an explained red is not golden evidence, regardless of whether its mechanism predates the batch. The update-set is signed, and every node's `spt update` verifies that signature: shipping on an explained red would make the signature attest to provenance grounded in a narrative rather than the gate. A signature must never attest to something weaker than the gate claims. **v0.45.0 having shipped carrying the same hazard is not precedent for repeating it — it is how the hazard became known.**\n\nRelease-shape independence remains substantive but moves out of band: at the ruled tip, the release driver records an audit that decodes the counter from the last published signed metadata, audits the changelog against the actual commit range rather than the milestone narrative, proves update-set compatibility constants unchanged at that SHA, and justifies the bump level from observable behavior changes.\n\nThere are **no post-golden edits**—not a changelog date or rider line. After the run, the tree is frozen. Any delta requires a new batch commit and rerun; otherwise ship exactly what was tested.\n\n### Amendment, 2026-08-02 (operator-ruled): the absolute narrows to a provable-delta exception\n\n**Struck:** the sentence above read as an absolute — *any* delta requires a rerun. **Replaced by:** post-golden edits are refused **by default**, and the refusal narrows only for a delta whose defect provably sits outside what golden validated.\n\n**Tested SHA equals shipped SHA** is unchanged as the governing principle for everything golden actually validated. What was over-broad was treating every byte of the tree as validated. Golden's verdict rests on what its gates inspect; a delta no gate reads cannot invalidate a verdict that never rested on it, and re-running the suite against a byte-identical compiled tree re-purchases evidence already held. The rule as written therefore charged a full window — both self-hosted test legs, both n1-gates, both two-host legs — to confirm a result it already had.\n…\n**Retirement inventory (this ADR's own rule, applied to this amendment).** The absolute was also doing a second job: it discouraged post-hoc tinkering of any kind, including edits that look harmless but are not. That job is re-homed onto the provability bar rather than dropped — the bar refuses precisely the \"surely this is harmless\" class, because it demands a diff and a measurement instead of a judgement. Sibling instance re-homed with it: `docs/RELEASE-RUNBOOK.md` step 1 carried the same absolute and now carries the same amendment.\n\n[Showing lines 1-73 of 88. Use :74 to continue. Some lines truncated to 768 chars]"}],"details":{"truncation":{"content":"# Golden CI: milestone-batch integration with fast-forward-only main\r\n\r\nStatus: accepted (operator-ruled 2026-07-27, grill session with doyle)\r\n\r\nPer-PR full-suite CI on two single-box runners produced eight-hour merge sweeps dominated by queue wait and environmental flakes, and the merge-then-verify gap let a PR merge on a stale green (#106, 2026-07-27 freeze). We decided: PRs run a **thin lane** only (lint, unit, traceability); the full suite runs once per milestone on a **golden branch** — a merge chain of every milestone PR, assembled by a builder and **ruled by the gater** — and on green, main advances by **fast-forward to the exact tested sha**. Nothing else ever moves main; an urgent fix is a golden batch of one.\r\n\r\n“Gater-assembled” would have the gater checking his own work, which is the failure this project has already paid for. Milestone A ran the corrected shape in practice: doyle assigned assembly to todlando and retained ruling. A gate loses its independence the moment its author rules it. Drift between documented and practised procedure is a finding to fix, never leave standing.\r\n\r\n## Considered options\r\n\r\n- **Bisection-first red handling (\"inverse merge pyramid\")** — the original proposal: split the batch in halves until the failure isolates. Rejected as the *primary* mechanism because this repo's measured flake rate (silent-peer: 4/30 on a quiet box before its root fix) makes half-verdicts unreliable, and each level costs a serialized full suite on single-box runners. Kept as the *last resort* behind the red protocol: names first, diagnose-and-fix against the batch, registry-matched flakes get one same-sha rerun.\r\n- **Green-then-merge-individually** — golden as a gate but PRs merge normally after. Rejected: recreated merge commits mean the final main sha was never tested, which is the exact stale-green class the strategy exists to kill.\r\n- **GitHub merge queue** — requires branch protection this repo deliberately lacks (agent-watcher enforcement), does rolling batches not milestone batches, cannot express the red protocol.\r\n- **Eject-and-proceed on conflict** — shipping the batch minus a conflicting PR. Rejected: a milestone ships whole; conflicts bounce to their author and the golden run waits.\r\n\r\n## Consequences\r\n\r\n- Retired once the pilot proves the mechanics: sacred-baseline runs, merge freezes, the main-run concurrency-cancellation hazard, and per-PR merge choreography.\r\n- The flake registry (checked-in, test-infra-owned, entries reviewed like code) becomes load-bearing: the red protocol reads it mechanically.\r\n- A milestone's first full-suite execution of a diff happens at golden time; builders keep local gate rigs for pre-batch confidence.\r\n- Rollout: pilot on the milestone after FIELD-TRUTH W1, delivered as one CI lane bundle (absorbs the seeded concurrency-exemption + workflow_dispatch fix); old procedures retire only after the pilot's first green fast-forward.\r\n\r\n## The silent-skip class\r\n\r\n<!-- [doc->REQ-GOLDEN-CI-LANE] -->\r\n\r\nMilestone A's golden pilot went green while the milestone's defining seam had never executed. The two-host cross-machine legs came back `skipped`, and a skipped job is **silence about its seam, never evidence**. Six distinct mechanisms produce evidence-shaped silence, and all six were present in the milestone's release path:\r\n\r\n- **Face 1 — the marker is absent.** The leg is opt-in on a token (`[twohost]` in the head commit message). Measured: it had executed **zero times across the last 40 runs**, including a release run and every main merge. From inside a run history, *standing design* and *standing oversight are indistinguishable* — the survey that shows a leg never running is the strongest available defence for concluding it was never meant to, which is precisely how the gap survived.\r\n- **Face 2 — a trigger-impossible expression sits in a GATE position.** `contains(github.event.pull_request.title, …)` in `golden.yml@6bf2bd9`, whose triggers are `push: golden/**` + `workflow_dispatch`: `github.event.pull_request` is always null there, so the clause is unreachable text that *reads* as a live route and invites a probe designed against it. **The defect is the gate position, not the reference.** The identical expression is defensive and correct elsewhere in the same file — `ref: ${{ github.event.pull_request.head.sha || github.sha }}` at `golden.yml@ce4386e:822` resolves correctly on push via its fallback, and `PR_NUMBER: ${{ github.event.pull_request.number }}` at `golden.yml@ce4386e:833` is empty on push and guarded by `[ -n \"$PR_NUMBER\" ]` …\n- **Face 3 — the dependency skips.** A `needs:` upstream that fails, combined with a gate carrying no `always()` / `!cancelled()`. A single *bystander* unit failure on one box would have skipped both two-host legs — manufacturing the exact instrument failure the red protocol classifies as blocking, in the run that was supposed to prove the seam. **Live proof:** on golden run `30501468421`, Windows `test` failed while both `twohost-a` and `twohost-b` still existed as queued job records; `!cancelled()` preserved the seam legs through the exact upstream-red shape this ruling was designed for. Queued existence proves the gate, not the seam—the seam remains unproven until both jobs conclude non-skipped.\r\n- **Face 4 — the attribution parse finds nothing.** `ci-notify.sh` extracts a line-anchored `Co-authored by:` trailer. A commit body containing literal backslash-`n` characters leaves the apparent trailer mid-line, so the extractor matches nothing and the co-author silently receives no notification. This is the same class: silence that reads as “there was none.” A missing parseable trailer must emit a workflow warning and explicitly report the doyle-only fallback. Notification delivery remains best-effort and cannot change the gate verdict.\r\n- **Face 5 — the red exits without evidence.** Golden run `30501468421`, Windows job `90742055246`, reported `worker_lifecycle_e2e` as only `running 1 test` followed by exit code 1: every child outcome, assertion, and observability point sat *after* a `taskkill /PID <daemon.pid> /F /T` reaper. A hard-killed harness cannot unwind, so it cannot print a panic or assertion. Emit complete child status/stdout/stderr before any destructive boundary. A breadcrumb pid is not identity: bind the observed daemon to its creation time, then require the live pid to retain that start time and resolve to the exact expected executable; refuse self, ancestors, unreadable identity, or mismatch. A red carrying no reason is closer to silence than evidence.\r\n- **Face 6 — a competent run measures the wrong tree.** The first reassembled tip `aa487b9` sat on a sibling line from `ce4386e`, omitting the six-commit repair batch—including the `SPT_HOME` isolation repair and the two-host independence workflow that produced the seam evidence. A golden run there would likely have gone green while testing none of the repairs it purported to validate. Every other check verified *what* the run measured; none verified **which tree** it measured. The discrepancy surfaced only because falsifiable source facts disagreed: the requirement seed promised five production `spt_home()` resolutions in `daemon_inhibit`, while the candidate carried the old three-call shape. This is provenance of the subject, not competence of the instrume…\n\r\n### Rulings\r\n\r\n1. **A load-bearing seam is never opt-in on the golden branch.** Golden legs are **default-on**, with an explicit `workflow_dispatch` opt-*out* reserved for intentionally isolating other evidence. Omission must not be able to skip a seam; only a deliberate, recorded act may. The mechanism in force: `if: ${{ !cancelled() && (github.event_name != 'workflow_dispatch' || inputs.twohost) }}` — on a `golden/**` push this reduces to `!cancelled()`, so the legs run unconditionally; on dispatch a typed `twohost: boolean, default: true` governs. This makes face 1 *structurally impossible* rather than merely unlikely.\r\n2. **A `needs:` used as a rendezvous barrier must say so with `!cancelled()`.** Where a dependency exists only to release coordinated roles together (each self-hosted box has one slot, so an unguarded `needs:` lets one role starve behind the other machine's leg), the gate must make the seam evidence independent of the suite's result. An unrelated red must not be able to erase it.\r\n3. **A dead clause inside a live gate is a booby trap — delete it, do not leave it.** It documents a route that does not exist and will be designed against.\r\n4. **Verdicts come from the job list and its conclusions, never from a notification.** An absent or `skipped` job is silence, not a pass. The run-level `success` is compatible with every face above. Missing attribution must likewise be loud even though notification remains best-effort: best-effort delivery is a promise about the channel, never a licence for the producer to fail quietly.\r\n5. **A milestone's defining seam must have an *executing* leg in the tree that ships.** Prefer probing the tree that ships over a marker-commit probe of an earlier tree: a probe of the pre-repair tree can be skipped by the very defect under repair.\r\n6. **After anything touches a workflow — including your own fix — re-read every verification procedure written against it.** The repair that closed face 1 retired the marker token as a gate, which silently turned “confirm the token is present” into a check measuring a mechanism that no longer existed. Both the gate's author and its verifier had written procedures against the old instrument. Quote conditions as `<file>@<sha>`, and read both the workflow and requirement registry at the sha under test, never in a working checkout. A stale local ref is a shared instrument, so its staleness is a fleet-wide defect rather than a personal slip; comparing against a branch name hides that defect. Prefer an explicit sha, or verify the ref before using it. Treat a workf…\n7. **Where a gate has several ways to silently not fire, two independent checkers verify it and a DISAGREEMENT between them is itself the finding.** A check with a single owner is not a mechanism.\r\n8. **Verify the subject before trusting its evidence.** Before pushing a golden candidate, assert the ruled repair tip is an ancestor, then independently assert file-level facts that characterize the intended tree; ancestry alone cannot catch a bad cherry-pick. Use explicit blob hashes for load-bearing files and workflow conditions read at the candidate SHA. Literal source counts must name a fixed-string predicate and its tool—for this incident, `grep -F -c 'spt_home()'`. A regex dialect where `()` is a group would silently match bare `spt_home` and return 10 instead of the intended 5; POSIX BRE treats the parentheses literally and returns 5, so a reported count without its tool and dialect is not reproducible evidence. A falsifiable count or hash can trip; …\n\r\nA future workflow lint should derive each workflow file's declared trigger set and reject unreachable `github.event.<field>` references in `if:` positions while allowing the same reference behind explicit fallbacks and presence guards. It must inspect the whole workflow after any gate edit, because repairing one instance does not repair sibling instances of the mechanism. The lint remains an inactive requirement seed until its delivery milestone.\r\n\r\n## Retired-host side-effect class\r\n\r\nThis is distinct from the six silent-evidence faces: **a mechanism was removed and a responsibility it discharged only as a side effect was not re-homed.** The dedicated release PR used to advance `main` when merged. Golden CI correctly retired that PR vehicle, but the original procedure added no explicit replacement because “advance main” had never been written as an obligation. The resulting release sequence could tag and publish the correct signed candidate while `origin/main` silently lagged it, causing the next milestone to branch from stale code.\r\n\r\nThe omission became visible because the release driver published his exact commands for review before running them: his first step fast-forwarded only a local branch and no later step pushed `main`. **Retired-host side-effect rule: when you retire a mechanism, enumerate its side effects and re-home each one—the work and the sentence that explains the work.** This retirement lost both in opposite directions: a responsibility vanished with its host (the release-PR merge stopped advancing `main`, and no step named the work), while a by-product outlived the sentence explaining it (the replacement fast-forward push still fires `push:[main]` CI, but the text saying what that run is for disappeared). One stopped happening unnoticed; one kept happening without a kno…\n\r\nA third paid precedent completes the class in the other direction: the name `docs-publish.yml` outlived the workflow itself after its docs step moved into `release.yml`, so a release driver followed the stale runbook name and waited for a workflow that could never appear (the documentation drift repaired for PR #113). The three failures are distinct consequences of one missing retirement inventory: responsibility vanished with its host, a surviving by-product lost the sentence that gave it meaning, and a name survived the thing it named.\r\n\r\n## Release shape under golden CI\r\n\r\n<!-- [doc->REQ-GOLDEN-CI-LANE] -->\r\n\r\nThe release runbook's dedicated release-PR rule and this ADR's fast-forward-only rule conflict under golden CI. A release PR stacked after the ruled tip would put the tag on a commit no golden run tested: the runbook's own feared unvalidated release commit, reached through the other door. **Tested SHA equals shipped SHA outranks bump-in-PR.** The version bump, lockfile, generated docs, and changelog ride the milestone batch and are tested with it.\r\n\r\nMain advances only to a SHA whose golden run is **green**. “Tested” means the suite passed; an explained red is not golden evidence, regardless of whether its mechanism predates the batch. The update-set is signed, and every node's `spt update` verifies that signature: shipping on an explained red would make the signature attest to provenance grounded in a narrative rather than the gate. A signature must never attest to something weaker than the gate claims. **v0.45.0 having shipped carrying the same hazard is not precedent for repeating it — it is how the hazard became known.**\r\n\r\nRelease-shape independence remains substantive but moves out of band: at the ruled tip, the release driver records an audit that decodes the counter from the last published signed metadata, audits the changelog against the actual commit range rather than the milestone narrative, proves update-set compatibility constants unchanged at that SHA, and justifies the bump level from observable behavior changes.\r\n\r\nThere are **no post-golden edits**—not a changelog date or rider line. After the run, the tree is frozen. Any delta requires a new batch commit and rerun; otherwise ship exactly what was tested.\r\n\r\n### Amendment, 2026-08-02 (operator-ruled): the absolute narrows to a provable-delta exception\r\n\r\n**Struck:** the sentence above read as an absolute — *any* delta requires a rerun. **Replaced by:** post-golden edits are refused **by default**, and the refusal narrows only for a delta whose defect provably sits outside what golden validated.\r\n\r\n**Tested SHA equals shipped SHA** is unchanged as the governing principle for everything golden actually validated. What was over-broad was treating every byte of the tree as validated. Golden's verdict rests on what its gates inspect; a delta no gate reads cannot invalidate a verdict that never rested on it, and re-running the suite against a byte-identical compiled tree re-purchases evidence already held. The rule as written therefore charged a full window — both self-hosted test legs, both n1-gates, both two-host legs — to confirm a result it already had.\r","truncated":true,"truncatedBy":"lines","totalLines":88,"totalBytes":17549,"outputLines":73,"outputBytes":17549,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":88,"displayContent":{"text":"# Golden CI: milestone-batch integration with fast-forward-only main\r\n\r\nStatus: accepted (operator-ruled 2026-07-27, grill session with doyle)\r\n\r\nPer-PR full-suite CI on two single-box runners produced eight-hour merge sweeps dominated by queue wait and environmental flakes, and the merge-then-verify gap let a PR merge on a stale green (#106, 2026-07-27 freeze). We decided: PRs run a **thin lane** only (lint, unit, traceability); the full suite runs once per milestone on a **golden branch** — a merge chain of every milestone PR, assembled by a builder and **ruled by the gater** — and on green, main advances by **fast-forward to the exact tested sha**. Nothing else ever moves main; an urgent fix is a golden batch of one.\r\n\r\n“Gater-assembled” would have the gater checking his own work, which is the failure this project has already paid for. Milestone A ran the corrected shape in practice: doyle assigned assembly to todlando and retained ruling. A gate loses its independence the moment its author rules it. Drift between documented and practised procedure is a finding to fix, never leave standing.\r\n\r\n## Considered options\r\n\r\n- **Bisection-first red handling (\"inverse merge pyramid\")** — the original proposal: split the batch in halves until the failure isolates. Rejected as the *primary* mechanism because this repo's measured flake rate (silent-peer: 4/30 on a quiet box before its root fix) makes half-verdicts unreliable, and each level costs a serialized full suite on single-box runners. Kept as the *last resort* behind the red protocol: names first, diagnose-and-fix against the batch, registry-matched flakes get one same-sha rerun.\r\n- **Green-then-merge-individually** — golden as a gate but PRs merge normally after. Rejected: recreated merge commits mean the final main sha was never tested, which is the exact stale-green class the strategy exists to kill.\r\n- **GitHub merge queue** — requires branch protection this repo deliberately lacks (agent-watcher enforcement), does rolling batches not milestone batches, cannot express the red protocol.\r\n- **Eject-and-proceed on conflict** — shipping the batch minus a conflicting PR. Rejected: a milestone ships whole; conflicts bounce to their author and the golden run waits.\r\n\r\n## Consequences\r\n\r\n- Retired once the pilot proves the mechanics: sacred-baseline runs, merge freezes, the main-run concurrency-cancellation hazard, and per-PR merge choreography.\r\n- The flake registry (checked-in, test-infra-owned, entries reviewed like code) becomes load-bearing: the red protocol reads it mechanically.\r\n- A milestone's first full-suite execution of a diff happens at golden time; builders keep local gate rigs for pre-batch confidence.\r\n- Rollout: pilot on the milestone after FIELD-TRUTH W1, delivered as one CI lane bundle (absorbs the seeded concurrency-exemption + workflow_dispatch fix); old procedures retire only after the pilot's first green fast-forward.\r\n\r\n## The silent-skip class\r\n\r\n<!-- [doc->REQ-GOLDEN-CI-LANE] -->\r\n\r\nMilestone A's golden pilot went green while the milestone's defining seam had never executed. The two-host cross-machine legs came back `skipped`, and a skipped job is **silence about its seam, never evidence**. Six distinct mechanisms produce evidence-shaped silence, and all six were present in the milestone's release path:\r\n\r\n- **Face 1 — the marker is absent.** The leg is opt-in on a token (`[twohost]` in the head commit message). Measured: it had executed **zero times across the last 40 runs**, including a release run and every main merge. From inside a run history, *standing design* and *standing oversight are indistinguishable* — the survey that shows a leg never running is the strongest available defence for concluding it was never meant to, which is precisely how the gap survived.\r\n- **Face 2 — a trigger-impossible expression sits in a GATE position.** `contains(github.event.pull_request.title, …)` in `golden.yml@6bf2bd9`, whose triggers are `push: golden/**` + `workflow_dispatch`: `github.event.pull_request` is always null there, so the clause is unreachable text that *reads* as a live route and invites a probe designed against it. **The defect is the gate position, not the reference.** The identical expression is defensive and correct elsewhere in the same file — `ref: ${{ github.event.pull_request.head.sha || github.sha }}` at `golden.yml@ce4386e:822` resolves correctly on push via its fallback, and `PR_NUMBER: ${{ github.event.pull_request.number }}` at `golden.yml@ce4386e:833` is empty on push and guarded by `[ -n \"$PR_NUMBER\" ]` …\n- **Face 3 — the dependency skips.** A `needs:` upstream that fails, combined with a gate carrying no `always()` / `!cancelled()`. A single *bystander* unit failure on one box would have skipped both two-host legs — manufacturing the exact instrument failure the red protocol classifies as blocking, in the run that was supposed to prove the seam. **Live proof:** on golden run `30501468421`, Windows `test` failed while both `twohost-a` and `twohost-b` still existed as queued job records; `!cancelled()` preserved the seam legs through the exact upstream-red shape this ruling was designed for. Queued existence proves the gate, not the seam—the seam remains unproven until both jobs conclude non-skipped.\r\n- **Face 4 — the attribution parse finds nothing.** `ci-notify.sh` extracts a line-anchored `Co-authored by:` trailer. A commit body containing literal backslash-`n` characters leaves the apparent trailer mid-line, so the extractor matches nothing and the co-author silently receives no notification. This is the same class: silence that reads as “there was none.” A missing parseable trailer must emit a workflow warning and explicitly report the doyle-only fallback. Notification delivery remains best-effort and cannot change the gate verdict.\r\n- **Face 5 — the red exits without evidence.** Golden run `30501468421`, Windows job `90742055246`, reported `worker_lifecycle_e2e` as only `running 1 test` followed by exit code 1: every child outcome, assertion, and observability point sat *after* a `taskkill /PID <daemon.pid> /F /T` reaper. A hard-killed harness cannot unwind, so it cannot print a panic or assertion. Emit complete child status/stdout/stderr before any destructive boundary. A breadcrumb pid is not identity: bind the observed daemon to its creation time, then require the live pid to retain that start time and resolve to the exact expected executable; refuse self, ancestors, unreadable identity, or mismatch. A red carrying no reason is closer to silence than evidence.\r\n- **Face 6 — a competent run measures the wrong tree.** The first reassembled tip `aa487b9` sat on a sibling line from `ce4386e`, omitting the six-commit repair batch—including the `SPT_HOME` isolation repair and the two-host independence workflow that produced the seam evidence. A golden run there would likely have gone green while testing none of the repairs it purported to validate. Every other check verified *what* the run measured; none verified **which tree** it measured. The discrepancy surfaced only because falsifiable source facts disagreed: the requirement seed promised five production `spt_home()` resolutions in `daemon_inhibit`, while the candidate carried the old three-call shape. This is provenance of the subject, not competence of the instrume…\n\r\n### Rulings\r\n\r\n1. **A load-bearing seam is never opt-in on the golden branch.** Golden legs are **default-on**, with an explicit `workflow_dispatch` opt-*out* reserved for intentionally isolating other evidence. Omission must not be able to skip a seam; only a deliberate, recorded act may. The mechanism in force: `if: ${{ !cancelled() && (github.event_name != 'workflow_dispatch' || inputs.twohost) }}` — on a `golden/**` push this reduces to `!cancelled()`, so the legs run unconditionally; on dispatch a typed `twohost: boolean, default: true` governs. This makes face 1 *structurally impossible* rather than merely unlikely.\r\n2. **A `needs:` used as a rendezvous barrier must say so with `!cancelled()`.** Where a dependency exists only to release coordinated roles together (each self-hosted box has one slot, so an unguarded `needs:` lets one role starve behind the other machine's leg), the gate must make the seam evidence independent of the suite's result. An unrelated red must not be able to erase it.\r\n3. **A dead clause inside a live gate is a booby trap — delete it, do not leave it.** It documents a route that does not exist and will be designed against.\r\n4. **Verdicts come from the job list and its conclusions, never from a notification.** An absent or `skipped` job is silence, not a pass. The run-level `success` is compatible with every face above. Missing attribution must likewise be loud even though notification remains best-effort: best-effort delivery is a promise about the channel, never a licence for the producer to fail quietly.\r\n5. **A milestone's defining seam must have an *executing* leg in the tree that ships.** Prefer probing the tree that ships over a marker-commit probe of an earlier tree: a probe of the pre-repair tree can be skipped by the very defect under repair.\r\n6. **After anything touches a workflow — including your own fix — re-read every verification procedure written against it.** The repair that closed face 1 retired the marker token as a gate, which silently turned “confirm the token is present” into a check measuring a mechanism that no longer existed. Both the gate's author and its verifier had written procedures against the old instrument. Quote conditions as `<file>@<sha>`, and read both the workflow and requirement registry at the sha under test, never in a working checkout. A stale local ref is a shared instrument, so its staleness is a fleet-wide defect rather than a personal slip; comparing against a branch name hides that defect. Prefer an explicit sha, or verify the ref before using it. Treat a workf…\n7. **Where a gate has several ways to silently not fire, two independent checkers verify it and a DISAGREEMENT between them is itself the finding.** A check with a single owner is not a mechanism.\r\n8. **Verify the subject before trusting its evidence.** Before pushing a golden candidate, assert the ruled repair tip is an ancestor, then independently assert file-level facts that characterize the intended tree; ancestry alone cannot catch a bad cherry-pick. Use explicit blob hashes for load-bearing files and workflow conditions read at the candidate SHA. Literal source counts must name a fixed-string predicate and its tool—for this incident, `grep -F -c 'spt_home()'`. A regex dialect where `()` is a group would silently match bare `spt_home` and return 10 instead of the intended 5; POSIX BRE treats the parentheses literally and returns 5, so a reported count without its tool and dialect is not reproducible evidence. A falsifiable count or hash can trip; …\n\r\nA future workflow lint should derive each workflow file's declared trigger set and reject unreachable `github.event.<field>` references in `if:` positions while allowing the same reference behind explicit fallbacks and presence guards. It must inspect the whole workflow after any gate edit, because repairing one instance does not repair sibling instances of the mechanism. The lint remains an inactive requirement seed until its delivery milestone.\r\n\r\n## Retired-host side-effect class\r\n\r\nThis is distinct from the six silent-evidence faces: **a mechanism was removed and a responsibility it discharged only as a side effect was not re-homed.** The dedicated release PR used to advance `main` when merged. Golden CI correctly retired that PR vehicle, but the original procedure added no explicit replacement because “advance main” had never been written as an obligation. The resulting release sequence could tag and publish the correct signed candidate while `origin/main` silently lagged it, causing the next milestone to branch from stale code.\r\n\r\nThe omission became visible because the release driver published his exact commands for review before running them: his first step fast-forwarded only a local branch and no later step pushed `main`. **Retired-host side-effect rule: when you retire a mechanism, enumerate its side effects and re-home each one—the work and the sentence that explains the work.** This retirement lost both in opposite directions: a responsibility vanished with its host (the release-PR merge stopped advancing `main`, and no step named the work), while a by-product outlived the sentence explaining it (the replacement fast-forward push still fires `push:[main]` CI, but the text saying what that run is for disappeared). One stopped happening unnoticed; one kept happening without a kno…\n\r\nA third paid precedent completes the class in the other direction: the name `docs-publish.yml` outlived the workflow itself after its docs step moved into `release.yml`, so a release driver followed the stale runbook name and waited for a workflow that could never appear (the documentation drift repaired for PR #113). The three failures are distinct consequences of one missing retirement inventory: responsibility vanished with its host, a surviving by-product lost the sentence that gave it meaning, and a name survived the thing it named.\r\n\r\n## Release shape under golden CI\r\n\r\n<!-- [doc->REQ-GOLDEN-CI-LANE] -->\r\n\r\nThe release runbook's dedicated release-PR rule and this ADR's fast-forward-only rule conflict under golden CI. A release PR stacked after the ruled tip would put the tag on a commit no golden run tested: the runbook's own feared unvalidated release commit, reached through the other door. **Tested SHA equals shipped SHA outranks bump-in-PR.** The version bump, lockfile, generated docs, and changelog ride the milestone batch and are tested with it.\r\n\r\nMain advances only to a SHA whose golden run is **green**. “Tested” means the suite passed; an explained red is not golden evidence, regardless of whether its mechanism predates the batch. The update-set is signed, and every node's `spt update` verifies that signature: shipping on an explained red would make the signature attest to provenance grounded in a narrative rather than the gate. A signature must never attest to something weaker than the gate claims. **v0.45.0 having shipped carrying the same hazard is not precedent for repeating it — it is how the hazard became known.**\r\n\r\nRelease-shape independence remains substantive but moves out of band: at the ruled tip, the release driver records an audit that decodes the counter from the last published signed metadata, audits the changelog against the actual commit range rather than the milestone narrative, proves update-set compatibility constants unchanged at that SHA, and justifies the bump level from observable behavior changes.\r\n\r\nThere are **no post-golden edits**—not a changelog date or rider line. After the run, the tree is frozen. Any delta requires a new batch commit and rerun; otherwise ship exactly what was tested.\r\n\r\n### Amendment, 2026-08-02 (operator-ruled): the absolute narrows to a provable-delta exception\r\n\r\n**Struck:** the sentence above read as an absolute — *any* delta requires a rerun. **Replaced by:** post-golden edits are refused **by default**, and the refusal narrows only for a delta whose defect provably sits outside what golden validated.\r\n\r\n**Tested SHA equals shipped SHA** is unchanged as the governing principle for everything golden actually validated. What was over-broad was treating every byte of the tree as validated. Golden's verdict rests on what its gates inspect; a delta no gate reads cannot invalidate a verdict that never rested on it, and re-running the suite against a byte-identical compiled tree re-purchases evidence already held. The rule as written therefore charged a full window — both self-hosted test legs, both n1-gates, both two-host legs — to confirm a result it already had.\r\n…\n**Retirement inventory (this ADR's own rule, applied to this amendment).** The absolute was also doing a second job: it discouraged post-hoc tinkering of any kind, including edits that look harmless but are not. That job is re-homed onto the provability bar rather than dropped — the bar refuses precisely the \"surely this is harmless\" class, because it demands a diff and a measurement instead of a judgement. Sibling instance re-homed with it: `docs/RELEASE-RUNBOOK.md` step 1 carried the same absolute and now carries the same amendment.","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,null,88]},"fileSize":20122,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\adr\\0050-golden-ci-merge-integration.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":88,"totalBytes":17549,"outputLines":73,"outputBytes":17549,"shownRange":{"start":1,"end":73},"nextOffset":74},"limits":{"columnTruncated":{"maxColumn":768}}}},"isError":false,"timestamp":1789107092084}}
{"type":"message","id":"bde02ae4","parentId":"9f58a603","timestamp":"2026-09-11T06:11:32.086Z","message":{"role":"toolResult","toolCallId":"call_BZLAIiMxzrNzT7HCmPSuDcjr|fc_0330c101aa2c61dc016aa39b91a19487d1a66b5eae23c7f1c1","toolName":"read","content":[{"type":"text","text":"# Traceability development contract\n\n> How spt-core uses [`traceable-reqs`](https://github.com/BigscreenVR/traceable-reqs) to keep every requirement traced from doc → impl → test. The manifest is `traceable-reqs.toml` (seeded from PRD `R-*` + KNOWN-HAZARDS invariants). This contract makes the trace pay off instead of rotting.\n\n## Why\n\nThe whole point of the rebuild is to *not* re-introduce the sister project's bugs and to ship the PRD's scope verifiably. A requirement that isn't traced to real evidence (a doc, an implementation, a test) is a requirement you're *hoping* is met. This contract converts that hope into a build that fails when evidence is missing.\n\n## The contract (rules)\n\n1. **The manifest is the authoritative requirement registry.** Every PRD `R-*` requirement and every KNOWN-HAZARDS invariant exists in `traceable-reqs.toml` as a `REQ-*` id. No work without a REQ; no REQ without intent to satisfy. The PRD holds the prose; the manifest holds the id + `required_stages`.\n2. **Tag in the same change as the evidence.** When you write the function / test / doc-section that satisfies a stage, add its `[<stage>-><REQ-ID>]` tag in *that same commit*. Never \"tag later\" — this single rule is what stops the trace from drifting.\n3. **Evidence-proximate tags, not file-tops.** A tag sits on or immediately above the real function, test, doc section, config entry, or workflow step that proves the stage. One tag = one piece of real evidence. Tags at file tops to satisfy coverage are noise and usually wrong.\n4. **KNOWN-HAZARDS are first-class requirements.** Each invariant is a `REQ-HAZARD-*` requiring `unit` (and `int` where cross-process/cross-node). A hazard cannot be \"covered\" without a test tagging it — the anti-regression promise becomes mechanical (PRD success criterion #6).\n5. **Activation, not premature failure.** Every requirement starts `required_stages = []` (inactive) so `check` stays green pre-code. A **milestone (M0–M5) activates** the requirements it delivers by setting their real `required_stages`. Deferred items (`docs/DEFERRED.md`) stay `[]` until promoted.\n6. **Scan roots stay honest.** `[scan].roots` includes every evidence location (`src`, `tests`, `docs`, and later `.github/workflows`, `scripts`). Audit roots whenever a new evidence dir appears — a missing root makes evidence *silently* vanish from the trace.\n7. **Scope at mint.** Every new `REQ-*` joins at least one `[[groups]]` subject scope in the same commit that mints it. The groups partition is what the confusion audit (Gate 4, 2026-07-30) turned into manifest structure: the `req-confusion-audit` skill scores confusability only *within* groups, so an unscoped requirement's confusable pairs go unexamined — roughly half of them, by the audit's measurement. `span-*` groups are the declared cross-scope cover for measured-hot pairs; add one when a new requirement is known to sit confusably against another scope. Do not derive scopes from id prefixes — subject matter, not spelling.\n\n### Stages\n\n`doc` (prose/design/rustdoc) · `impl` (production code) · `unit` (unit test) · `int` (integration / e2e / cross-node). Default activation policy: `[\"doc\",\"impl\",\"unit\"]`; networking/lifecycle/cross-node reqs add `int`.\n\n### Tag examples\n\nReal tags are `[<stage>->REQ-ID]` with a bare stage word. The examples below\nangle-bracket the stage (`[<impl>->...]`) only so the scanner treats them as\nillustrations, not live evidence — write a bare stage word in real code.\n\n…\n\n…\n- **M1–M5:** each milestone activates + covers its requirements before it's called done.\n\n[Showing lines 1-28 of 75. Use :29 to continue]"}],"details":{"truncation":{"content":"# Traceability development contract\n\n> How spt-core uses [`traceable-reqs`](https://github.com/BigscreenVR/traceable-reqs) to keep every requirement traced from doc → impl → test. The manifest is `traceable-reqs.toml` (seeded from PRD `R-*` + KNOWN-HAZARDS invariants). This contract makes the trace pay off instead of rotting.\n\n## Why\n\nThe whole point of the rebuild is to *not* re-introduce the sister project's bugs and to ship the PRD's scope verifiably. A requirement that isn't traced to real evidence (a doc, an implementation, a test) is a requirement you're *hoping* is met. This contract converts that hope into a build that fails when evidence is missing.\n\n## The contract (rules)\n\n1. **The manifest is the authoritative requirement registry.** Every PRD `R-*` requirement and every KNOWN-HAZARDS invariant exists in `traceable-reqs.toml` as a `REQ-*` id. No work without a REQ; no REQ without intent to satisfy. The PRD holds the prose; the manifest holds the id + `required_stages`.\n2. **Tag in the same change as the evidence.** When you write the function / test / doc-section that satisfies a stage, add its `[<stage>-><REQ-ID>]` tag in *that same commit*. Never \"tag later\" — this single rule is what stops the trace from drifting.\n3. **Evidence-proximate tags, not file-tops.** A tag sits on or immediately above the real function, test, doc section, config entry, or workflow step that proves the stage. One tag = one piece of real evidence. Tags at file tops to satisfy coverage are noise and usually wrong.\n4. **KNOWN-HAZARDS are first-class requirements.** Each invariant is a `REQ-HAZARD-*` requiring `unit` (and `int` where cross-process/cross-node). A hazard cannot be \"covered\" without a test tagging it — the anti-regression promise becomes mechanical (PRD success criterion #6).\n5. **Activation, not premature failure.** Every requirement starts `required_stages = []` (inactive) so `check` stays green pre-code. A **milestone (M0–M5) activates** the requirements it delivers by setting their real `required_stages`. Deferred items (`docs/DEFERRED.md`) stay `[]` until promoted.\n6. **Scan roots stay honest.** `[scan].roots` includes every evidence location (`src`, `tests`, `docs`, and later `.github/workflows`, `scripts`). Audit roots whenever a new evidence dir appears — a missing root makes evidence *silently* vanish from the trace.\n7. **Scope at mint.** Every new `REQ-*` joins at least one `[[groups]]` subject scope in the same commit that mints it. The groups partition is what the confusion audit (Gate 4, 2026-07-30) turned into manifest structure: the `req-confusion-audit` skill scores confusability only *within* groups, so an unscoped requirement's confusable pairs go unexamined — roughly half of them, by the audit's measurement. `span-*` groups are the declared cross-scope cover for measured-hot pairs; add one when a new requirement is known to sit confusably against another scope. Do not derive scopes from id prefixes — subject matter, not spelling.\n\n### Stages\n\n`doc` (prose/design/rustdoc) · `impl` (production code) · `unit` (unit test) · `int` (integration / e2e / cross-node). Default activation policy: `[\"doc\",\"impl\",\"unit\"]`; networking/lifecycle/cross-node reqs add `int`.\n\n### Tag examples\n\nReal tags are `[<stage>->REQ-ID]` with a bare stage word. The examples below\nangle-bracket the stage (`[<impl>->...]`) only so the scanner treats them as\nillustrations, not live evidence — write a bare stage word in real code.\n","truncated":true,"truncatedBy":"lines","totalLines":75,"totalBytes":3502,"outputLines":28,"outputBytes":3502,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":75,"displayContent":{"text":"# Traceability development contract\n\n> How spt-core uses [`traceable-reqs`](https://github.com/BigscreenVR/traceable-reqs) to keep every requirement traced from doc → impl → test. The manifest is `traceable-reqs.toml` (seeded from PRD `R-*` + KNOWN-HAZARDS invariants). This contract makes the trace pay off instead of rotting.\n\n## Why\n\nThe whole point of the rebuild is to *not* re-introduce the sister project's bugs and to ship the PRD's scope verifiably. A requirement that isn't traced to real evidence (a doc, an implementation, a test) is a requirement you're *hoping* is met. This contract converts that hope into a build that fails when evidence is missing.\n\n## The contract (rules)\n\n1. **The manifest is the authoritative requirement registry.** Every PRD `R-*` requirement and every KNOWN-HAZARDS invariant exists in `traceable-reqs.toml` as a `REQ-*` id. No work without a REQ; no REQ without intent to satisfy. The PRD holds the prose; the manifest holds the id + `required_stages`.\n2. **Tag in the same change as the evidence.** When you write the function / test / doc-section that satisfies a stage, add its `[<stage>-><REQ-ID>]` tag in *that same commit*. Never \"tag later\" — this single rule is what stops the trace from drifting.\n3. **Evidence-proximate tags, not file-tops.** A tag sits on or immediately above the real function, test, doc section, config entry, or workflow step that proves the stage. One tag = one piece of real evidence. Tags at file tops to satisfy coverage are noise and usually wrong.\n4. **KNOWN-HAZARDS are first-class requirements.** Each invariant is a `REQ-HAZARD-*` requiring `unit` (and `int` where cross-process/cross-node). A hazard cannot be \"covered\" without a test tagging it — the anti-regression promise becomes mechanical (PRD success criterion #6).\n5. **Activation, not premature failure.** Every requirement starts `required_stages = []` (inactive) so `check` stays green pre-code. A **milestone (M0–M5) activates** the requirements it delivers by setting their real `required_stages`. Deferred items (`docs/DEFERRED.md`) stay `[]` until promoted.\n6. **Scan roots stay honest.** `[scan].roots` includes every evidence location (`src`, `tests`, `docs`, and later `.github/workflows`, `scripts`). Audit roots whenever a new evidence dir appears — a missing root makes evidence *silently* vanish from the trace.\n7. **Scope at mint.** Every new `REQ-*` joins at least one `[[groups]]` subject scope in the same commit that mints it. The groups partition is what the confusion audit (Gate 4, 2026-07-30) turned into manifest structure: the `req-confusion-audit` skill scores confusability only *within* groups, so an unscoped requirement's confusable pairs go unexamined — roughly half of them, by the audit's measurement. `span-*` groups are the declared cross-scope cover for measured-hot pairs; add one when a new requirement is known to sit confusably against another scope. Do not derive scopes from id prefixes — subject matter, not spelling.\n\n### Stages\n\n`doc` (prose/design/rustdoc) · `impl` (production code) · `unit` (unit test) · `int` (integration / e2e / cross-node). Default activation policy: `[\"doc\",\"impl\",\"unit\"]`; networking/lifecycle/cross-node reqs add `int`.\n\n### Tag examples\n\nReal tags are `[<stage>->REQ-ID]` with a bare stage word. The examples below\nangle-bracket the stage (`[<impl>->...]`) only so the scanner treats them as\nillustrations, not live evidence — write a bare stage word in real code.\n\n…\n\n…\n- **M1–M5:** each milestone activates + covers its requirements before it's called done.","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,null,41,null,75]},"fileSize":5982,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\docs\\TRACEABILITY.md"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":75,"totalBytes":3502,"outputLines":28,"outputBytes":3502,"shownRange":{"start":1,"end":28},"nextOffset":29}}},"isError":false,"timestamp":1789107092085}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_ho7uyFYwgAuTIUosMPJXFo8u|fc_0330c101aa2c61dc016aa39ba05efc87d1a4407d406090149f","toolName":"read","startedAt":"2026-09-11T06:11:46.816Z","args":{"path":".spt/preserved/infra-close069-20260911/audit.json:154-204:raw"},"intent":"Reading assigned prior audit rows"},"id":"9d9e75d4","parentId":"bde02ae4","timestamp":"2026-09-11T06:11:46.816Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_eosxKySKbDJIlAchBbF9Kw7M|fc_0330c101aa2c61dc016aa39ba05f1487d1a51c6a0f1f36472c","toolName":"grep","startedAt":"2026-09-11T06:11:46.816Z","args":{"path":"crates/spt/tests;crates/spt-daemon/src/daemon.rs"},"intent":"Checking guard and successor implementation"},"id":"eaf36ef5","parentId":"9d9e75d4","timestamp":"2026-09-11T06:11:46.816Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_Of2coArKiHm3ktc8WKni3pAR|fc_0330c101aa2c61dc016aa39ba05f2087d1b1b1eb793a0d633c","toolName":"grep","startedAt":"2026-09-11T06:11:46.816Z","args":{"path":"crates/xtask/src/brainread.rs;crates/spt-daemon/src/docshost.rs"},"intent":"Checking deadline and docs seams"},"id":"f139e4e8","parentId":"eaf36ef5","timestamp":"2026-09-11T06:11:46.816Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_n3G04BdBBAFgD5uRhSNGd2wZ|fc_0330c101aa2c61dc016aa39ba05f2887d1a7f12202a1f5a2e1","toolName":"read","startedAt":"2026-09-11T06:11:46.816Z","args":{"path":"issue://BigscreenVR/spt-bs-releases/304"},"intent":"Reading current milestone intake"},"id":"fdd3f27e","parentId":"f139e4e8","timestamp":"2026-09-11T06:11:46.816Z"}
{"type":"message","id":"703bc778","parentId":"fdd3f27e","timestamp":"2026-09-11T06:11:46.816Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_ho7uyFYwgAuTIUosMPJXFo8u|fc_0330c101aa2c61dc016aa39ba05efc87d1a4407d406090149f","name":"read","arguments":{"i":"Reading assigned prior audit rows","path":".spt/preserved/infra-close069-20260911/audit.json:154-204:raw"},"intent":"Reading assigned prior audit rows"},{"type":"toolCall","id":"call_eosxKySKbDJIlAchBbF9Kw7M|fc_0330c101aa2c61dc016aa39ba05f1487d1a51c6a0f1f36472c","name":"grep","arguments":{"i":"Checking guard and successor implementation","pattern":"DaemonReaper|daemon_pid_path|SUCCEEDS|pid.prev|struct .*Guard","path":"crates/spt/tests;crates/spt-daemon/src/daemon.rs","case":false,"gitignore":true,"skip":null},"intent":"Checking guard and successor implementation"},{"type":"toolCall","id":"call_Of2coArKiHm3ktc8WKni3pAR|fc_0330c101aa2c61dc016aa39ba05f2087d1b1b1eb793a0d633c","name":"grep","arguments":{"i":"Checking deadline and docs seams","pattern":"const.*FILES|dispatch.rs|serve_sync|serve_.*feed|SPT_DOCS_PORT|SPT_TEST_EPHEMERAL","path":"crates/xtask/src/brainread.rs;crates/spt-daemon/src/docshost.rs","case":false,"gitignore":true,"skip":null},"intent":"Checking deadline and docs seams"},{"type":"toolCall","id":"call_n3G04BdBBAFgD5uRhSNGd2wZ|fc_0330c101aa2c61dc016aa39ba05f2887d1a7f12202a1f5a2e1","name":"read","arguments":{"i":"Reading current milestone intake","path":"issue://BigscreenVR/spt-bs-releases/304"},"intent":"Reading current milestone intake"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":12231,"output":251,"cacheRead":100352,"cacheWrite":0,"totalTokens":112834,"cost":{"input":0.12231000000000002,"output":0.01255,"cacheRead":0.100352,"cacheWrite":0,"total":0.235212}},"stopReason":"toolUse","timestamp":1789107092109,"responseId":"resp_0330c101aa2c61dc016aa39b9243c887d1b9a4d10a7860fa63","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0330c101aa2c61dc016aa39ba05efc87d1a4407d406090149f","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading assigned prior audit rows\",\"path\":\".spt/preserved/infra-close069-20260911/audit.json:154-204:raw\"}","call_id":"call_ho7uyFYwgAuTIUosMPJXFo8u","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39ba05f1487d1a51c6a0f1f36472c","type":"function_call","status":"completed","arguments":"{\"i\":\"Checking guard and successor implementation\",\"pattern\":\"DaemonReaper|daemon_pid_path|SUCCEEDS|pid.prev|struct .*Guard\",\"path\":\"crates/spt/tests;crates/spt-daemon/src/daemon.rs\",\"case\":false,\"gitignore\":true,\"skip\":null}","call_id":"call_eosxKySKbDJIlAchBbF9Kw7M","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"grep","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39ba05f2087d1b1b1eb793a0d633c","type":"function_call","status":"completed","arguments":"{\"i\":\"Checking deadline and docs seams\",\"pattern\":\"const.*FILES|dispatch.rs|serve_sync|serve_.*feed|SPT_DOCS_PORT|SPT_TEST_EPHEMERAL\",\"path\":\"crates/xtask/src/brainread.rs;crates/spt-daemon/src/docshost.rs\",\"case\":false,\"gitignore\":true,\"skip\":null}","call_id":"call_Of2coArKiHm3ktc8WKni3pAR","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"grep","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39ba05f2887d1a7f12202a1f5a2e1","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading current milestone intake\",\"path\":\"issue://BigscreenVR/spt-bs-releases/304\"}","call_id":"call_n3G04BdBBAFgD5uRhSNGd2wZ","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}}]},"duration":14701.867500000633,"ttft":14626.497900000773,"completedAt":1789107106811,"contextSnapshot":{"promptTokens":112583,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"message","id":"f63bc858","parentId":"703bc778","timestamp":"2026-09-11T06:11:46.819Z","message":{"role":"toolResult","toolCallId":"call_ho7uyFYwgAuTIUosMPJXFo8u|fc_0330c101aa2c61dc016aa39ba05efc87d1a4407d406090149f","toolName":"read","content":[{"type":"text","text":"      {\n        \"path\": \".github/workflows/golden.yml\",\n        \"description\": \"Docs-floor rereads at 599/622; Windows start still 32 GiB at 229; docs steps retain implicit preceding-success coupling.\"\n      },\n      {\n        \"path\": \"crates/spt-daemon/tests/attach.rs\",\n        \"description\": \"IR-66 remedies present: delayed TICK39 on Unix/Windows at 531/539, delayed ALT_VIEWPORT_MARKER at 656.\"\n      },\n      {\n        \"path\": \"WEBSERVE-272-JIT.md:111-119\",\n        \"description\": \"IR-66 explicitly ruled satisfied; workflow floor rider and driver adoption tracked separately.\"\n      },\n      {\n        \"path\": \".github/ci/reap-census.ps1\",\n        \"description\": \"Family-only process predicate remains at 70–73/123; does not implement IR-76's compiler-load predicate.\"\n      },\n      {\n        \"path\": \"docs/GOLDEN-CI.md:26-51\",\n        \"description\": \"Existing quiet-window contract includes CI occupancy, local build processes, and parent-chain attribution; reuse instead of introducing another definition.\"\n      },\n      {\n        \"path\": \"crates/spt-store/src/proc.rs:46-49,430-433\",\n        \"description\": \"kill_pid and kill_pid_tree still accept bare numeric PIDs; IR-81 primitive-level remedy not present.\"\n      },\n      {\n        \"path\": \"crates/spt-daemon/src/daemon.rs:475-476\",\n        \"description\": \"Pidfile still overwritten directly; IR-82 predecessor preservation not implemented.\"\n      },\n      {\n        \"path\": \"crates/xtask/src/brainread.rs:194-203,295-320\",\n        \"description\": \"IR-94 name-shape predicate and three-file enumeration remain.\"\n      },\n      {\n        \"path\": \"crates/xtask/src/main.rs:69-70\",\n        \"description\": \"pick-audit and disk-floor verbs exist, contradicting stale future-build wording in IR-57/59.\"\n      }\n    ],\n    \"architecture\": \"Separate structural enforcement, procedural adoption, box mitigations, and incident diagnosis. Workflow floor placement is distinct from capacity sizing; process custody is distinct from performance attribution; publication ordering is distinct from inject coverage. Release SHIP authority and passing batteries do not discharge unresolved mechanism claims.\",\n    \"report\": \"## Scope and reading key\\n47 assigned entries: IR-50–97, excluding IR-54 (starts earlier). IR-49's preceding body and the CI-RIDER historical section were seen but not assigned as new IR entries. IR-31 is outside this range and remains the earlier-range owner's embedded-entry responsibility.\\n\\nTrigger = an entry's remedy/intake trigger, not proof its failure recurred. FIRED may be historically established; UNKNOWN means the supplied release facts and inspected material do not establish a qualifying new touch/event. Existing BUILT/CLOSED states stand without gratuitous re-verification. Actions are recommendations for the parent's ruling, not board mutations.\\n\\n## Exhaustive disposition table\\n| IR | Current entry state | Trigger | Recommendation and evidence |\\n|---|---|---|---|\\n| 50 | CLOSED / BUILT, landed v0.59.0 | FIRED historically | CARRY closed. Census/adoption completion and explicit engine-room exclusion already evidenced; release facts supply no reopening. |\\n| 51 | OPEN | UNKNOWN for #199 causal attribution; historical hermeticity pass available | CARRY. Ephemeral advisory ports do not disable peer pump/discovery or establish network causality. Preserve sequencing prohibition against net-off-as-green. |\\n| 52 | BUILT | FIRED historically, generator touch SIGNET | CARRY built. Full recursive command-tree rendering and previously omitted leaves recorded; do not reopen from old third-instance pre-build prose. |\\n| 53 | BUILT / landed v0.59.0 | FIRED historically | CARRY built. Cold-boot arm explicitly names unproved property; three narrower clock-aging siblings remain touch-triggered, not newly diagnosed by release success. |\\n| 55 | OPEN, ARMED-FOR-CAPTURE, hertz | FIRED (standing unfiltered-battery trigger) | CARRY armed, owner unavailable rather than executing. Nextest containment and prior 5×663 green settle sweep are not leak closure; no fresh wedge reported. Keep capture-before-kill protocol. |\\n| 56 | BUILT | FIRED historically | CARRY built. Cross-worktree refusal and explicit foreign-pool takeover measured in entry; IR-42 admission boundary intentionally remains. |\\n| 57 | OPEN, living gater procedure | FIRED (assembly/release arc) | CARRY procedure; correct stale proposed-tool wording: pick-audit already exists (xtask main:69) and caught real LOSS. Release build success proves compilation, not per-pick fidelity or repaired-file behavior. |\\n| 58 | OPEN, unowned; original claim retracted | FIRED (brainread/xtask work this milestone) | COMPOSE cargo-enumerated duplicate-bin check at next tooling intake; no closure evidence. Never resurrect withdrawn nonexistent-bin/prose correction. |\\n| 59 | OPEN, arithmetic/discipline | FIRED, including latest post-push disk-floor red | COMPOSE residual driver adoption/capacity work, carry discipline. Workflow start/end and docs-floor logging now exist; xtask disk-floor exists. Root target 62.32 GiB + CI debug 59.70 GiB and later 4.22 GiB cleanup are mitigations, not bounded accumulation. Do not call 14.3 GiB an explanation for unavailable earlier unit logs. |\\n| 60 | OPEN, script discipline | FIRED (diagnostic/gate reporting) | COMPOSE into next shared driver touch, carry open. Preserve leg verdict separately from wrapper completion; 3167 unit pass then floor red must be reported as distinct outcomes, not flattened to all-green or all-unit-red. Missing exit also requires reading raw Summary (IR-79), not inventing completion. |\\n| 61 | OPEN, accepted with mitigation | UNKNOWN substantive scanner touch | CARRY. No supplied fact establishes literal-tracker unification; unrelated xtask work alone is not this specific trigger. |\\n| 62 | BUILT docs-collision remedy; residual caveat | FIRED historically | CARRY built scoped to docs listener. Other bind surfaces remain conditional residuals; do not imply whole network hermeticity. |\\n| 63 | OPEN, mitigated, historical queued hertz lane | FIRED historically/rig work | COMPOSE with teardown/IR-79/97 adoption, keep open. Path-safe reaps are mitigation; no complete producer-side teardown proof. Update queued-owner language to pending acknowledgement, not active execution. Historical rotating victims do not classify the new sync/convoy red. |\\n| 64 | OPEN, operator reservoir | FIRED historically by IR-86 in-job floor failure; latest disk red reinforces relevance | COMPOSE operator capacity/accept-tax decision, carry open. Current cleanup does not move operator-owned bulk or prove permanent headroom. Do not recite historical 845 GB as a freshly measured current census. |\\n| 65 | REMEDIATED-AT-BOX, OPEN recheck record | UNKNOWN snap/auditd update or reimage | CARRY recheck record; no box commands needed this sweep. Release green is not evidence that effective audit configuration survived a named reset event. |\\n| 66 | BUILT; explicitly due to leave at WEBSERVE close | FIRED, close overdue | CLOSE eligible now. JIT:111–116 already rules satisfied; current attach.rs:531/539/656 retains both delayed needles. Remove stale next-intake two-edit rider from sweep summary; this is source-backed closure, not green-alone retirement. |\\n| 67 | BUILT, battery-template remedy | FIRED historically/intake | CARRY built. Scoped 121-pass battery is only its named scope; do not use --bins as integration coverage or promote it to full golden acceptance. |\\n| 68 | OPEN investigation | UNKNOWN new PSYCHE_INGEST_FAIL/probe slot | CARRY. Existing nonempty-lock experiment refuted the proposed cause; unrelated release facts cannot reinstate index.lock attribution. |\\n| 69 | OPEN; header says parked pre-assembly | FIRED historically close-out recensus | COMPOSE #243 residual plus separately tracked anchored-consumer rider; correct stale header. Body already records landed ec6da9b0 and 338 cli + 2 main residuals. Need residual conversion, generator fix, and SHA-pinned zero recensus before closure. Delivery.rs post-cut sites already converted; no new lane owed there. |\\n| 70 | OPEN, recurrence remedy unscheduled | UNKNOWN construction/API/sink touch | CARRY. Shipped default_bus site correction is not enforced assembly-point closure. IR-92 funnel work may make this a useful next construction-seam rider, but do not assert its trigger from publication work alone. |\\n| 71 | OPEN observability | UNKNOWN qualifying controller-lifecycle/breadcrumb touch | CARRY, eligible next lifecycle instrument rider. Existing info.json polling barrier proves convergence separately; no new persisted-release breadcrumb evidenced. |\\n| 72 | OPEN observability | UNKNOWN qualifying read-model/holder-inspection touch | CARRY. Cleanup process-table custody is not a supported named-seat read verb. |\\n| 73 | OPEN, title/body claim eight pre-checkout sites still owed | FIRED; implementation already present | CLOSE eligible for the entry's original two halves, with implementation evidence explicitly stated. All 5 ci and 3 release sites are after checkout with IR-73 comments; golden docs rereads exist and IR-86 records their live catch. Current header is stale. Capacity derivation and docs dependency coupling remain IR-86, not reasons to re-build IR-73. |\\n| 74 | OPEN /tmp population | FIRED as between-milestone audit opportunity; current Linux touch unknown | COMPOSE bounded /tmp lifecycle at box-audit intake, not a fresh numeric census. Windows cleanup says nothing about kitsubito's 21,643 historical homes. |\\n| 75 | OPEN Linux treqs 127 | UNKNOWN new Linux-driver touch; audit opportunity remains | COMPOSE install-or-explicit-platform-independent-coverage decision with Linux box audit. No proof here of current installation or driver removal; retain stale-state verification obligation, never infer it from overall green. |\\n| 76 | OPEN quiet-window/measurement | FIRED driver/workflow/runbook arc | COMPOSE outstanding enforcement and compiler-load census. Existing GOLDEN-CI:26–51 already supplies a better occupancy/parent-chain contract; reap-census still selects only SPT family. IR-87 proves queue interference, not cause of sync expiry. Historical headline 'manufactured' is stronger than overlap alone; new sweep must not repeat it as a diagnosis. |\\n| 77 | OPEN boot interval visibility | UNKNOWN exact boot/ready-stamp touch | CARRY, compose if next daemon-boot instrumentation lane opens. No timestamped child-entry→ready proof surfaced; full test duration is not boot interval. |\\n| 78 | OPEN silent docs-port override | UNKNOWN new docshost touch; historical belief incident already witnessed | CARRY tiny next-docshost rider. No release fact proves notice implemented; precedence need not be redesigned. |\\n| 79 | OPEN panic/timeout teardown exposure | UNKNOWN new common-module touch; exposure continues | COMPOSE first-wave guard adoption with IR-63/97; pending owner acknowledgement. Preserve panic-vs-hard-kill boundary: Rust Drop alone does not guarantee cleanup on process termination/SIGKILL. Entry's blanket timeout coverage claim needs qualification, not adoption as a guarantee. |\\n| 80 | OPEN; initial product-candidate headline superseded by amendments | FIRED historical investigation opportunity | CARRY residual class, reconcile stale opening. Body identifies brainproc shell-wrapper fixture mechanism and direct production spawn; does not classify all 12 union members. LEAK-count reduction or passing Windows unit set cannot close this. No owner is executing by implication. |\\n| 81 | OPEN primitive + gate; adapter arm CLOSED | FIRED historical proc/xtask work | COMPOSE remaining primitive and script-gate obligations. Current kill_pid(pid) and kill_pid_tree(root) remain bare-PID APIs (proc.rs:46/430); KH7.51 records a broker-site birth-safe correction but one site does not close primitive enforceability. Adapter closure stands, incident cause remains separate. |\\n| 82 | RULED, remedy historically linked #285 | FIRED historical lifecycle/#285 lane opportunity | COMPOSE unbuilt predecessor record independently of #285's site repair. daemon.rs:476 still direct-writes pidfile; no predecessor retention at this path. Header 'main ends at IR-78' is historical/stale. Do not call linked lane completion IR-82 completion. |\\n| 83 | OPEN, operator-rule blocked historical prose | FIRED; superseded box evidence in IR-89 | CARRY direction-witness enforcement residual, reconcile obsolete blocker/LAN-only prescription. IR-89 records actual tailnet ACL+firewall grants and successful tailnet probes, refuting a universal 'never tailnet' necessity. Need parent ruling to replace obsolete remediation with layer-specific admission + permanent reverse witness, not infer full closure from a one-box green. |\\n| 84 | OPEN, first instrument half landed with filing | FIRED historically | CARRY unresolved stall arithmetic/enforcement residual; acknowledge clocked emitter half as built. Timestamp instrumentation does not explain the extra ~27–34 s, shorten behavior, or prove every future arm stamped. |\\n| 85 | OPEN, caps mitigation only | FIRED arm 1; operator arms UNKNOWN | COMPOSE redesigned discriminator after guard/occupancy prerequisites, keep open. Old-sha slowdown establishes head growth not necessary, not environment apportionment. Alternate AB/BA, bank per-leg conditions/output; cap 80/40 remains mitigation. No Defender/torrent/disk causal allocation from concurrency or reclaim recovery. Hertz offline: brief delivered, unacknowledged. |\\n| 86 | OPEN, capacity derivation + docs coupling | FIRED golden/workflow arc | COMPOSE workflow sizing/independent docs dependency rider. golden.yml still 32 GiB start (229), docs floor (626), and OS-only success-coupled conditions (600/617/623). Historical 67.4 GiB footprint motivates re-derivation, not universal guaranteed peak. Latest 14.3<32 post-unit red is additional capacity evidence, not a new product failure. |\\n| 87 | OPEN independent job clocks | FIRED; exact recurrence banked at a9e786b2 | COMPOSE scheduling/rendezvous rider. Entry timeline proves B ended before A began, caused by golden head's own PR runner occupancy; include self-PR, not merely other lanes. Keep raw GitHub conclusions alongside VOID scoring. 900s panel alone cannot separate this from firewall. |\\n| 88 | OPEN pool-release vehicle | FIRED historical teardown; runbook adoption due | COMPOSE permanent release-before-delete/prebuilt recipe; carry open until adoption documented. Positive control already proves cargo-run regrowth vs prebuilt non-regrowth; current cleanup alone doesn't show recipe institutionalized. Prefer existing proven sequence, not an in-verb refusal that can only run after cargo already rebuilt it. |\\n| 89 | BOX applied; WORKFLOW built, landed-pending-golden | FIRED: multiple subsequent goldens | CARRY built pending exact step evidence; flag 'until next golden' stale immediately. No full probe-step outcomes were supplied/read here; next golden occurred but that alone is not exercise proof (steps can skip/partners desynchronize). Read retained step logs to replace pending wording with precise exercised/skipped/failed result; do not reapply operator rules or blame IR-87's 900s red on firewall. |\\n| 90 | OPEN disk refusal/context | FIRED, ripe now | COMPOSE rig-root/target-volume start refusal + current free-space failure context, prerequisite for IR-85 rerun. Reclaims mitigate only. Latest known 3167 unit pass followed by disk floor red is classified at its observed step; unavailable earlier PR logs remain unclassified. |\\n| 91 | CLOSED by filing lane | FIRED historically | CARRY closed. Preserve cited tracked artifacts and scratch manifests; parent cleanup retained evidence, so no reopening shown. |\\n| 92 | OPEN, says fix unassigned | FIRED inject/IO-funnel remedy; parent reports core215/217 merged | PARENT DECISION. Mark header stale but do not close here. Source/contract verification must distinguish inject success publication from relay ordering and per-msg-id exact-once; parent owns substantive reconciliation. |\\n| 93 | OPEN production symbols | UNKNOWN new packaging touch; release build alone is not a source touch | COMPOSE next packaging intake decision, keep open. Successful release build is not PDB availability, symbol matching, installation, or usable frame evidence. Preserve size/profile/operator trade rather than assuming approval. |\\n| 94 | OPEN scanner reach | FIRED at newly added brainread gate; mandatory before bounded serve_sync migration | COMPOSE fail-on-unclassified stream-server census. Current brainread.rs:199 and 306–320 retain name shape/three-file registry. Independent gate defect, not cause of golden sync red. |\\n| 95 | OPEN, measured/censused, diagnostic-only instrumentation | FIRED comparison already ran | COMPOSE prioritized observability + separately versioned exchange-correlated producer trace; retain open. 317/321 is classifier estimate with membership slop, 15 unclassified, not repo-wide floor/rate; no blanket 304-site editing. Diagnostic patch is unlanded, not release behavior. Preserve censored expiry, filtered final snapshot, no stream-between-polls claim, and no inferred budget fix. |\\n| 96 | OPEN cause-unclassified | NOT FIRED for named new qualifying event on supplied facts; cheap discriminator still unrun | CARRY with explicit next-intake investigation, not resolved/non-defect. 0/1 candidate CI vs 3/3 diagnostic HEAVY is confounded tree/workload/box, plus IR-97. Brief delivered to offline hertz is pending acknowledgement, not executing. |\\n| 97 | OPEN protocol deviation | FIRED repeated-run experiment | COMPOSE mandatory between-run identity census/accounting before any repeated IR-85/95/96 work. 0/6/12 carried residues are counts, not measured load or sync cause; 18 seen vs 15 killed does not prove three self-exits. Cleanups do not cure harness enforcement. |\\n\\n## Load-bearing deltas for the parent's edit\\n1. **Retire duplicate work, not residual mechanisms:** close IR-66; IR-73's source contract is implemented at all eight sites and both docs rereads. Amend their stale top-of-register riders. Keep IR-86 capacity/docs dependency debt separate. IR-57 pick-audit and IR-59 disk-floor are already tools, not future tooling proposals.\\n2. **Lifecycle wording needs reconciliation:** IR-69's parked header contradicts its own landed/residual addendum; IR-83's rule-blocked/LAN-only prose conflicts with IR-89's applied tailnet and firewall proof; IR-89's next-golden trigger fired but exact step proof is still needed; IR-92's unassigned header conflicts with parent's merged core215/217 fact. IR-80's product-candidate opening must be read through later scoped fixture findings. IR-82's #285 lane linkage did not deliver its pidfile retention.\\n3. **No causal laundering at release close:** v0.69.0 c105 at 16df0e41 shipped under explicit operator SHIP with known candidate a9e786b2 sync red. 121 scoped passes, release build success, and 3167 Windows unit passes prove exactly those observations. The later floor failure at 14.3 vs 32 GiB is not a unit-test failure; unavailable earlier PR unit logs are still unclassified. No disk/load attribution for sync/convoy from overlap or pass-after-reclaim.\\n4. **Cleanup accounting remains mitigation:** retain separate 62.32 GiB root-target and 59.70 GiB CI-debug measurements; later 38 clean merged worktrees/obsolete clone etc yielded net 4.22 GiB. Do not conflate file-length totals with free-space deltas, or report a structural capacity fix. Parent confirms no dirty/unmerged/retained evidence removed.\\n5. **Coherent next-intake packages:** (A) workflow/driver resource contract: IR-59/60/76/86/87/90/97, preserving separate conditions and budgets; (B) pool teardown adoption: IR-88 with earlier-range pool audit, IR-64 operator decision separate; (C) test lifetime work: IR-63/79/80 plus Linux IR-74/75, without collapsing fixture vs product identity debt IR-81/82; (D) diagnostic continuation: IR-85/95/96 only after occupancy/disk/between-run prerequisites, with no budget widening; (E) small seam-triggered items: IR-94 gate reach and IR-93 symbol packaging. All hertz-shaped work is proposed/pending acknowledgement while offline, not dispatched-and-executing.\\n\\n## Verification limits\\nRead-only tools only; no tests, builds, formatters, linters, probes, re-runs, board writes, or file edits. Closure recommendations use existing recorded proof plus targeted current-source reads, not new runtime verification. Some touch triggers are honestly UNKNOWN because exhaustive change-history traversal was neither supplied nor necessary for a carry ruling.\"\n  },\n  \"parent_rulings\": {\n    \"ir92\": \"Core PR215 docs-only; product inject publisher remains absent. Deployah corrected source comment 5628532753 and confirmed readback in delivery16. IR92 stays open.\",\n    \"closure\": [\n      1,\n      4,\n      66,\n      73\n    ],\n    \"others\": \"Existing built/retired dispositions preserved; residuals carry or compose as recorded in tracked sweep. UNKNOWN triggers are not disproved; source reads are not new executions.\"\n  }\n}\n\n[Showing lines 154-204 of 205. Use :205 to continue]"}],"details":{"truncation":{"content":"      {\n        \"path\": \".github/workflows/golden.yml\",\n        \"description\": \"Docs-floor rereads at 599/622; Windows start still 32 GiB at 229; docs steps retain implicit preceding-success coupling.\"\n      },\n      {\n        \"path\": \"crates/spt-daemon/tests/attach.rs\",\n        \"description\": \"IR-66 remedies present: delayed TICK39 on Unix/Windows at 531/539, delayed ALT_VIEWPORT_MARKER at 656.\"\n      },\n      {\n        \"path\": \"WEBSERVE-272-JIT.md:111-119\",\n        \"description\": \"IR-66 explicitly ruled satisfied; workflow floor rider and driver adoption tracked separately.\"\n      },\n      {\n        \"path\": \".github/ci/reap-census.ps1\",\n        \"description\": \"Family-only process predicate remains at 70–73/123; does not implement IR-76's compiler-load predicate.\"\n      },\n      {\n        \"path\": \"docs/GOLDEN-CI.md:26-51\",\n        \"description\": \"Existing quiet-window contract includes CI occupancy, local build processes, and parent-chain attribution; reuse instead of introducing another definition.\"\n      },\n      {\n        \"path\": \"crates/spt-store/src/proc.rs:46-49,430-433\",\n        \"description\": \"kill_pid and kill_pid_tree still accept bare numeric PIDs; IR-81 primitive-level remedy not present.\"\n      },\n      {\n        \"path\": \"crates/spt-daemon/src/daemon.rs:475-476\",\n        \"description\": \"Pidfile still overwritten directly; IR-82 predecessor preservation not implemented.\"\n      },\n      {\n        \"path\": \"crates/xtask/src/brainread.rs:194-203,295-320\",\n        \"description\": \"IR-94 name-shape predicate and three-file enumeration remain.\"\n      },\n      {\n        \"path\": \"crates/xtask/src/main.rs:69-70\",\n        \"description\": \"pick-audit and disk-floor verbs exist, contradicting stale future-build wording in IR-57/59.\"\n      }\n    ],\n    \"architecture\": \"Separate structural enforcement, procedural adoption, box mitigations, and incident diagnosis. Workflow floor placement is distinct from capacity sizing; process custody is distinct from performance attribution; publication ordering is distinct from inject coverage. Release SHIP authority and passing batteries do not discharge unresolved mechanism claims.\",\n    \"report\": \"## Scope and reading key\\n47 assigned entries: IR-50–97, excluding IR-54 (starts earlier). IR-49's preceding body and the CI-RIDER historical section were seen but not assigned as new IR entries. IR-31 is outside this range and remains the earlier-range owner's embedded-entry responsibility.\\n\\nTrigger = an entry's remedy/intake trigger, not proof its failure recurred. FIRED may be historically established; UNKNOWN means the supplied release facts and inspected material do not establish a qualifying new touch/event. Existing BUILT/CLOSED states stand without gratuitous re-verification. Actions are recommendations for the parent's ruling, not board mutations.\\n\\n## Exhaustive disposition table\\n| IR | Current entry state | Trigger | Recommendation and evidence |\\n|---|---|---|---|\\n| 50 | CLOSED / BUILT, landed v0.59.0 | FIRED historically | CARRY closed. Census/adoption completion and explicit engine-room exclusion already evidenced; release facts supply no reopening. |\\n| 51 | OPEN | UNKNOWN for #199 causal attribution; historical hermeticity pass available | CARRY. Ephemeral advisory ports do not disable peer pump/discovery or establish network causality. Preserve sequencing prohibition against net-off-as-green. |\\n| 52 | BUILT | FIRED historically, generator touch SIGNET | CARRY built. Full recursive command-tree rendering and previously omitted leaves recorded; do not reopen from old third-instance pre-build prose. |\\n| 53 | BUILT / landed v0.59.0 | FIRED historically | CARRY built. Cold-boot arm explicitly names unproved property; three narrower clock-aging siblings remain touch-triggered, not newly diagnosed by release success. |\\n| 55 | OPEN, ARMED-FOR-CAPTURE, hertz | FIRED (standing unfiltered-battery trigger) | CARRY armed, owner unavailable rather than executing. Nextest containment and prior 5×663 green settle sweep are not leak closure; no fresh wedge reported. Keep capture-before-kill protocol. |\\n| 56 | BUILT | FIRED historically | CARRY built. Cross-worktree refusal and explicit foreign-pool takeover measured in entry; IR-42 admission boundary intentionally remains. |\\n| 57 | OPEN, living gater procedure | FIRED (assembly/release arc) | CARRY procedure; correct stale proposed-tool wording: pick-audit already exists (xtask main:69) and caught real LOSS. Release build success proves compilation, not per-pick fidelity or repaired-file behavior. |\\n| 58 | OPEN, unowned; original claim retracted | FIRED (brainread/xtask work this milestone) | COMPOSE cargo-enumerated duplicate-bin check at next tooling intake; no closure evidence. Never resurrect withdrawn nonexistent-bin/prose correction. |\\n| 59 | OPEN, arithmetic/discipline | FIRED, including latest post-push disk-floor red | COMPOSE residual driver adoption/capacity work, carry discipline. Workflow start/end and docs-floor logging now exist; xtask disk-floor exists. Root target 62.32 GiB + CI debug 59.70 GiB and later 4.22 GiB cleanup are mitigations, not bounded accumulation. Do not call 14.3 GiB an explanation for unavailable earlier unit logs. |\\n| 60 | OPEN, script discipline | FIRED (diagnostic/gate reporting) | COMPOSE into next shared driver touch, carry open. Preserve leg verdict separately from wrapper completion; 3167 unit pass then floor red must be reported as distinct outcomes, not flattened to all-green or all-unit-red. Missing exit also requires reading raw Summary (IR-79), not inventing completion. |\\n| 61 | OPEN, accepted with mitigation | UNKNOWN substantive scanner touch | CARRY. No supplied fact establishes literal-tracker unification; unrelated xtask work alone is not this specific trigger. |\\n| 62 | BUILT docs-collision remedy; residual caveat | FIRED historically | CARRY built scoped to docs listener. Other bind surfaces remain conditional residuals; do not imply whole network hermeticity. |\\n| 63 | OPEN, mitigated, historical queued hertz lane | FIRED historically/rig work | COMPOSE with teardown/IR-79/97 adoption, keep open. Path-safe reaps are mitigation; no complete producer-side teardown proof. Update queued-owner language to pending acknowledgement, not active execution. Historical rotating victims do not classify the new sync/convoy red. |\\n| 64 | OPEN, operator reservoir | FIRED historically by IR-86 in-job floor failure; latest disk red reinforces relevance | COMPOSE operator capacity/accept-tax decision, carry open. Current cleanup does not move operator-owned bulk or prove permanent headroom. Do not recite historical 845 GB as a freshly measured current census. |\\n| 65 | REMEDIATED-AT-BOX, OPEN recheck record | UNKNOWN snap/auditd update or reimage | CARRY recheck record; no box commands needed this sweep. Release green is not evidence that effective audit configuration survived a named reset event. |\\n| 66 | BUILT; explicitly due to leave at WEBSERVE close | FIRED, close overdue | CLOSE eligible now. JIT:111–116 already rules satisfied; current attach.rs:531/539/656 retains both delayed needles. Remove stale next-intake two-edit rider from sweep summary; this is source-backed closure, not green-alone retirement. |\\n| 67 | BUILT, battery-template remedy | FIRED historically/intake | CARRY built. Scoped 121-pass battery is only its named scope; do not use --bins as integration coverage or promote it to full golden acceptance. |\\n| 68 | OPEN investigation | UNKNOWN new PSYCHE_INGEST_FAIL/probe slot | CARRY. Existing nonempty-lock experiment refuted the proposed cause; unrelated release facts cannot reinstate index.lock attribution. |\\n| 69 | OPEN; header says parked pre-assembly | FIRED historically close-out recensus | COMPOSE #243 residual plus separately tracked anchored-consumer rider; correct stale header. Body already records landed ec6da9b0 and 338 cli + 2 main residuals. Need residual conversion, generator fix, and SHA-pinned zero recensus before closure. Delivery.rs post-cut sites already converted; no new lane owed there. |\\n| 70 | OPEN, recurrence remedy unscheduled | UNKNOWN construction/API/sink touch | CARRY. Shipped default_bus site correction is not enforced assembly-point closure. IR-92 funnel work may make this a useful next construction-seam rider, but do not assert its trigger from publication work alone. |\\n| 71 | OPEN observability | UNKNOWN qualifying controller-lifecycle/breadcrumb touch | CARRY, eligible next lifecycle instrument rider. Existing info.json polling barrier proves convergence separately; no new persisted-release breadcrumb evidenced. |\\n| 72 | OPEN observability | UNKNOWN qualifying read-model/holder-inspection touch | CARRY. Cleanup process-table custody is not a supported named-seat read verb. |\\n| 73 | OPEN, title/body claim eight pre-checkout sites still owed | FIRED; implementation already present | CLOSE eligible for the entry's original two halves, with implementation evidence explicitly stated. All 5 ci and 3 release sites are after checkout with IR-73 comments; golden docs rereads exist and IR-86 records their live catch. Current header is stale. Capacity derivation and docs dependency coupling remain IR-86, not reasons to re-build IR-73. |\\n| 74 | OPEN /tmp population | FIRED as between-milestone audit opportunity; current Linux touch unknown | COMPOSE bounded /tmp lifecycle at box-audit intake, not a fresh numeric census. Windows cleanup says nothing about kitsubito's 21,643 historical homes. |\\n| 75 | OPEN Linux treqs 127 | UNKNOWN new Linux-driver touch; audit opportunity remains | COMPOSE install-or-explicit-platform-independent-coverage decision with Linux box audit. No proof here of current installation or driver removal; retain stale-state verification obligation, never infer it from overall green. |\\n| 76 | OPEN quiet-window/measurement | FIRED driver/workflow/runbook arc | COMPOSE outstanding enforcement and compiler-load census. Existing GOLDEN-CI:26–51 already supplies a better occupancy/parent-chain contract; reap-census still selects only SPT family. IR-87 proves queue interference, not cause of sync expiry. Historical headline 'manufactured' is stronger than overlap alone; new sweep must not repeat it as a diagnosis. |\\n| 77 | OPEN boot interval visibility | UNKNOWN exact boot/ready-stamp touch | CARRY, compose if next daemon-boot instrumentation lane opens. No timestamped child-entry→ready proof surfaced; full test duration is not boot interval. |\\n| 78 | OPEN silent docs-port override | UNKNOWN new docshost touch; historical belief incident already witnessed | CARRY tiny next-docshost rider. No release fact proves notice implemented; precedence need not be redesigned. |\\n| 79 | OPEN panic/timeout teardown exposure | UNKNOWN new common-module touch; exposure continues | COMPOSE first-wave guard adoption with IR-63/97; pending owner acknowledgement. Preserve panic-vs-hard-kill boundary: Rust Drop alone does not guarantee cleanup on process termination/SIGKILL. Entry's blanket timeout coverage claim needs qualification, not adoption as a guarantee. |\\n| 80 | OPEN; initial product-candidate headline superseded by amendments | FIRED historical investigation opportunity | CARRY residual class, reconcile stale opening. Body identifies brainproc shell-wrapper fixture mechanism and direct production spawn; does not classify all 12 union members. LEAK-count reduction or passing Windows unit set cannot close this. No owner is executing by implication. |\\n| 81 | OPEN primitive + gate; adapter arm CLOSED | FIRED historical proc/xtask work | COMPOSE remaining primitive and script-gate obligations. Current kill_pid(pid) and kill_pid_tree(root) remain bare-PID APIs (proc.rs:46/430); KH7.51 records a broker-site birth-safe correction but one site does not close primitive enforceability. Adapter closure stands, incident cause remains separate. |\\n| 82 | RULED, remedy historically linked #285 | FIRED historical lifecycle/#285 lane opportunity | COMPOSE unbuilt predecessor record independently of #285's site repair. daemon.rs:476 still direct-writes pidfile; no predecessor retention at this path. Header 'main ends at IR-78' is historical/stale. Do not call linked lane completion IR-82 completion. |\\n| 83 | OPEN, operator-rule blocked historical prose | FIRED; superseded box evidence in IR-89 | CARRY direction-witness enforcement residual, reconcile obsolete blocker/LAN-only prescription. IR-89 records actual tailnet ACL+firewall grants and successful tailnet probes, refuting a universal 'never tailnet' necessity. Need parent ruling to replace obsolete remediation with layer-specific admission + permanent reverse witness, not infer full closure from a one-box green. |\\n| 84 | OPEN, first instrument half landed with filing | FIRED historically | CARRY unresolved stall arithmetic/enforcement residual; acknowledge clocked emitter half as built. Timestamp instrumentation does not explain the extra ~27–34 s, shorten behavior, or prove every future arm stamped. |\\n| 85 | OPEN, caps mitigation only | FIRED arm 1; operator arms UNKNOWN | COMPOSE redesigned discriminator after guard/occupancy prerequisites, keep open. Old-sha slowdown establishes head growth not necessary, not environment apportionment. Alternate AB/BA, bank per-leg conditions/output; cap 80/40 remains mitigation. No Defender/torrent/disk causal allocation from concurrency or reclaim recovery. Hertz offline: brief delivered, unacknowledged. |\\n| 86 | OPEN, capacity derivation + docs coupling | FIRED golden/workflow arc | COMPOSE workflow sizing/independent docs dependency rider. golden.yml still 32 GiB start (229), docs floor (626), and OS-only success-coupled conditions (600/617/623). Historical 67.4 GiB footprint motivates re-derivation, not universal guaranteed peak. Latest 14.3<32 post-unit red is additional capacity evidence, not a new product failure. |\\n| 87 | OPEN independent job clocks | FIRED; exact recurrence banked at a9e786b2 | COMPOSE scheduling/rendezvous rider. Entry timeline proves B ended before A began, caused by golden head's own PR runner occupancy; include self-PR, not merely other lanes. Keep raw GitHub conclusions alongside VOID scoring. 900s panel alone cannot separate this from firewall. |\\n| 88 | OPEN pool-release vehicle | FIRED historical teardown; runbook adoption due | COMPOSE permanent release-before-delete/prebuilt recipe; carry open until adoption documented. Positive control already proves cargo-run regrowth vs prebuilt non-regrowth; current cleanup alone doesn't show recipe institutionalized. Prefer existing proven sequence, not an in-verb refusal that can only run after cargo already rebuilt it. |\\n| 89 | BOX applied; WORKFLOW built, landed-pending-golden | FIRED: multiple subsequent goldens | CARRY built pending exact step evidence; flag 'until next golden' stale immediately. No full probe-step outcomes were supplied/read here; next golden occurred but that alone is not exercise proof (steps can skip/partners desynchronize). Read retained step logs to replace pending wording with precise exercised/skipped/failed result; do not reapply operator rules or blame IR-87's 900s red on firewall. |\\n| 90 | OPEN disk refusal/context | FIRED, ripe now | COMPOSE rig-root/target-volume start refusal + current free-space failure context, prerequisite for IR-85 rerun. Reclaims mitigate only. Latest known 3167 unit pass followed by disk floor red is classified at its observed step; unavailable earlier PR logs remain unclassified. |\\n| 91 | CLOSED by filing lane | FIRED historically | CARRY closed. Preserve cited tracked artifacts and scratch manifests; parent cleanup retained evidence, so no reopening shown. |\\n| 92 | OPEN, says fix unassigned | FIRED inject/IO-funnel remedy; parent reports core215/217 merged | PARENT DECISION. Mark header stale but do not close here. Source/contract verification must distinguish inject success publication from relay ordering and per-msg-id exact-once; parent owns substantive reconciliation. |\\n| 93 | OPEN production symbols | UNKNOWN new packaging touch; release build alone is not a source touch | COMPOSE next packaging intake decision, keep open. Successful release build is not PDB availability, symbol matching, installation, or usable frame evidence. Preserve size/profile/operator trade rather than assuming approval. |\\n| 94 | OPEN scanner reach | FIRED at newly added brainread gate; mandatory before bounded serve_sync migration | COMPOSE fail-on-unclassified stream-server census. Current brainread.rs:199 and 306–320 retain name shape/three-file registry. Independent gate defect, not cause of golden sync red. |\\n| 95 | OPEN, measured/censused, diagnostic-only instrumentation | FIRED comparison already ran | COMPOSE prioritized observability + separately versioned exchange-correlated producer trace; retain open. 317/321 is classifier estimate with membership slop, 15 unclassified, not repo-wide floor/rate; no blanket 304-site editing. Diagnostic patch is unlanded, not release behavior. Preserve censored expiry, filtered final snapshot, no stream-between-polls claim, and no inferred budget fix. |\\n| 96 | OPEN cause-unclassified | NOT FIRED for named new qualifying event on supplied facts; cheap discriminator still unrun | CARRY with explicit next-intake investigation, not resolved/non-defect. 0/1 candidate CI vs 3/3 diagnostic HEAVY is confounded tree/workload/box, plus IR-97. Brief delivered to offline hertz is pending acknowledgement, not executing. |\\n| 97 | OPEN protocol deviation | FIRED repeated-run experiment | COMPOSE mandatory between-run identity census/accounting before any repeated IR-85/95/96 work. 0/6/12 carried residues are counts, not measured load or sync cause; 18 seen vs 15 killed does not prove three self-exits. Cleanups do not cure harness enforcement. |\\n\\n## Load-bearing deltas for the parent's edit\\n1. **Retire duplicate work, not residual mechanisms:** close IR-66; IR-73's source contract is implemented at all eight sites and both docs rereads. Amend their stale top-of-register riders. Keep IR-86 capacity/docs dependency debt separate. IR-57 pick-audit and IR-59 disk-floor are already tools, not future tooling proposals.\\n2. **Lifecycle wording needs reconciliation:** IR-69's parked header contradicts its own landed/residual addendum; IR-83's rule-blocked/LAN-only prose conflicts with IR-89's applied tailnet and firewall proof; IR-89's next-golden trigger fired but exact step proof is still needed; IR-92's unassigned header conflicts with parent's merged core215/217 fact. IR-80's product-candidate opening must be read through later scoped fixture findings. IR-82's #285 lane linkage did not deliver its pidfile retention.\\n3. **No causal laundering at release close:** v0.69.0 c105 at 16df0e41 shipped under explicit operator SHIP with known candidate a9e786b2 sync red. 121 scoped passes, release build success, and 3167 Windows unit passes prove exactly those observations. The later floor failure at 14.3 vs 32 GiB is not a unit-test failure; unavailable earlier PR unit logs are still unclassified. No disk/load attribution for sync/convoy from overlap or pass-after-reclaim.\\n4. **Cleanup accounting remains mitigation:** retain separate 62.32 GiB root-target and 59.70 GiB CI-debug measurements; later 38 clean merged worktrees/obsolete clone etc yielded net 4.22 GiB. Do not conflate file-length totals with free-space deltas, or report a structural capacity fix. Parent confirms no dirty/unmerged/retained evidence removed.\\n5. **Coherent next-intake packages:** (A) workflow/driver resource contract: IR-59/60/76/86/87/90/97, preserving separate conditions and budgets; (B) pool teardown adoption: IR-88 with earlier-range pool audit, IR-64 operator decision separate; (C) test lifetime work: IR-63/79/80 plus Linux IR-74/75, without collapsing fixture vs product identity debt IR-81/82; (D) diagnostic continuation: IR-85/95/96 only after occupancy/disk/between-run prerequisites, with no budget widening; (E) small seam-triggered items: IR-94 gate reach and IR-93 symbol packaging. All hertz-shaped work is proposed/pending acknowledgement while offline, not dispatched-and-executing.\\n\\n## Verification limits\\nRead-only tools only; no tests, builds, formatters, linters, probes, re-runs, board writes, or file edits. Closure recommendations use existing recorded proof plus targeted current-source reads, not new runtime verification. Some touch triggers are honestly UNKNOWN because exhaustive change-history traversal was neither supplied nor necessary for a carry ruling.\"\n  },\n  \"parent_rulings\": {\n    \"ir92\": \"Core PR215 docs-only; product inject publisher remains absent. Deployah corrected source comment 5628532753 and confirmed readback in delivery16. IR92 stays open.\",\n    \"closure\": [\n      1,\n      4,\n      66,\n      73\n    ],\n    \"others\": \"Existing built/retired dispositions preserved; residuals carry or compose as recorded in tracked sweep. UNKNOWN triggers are not disproved; source reads are not new executions.\"\n  }\n}","truncated":true,"truncatedBy":"lines","totalLines":52,"totalBytes":21137,"outputLines":51,"outputBytes":21137,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":205,"displayContent":{"text":"      {\n        \"path\": \".github/workflows/golden.yml\",\n        \"description\": \"Docs-floor rereads at 599/622; Windows start still 32 GiB at 229; docs steps retain implicit preceding-success coupling.\"\n      },\n      {\n        \"path\": \"crates/spt-daemon/tests/attach.rs\",\n        \"description\": \"IR-66 remedies present: delayed TICK39 on Unix/Windows at 531/539, delayed ALT_VIEWPORT_MARKER at 656.\"\n      },\n      {\n        \"path\": \"WEBSERVE-272-JIT.md:111-119\",\n        \"description\": \"IR-66 explicitly ruled satisfied; workflow floor rider and driver adoption tracked separately.\"\n      },\n      {\n        \"path\": \".github/ci/reap-census.ps1\",\n        \"description\": \"Family-only process predicate remains at 70–73/123; does not implement IR-76's compiler-load predicate.\"\n      },\n      {\n        \"path\": \"docs/GOLDEN-CI.md:26-51\",\n        \"description\": \"Existing quiet-window contract includes CI occupancy, local build processes, and parent-chain attribution; reuse instead of introducing another definition.\"\n      },\n      {\n        \"path\": \"crates/spt-store/src/proc.rs:46-49,430-433\",\n        \"description\": \"kill_pid and kill_pid_tree still accept bare numeric PIDs; IR-81 primitive-level remedy not present.\"\n      },\n      {\n        \"path\": \"crates/spt-daemon/src/daemon.rs:475-476\",\n        \"description\": \"Pidfile still overwritten directly; IR-82 predecessor preservation not implemented.\"\n      },\n      {\n        \"path\": \"crates/xtask/src/brainread.rs:194-203,295-320\",\n        \"description\": \"IR-94 name-shape predicate and three-file enumeration remain.\"\n      },\n      {\n        \"path\": \"crates/xtask/src/main.rs:69-70\",\n        \"description\": \"pick-audit and disk-floor verbs exist, contradicting stale future-build wording in IR-57/59.\"\n      }\n    ],\n    \"architecture\": \"Separate structural enforcement, procedural adoption, box mitigations, and incident diagnosis. Workflow floor placement is distinct from capacity sizing; process custody is distinct from performance attribution; publication ordering is distinct from inject coverage. Release SHIP authority and passing batteries do not discharge unresolved mechanism claims.\",\n    \"report\": \"## Scope and reading key\\n47 assigned entries: IR-50–97, excluding IR-54 (starts earlier). IR-49's preceding body and the CI-RIDER historical section were seen but not assigned as new IR entries. IR-31 is outside this range and remains the earlier-range owner's embedded-entry responsibility.\\n\\nTrigger = an entry's remedy/intake trigger, not proof its failure recurred. FIRED may be historically established; UNKNOWN means the supplied release facts and inspected material do not establish a qualifying new touch/event. Existing BUILT/CLOSED states stand without gratuitous re-verification. Actions are recommendations for the parent's ruling, not board mutations.\\n\\n## Exhaustive disposition table\\n| IR | Current entry state | Trigger | Recommendation and evidence |\\n|---|---|---|---|\\n| 50 | CLOSED / BUILT, landed v0.59.0 | FIRED historically | CARRY closed. Census/adoption completion and explicit engine-room exclusion already evidenced; release facts supply no reopening. |\\n| 51 | OPEN | UNKNOWN for #199 causal attribution; historical hermeticity pass available | CARRY. Ephemeral advisory ports do not disable peer pump/discovery or establish network causality. Preserve sequencing prohibition against net-off-as-green. |\\n| 52 | BUILT | FIRED historically, generator touch SIGNET | CARRY built. Full recursive command-tree rendering and previously omitted leaves recorded; do not reopen from old third-instance pre-build prose. |\\n| 53 | BUILT / landed v0.59.0 | FIRED historically | CARRY built. Cold-boot arm explicitly names unproved property; three narrower clock-aging siblings remain touch-triggered, not newly diagnosed by release success. |\\n| 55 | OPEN, ARMED-FOR-CAPTURE, hertz | FIRED (standing unfiltered-battery trigger) | CARRY armed, owner unavailable rather than executing. Nextest containment and prior 5×663 green settle sweep are not leak closure; no fresh wedge reported. Keep capture-before-kill protocol. |\\n| 56 | BUILT | FIRED historically | CARRY built. Cross-worktree refusal and explicit foreign-pool takeover measured in entry; IR-42 admission boundary intentionally remains. |\\n| 57 | OPEN, living gater procedure | FIRED (assembly/release arc) | CARRY procedure; correct stale proposed-tool wording: pick-audit already exists (xtask main:69) and caught real LOSS. Release build success proves compilation, not per-pick fidelity or repaired-file behavior. |\\n| 58 | OPEN, unowned; original claim retracted | FIRED (brainread/xtask work this milestone) | COMPOSE cargo-enumerated duplicate-bin check at next tooling intake; no closure evidence. Never resurrect withdrawn nonexistent-bin/prose correction. |\\n| 59 | OPEN, arithmetic/discipline | FIRED, including latest post-push disk-floor red | COMPOSE residual driver adoption/capacity work, carry discipline. Workflow start/end and docs-floor logging now exist; xtask disk-floor exists. Root target 62.32 GiB + CI debug 59.70 GiB and later 4.22 GiB cleanup are mitigations, not bounded accumulation. Do not call 14.3 GiB an explanation for unavailable earlier unit logs. |\\n| 60 | OPEN, script discipline | FIRED (diagnostic/gate reporting) | COMPOSE into next shared driver touch, carry open. Preserve leg verdict separately from wrapper completion; 3167 unit pass then floor red must be reported as distinct outcomes, not flattened to all-green or all-unit-red. Missing exit also requires reading raw Summary (IR-79), not inventing completion. |\\n| 61 | OPEN, accepted with mitigation | UNKNOWN substantive scanner touch | CARRY. No supplied fact establishes literal-tracker unification; unrelated xtask work alone is not this specific trigger. |\\n| 62 | BUILT docs-collision remedy; residual caveat | FIRED historically | CARRY built scoped to docs listener. Other bind surfaces remain conditional residuals; do not imply whole network hermeticity. |\\n| 63 | OPEN, mitigated, historical queued hertz lane | FIRED historically/rig work | COMPOSE with teardown/IR-79/97 adoption, keep open. Path-safe reaps are mitigation; no complete producer-side teardown proof. Update queued-owner language to pending acknowledgement, not active execution. Historical rotating victims do not classify the new sync/convoy red. |\\n| 64 | OPEN, operator reservoir | FIRED historically by IR-86 in-job floor failure; latest disk red reinforces relevance | COMPOSE operator capacity/accept-tax decision, carry open. Current cleanup does not move operator-owned bulk or prove permanent headroom. Do not recite historical 845 GB as a freshly measured current census. |\\n| 65 | REMEDIATED-AT-BOX, OPEN recheck record | UNKNOWN snap/auditd update or reimage | CARRY recheck record; no box commands needed this sweep. Release green is not evidence that effective audit configuration survived a named reset event. |\\n| 66 | BUILT; explicitly due to leave at WEBSERVE close | FIRED, close overdue | CLOSE eligible now. JIT:111–116 already rules satisfied; current attach.rs:531/539/656 retains both delayed needles. Remove stale next-intake two-edit rider from sweep summary; this is source-backed closure, not green-alone retirement. |\\n| 67 | BUILT, battery-template remedy | FIRED historically/intake | CARRY built. Scoped 121-pass battery is only its named scope; do not use --bins as integration coverage or promote it to full golden acceptance. |\\n| 68 | OPEN investigation | UNKNOWN new PSYCHE_INGEST_FAIL/probe slot | CARRY. Existing nonempty-lock experiment refuted the proposed cause; unrelated release facts cannot reinstate index.lock attribution. |\\n| 69 | OPEN; header says parked pre-assembly | FIRED historically close-out recensus | COMPOSE #243 residual plus separately tracked anchored-consumer rider; correct stale header. Body already records landed ec6da9b0 and 338 cli + 2 main residuals. Need residual conversion, generator fix, and SHA-pinned zero recensus before closure. Delivery.rs post-cut sites already converted; no new lane owed there. |\\n| 70 | OPEN, recurrence remedy unscheduled | UNKNOWN construction/API/sink touch | CARRY. Shipped default_bus site correction is not enforced assembly-point closure. IR-92 funnel work may make this a useful next construction-seam rider, but do not assert its trigger from publication work alone. |\\n| 71 | OPEN observability | UNKNOWN qualifying controller-lifecycle/breadcrumb touch | CARRY, eligible next lifecycle instrument rider. Existing info.json polling barrier proves convergence separately; no new persisted-release breadcrumb evidenced. |\\n| 72 | OPEN observability | UNKNOWN qualifying read-model/holder-inspection touch | CARRY. Cleanup process-table custody is not a supported named-seat read verb. |\\n| 73 | OPEN, title/body claim eight pre-checkout sites still owed | FIRED; implementation already present | CLOSE eligible for the entry's original two halves, with implementation evidence explicitly stated. All 5 ci and 3 release sites are after checkout with IR-73 comments; golden docs rereads exist and IR-86 records their live catch. Current header is stale. Capacity derivation and docs dependency coupling remain IR-86, not reasons to re-build IR-73. |\\n| 74 | OPEN /tmp population | FIRED as between-milestone audit opportunity; current Linux touch unknown | COMPOSE bounded /tmp lifecycle at box-audit intake, not a fresh numeric census. Windows cleanup says nothing about kitsubito's 21,643 historical homes. |\\n| 75 | OPEN Linux treqs 127 | UNKNOWN new Linux-driver touch; audit opportunity remains | COMPOSE install-or-explicit-platform-independent-coverage decision with Linux box audit. No proof here of current installation or driver removal; retain stale-state verification obligation, never infer it from overall green. |\\n| 76 | OPEN quiet-window/measurement | FIRED driver/workflow/runbook arc | COMPOSE outstanding enforcement and compiler-load census. Existing GOLDEN-CI:26–51 already supplies a better occupancy/parent-chain contract; reap-census still selects only SPT family. IR-87 proves queue interference, not cause of sync expiry. Historical headline 'manufactured' is stronger than overlap alone; new sweep must not repeat it as a diagnosis. |\\n| 77 | OPEN boot interval visibility | UNKNOWN exact boot/ready-stamp touch | CARRY, compose if next daemon-boot instrumentation lane opens. No timestamped child-entry→ready proof surfaced; full test duration is not boot interval. |\\n| 78 | OPEN silent docs-port override | UNKNOWN new docshost touch; historical belief incident already witnessed | CARRY tiny next-docshost rider. No release fact proves notice implemented; precedence need not be redesigned. |\\n| 79 | OPEN panic/timeout teardown exposure | UNKNOWN new common-module touch; exposure continues | COMPOSE first-wave guard adoption with IR-63/97; pending owner acknowledgement. Preserve panic-vs-hard-kill boundary: Rust Drop alone does not guarantee cleanup on process termination/SIGKILL. Entry's blanket timeout coverage claim needs qualification, not adoption as a guarantee. |\\n| 80 | OPEN; initial product-candidate headline superseded by amendments | FIRED historical investigation opportunity | CARRY residual class, reconcile stale opening. Body identifies brainproc shell-wrapper fixture mechanism and direct production spawn; does not classify all 12 union members. LEAK-count reduction or passing Windows unit set cannot close this. No owner is executing by implication. |\\n| 81 | OPEN primitive + gate; adapter arm CLOSED | FIRED historical proc/xtask work | COMPOSE remaining primitive and script-gate obligations. Current kill_pid(pid) and kill_pid_tree(root) remain bare-PID APIs (proc.rs:46/430); KH7.51 records a broker-site birth-safe correction but one site does not close primitive enforceability. Adapter closure stands, incident cause remains separate. |\\n| 82 | RULED, remedy historically linked #285 | FIRED historical lifecycle/#285 lane opportunity | COMPOSE unbuilt predecessor record independently of #285's site repair. daemon.rs:476 still direct-writes pidfile; no predecessor retention at this path. Header 'main ends at IR-78' is historical/stale. Do not call linked lane completion IR-82 completion. |\\n| 83 | OPEN, operator-rule blocked historical prose | FIRED; superseded box evidence in IR-89 | CARRY direction-witness enforcement residual, reconcile obsolete blocker/LAN-only prescription. IR-89 records actual tailnet ACL+firewall grants and successful tailnet probes, refuting a universal 'never tailnet' necessity. Need parent ruling to replace obsolete remediation with layer-specific admission + permanent reverse witness, not infer full closure from a one-box green. |\\n| 84 | OPEN, first instrument half landed with filing | FIRED historically | CARRY unresolved stall arithmetic/enforcement residual; acknowledge clocked emitter half as built. Timestamp instrumentation does not explain the extra ~27–34 s, shorten behavior, or prove every future arm stamped. |\\n| 85 | OPEN, caps mitigation only | FIRED arm 1; operator arms UNKNOWN | COMPOSE redesigned discriminator after guard/occupancy prerequisites, keep open. Old-sha slowdown establishes head growth not necessary, not environment apportionment. Alternate AB/BA, bank per-leg conditions/output; cap 80/40 remains mitigation. No Defender/torrent/disk causal allocation from concurrency or reclaim recovery. Hertz offline: brief delivered, unacknowledged. |\\n| 86 | OPEN, capacity derivation + docs coupling | FIRED golden/workflow arc | COMPOSE workflow sizing/independent docs dependency rider. golden.yml still 32 GiB start (229), docs floor (626), and OS-only success-coupled conditions (600/617/623). Historical 67.4 GiB footprint motivates re-derivation, not universal guaranteed peak. Latest 14.3<32 post-unit red is additional capacity evidence, not a new product failure. |\\n| 87 | OPEN independent job clocks | FIRED; exact recurrence banked at a9e786b2 | COMPOSE scheduling/rendezvous rider. Entry timeline proves B ended before A began, caused by golden head's own PR runner occupancy; include self-PR, not merely other lanes. Keep raw GitHub conclusions alongside VOID scoring. 900s panel alone cannot separate this from firewall. |\\n| 88 | OPEN pool-release vehicle | FIRED historical teardown; runbook adoption due | COMPOSE permanent release-before-delete/prebuilt recipe; carry open until adoption documented. Positive control already proves cargo-run regrowth vs prebuilt non-regrowth; current cleanup alone doesn't show recipe institutionalized. Prefer existing proven sequence, not an in-verb refusal that can only run after cargo already rebuilt it. |\\n| 89 | BOX applied; WORKFLOW built, landed-pending-golden | FIRED: multiple subsequent goldens | CARRY built pending exact step evidence; flag 'until next golden' stale immediately. No full probe-step outcomes were supplied/read here; next golden occurred but that alone is not exercise proof (steps can skip/partners desynchronize). Read retained step logs to replace pending wording with precise exercised/skipped/failed result; do not reapply operator rules or blame IR-87's 900s red on firewall. |\\n| 90 | OPEN disk refusal/context | FIRED, ripe now | COMPOSE rig-root/target-volume start refusal + current free-space failure context, prerequisite for IR-85 rerun. Reclaims mitigate only. Latest known 3167 unit pass followed by disk floor red is classified at its observed step; unavailable earlier PR logs remain unclassified. |\\n| 91 | CLOSED by filing lane | FIRED historically | CARRY closed. Preserve cited tracked artifacts and scratch manifests; parent cleanup retained evidence, so no reopening shown. |\\n| 92 | OPEN, says fix unassigned | FIRED inject/IO-funnel remedy; parent reports core215/217 merged | PARENT DECISION. Mark header stale but do not close here. Source/contract verification must distinguish inject success publication from relay ordering and per-msg-id exact-once; parent owns substantive reconciliation. |\\n| 93 | OPEN production symbols | UNKNOWN new packaging touch; release build alone is not a source touch | COMPOSE next packaging intake decision, keep open. Successful release build is not PDB availability, symbol matching, installation, or usable frame evidence. Preserve size/profile/operator trade rather than assuming approval. |\\n| 94 | OPEN scanner reach | FIRED at newly added brainread gate; mandatory before bounded serve_sync migration | COMPOSE fail-on-unclassified stream-server census. Current brainread.rs:199 and 306–320 retain name shape/three-file registry. Independent gate defect, not cause of golden sync red. |\\n| 95 | OPEN, measured/censused, diagnostic-only instrumentation | FIRED comparison already ran | COMPOSE prioritized observability + separately versioned exchange-correlated producer trace; retain open. 317/321 is classifier estimate with membership slop, 15 unclassified, not repo-wide floor/rate; no blanket 304-site editing. Diagnostic patch is unlanded, not release behavior. Preserve censored expiry, filtered final snapshot, no stream-between-polls claim, and no inferred budget fix. |\\n| 96 | OPEN cause-unclassified | NOT FIRED for named new qualifying event on supplied facts; cheap discriminator still unrun | CARRY with explicit next-intake investigation, not resolved/non-defect. 0/1 candidate CI vs 3/3 diagnostic HEAVY is confounded tree/workload/box, plus IR-97. Brief delivered to offline hertz is pending acknowledgement, not executing. |\\n| 97 | OPEN protocol deviation | FIRED repeated-run experiment | COMPOSE mandatory between-run identity census/accounting before any repeated IR-85/95/96 work. 0/6/12 carried residues are counts, not measured load or sync cause; 18 seen vs 15 killed does not prove three self-exits. Cleanups do not cure harness enforcement. |\\n\\n## Load-bearing deltas for the parent's edit\\n1. **Retire duplicate work, not residual mechanisms:** close IR-66; IR-73's source contract is implemented at all eight sites and both docs rereads. Amend their stale top-of-register riders. Keep IR-86 capacity/docs dependency debt separate. IR-57 pick-audit and IR-59 disk-floor are already tools, not future tooling proposals.\\n2. **Lifecycle wording needs reconciliation:** IR-69's parked header contradicts its own landed/residual addendum; IR-83's rule-blocked/LAN-only prose conflicts with IR-89's applied tailnet and firewall proof; IR-89's next-golden trigger fired but exact step proof is still needed; IR-92's unassigned header conflicts with parent's merged core215/217 fact. IR-80's product-candidate opening must be read through later scoped fixture findings. IR-82's #285 lane linkage did not deliver its pidfile retention.\\n3. **No causal laundering at release close:** v0.69.0 c105 at 16df0e41 shipped under explicit operator SHIP with known candidate a9e786b2 sync red. 121 scoped passes, release build success, and 3167 Windows unit passes prove exactly those observations. The later floor failure at 14.3 vs 32 GiB is not a unit-test failure; unavailable earlier PR unit logs are still unclassified. No disk/load attribution for sync/convoy from overlap or pass-after-reclaim.\\n4. **Cleanup accounting remains mitigation:** retain separate 62.32 GiB root-target and 59.70 GiB CI-debug measurements; later 38 clean merged worktrees/obsolete clone etc yielded net 4.22 GiB. Do not conflate file-length totals with free-space deltas, or report a structural capacity fix. Parent confirms no dirty/unmerged/retained evidence removed.\\n5. **Coherent next-intake packages:** (A) workflow/driver resource contract: IR-59/60/76/86/87/90/97, preserving separate conditions and budgets; (B) pool teardown adoption: IR-88 with earlier-range pool audit, IR-64 operator decision separate; (C) test lifetime work: IR-63/79/80 plus Linux IR-74/75, without collapsing fixture vs product identity debt IR-81/82; (D) diagnostic continuation: IR-85/95/96 only after occupancy/disk/between-run prerequisites, with no budget widening; (E) small seam-triggered items: IR-94 gate reach and IR-93 symbol packaging. All hertz-shaped work is proposed/pending acknowledgement while offline, not dispatched-and-executing.\\n\\n## Verification limits\\nRead-only tools only; no tests, builds, formatters, linters, probes, re-runs, board writes, or file edits. Closure recommendations use existing recorded proof plus targeted current-source reads, not new runtime verification. Some touch triggers are honestly UNKNOWN because exhaustive change-history traversal was neither supplied nor necessary for a carry ruling.\"\n  },\n  \"parent_rulings\": {\n    \"ir92\": \"Core PR215 docs-only; product inject publisher remains absent. Deployah corrected source comment 5628532753 and confirmed readback in delivery16. IR92 stays open.\",\n    \"closure\": [\n      1,\n      4,\n      66,\n      73\n    ],\n    \"others\": \"Existing built/retired dispositions preserved; residuals carry or compose as recorded in tracked sweep. UNKNOWN triggers are not disproved; source reads are not new executions.\"\n  }\n}","startLine":154,"lineNumbers":[154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204]},"fileSize":41129,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.spt\\preserved\\infra-close069-20260911\\audit.json"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":205,"totalBytes":21137,"outputLines":51,"outputBytes":21137,"shownRange":{"start":154,"end":204},"nextOffset":205}}},"isError":false,"timestamp":1789107106819}}
{"type":"message","id":"405896fa","parentId":"f63bc858","timestamp":"2026-09-11T06:11:46.835Z","message":{"role":"toolResult","toolCallId":"call_Of2coArKiHm3ktc8WKni3pAR|fc_0330c101aa2c61dc016aa39ba05f2087d1b1b1eb793a0d633c","toolName":"grep","content":[{"type":"text","text":"# crates/\n\n## xtask/src/\n### brainread.rs\n 193|\n*194|/// Includes all future serve_*_feed bodies, not merely the current nine.\n 195|pub fn feed_bodies_calling_call_deadline(src: &str) -> Result<Vec<Finding>, String> {\n 196|    let words = tokens(src)?;\n 197|    let mut findings = Vec::new();\n 198|    for f in functions(&words)? {\n*199|        if (f.name.starts_with(\"serve_\") && f.name.ends_with(\"_feed\")) || f.name == \"serve_attach\" {\n 200|            for token in f.body.iter().filter(|t| t.text == \"call_deadline\") {\n 201|                findings.push(Finding {\n 202|                    line: token.line,\n...\n 295|    let feeds = [\n*296|        \"serve_registry_feed\",\n*297|        \"serve_notif_feed\",\n*298|        \"serve_seal_feed\",\n*299|        \"serve_knock_feed\",\n*300|        \"serve_fork_feed\",\n*301|        \"serve_redeem_feed\",\n*302|        \"serve_answer_feed\",\n*303|        \"serve_presence_feed\",\n*304|        \"serve_wan_feed\",\n 305|    ];\n 306|    for (relative, streams, replies) in [\n 307|        (\n*308|            \"crates/spt-daemon/src/dispatch.rs\",\n 309|            feeds.as_slice(),\n 310|            vec![(\"peek_first_line\", \"brain\")],\n 311|        ),\n...\n 346|    fn stream_deadline_is_rejected_but_reply_deadline_is_not() {\n*347|        let src = \"fn serve_future_feed() {\\n brain.call_deadline();\\n}\\nfn peek_first_line() { brain.call_deadline(); }\\nfn serve_attach() { brain.call_deadline(); }\";\n 348|        let findings = feed_bodies_calling_call_deadline(src).unwrap();\n 349|        assert_eq!(findings.iter().map(|f| f.line).collect::<Vec<_>>(), [2, 5]);\n 350|    }\n...\n 368|    fn literal_braces_and_nested_comments_do_not_hide_a_stream_body() {\n*369|        let src = r###\"fn serve_x_feed<'a>() { let s = r##\"} brain.read_event()\"##; let c = '}'; /* outer /* } */ */ brain.call_deadline(); }\"###;\n 370|        assert!(read_event_sites(src).unwrap().is_empty());\n 371|        assert_eq!(feed_bodies_calling_call_deadline(src).unwrap().len(), 1);\n 372|    }\n\n## spt-daemon/src/\n### docshost.rs\n 4|//! surface; this module retains the docs sanitizer and containment implementation.\n*5|//! Only the port is configurable (`daemon.json` `docs_port`, `SPT_DOCS_PORT`\n 6|//! env wins). GET/HEAD only; a missing docs bundle never prevents binding.\n 7|//!\n 8|//! ## The cross-node leg (W1, REQ-WEB-CROSS-NODE-PROXY)\n...\n 68|/// The env override for the docs port (wins over `daemon.json`).\n*69|pub const DOCS_PORT_ENV: &str = \"SPT_DOCS_PORT\";\n 70|\n 71|/// Rig-only switch: advisory listeners bind ephemeral ports instead of the\n 72|/// production well-known ports shared with resident fleet daemons.\n*73|pub const TEST_EPHEMERAL_ADVISORY_PORTS_ENV: &str = \"SPT_TEST_EPHEMERAL_ADVISORY_PORTS\";\n 74|\n 75|/// Resolve the effective docs port: env override > config > default. A\n 76|/// malformed env value degrades to the next layer (a broken override must\n...\n 90|/// Daemon-side resolution adds the rig's ephemeral-port posture without\n*91|/// changing the public `SPT_DOCS_PORT=0` contract used by `spt docs url`.\n 92|// [impl->REQ-TEST-DAEMON-EPHEMERAL-ADVISORY-PORTS]\n 93|pub fn resolve_daemon_docs_port(\n 94|    config_port: Option<u16>,"}],"details":{"scopePath":"crates/xtask/src/brainread.rs, crates/spt-daemon/src/docshost.rs","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\crates","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":18,"fileCount":2,"files":["crates/xtask/src/brainread.rs","crates/spt-daemon/src/docshost.rs"],"fileMatches":[{"path":"crates/xtask/src/brainread.rs","count":14},{"path":"crates/spt-daemon/src/docshost.rs","count":4}],"truncated":false,"displayContent":"# crates/\n\n## xtask/src/\n### brainread.rs\n 193│\n*194│/// Includes all future serve_*_feed bodies, not merely the current nine.\n 195│pub fn feed_bodies_calling_call_deadline(src: &str) -> Result<Vec<Finding>, String> {\n 196│    let words = tokens(src)?;\n 197│    let mut findings = Vec::new();\n 198│    for f in functions(&words)? {\n*199│        if (f.name.starts_with(\"serve_\") && f.name.ends_with(\"_feed\")) || f.name == \"serve_attach\" {\n 200│            for token in f.body.iter().filter(|t| t.text == \"call_deadline\") {\n 201│                findings.push(Finding {\n 202│                    line: token.line,\n    │...\n 295│    let feeds = [\n*296│        \"serve_registry_feed\",\n*297│        \"serve_notif_feed\",\n*298│        \"serve_seal_feed\",\n*299│        \"serve_knock_feed\",\n*300│        \"serve_fork_feed\",\n*301│        \"serve_redeem_feed\",\n*302│        \"serve_answer_feed\",\n*303│        \"serve_presence_feed\",\n*304│        \"serve_wan_feed\",\n 305│    ];\n 306│    for (relative, streams, replies) in [\n 307│        (\n*308│            \"crates/spt-daemon/src/dispatch.rs\",\n 309│            feeds.as_slice(),\n 310│            vec![(\"peek_first_line\", \"brain\")],\n 311│        ),\n    │...\n 346│    fn stream_deadline_is_rejected_but_reply_deadline_is_not() {\n*347│        let src = \"fn serve_future_feed() {\\n brain.call_deadline();\\n}\\nfn peek_first_line() { brain.call_deadline(); }\\nfn serve_attach() { brain.call_deadline(); }\";\n 348│        let findings = feed_bodies_calling_call_deadline(src).unwrap();\n 349│        assert_eq!(findings.iter().map(|f| f.line).collect::<Vec<_>>(), [2, 5]);\n 350│    }\n    │...\n 368│    fn literal_braces_and_nested_comments_do_not_hide_a_stream_body() {\n*369│        let src = r###\"fn serve_x_feed<'a>() { let s = r##\"} brain.read_event()\"##; let c = '}'; /* outer /* } */ */ brain.call_deadline(); }\"###;\n 370│        assert!(read_event_sites(src).unwrap().is_empty());\n 371│        assert_eq!(feed_bodies_calling_call_deadline(src).unwrap().len(), 1);\n 372│    }\n\n## spt-daemon/src/\n### docshost.rs\n  4│//! surface; this module retains the docs sanitizer and containment implementation.\n *5│//! Only the port is configurable (`daemon.json` `docs_port`, `SPT_DOCS_PORT`\n  6│//! env wins). GET/HEAD only; a missing docs bundle never prevents binding.\n  7│//!\n  8│//! ## The cross-node leg (W1, REQ-WEB-CROSS-NODE-PROXY)\n   │...\n 68│/// The env override for the docs port (wins over `daemon.json`).\n*69│pub const DOCS_PORT_ENV: &str = \"SPT_DOCS_PORT\";\n 70│\n 71│/// Rig-only switch: advisory listeners bind ephemeral ports instead of the\n 72│/// production well-known ports shared with resident fleet daemons.\n*73│pub const TEST_EPHEMERAL_ADVISORY_PORTS_ENV: &str = \"SPT_TEST_EPHEMERAL_ADVISORY_PORTS\";\n 74│\n 75│/// Resolve the effective docs port: env override > config > default. A\n 76│/// malformed env value degrades to the next layer (a broken override must\n   │...\n 90│/// Daemon-side resolution adds the rig's ephemeral-port posture without\n*91│/// changing the public `SPT_DOCS_PORT=0` contract used by `spt docs url`.\n 92│// [impl->REQ-TEST-DAEMON-EPHEMERAL-ADVISORY-PORTS]\n 93│pub fn resolve_daemon_docs_port(\n 94│    config_port: Option<u16>,"},"isError":false,"timestamp":1789107106835}}
{"type":"message","id":"35964438","parentId":"405896fa","timestamp":"2026-09-11T06:11:46.847Z","message":{"role":"toolResult","toolCallId":"call_eosxKySKbDJIlAchBbF9Kw7M|fc_0330c101aa2c61dc016aa39ba05f1487d1a51c6a0f1f36472c","toolName":"grep","content":[{"type":"text","text":"# crates/spt/tests/\n## activity_link_push_e2e.rs\n 529|    // and both pids it would target (`brain.ready`'s and `daemon.pid`'s) are\n*530|    // GUARANTEED FREED once the stop succeeds — a bare `taskkill /F /T` on them\n 531|    // is a coin flip against pid reuse, which on this box re-mints a freed number\n 532|    // in as little as 2.2 s. So the insurance kills authenticate first and refuse\n 533|    // a pid that is gone, recycled, or no longer this test's `spt` image.\n## bind_adapter_profile_persist_e2e.rs\n 87|    // A minimal harness adapter `dummyharness` (bare parent) — registered + a\n*88|    // manifest path so `api`'s up-front manifest resolution succeeds. No profile is\n 89|    // declared: the bare-parent bind never resolves the `:fast` profile (that lives\n 90|    // only on the seeded prior record).\n 91|    let manifest_toml = \"[adapter]\\nname=\\\"dummyharness\\\"\\nkind=\\\"harness\\\"\\nversion=\\\"1\\\"\\n\\\n## boundary_events_e2e.rs\n 99|        out.status.success(),\n*100|        \"a poll SUCCEEDS — silence is the normal case, not a failure: {}\",\n 101|        String::from_utf8_lossy(&out.stderr)\n 102|    );\n 103|    let text = String::from_utf8_lossy(&out.stdout).to_string();\n...\n 142|            out.status.success(),\n*143|            \"a clear boundary succeeds: {}\",\n 144|            String::from_utf8_lossy(&out.stderr)\n 145|        );\n 146|        let out = boundary(&spt_bin, home.path(), author, \"compact\", \"boundary-sid-1\", \"boundary-sid-2\");\n...\n 148|            out.status.success(),\n*149|            \"a compact boundary succeeds: {}\",\n 150|            String::from_utf8_lossy(&out.stderr)\n 151|        );\n 152|\n*153|        // ── (3) A REPEAT of the session already current. It SUCCEEDS — a\n 154|        //    re-report is not an error — and it must add nothing, because it\n 155|        //    crossed no edge. Asserted before the read below so its row, if the\n 156|        //    gate ever regresses, lands inside the window being counted.\n## boundary_ready_strand_e2e.rs\n 69|\n*70|    // A minimal harness adapter so `api`'s up-front manifest resolution succeeds.\n 71|    let manifest_toml = \"[adapter]\\nname=\\\"dummyharness\\\"\\nkind=\\\"harness\\\"\\nversion=\\\"1\\\"\\n\\\n 72|         min_spt_core_version=\\\"0\\\"\\n\";\n 73|    let manifest_path = home.path().join(\"dummyharness.toml\");\n## commune_two_cwd_e2e.rs\n 209|    // ══ LEG A's CLAIMS ══════════════════════════════════════════════════════\n*210|    assert!(out.status.success(), \"the pull still succeeds: {out:?}\");\n 211|\n 212|    // [int->REQ-PSYCHE-INGEST-FAILURE-LOUD] invariant 2 (the staleness half):\n 213|    // a resume composed over a drop that can NEVER ingest does not present its\n## contract_e2e.rs\n 41|/// socket so the child `spt api …` invocations find a running daemon (their\n*42|/// `ensure_running` ping succeeds → no real `spt daemon` spawned). The serve\n 43|/// thread is leaked; it dies with the test process. Call after `SPT_HOME` is set.\n 44|// [int->REQ-DAEMON-3]\n 45|fn start_inproc_daemon() {\n## create_bind_rest_active_e2e.rs\n 85|\n*86|    // A minimal harness adapter so `api`'s up-front manifest resolution succeeds.\n 87|    let manifest_toml = \"[adapter]\\nname=\\\"dummyharness\\\"\\nkind=\\\"harness\\\"\\nversion=\\\"1\\\"\\n\\\n 88|         min_spt_core_version=\\\"0\\\"\\n\";\n 89|    let manifest_path = home.path().join(\"dummyharness.toml\");\n## docs_bundle_e2e.rs\n 212|        stage_and_apply(&home3, &spt3, &artifact, None, None);\n*213|    assert!(ok3, \"docs-less apply succeeds: {stderr3}\");\n 214|    assert!(\n 215|        !stdout3.contains(\"UPDATE_DOCS\") && !stderr3.contains(\"UPDATE_DOCS\"),\n 216|        \"no docs tokens for a docs-less release: {stdout3} {stderr3}\"\n## drive_e2e.rs\n 299|        post_relink.status.success(),\n*300|        \"post-relink drain succeeds: {}\",\n 301|        String::from_utf8_lossy(&post_relink.stderr)\n 302|    );\n 303|    let post_relink = String::from_utf8_lossy(&post_relink.stdout);\n## endpoint_teardown_authority_e2e.rs\n 530|/// harness, and DESCENDANT — the stamp stays put across a settle window, and\n*531|/// `endpoint start <same>` afterwards SUCCEEDS instead of answering\n 532|/// `ENDPOINT_CREATE_CONFLICT` about a session stop claimed to have ended.\n 533|// [int->REQ-ENDPOINT-TEARDOWN-AUTHORITY]\n 534|// [int->REQ-TEARDOWN-UNCOOPERATIVE-HOST]\n## engine_room_bringup_e2e.rs\n 1994|/// reason: on a one-subnet node `assign_home` auto-homes, so the bind's own\n*1995|/// creation arm succeeds and writes the record the bring-up never wrote. The\n 1996|/// defect is INVISIBLE at one subnet by construction. Both hiding mechanisms\n 1997|/// have to be removed at once — a real bring-up, and a node holding more than\n 1998|/// one subnet — which is what this cell does.\n## gateway_e2e.rs\n 171|        send_user_msg(&spt_bin, home.path(), peer_u, gw, gw_session, \"ship it now\"),\n*172|        \"send from the gateway succeeds\"\n 173|    );\n 174|    let body = spooled_body(&peer_u_perch);\n 175|    let p = spt_proto::event::parse_event(&body)\n...\n 212|        send_user_msg(&spt_bin, home.path(), peer_a, agent, agent_session, \"do this\"),\n*213|        \"send from the agent succeeds (degraded, never rejected)\"\n 214|    );\n 215|    let spooled = spooled_body(&peer_a_perch);\n 216|    // REPINNED TO THE W2 CONTRACT (WEBSERVE W2, commit 92715374, which said this\n## gateway_owner_shell_e2e.rs\n 3|//! GATEWAY-typed owner (state=\"gateway\", the gateway_e2e mock-gateway type) owns\n*4|//! a shell and succeeds on EVERY ownership path same-node, and control-\n 5|//! exclusivity keys on the owner ENDPOINT-ID, never the type.\n 6|//!\n 7|//! PROOF-NOT-CHANGE (M11-T0 audit found no type-gate on any ownership path) — if\n## io_events_poll_e2e.rs\n 95|        out.status.success(),\n*96|        \"the ingest call succeeds — the funnel must never fail the hook: {}\",\n 97|        String::from_utf8_lossy(&out.stderr)\n 98|    );\n 99|}\n...\n 113|        out.status.success(),\n*114|        \"a poll SUCCEEDS — silence is the normal case, not a failure: {}\",\n 115|        String::from_utf8_lossy(&out.stderr)\n 116|    );\n 117|    let text = String::from_utf8_lossy(&out.stdout).to_string();\n## io_state_payload_e2e.rs\n 185|        out.status.success(),\n*186|        \"a payloadless `api state busy` still succeeds: {}\",\n 187|        String::from_utf8_lossy(&out.stderr)\n 188|    );\n 189|    let drained = drain();\n...\n 224|        out.status.success(),\n*225|        \"the repeat `api state idle` succeeds too: {}\",\n 226|        String::from_utf8_lossy(&out.stderr)\n 227|    );\n 228|\n## knock_mutual_cross_node_e2e.rs\n 124|/// reaped SCOPED on drop (never machine-wide — this box hosts the live fleet).\n*125|struct DaemonGuard {\n 126|    home: PathBuf,\n 127|    spt: PathBuf,\n 128|    broker: Option<Child>,\n...\n 300|    );\n*301|    assert!(minted.status.success(), \"the mint succeeds: {minted:?}\");\n 302|    handed_code(&out)\n 303|}\n 304|\n...\n 446|    let (ok, out, err) = redeem_on_a(&spt, home_a.path(), &code_own, true, Some(REDEEMER));\n*447|    assert!(ok, \"the cross-node redemption succeeds:\\n{out}{err}\");\n 448|    assert!(out.contains(\"redeemed\"), \"a decision is stated:\\n{out}\");\n 449|    // The retired shipped behaviour refused this route outright, with a message\n 450|    // explaining itself on the axis of flag ownership. It is gone from the\n## listen_seed_retry_e2e.rs\n 33|/// the child `spt api …` invocations find a running daemon (their\n*34|/// `ensure_running` ping succeeds → no real `spt daemon` is spawned). The serve\n 35|/// thread is leaked; it dies with the test process. Call after `SPT_HOME` is set.\n 36|fn start_inproc_daemon() {\n 37|    let reg = std::sync::Arc::new(spt_daemon::SeedRegistry::new());\n## live_resolve_e2e.rs\n 152|    let out = spt(&[\"api\", \"listen\", \"agent-c\", \"--parent-pid\", &pid, \"--once\"]);\n*153|    // The WRONG-way arm: a listen that succeeds here printed nothing at all about what\n 154|    // the child actually did, which is the same blindness as the positive arms.\n 155|    assert!(\n 156|        !out.status.success(),\n## midturn_span_e2e.rs\n 127|        out.status.success(),\n*128|        \"a poll SUCCEEDS: {}\",\n 129|        String::from_utf8_lossy(&out.stderr)\n 130|    );\n 131|    let text = String::from_utf8_lossy(&out.stdout).to_string();\n...\n 187|                out.status.success(),\n*188|                \"a span ingest succeeds — the funnel never fails the hook: {}\",\n 189|                String::from_utf8_lossy(&out.stderr)\n 190|            );\n 191|        }\n...\n 284|            out.status.success(),\n*285|            \"the ingest itself still succeeds: {}\",\n 286|            String::from_utf8_lossy(&out.stderr)\n 287|        );\n 288|\n## nested_resolution_e2e.rs\n 7|//! 2. A PARENT perch `dunsen` bound + homed to `alpha`.\n*8|//! 3. `spt ready dunsen-w1` (a NESTED worker id) with NO `--subnet` → succeeds and the\n 9|//!    nested perch homes to `alpha` (DERIVED from the parent), never refusing.\n 10|//! 4. CONTROL — a SELF id (`elm`, no parent) with NO `--subnet` on the same\n 11|//!    multi-subnet node STILL refuses `READY_FAIL` (only nested ids gain derivation;\n\nShowing files 1-20 of 28. Use skip=20 for the next page, or narrow paths/pattern."}],"details":{"scopePath":"crates/spt/tests, crates/spt-daemon/src/daemon.rs","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\crates","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":30,"fileCount":20,"files":["crates/spt/tests/activity_link_push_e2e.rs","crates/spt/tests/bind_adapter_profile_persist_e2e.rs","crates/spt/tests/boundary_events_e2e.rs","crates/spt/tests/boundary_ready_strand_e2e.rs","crates/spt/tests/commune_two_cwd_e2e.rs","crates/spt/tests/contract_e2e.rs","crates/spt/tests/create_bind_rest_active_e2e.rs","crates/spt/tests/docs_bundle_e2e.rs","crates/spt/tests/drive_e2e.rs","crates/spt/tests/endpoint_teardown_authority_e2e.rs","crates/spt/tests/engine_room_bringup_e2e.rs","crates/spt/tests/gateway_e2e.rs","crates/spt/tests/gateway_owner_shell_e2e.rs","crates/spt/tests/io_events_poll_e2e.rs","crates/spt/tests/io_state_payload_e2e.rs","crates/spt/tests/knock_mutual_cross_node_e2e.rs","crates/spt/tests/listen_seed_retry_e2e.rs","crates/spt/tests/live_resolve_e2e.rs","crates/spt/tests/midturn_span_e2e.rs","crates/spt/tests/nested_resolution_e2e.rs"],"fileMatches":[{"path":"crates/spt/tests/activity_link_push_e2e.rs","count":1},{"path":"crates/spt/tests/bind_adapter_profile_persist_e2e.rs","count":1},{"path":"crates/spt/tests/boundary_events_e2e.rs","count":4},{"path":"crates/spt/tests/boundary_ready_strand_e2e.rs","count":1},{"path":"crates/spt/tests/commune_two_cwd_e2e.rs","count":1},{"path":"crates/spt/tests/contract_e2e.rs","count":1},{"path":"crates/spt/tests/create_bind_rest_active_e2e.rs","count":1},{"path":"crates/spt/tests/docs_bundle_e2e.rs","count":1},{"path":"crates/spt/tests/drive_e2e.rs","count":1},{"path":"crates/spt/tests/endpoint_teardown_authority_e2e.rs","count":1},{"path":"crates/spt/tests/engine_room_bringup_e2e.rs","count":1},{"path":"crates/spt/tests/gateway_e2e.rs","count":2},{"path":"crates/spt/tests/gateway_owner_shell_e2e.rs","count":1},{"path":"crates/spt/tests/io_events_poll_e2e.rs","count":2},{"path":"crates/spt/tests/io_state_payload_e2e.rs","count":2},{"path":"crates/spt/tests/knock_mutual_cross_node_e2e.rs","count":3},{"path":"crates/spt/tests/listen_seed_retry_e2e.rs","count":1},{"path":"crates/spt/tests/live_resolve_e2e.rs","count":1},{"path":"crates/spt/tests/midturn_span_e2e.rs","count":3},{"path":"crates/spt/tests/nested_resolution_e2e.rs","count":1}],"truncated":true,"fileLimitReached":20,"displayContent":"# crates/spt/tests/\n## activity_link_push_e2e.rs\n 529│    // and both pids it would target (`brain.ready`'s and `daemon.pid`'s) are\n*530│    // GUARANTEED FREED once the stop succeeds — a bare `taskkill /F /T` on them\n 531│    // is a coin flip against pid reuse, which on this box re-mints a freed number\n 532│    // in as little as 2.2 s. So the insurance kills authenticate first and refuse\n 533│    // a pid that is gone, recycled, or no longer this test's `spt` image.\n## bind_adapter_profile_persist_e2e.rs\n 87│    // A minimal harness adapter `dummyharness` (bare parent) — registered + a\n*88│    // manifest path so `api`'s up-front manifest resolution succeeds. No profile is\n 89│    // declared: the bare-parent bind never resolves the `:fast` profile (that lives\n 90│    // only on the seeded prior record).\n 91│    let manifest_toml = \"[adapter]\\nname=\\\"dummyharness\\\"\\nkind=\\\"harness\\\"\\nversion=\\\"1\\\"\\n\\\n## boundary_events_e2e.rs\n  99│        out.status.success(),\n*100│        \"a poll SUCCEEDS — silence is the normal case, not a failure: {}\",\n 101│        String::from_utf8_lossy(&out.stderr)\n 102│    );\n 103│    let text = String::from_utf8_lossy(&out.stdout).to_string();\n    │...\n 142│            out.status.success(),\n*143│            \"a clear boundary succeeds: {}\",\n 144│            String::from_utf8_lossy(&out.stderr)\n 145│        );\n 146│        let out = boundary(&spt_bin, home.path(), author, \"compact\", \"boundary-sid-1\", \"boundary-sid-2\");\n    │...\n 148│            out.status.success(),\n*149│            \"a compact boundary succeeds: {}\",\n 150│            String::from_utf8_lossy(&out.stderr)\n 151│        );\n 152│\n*153│        // ── (3) A REPEAT of the session already current. It SUCCEEDS — a\n 154│        //    re-report is not an error — and it must add nothing, because it\n 155│        //    crossed no edge. Asserted before the read below so its row, if the\n 156│        //    gate ever regresses, lands inside the window being counted.\n## boundary_ready_strand_e2e.rs\n 69│\n*70│    // A minimal harness adapter so `api`'s up-front manifest resolution succeeds.\n 71│    let manifest_toml = \"[adapter]\\nname=\\\"dummyharness\\\"\\nkind=\\\"harness\\\"\\nversion=\\\"1\\\"\\n\\\n 72│         min_spt_core_version=\\\"0\\\"\\n\";\n 73│    let manifest_path = home.path().join(\"dummyharness.toml\");\n## commune_two_cwd_e2e.rs\n 209│    // ══ LEG A's CLAIMS ══════════════════════════════════════════════════════\n*210│    assert!(out.status.success(), \"the pull still succeeds: {out:?}\");\n 211│\n 212│    // [int->REQ-PSYCHE-INGEST-FAILURE-LOUD] invariant 2 (the staleness half):\n 213│    // a resume composed over a drop that can NEVER ingest does not present its\n## contract_e2e.rs\n 41│/// socket so the child `spt api …` invocations find a running daemon (their\n*42│/// `ensure_running` ping succeeds → no real `spt daemon` spawned). The serve\n 43│/// thread is leaked; it dies with the test process. Call after `SPT_HOME` is set.\n 44│// [int->REQ-DAEMON-3]\n 45│fn start_inproc_daemon() {\n## create_bind_rest_active_e2e.rs\n 85│\n*86│    // A minimal harness adapter so `api`'s up-front manifest resolution succeeds.\n 87│    let manifest_toml = \"[adapter]\\nname=\\\"dummyharness\\\"\\nkind=\\\"harness\\\"\\nversion=\\\"1\\\"\\n\\\n 88│         min_spt_core_version=\\\"0\\\"\\n\";\n 89│    let manifest_path = home.path().join(\"dummyharness.toml\");\n## docs_bundle_e2e.rs\n 212│        stage_and_apply(&home3, &spt3, &artifact, None, None);\n*213│    assert!(ok3, \"docs-less apply succeeds: {stderr3}\");\n 214│    assert!(\n 215│        !stdout3.contains(\"UPDATE_DOCS\") && !stderr3.contains(\"UPDATE_DOCS\"),\n 216│        \"no docs tokens for a docs-less release: {stdout3} {stderr3}\"\n## drive_e2e.rs\n 299│        post_relink.status.success(),\n*300│        \"post-relink drain succeeds: {}\",\n 301│        String::from_utf8_lossy(&post_relink.stderr)\n 302│    );\n 303│    let post_relink = String::from_utf8_lossy(&post_relink.stdout);\n## endpoint_teardown_authority_e2e.rs\n 530│/// harness, and DESCENDANT — the stamp stays put across a settle window, and\n*531│/// `endpoint start <same>` afterwards SUCCEEDS instead of answering\n 532│/// `ENDPOINT_CREATE_CONFLICT` about a session stop claimed to have ended.\n 533│// [int->REQ-ENDPOINT-TEARDOWN-AUTHORITY]\n 534│// [int->REQ-TEARDOWN-UNCOOPERATIVE-HOST]\n## engine_room_bringup_e2e.rs\n 1994│/// reason: on a one-subnet node `assign_home` auto-homes, so the bind's own\n*1995│/// creation arm succeeds and writes the record the bring-up never wrote. The\n 1996│/// defect is INVISIBLE at one subnet by construction. Both hiding mechanisms\n 1997│/// have to be removed at once — a real bring-up, and a node holding more than\n 1998│/// one subnet — which is what this cell does.\n## gateway_e2e.rs\n 171│        send_user_msg(&spt_bin, home.path(), peer_u, gw, gw_session, \"ship it now\"),\n*172│        \"send from the gateway succeeds\"\n 173│    );\n 174│    let body = spooled_body(&peer_u_perch);\n 175│    let p = spt_proto::event::parse_event(&body)\n    │...\n 212│        send_user_msg(&spt_bin, home.path(), peer_a, agent, agent_session, \"do this\"),\n*213│        \"send from the agent succeeds (degraded, never rejected)\"\n 214│    );\n 215│    let spooled = spooled_body(&peer_a_perch);\n 216│    // REPINNED TO THE W2 CONTRACT (WEBSERVE W2, commit 92715374, which said this\n## gateway_owner_shell_e2e.rs\n 3│//! GATEWAY-typed owner (state=\"gateway\", the gateway_e2e mock-gateway type) owns\n*4│//! a shell and succeeds on EVERY ownership path same-node, and control-\n 5│//! exclusivity keys on the owner ENDPOINT-ID, never the type.\n 6│//!\n 7│//! PROOF-NOT-CHANGE (M11-T0 audit found no type-gate on any ownership path) — if\n## io_events_poll_e2e.rs\n  95│        out.status.success(),\n *96│        \"the ingest call succeeds — the funnel must never fail the hook: {}\",\n  97│        String::from_utf8_lossy(&out.stderr)\n  98│    );\n  99│}\n    │...\n 113│        out.status.success(),\n*114│        \"a poll SUCCEEDS — silence is the normal case, not a failure: {}\",\n 115│        String::from_utf8_lossy(&out.stderr)\n 116│    );\n 117│    let text = String::from_utf8_lossy(&out.stdout).to_string();\n## io_state_payload_e2e.rs\n 185│        out.status.success(),\n*186│        \"a payloadless `api state busy` still succeeds: {}\",\n 187│        String::from_utf8_lossy(&out.stderr)\n 188│    );\n 189│    let drained = drain();\n    │...\n 224│        out.status.success(),\n*225│        \"the repeat `api state idle` succeeds too: {}\",\n 226│        String::from_utf8_lossy(&out.stderr)\n 227│    );\n 228│\n## knock_mutual_cross_node_e2e.rs\n 124│/// reaped SCOPED on drop (never machine-wide — this box hosts the live fleet).\n*125│struct DaemonGuard {\n 126│    home: PathBuf,\n 127│    spt: PathBuf,\n 128│    broker: Option<Child>,\n    │...\n 300│    );\n*301│    assert!(minted.status.success(), \"the mint succeeds: {minted:?}\");\n 302│    handed_code(&out)\n 303│}\n 304│\n    │...\n 446│    let (ok, out, err) = redeem_on_a(&spt, home_a.path(), &code_own, true, Some(REDEEMER));\n*447│    assert!(ok, \"the cross-node redemption succeeds:\\n{out}{err}\");\n 448│    assert!(out.contains(\"redeemed\"), \"a decision is stated:\\n{out}\");\n 449│    // The retired shipped behaviour refused this route outright, with a message\n 450│    // explaining itself on the axis of flag ownership. It is gone from the\n## listen_seed_retry_e2e.rs\n 33│/// the child `spt api …` invocations find a running daemon (their\n*34│/// `ensure_running` ping succeeds → no real `spt daemon` is spawned). The serve\n 35│/// thread is leaked; it dies with the test process. Call after `SPT_HOME` is set.\n 36│fn start_inproc_daemon() {\n 37│    let reg = std::sync::Arc::new(spt_daemon::SeedRegistry::new());\n## live_resolve_e2e.rs\n 152│    let out = spt(&[\"api\", \"listen\", \"agent-c\", \"--parent-pid\", &pid, \"--once\"]);\n*153│    // The WRONG-way arm: a listen that succeeds here printed nothing at all about what\n 154│    // the child actually did, which is the same blindness as the positive arms.\n 155│    assert!(\n 156│        !out.status.success(),\n## midturn_span_e2e.rs\n 127│        out.status.success(),\n*128│        \"a poll SUCCEEDS: {}\",\n 129│        String::from_utf8_lossy(&out.stderr)\n 130│    );\n 131│    let text = String::from_utf8_lossy(&out.stdout).to_string();\n    │...\n 187│                out.status.success(),\n*188│                \"a span ingest succeeds — the funnel never fails the hook: {}\",\n 189│                String::from_utf8_lossy(&out.stderr)\n 190│            );\n 191│        }\n    │...\n 284│            out.status.success(),\n*285│            \"the ingest itself still succeeds: {}\",\n 286│            String::from_utf8_lossy(&out.stderr)\n 287│        );\n 288│\n## nested_resolution_e2e.rs\n  7│//! 2. A PARENT perch `dunsen` bound + homed to `alpha`.\n *8│//! 3. `spt ready dunsen-w1` (a NESTED worker id) with NO `--subnet` → succeeds and the\n  9│//!    nested perch homes to `alpha` (DERIVED from the parent), never refusing.\n 10│//! 4. CONTROL — a SELF id (`elm`, no parent) with NO `--subnet` on the same\n 11│//!    multi-subnet node STILL refuses `READY_FAIL` (only nested ids gain derivation;"},"isError":false,"timestamp":1789107106847}}
{"type":"message","id":"aa8317c3","parentId":"35964438","timestamp":"2026-09-11T06:11:47.297Z","message":{"role":"toolResult","toolCallId":"call_n3G04BdBBAFgD5uRhSNGd2wZ|fc_0330c101aa2c61dc016aa39ba05f2887d1a7f12202a1f5a2e1","toolName":"read","content":[{"type":"text","text":"# Issue #304: REMOTE-FRICTION — access, serving, roster and terminal responsiveness\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T06:10:06Z\nUpdated: 2026-09-11T06:11:34Z\nLabels: state: BACKLOG, kind: MILESTONE\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/304\n\n## Body\n\n---\nRequester: doyle\n\n## Comments (1)\n\n### @SaberMage · 2026-09-11T06:11:34Z\n\nIntake, not implementation greenlight. Operator bag retained in full: #297 #299 #300 #301 #302. Added adjacent requests: #251 safe RC viewer detach; #282 bound-port URL correctness and isolated serving acceptance; #288 accurate shell-cmd discovery; #230 visible stale-viewer version state; #49 and #267 refresh/update RC freeze reports, grouped for one RCA without assuming duplicate causes. #49 retains its prior joint-ship ruling with #42 until operator explicitly changes it. Excluded #296: comments establish omp-spt-owned replay remedy and field acceptance, not core work; #303 remains CUT and adapter-owned. No broad networking cleanup or new RC diagnostic product added implicitly. Complete infra-register sweep is running read-only; ripe riders will be recorded separately. Grill precedes final wave plan/REQ activation and implementation. Product changes go to todlando, test/CI rework to hertz, golden heads to deployah.\n\n*\\-doyle@HFENDULEAM*\n\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/304#issuecomment-5630275229"}],"details":{"contentType":"text/markdown","totalLines":23,"displayContent":{"text":"# Issue #304: REMOTE-FRICTION — access, serving, roster and terminal responsiveness\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T06:10:06Z\nUpdated: 2026-09-11T06:11:34Z\nLabels: state: BACKLOG, kind: MILESTONE\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/304\n\n## Body\n\n---\nRequester: doyle\n\n## Comments (1)\n\n### @SaberMage · 2026-09-11T06:11:34Z\n\nIntake, not implementation greenlight. Operator bag retained in full: #297 #299 #300 #301 #302. Added adjacent requests: #251 safe RC viewer detach; #282 bound-port URL correctness and isolated serving acceptance; #288 accurate shell-cmd discovery; #230 visible stale-viewer version state; #49 and #267 refresh/update RC freeze reports, grouped for one RCA without assuming duplicate causes. #49 retains its prior joint-ship ruling with #42 until operator explicitly changes it. Excluded #296: comments establish omp-spt-owned replay remedy and field acceptance, not core work; #303 remains CUT and adapter-owned. No broad networking cleanup or new RC diagnostic product added implicitly. Complete infra-register sweep is running read-only; ripe riders will be recorded separately. Grill precedes final wave plan/REQ activation and implementation. Product changes go to todlando, test/CI rework to hertz, golden heads to deployah.\n\n*\\-doyle@HFENDULEAM*\n\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/304#issuecomment-5630275229","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]},"meta":{"source":{"type":"internal","value":"issue://BigscreenVR/spt-bs-releases/304"}}},"isError":false,"timestamp":1789107107296}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_rYRhGsUr623ggH6nxGRl1jXk|fc_0330c101aa2c61dc016aa39bac681487d1a982f5d32991b62a","toolName":"read","startedAt":"2026-09-11T06:11:58.880Z","args":{"path":"issue://BigscreenVR/spt-bs-releases/297"},"intent":"Reading firewall intake disposition"},"id":"96bb7c5d","parentId":"aa8317c3","timestamp":"2026-09-11T06:11:58.880Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_ukXmlqLRDpO7pVA0FkFoqOnA|fc_0330c101aa2c61dc016aa39bac682887d1a297879873c1323d","toolName":"read","startedAt":"2026-09-11T06:11:58.881Z","args":{"path":"issue://BigscreenVR/spt-bs-releases/299"},"intent":"Reading roster intake scope"},"id":"4d477901","parentId":"96bb7c5d","timestamp":"2026-09-11T06:11:58.881Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_wWJFCWEwn9WAmDtcwSZit778|fc_0330c101aa2c61dc016aa39bac683487d1b1885961c639f983","toolName":"read","startedAt":"2026-09-11T06:11:58.881Z","args":{"path":"issue://BigscreenVR/spt-bs-releases/300"},"intent":"Reading user-input serving scope"},"id":"0c048997","parentId":"4d477901","timestamp":"2026-09-11T06:11:58.881Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_lDBnENwhRYEGsuaJP3SPJepG|fc_0330c101aa2c61dc016aa39bac684087d18df0ab81ff2150f4","toolName":"read","startedAt":"2026-09-11T06:11:58.881Z","args":{"path":"issue://BigscreenVR/spt-bs-releases/301"},"intent":"Reading root landing scope"},"id":"d197a9ad","parentId":"0c048997","timestamp":"2026-09-11T06:11:58.881Z"}
{"type":"message","id":"4c387a65","parentId":"d197a9ad","timestamp":"2026-09-11T06:11:58.882Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Reading intake details**"},{"type":"toolCall","id":"call_rYRhGsUr623ggH6nxGRl1jXk|fc_0330c101aa2c61dc016aa39bac681487d1a982f5d32991b62a","name":"read","arguments":{"i":"Reading firewall intake disposition","path":"issue://BigscreenVR/spt-bs-releases/297"},"intent":"Reading firewall intake disposition"},{"type":"toolCall","id":"call_ukXmlqLRDpO7pVA0FkFoqOnA|fc_0330c101aa2c61dc016aa39bac682887d1a297879873c1323d","name":"read","arguments":{"i":"Reading roster intake scope","path":"issue://BigscreenVR/spt-bs-releases/299"},"intent":"Reading roster intake scope"},{"type":"toolCall","id":"call_wWJFCWEwn9WAmDtcwSZit778|fc_0330c101aa2c61dc016aa39bac683487d1b1885961c639f983","name":"read","arguments":{"i":"Reading user-input serving scope","path":"issue://BigscreenVR/spt-bs-releases/300"},"intent":"Reading user-input serving scope"},{"type":"toolCall","id":"call_lDBnENwhRYEGsuaJP3SPJepG|fc_0330c101aa2c61dc016aa39bac684087d18df0ab81ff2150f4","name":"read","arguments":{"i":"Reading root landing scope","path":"issue://BigscreenVR/spt-bs-releases/301"},"intent":"Reading root landing scope"},{"type":"toolCall","id":"call_N9SMwNN18CmgYA3Ztk062YjJ|fc_0330c101aa2c61dc016aa39bac684887d1894e4ab82106b7cc","name":"read","arguments":{"i":"Reading recurring freeze scope","path":"issue://BigscreenVR/spt-bs-releases/302"},"intent":"Reading recurring freeze scope"},{"type":"toolCall","id":"call_72e44xTrwgLSYhKiv9zq3ssj|fc_0330c101aa2c61dc016aa39bac685087d19e57dc9101edcc1d","name":"read","arguments":{"i":"Reading exact docs override logic","path":"crates/spt-daemon/src/docshost.rs:90-110"},"intent":"Reading exact docs override logic"},{"type":"toolCall","id":"call_0aYls5e9pMKqUtfreV6Bfc67|fc_0330c101aa2c61dc016aa39bac685487d1aee8c186eb6d3dd4","name":"read","arguments":{"i":"Reading exact successor write","path":"crates/spt-daemon/src/daemon.rs:464-480"},"intent":"Reading exact successor write"},{"type":"toolCall","id":"call_MOUecAtEHPepLtAKHGhHeIDs|fc_0330c101aa2c61dc016aa39bac685c87d1be64dbe369e1f1fc","name":"glob","arguments":{"i":"Locating existing shared guard helpers","path":"crates/spt/tests/common/*;crates/xtask/src/*kill*","hidden":true,"gitignore":true,"limit":30},"intent":"Locating existing shared guard helpers"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":9141,"output":315,"cacheRead":112384,"cacheWrite":0,"totalTokens":121840,"reasoningTokens":18,"cost":{"input":0.09141,"output":0.01575,"cacheRead":0.112384,"cacheWrite":0,"total":0.21954400000000002}},"stopReason":"toolUse","timestamp":1789107107355,"responseId":"resp_0330c101aa2c61dc016aa39ba1640487d19ffcae8fa6f220a6","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0330c101aa2c61dc016aa39ba2fe7c87d1ab6ca7b5a9449079","type":"reasoning","content":[],"encrypted_content":"gAAAAABqo5us74Qxuh6SZ7hpHpo0pooeYSZshU2b6EpGxaYMv30CLleQ56m7FGQ73KXHsz2B_YlUqNn6HBWtvvlrFe8Nm4VwRdhvyasZuhmHWYGSCD1N9dZFD8bz4tBEVS8KATpVO5AYHV6J3m7LOKFTb7uUxBopNNCi8fBmMwWhV1lGWDvN5HikNjTJNAnlaT37Yk1QdUhN2QNlJMd8w4-lyGbuGazvB_nFF22HGihgPy6uGomL5uk7gGU1TaDuhtBn3bFeFlxC7CrF-CjvgFkdJ9Wx6GL4PhCGxEjXMPzR5ybRkBxpfKdk1n4UDQqHZq3iGPhl3qYPkoubfvZiEoA-Qefx7ByU-F6k58zIOHhZiCy8u1LItVgSasrnPaE-XaUAbHAO1fcc9Xp968eZOEHXSOtMhNdNFhiRCaQVaf_62FoERZyqo6NB87WAXBzhOyuok_tauhqcyRalFk_jNj7xq4CKIs2P3ft3Ofn8brdSH7BZrF5_aBC-2XKmw8vp-sUzumiQP9prEtoCZ5tKzZW2AQ8ZMSilVWzCpZk-Sf8MwRMO4bU1W_Qh-wsGAzJYQHqx20T0iVO5nWLgR4wk2Mw9an_Bw5GlhaX6u2p6NrtauLsRn-gK6fjsVQ7D3P0MCvVdB2_JkgjF1-C9DAUm63tKOP_K4GgZ9O7FAd9p61DHVHblxIDJPdaHpWZQAiDAVQwjqYY4C6xEsPiAbhnsGkGl5JDmWoKxb-zBwParDLNvbJxupFpWIxpdOej98tHgZypjUO_JvgAM7tys0Si3Do-j1esUfjQNqCxoPS9xQWXRjPPWqLwg_SjpJqA7ZgmWAYVXhlnZ43gjrNdw_3Ho04G2VM5N-ogXVjJ8gZjH0GULsgG3ldPk4vD65oVUF67eZpyogfwh8a8cQMqTgoag3urkXZTXEURLUUsJKrQXHfVFe2rPfkvzvRtdLnkrIP8Hwti_JCo0120Zfrs20dXwn4dawB_AS544jjKgYG1wuc9-dqp13y8juk68bvjvMi2yWdCGtKS9AB1T1VDIeLTuF0r3CCL2W4Z1jX0Vgxzd7iUcFW65mTAJKEzk4jRPvnb35-XElyNjs7cC9zQW29kaAOqW7ttpO6tknjlc_8LhG0i7UIN0g5DDJBfTnvCJcL_LB9RODRB8147JicBv6IstZQf-kasRuGXQOUCZXxtvqdOCwClIEaSvX0httOCqVoy5HOGKOa7aDX7oa-K09uPxkUXOLvjs58wz45inH5H60cmSD8qLLyxr02RmZ_a2HpOaczvlGD-XsW8TqsO6SmX6LPnyKnDtDicSpLho-YkBdscDvXZmA0L5kbSdHXpjmCB9qi9j2SkbbAzlWvtKIRCfDfU9ex_y-kLvNGe-VavGck0M2cDd5uPOacc=","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"summary":[{"type":"summary_text","text":"**Reading intake details**"}],"metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bac681487d1a982f5d32991b62a","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading firewall intake disposition\",\"path\":\"issue://BigscreenVR/spt-bs-releases/297\"}","call_id":"call_rYRhGsUr623ggH6nxGRl1jXk","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bac682887d1a297879873c1323d","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading roster intake scope\",\"path\":\"issue://BigscreenVR/spt-bs-releases/299\"}","call_id":"call_ukXmlqLRDpO7pVA0FkFoqOnA","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bac683487d1b1885961c639f983","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading user-input serving scope\",\"path\":\"issue://BigscreenVR/spt-bs-releases/300\"}","call_id":"call_wWJFCWEwn9WAmDtcwSZit778","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bac684087d18df0ab81ff2150f4","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading root landing scope\",\"path\":\"issue://BigscreenVR/spt-bs-releases/301\"}","call_id":"call_lDBnENwhRYEGsuaJP3SPJepG","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bac684887d1894e4ab82106b7cc","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading recurring freeze scope\",\"path\":\"issue://BigscreenVR/spt-bs-releases/302\"}","call_id":"call_N9SMwNN18CmgYA3Ztk062YjJ","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bac685087d19e57dc9101edcc1d","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading exact docs override logic\",\"path\":\"crates/spt-daemon/src/docshost.rs:90-110\"}","call_id":"call_72e44xTrwgLSYhKiv9zq3ssj","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bac685487d1aee8c186eb6d3dd4","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading exact successor write\",\"path\":\"crates/spt-daemon/src/daemon.rs:464-480\"}","call_id":"call_0aYls5e9pMKqUtfreV6Bfc67","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bac685c87d1be64dbe369e1f1fc","type":"function_call","status":"completed","arguments":"{\"i\":\"Locating existing shared guard helpers\",\"path\":\"crates/spt/tests/common/*;crates/xtask/src/*kill*\",\"hidden\":true,\"gitignore\":true,\"limit\":30}","call_id":"call_MOUecAtEHPepLtAKHGhHeIDs","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"glob","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}}]},"duration":11500.805399999954,"ttft":1997.662600000389,"completedAt":1789107118857,"contextSnapshot":{"promptTokens":121525,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_N9SMwNN18CmgYA3Ztk062YjJ|fc_0330c101aa2c61dc016aa39bac684887d1894e4ab82106b7cc","toolName":"read","startedAt":"2026-09-11T06:11:58.882Z","args":{"path":"issue://BigscreenVR/spt-bs-releases/302"},"intent":"Reading recurring freeze scope"},"id":"e713e8e4","parentId":"4c387a65","timestamp":"2026-09-11T06:11:58.882Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_72e44xTrwgLSYhKiv9zq3ssj|fc_0330c101aa2c61dc016aa39bac685087d19e57dc9101edcc1d","toolName":"read","startedAt":"2026-09-11T06:11:58.883Z","args":{"path":"crates/spt-daemon/src/docshost.rs:90-110"},"intent":"Reading exact docs override logic"},"id":"51386353","parentId":"e713e8e4","timestamp":"2026-09-11T06:11:58.883Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_0aYls5e9pMKqUtfreV6Bfc67|fc_0330c101aa2c61dc016aa39bac685487d1aee8c186eb6d3dd4","toolName":"read","startedAt":"2026-09-11T06:11:58.883Z","args":{"path":"crates/spt-daemon/src/daemon.rs:464-480"},"intent":"Reading exact successor write"},"id":"e4f6c58a","parentId":"51386353","timestamp":"2026-09-11T06:11:58.883Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_MOUecAtEHPepLtAKHGhHeIDs|fc_0330c101aa2c61dc016aa39bac685c87d1be64dbe369e1f1fc","toolName":"glob","startedAt":"2026-09-11T06:11:58.883Z","args":{"path":"crates/spt/tests/common/*;crates/xtask/src/*kill*"},"intent":"Locating existing shared guard helpers"},"id":"7784fffd","parentId":"e4f6c58a","timestamp":"2026-09-11T06:11:58.883Z"}
{"type":"message","id":"c7bf56f4","parentId":"7784fffd","timestamp":"2026-09-11T06:11:58.895Z","message":{"role":"toolResult","toolCallId":"call_MOUecAtEHPepLtAKHGhHeIDs|fc_0330c101aa2c61dc016aa39bac685c87d1be64dbe369e1f1fc","toolName":"glob","content":[{"type":"text","text":"# crates/spt/tests/common/\nreap.rs\nmod.rs"}],"details":{"scopePath":"crates/spt/tests/common/*, crates/xtask/src/*kill*","fileCount":2,"files":["crates/spt/tests/common/reap.rs","crates/spt/tests/common/mod.rs"],"truncated":false,"cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core"},"isError":false,"timestamp":1789107118894}}
{"type":"message","id":"1ab393a2","parentId":"c7bf56f4","timestamp":"2026-09-11T06:11:58.922Z","message":{"role":"toolResult","toolCallId":"call_72e44xTrwgLSYhKiv9zq3ssj|fc_0330c101aa2c61dc016aa39bac685087d19e57dc9101edcc1d","toolName":"read","content":[{"type":"text","text":"\n/// Daemon-side resolution adds the rig's ephemeral-port posture without\n/// changing the public `SPT_DOCS_PORT=0` contract used by `spt docs url`.\n// [impl->REQ-TEST-DAEMON-EPHEMERAL-ADVISORY-PORTS]\npub fn resolve_daemon_docs_port(\n    config_port: Option<u16>,\n    env_value: Option<&str>,\n    ephemeral_advisory_ports: bool,\n) -> u16 {\n    if ephemeral_advisory_ports {\n        return 0;\n    }\n    resolve_docs_port(config_port, env_value)\n}\n\n/// The canonical node-prefixed URL printed by `spt docs url`.\n// [impl->REQ-DOCS-LOCAL-SERVER]\n// [impl->REQ-WEB-URL-NODE-PREFIX]\npub fn docs_url(node: &str, port: u16) -> String {\n    let node = spt_store::serving::encode_url_segment(&node.to_ascii_lowercase());\n    format!(\"http://localhost:{port}/{node}/docs/\")\n}\n\n/// Percent-decode a URI path (the sanitizer runs AFTER decoding, so\n/// `%2e%2e` cannot smuggle a traversal). Invalid escapes ⇒ `None` (reject).\n\n[Showing lines 89-113 of 572. Use :114 to continue]"}],"details":{"truncation":{"content":"\r\n/// Daemon-side resolution adds the rig's ephemeral-port posture without\r\n/// changing the public `SPT_DOCS_PORT=0` contract used by `spt docs url`.\r\n// [impl->REQ-TEST-DAEMON-EPHEMERAL-ADVISORY-PORTS]\r\npub fn resolve_daemon_docs_port(\r\n    config_port: Option<u16>,\r\n    env_value: Option<&str>,\r\n    ephemeral_advisory_ports: bool,\r\n) -> u16 {\r\n    if ephemeral_advisory_ports {\r\n        return 0;\r\n    }\r\n    resolve_docs_port(config_port, env_value)\r\n}\r\n\r\n/// The canonical node-prefixed URL printed by `spt docs url`.\r\n// [impl->REQ-DOCS-LOCAL-SERVER]\r\n// [impl->REQ-WEB-URL-NODE-PREFIX]\r\npub fn docs_url(node: &str, port: u16) -> String {\r\n    let node = spt_store::serving::encode_url_segment(&node.to_ascii_lowercase());\r\n    format!(\"http://localhost:{port}/{node}/docs/\")\r\n}\r\n\r\n/// Percent-decode a URI path (the sanitizer runs AFTER decoding, so\r\n/// `%2e%2e` cannot smuggle a traversal). Invalid escapes ⇒ `None` (reject).\r","truncated":true,"truncatedBy":"lines","totalLines":484,"totalBytes":939,"outputLines":25,"outputBytes":939,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":572,"displayContent":{"text":"\r\n/// Daemon-side resolution adds the rig's ephemeral-port posture without\r\n/// changing the public `SPT_DOCS_PORT=0` contract used by `spt docs url`.\r\n// [impl->REQ-TEST-DAEMON-EPHEMERAL-ADVISORY-PORTS]\r\npub fn resolve_daemon_docs_port(\r\n    config_port: Option<u16>,\r\n    env_value: Option<&str>,\r\n    ephemeral_advisory_ports: bool,\r\n) -> u16 {\r\n    if ephemeral_advisory_ports {\r\n        return 0;\r\n    }\r\n    resolve_docs_port(config_port, env_value)\r\n}\r\n\r\n/// The canonical node-prefixed URL printed by `spt docs url`.\r\n// [impl->REQ-DOCS-LOCAL-SERVER]\r\n// [impl->REQ-WEB-URL-NODE-PREFIX]\r\npub fn docs_url(node: &str, port: u16) -> String {\r\n    let node = spt_store::serving::encode_url_segment(&node.to_ascii_lowercase());\r\n    format!(\"http://localhost:{port}/{node}/docs/\")\r\n}\r\n\r\n/// Percent-decode a URI path (the sanitizer runs AFTER decoding, so\r\n/// `%2e%2e` cannot smuggle a traversal). Invalid escapes ⇒ `None` (reject).\r","startLine":89,"lineNumbers":[89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113]},"fileSize":23204,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\crates\\spt-daemon\\src\\docshost.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":572,"totalBytes":939,"outputLines":25,"outputBytes":939,"shownRange":{"start":89,"end":113},"nextOffset":114}}},"isError":false,"timestamp":1789107118921}}
{"type":"message","id":"057d30b2","parentId":"1ab393a2","timestamp":"2026-09-11T06:11:58.939Z","message":{"role":"toolResult","toolCallId":"call_0aYls5e9pMKqUtfreV6Bfc67|fc_0330c101aa2c61dc016aa39bac685487d1aee8c186eb6d3dd4","toolName":"read","content":[{"type":"text","text":"        {\n            let (_handle, restart) = crate::brainproc::spawn_brain_supervisor(\n…\n                Arc::clone(&reaper),\n                // The DRAINED promotion gate (REQ-UPDATE-PROMOTE-DRAINED) reads this\n                // broker's live control-plane truth in-process; None on a bind-failed\n                // daemon degrades the gate to readiness-only.\n                broker_handle.clone(),\n            );\n            if let Some(broker) = &broker_handle {\n                broker.set_brain_restart(restart);\n            }\n        }\n\n        // Best-effort breadcrumb: record our pid for management/cleanup. Liveness\n        // is the socket ping, never this file, so a stale value is harmless.\n        let _ = std::fs::write(daemon_pid_path(), std::process::id().to_string());\n\n        // The seed-control channel is the foreground loop. Binding it is what\n        // arbitrates the single-daemon-per-home invariant: a second daemon racing\n        // to start fails this bind and exits, leaving the winner serving. It\n        // returns only on a graceful `daemon stop` (the KIND_STOP latch).\n        let serve = seedmap::serve_seed_control(&seed_socket_name(), reg);\n\n\n[Showing lines 463-483 of 3532. Use :484 to continue]"}],"details":{"truncation":{"content":"                Arc::clone(&reaper),\r\n                // The DRAINED promotion gate (REQ-UPDATE-PROMOTE-DRAINED) reads this\r\n                // broker's live control-plane truth in-process; None on a bind-failed\r\n                // daemon degrades the gate to readiness-only.\r\n                broker_handle.clone(),\r\n            );\r\n            if let Some(broker) = &broker_handle {\r\n                broker.set_brain_restart(restart);\r\n            }\r\n        }\r\n\r\n        // Best-effort breadcrumb: record our pid for management/cleanup. Liveness\r\n        // is the socket ping, never this file, so a stale value is harmless.\r\n        let _ = std::fs::write(daemon_pid_path(), std::process::id().to_string());\r\n\r\n        // The seed-control channel is the foreground loop. Binding it is what\r\n        // arbitrates the single-daemon-per-home invariant: a second daemon racing\r\n        // to start fails this bind and exits, leaving the winner serving. It\r\n        // returns only on a graceful `daemon stop` (the KIND_STOP latch).\r\n        let serve = seedmap::serve_seed_control(&seed_socket_name(), reg);\r\n\r","truncated":true,"truncatedBy":"lines","totalLines":3070,"totalBytes":1110,"outputLines":21,"outputBytes":1110,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":3532,"displayContent":{"text":"        {\n            let (_handle, restart) = crate::brainproc::spawn_brain_supervisor(\n…\n                Arc::clone(&reaper),\r\n                // The DRAINED promotion gate (REQ-UPDATE-PROMOTE-DRAINED) reads this\r\n                // broker's live control-plane truth in-process; None on a bind-failed\r\n                // daemon degrades the gate to readiness-only.\r\n                broker_handle.clone(),\r\n            );\r\n            if let Some(broker) = &broker_handle {\r\n                broker.set_brain_restart(restart);\r\n            }\r\n        }\r\n\r\n        // Best-effort breadcrumb: record our pid for management/cleanup. Liveness\r\n        // is the socket ping, never this file, so a stale value is harmless.\r\n        let _ = std::fs::write(daemon_pid_path(), std::process::id().to_string());\r\n\r\n        // The seed-control channel is the foreground loop. Binding it is what\r\n        // arbitrates the single-daemon-per-home invariant: a second daemon racing\r\n        // to start fails this bind and exits, leaving the winner serving. It\r\n        // returns only on a graceful `daemon stop` (the KIND_STOP latch).\r\n        let serve = seedmap::serve_seed_control(&seed_socket_name(), reg);\r\n\r","startLine":460,"lineNumbers":[460,461,null,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,480,481,482,483]},"fileSize":176265,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\crates\\spt-daemon\\src\\daemon.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":3532,"totalBytes":1110,"outputLines":21,"outputBytes":1110,"shownRange":{"start":463,"end":483},"nextOffset":484}}},"isError":false,"timestamp":1789107118939}}
{"type":"message","id":"fcf1e993","parentId":"057d30b2","timestamp":"2026-09-11T06:11:59.280Z","message":{"role":"toolResult","toolCallId":"call_wWJFCWEwn9WAmDtcwSZit778|fc_0330c101aa2c61dc016aa39bac683487d1b1885961c639f983","toolName":"read","content":[{"type":"text","text":"# Issue #300: Remote spt rc input bypasses FILE_ACCESS_HELPER auto-serving promised by #17\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T04:45:52Z\nUpdated: 2026-09-11T05:14:14Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/300\n\n## Body\n\nOperator 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\n\n## Comments (1)\n\n### @SaberMage · 2026-09-11T05:14:14Z\n\nOperator clarification (2026-09-11): the intended automatic file-serving trigger is I/O kind USER_INPUT, NOT MSG_OUT.\n\nThis governs the corrective implementation and acceptance. My earlier MSG_OUT/user-msg discussion described the existing implementation's restriction, not the intended contract. Do not carry that restriction forward as a requirement or require an attached user's input to become an outbound message. Connect the helper to USER_INPUT, retaining the authenticated user/controller node provenance needed to resolve and authorize the quoted path on the user's node. Preserve reference-serving, 24h TTL, receiving-agent audience and once-per-input/path guidance. Raw terminal keystrokes are not a substitute for the USER_INPUT event.\n\nAcceptance must cover actual remote spt rc user input producing USER_INPUT and the scoped helper registration, without requiring MSG_OUT. No implementation or issue-state change claimed by this clarification.\n\n*\\-doyle@HFENDULEAM*\n\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/300#issuecomment-5629825293"}],"details":{"contentType":"text/markdown","totalLines":35,"displayContent":{"text":"# Issue #300: Remote spt rc input bypasses FILE_ACCESS_HELPER auto-serving promised by #17\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T04:45:52Z\nUpdated: 2026-09-11T05:14:14Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/300\n\n## Body\n\nOperator 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\n\n## Comments (1)\n\n### @SaberMage · 2026-09-11T05:14:14Z\n\nOperator clarification (2026-09-11): the intended automatic file-serving trigger is I/O kind USER_INPUT, NOT MSG_OUT.\n\nThis governs the corrective implementation and acceptance. My earlier MSG_OUT/user-msg discussion described the existing implementation's restriction, not the intended contract. Do not carry that restriction forward as a requirement or require an attached user's input to become an outbound message. Connect the helper to USER_INPUT, retaining the authenticated user/controller node provenance needed to resolve and authorize the quoted path on the user's node. Preserve reference-serving, 24h TTL, receiving-agent audience and once-per-input/path guidance. Raw terminal keystrokes are not a substitute for the USER_INPUT event.\n\nAcceptance must cover actual remote spt rc user input producing USER_INPUT and the scoped helper registration, without requiring MSG_OUT. No implementation or issue-state change claimed by this clarification.\n\n*\\-doyle@HFENDULEAM*\n\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/300#issuecomment-5629825293","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35]},"meta":{"source":{"type":"internal","value":"issue://BigscreenVR/spt-bs-releases/300"}}},"isError":false,"timestamp":1789107119280}}
{"type":"message","id":"82ecbe3a","parentId":"fcf1e993","timestamp":"2026-09-11T06:11:59.297Z","message":{"role":"toolResult","toolCallId":"call_lDBnENwhRYEGsuaJP3SPJepG|fc_0330c101aa2c61dc016aa39bac684087d18df0ab81ff2150f4","toolName":"read","content":[{"type":"text","text":"# Issue #301: fix: `localhost:5474/<node-name>/` shows \"Served Resources\"\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T05:10:46Z\nUpdated: 2026-09-11T05:58:15Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/301\n\n## Body\n\na \"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."}],"details":{"contentType":"text/markdown","totalLines":17,"displayContent":{"text":"# Issue #301: fix: `localhost:5474/<node-name>/` shows \"Served Resources\"\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T05:10:46Z\nUpdated: 2026-09-11T05:58:15Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/301\n\n## Body\n\na \"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.","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]},"meta":{"source":{"type":"internal","value":"issue://BigscreenVR/spt-bs-releases/301"}}},"isError":false,"timestamp":1789107119296}}
{"type":"message","id":"72fc5e2e","parentId":"82ecbe3a","timestamp":"2026-09-11T06:11:59.322Z","message":{"role":"toolResult","toolCallId":"call_rYRhGsUr623ggH6nxGRl1jXk|fc_0330c101aa2c61dc016aa39bac681487d1a982f5d32991b62a","toolName":"read","content":[{"type":"text","text":"# Issue #297: Windows serve lan --bootstrap leaves TCP listener inaccessible over Tailscale\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T03:03:17Z\nUpdated: 2026-09-11T03:17:19Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/297\n\n## Body\n\nOperator 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\n\n## Comments (1)\n\n### @SaberMage · 2026-09-11T03:17:18Z\n\nOperator confirms the enlyzeam access incident is resolved: it was a Tailscale configuration issue. Doyle independently received HTTP 200 from the bootstrap install page over Tailscale before that confirmation. Do not attribute this incident to the missing Windows TCP rule. Keep this request open for the separately source-verified bootstrap-process gap: install and reconciliation admit UDP only; bootstrap start does not reconcile TCP admission or explain unmet firewall prerequisites. No state change requested.\n\n*\\-doyle@HFENDULEAM*\n\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/297#issuecomment-5628923449"}],"details":{"contentType":"text/markdown","totalLines":31,"displayContent":{"text":"# Issue #297: Windows serve lan --bootstrap leaves TCP listener inaccessible over Tailscale\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T03:03:17Z\nUpdated: 2026-09-11T03:17:19Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/297\n\n## Body\n\nOperator 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\n\n## Comments (1)\n\n### @SaberMage · 2026-09-11T03:17:18Z\n\nOperator confirms the enlyzeam access incident is resolved: it was a Tailscale configuration issue. Doyle independently received HTTP 200 from the bootstrap install page over Tailscale before that confirmation. Do not attribute this incident to the missing Windows TCP rule. Keep this request open for the separately source-verified bootstrap-process gap: install and reconciliation admit UDP only; bootstrap start does not reconcile TCP admission or explain unmet firewall prerequisites. No state change requested.\n\n*\\-doyle@HFENDULEAM*\n\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/297#issuecomment-5628923449","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31]},"meta":{"source":{"type":"internal","value":"issue://BigscreenVR/spt-bs-releases/297"}}},"isError":false,"timestamp":1789107119322}}
{"type":"message","id":"c0d9960d","parentId":"72fc5e2e","timestamp":"2026-09-11T06:11:59.323Z","message":{"role":"toolResult","toolCallId":"call_N9SMwNN18CmgYA3Ztk062YjJ|fc_0330c101aa2c61dc016aa39bac684887d1894e4ab82106b7cc","toolName":"read","content":[{"type":"text","text":"# Issue #302: diagnose + fix: rc sessions frequently hitch\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T05:44:43Z\nUpdated: 2026-09-11T05:56:54Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/302\n\n## Body\n\npty 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."}],"details":{"contentType":"text/markdown","totalLines":17,"displayContent":{"text":"# Issue #302: diagnose + fix: rc sessions frequently hitch\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T05:44:43Z\nUpdated: 2026-09-11T05:56:54Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/302\n\n## Body\n\npty 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.","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]},"meta":{"source":{"type":"internal","value":"issue://BigscreenVR/spt-bs-releases/302"}}},"isError":false,"timestamp":1789107119323}}
{"type":"message","id":"794ae7a5","parentId":"c0d9960d","timestamp":"2026-09-11T06:11:59.342Z","message":{"role":"toolResult","toolCallId":"call_ukXmlqLRDpO7pVA0FkFoqOnA|fc_0330c101aa2c61dc016aa39bac682887d1a297879873c1323d","toolName":"read","content":[{"type":"text","text":"# Issue #299: Diagnose endpoint list --show-all recurring ~10s stalls with complete unchanged output\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T04:39:23Z\nUpdated: 2026-09-11T04:39:33Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/299\n\n## Body\n\nPerri 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\n\n## Comments (1)\n\n### @SaberMage · 2026-09-11T04:39:33Z\n\nReporter perri, HFENDULEAM, spt-core 0.69.0, 2026-09-11. Standalone unpiped CLI measurements: 3822ms, 10120ms, 10105ms; each rc=0, 2497 bytes, byte-identical complete roster. Accept these observations; do not require adapter reproduction.\n\nField evidence reported: archive of 1210 UPS traces over 50.4h / 10 endpoints; three nonzero live-roster stages: Sept10 18:38Z total10086/live7454ms, 22:57Z total10307/live10058ms, 23:34Z total11174/live10061ms. A ~10s deadline is a hypothesis, not established root cause. Correlated node status: 2/7 peers unreachable at quic-connect; unreachable-peer waiting and a warm-path explanation remain unproven. Adapter imposes no subprocess timeout; standalone call reproduces without adapter. Old 5s hook budget could kill these calls without a completed trace; current 20s budget mitigates, not fixes. Do not derive a failure rate from survivor-only traces.\n\nCore-side diagnosis: identify where elapsed time is spent and why repeated reads return the same complete data only after this delay. Preserve full roster, suspended rows, local merge, and truthful unavailable state. Do not fix by returning a fabricated empty/partial roster, moving the read past destructive message consumption, or widening a harness-specific timeout. No harness-specific core branch. Instrument to distinguish network deadline, local coordinator contention and local read/metadata cost before proposing a fix; no causal claim from timing alone.\n\nPublic contract: /cli/reference.md#spt-endpoint-list documents merged roster and show-all (suspended rows); /harness-contract/api.md#spt-whoami documents bounded identity-only whoami, NOT an equivalent roster replacement. It does not promise a numerical endpoint-list latency bound. Clarify list freshness/blocking semantics with the eventual remedy. Gate regression at the diagnosed seam; demonstrate complete output without the diagnosed unnecessary wait. Not urgent per reporter; no additional adapter work owed unless a discriminating probe is needed.\n\n*\\-doyle@HFENDULEAM*\n\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/299#issuecomment-5629569142"}],"details":{"contentType":"text/markdown","totalLines":33,"displayContent":{"text":"# Issue #299: Diagnose endpoint list --show-all recurring ~10s stalls with complete unchanged output\n\nState: OPEN\nAuthor: @SaberMage\nCreated: 2026-09-11T04:39:23Z\nUpdated: 2026-09-11T04:39:33Z\nLabels: state: BACKLOG, type: BUGFIX\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/299\n\n## Body\n\nPerri 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\n\n## Comments (1)\n\n### @SaberMage · 2026-09-11T04:39:33Z\n\nReporter perri, HFENDULEAM, spt-core 0.69.0, 2026-09-11. Standalone unpiped CLI measurements: 3822ms, 10120ms, 10105ms; each rc=0, 2497 bytes, byte-identical complete roster. Accept these observations; do not require adapter reproduction.\n\nField evidence reported: archive of 1210 UPS traces over 50.4h / 10 endpoints; three nonzero live-roster stages: Sept10 18:38Z total10086/live7454ms, 22:57Z total10307/live10058ms, 23:34Z total11174/live10061ms. A ~10s deadline is a hypothesis, not established root cause. Correlated node status: 2/7 peers unreachable at quic-connect; unreachable-peer waiting and a warm-path explanation remain unproven. Adapter imposes no subprocess timeout; standalone call reproduces without adapter. Old 5s hook budget could kill these calls without a completed trace; current 20s budget mitigates, not fixes. Do not derive a failure rate from survivor-only traces.\n\nCore-side diagnosis: identify where elapsed time is spent and why repeated reads return the same complete data only after this delay. Preserve full roster, suspended rows, local merge, and truthful unavailable state. Do not fix by returning a fabricated empty/partial roster, moving the read past destructive message consumption, or widening a harness-specific timeout. No harness-specific core branch. Instrument to distinguish network deadline, local coordinator contention and local read/metadata cost before proposing a fix; no causal claim from timing alone.\n\nPublic contract: /cli/reference.md#spt-endpoint-list documents merged roster and show-all (suspended rows); /harness-contract/api.md#spt-whoami documents bounded identity-only whoami, NOT an equivalent roster replacement. It does not promise a numerical endpoint-list latency bound. Clarify list freshness/blocking semantics with the eventual remedy. Gate regression at the diagnosed seam; demonstrate complete output without the diagnosed unnecessary wait. Not urgent per reporter; no additional adapter work owed unless a discriminating probe is needed.\n\n*\\-doyle@HFENDULEAM*\n\nURL: https://github.com/BigscreenVR/spt-bs-releases/issues/299#issuecomment-5629569142","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33]},"meta":{"source":{"type":"internal","value":"issue://BigscreenVR/spt-bs-releases/299"}}},"isError":false,"timestamp":1789107119341}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_eMSitTgXsTUnHbvu6os6dBTV|fc_0330c101aa2c61dc016aa39bb6703887d19bb901f43040dc1b","toolName":"read","startedAt":"2026-09-11T06:12:08.854Z","args":{"path":"crates/spt/tests/common/reap.rs:1-100"},"intent":"Reading shared reaper substrate"},"id":"7fad1211","parentId":"794ae7a5","timestamp":"2026-09-11T06:12:08.854Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_YcHQLNeAMyM2asfYWy7R2A8f|fc_0330c101aa2c61dc016aa39bb6705087d19b85851db8a4a745","toolName":"read","startedAt":"2026-09-11T06:12:08.854Z","args":{"path":"crates/spt/tests/common/mod.rs:1-60"},"intent":"Reading shared fixture module"},"id":"c114de36","parentId":"7fad1211","timestamp":"2026-09-11T06:12:08.854Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_r5lz1Pm7pQbMxITTa1IT0PmF|fc_0330c101aa2c61dc016aa39bb6705887d1b008e2831dcedb1e","toolName":"grep","startedAt":"2026-09-11T06:12:08.854Z","args":{"path":"crates/spt/tests/projindex_writer_e2e.rs;crates/spt/tests/projindex_reader_e2e.rs;crates/spt/tests/brain_split.rs;crates/spt/tests/brain_respawn_rename.rs;crates/spt/tests/endpoint_autostart_e2e.rs"},"intent":"Locating guard adoption coverage"},"id":"609be231","parentId":"c114de36","timestamp":"2026-09-11T06:12:08.854Z"}
{"type":"message","id":"a00775c1","parentId":"609be231","timestamp":"2026-09-11T06:12:08.854Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Clarifying empty-check ambiguity**"},{"type":"toolCall","id":"call_eMSitTgXsTUnHbvu6os6dBTV|fc_0330c101aa2c61dc016aa39bb6703887d19bb901f43040dc1b","name":"read","arguments":{"i":"Reading shared reaper substrate","path":"crates/spt/tests/common/reap.rs:1-100"},"intent":"Reading shared reaper substrate"},{"type":"toolCall","id":"call_YcHQLNeAMyM2asfYWy7R2A8f|fc_0330c101aa2c61dc016aa39bb6705087d19b85851db8a4a745","name":"read","arguments":{"i":"Reading shared fixture module","path":"crates/spt/tests/common/mod.rs:1-60"},"intent":"Reading shared fixture module"},{"type":"toolCall","id":"call_r5lz1Pm7pQbMxITTa1IT0PmF|fc_0330c101aa2c61dc016aa39bb6705887d1b008e2831dcedb1e","name":"grep","arguments":{"i":"Locating guard adoption coverage","pattern":"DaemonReaper|common::reap|reap::","path":"crates/spt/tests/projindex_writer_e2e.rs;crates/spt/tests/projindex_reader_e2e.rs;crates/spt/tests/brain_split.rs;crates/spt/tests/brain_respawn_rename.rs;crates/spt/tests/endpoint_autostart_e2e.rs","case":true,"gitignore":true,"skip":null},"intent":"Locating guard adoption coverage"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":116418,"output":213,"cacheRead":8448,"cacheWrite":0,"totalTokens":125079,"reasoningTokens":13,"cost":{"input":1.16418,"output":0.01065,"cacheRead":0.008447999999999999,"cacheWrite":0,"total":1.183278}},"stopReason":"toolUse","timestamp":1789107119406,"responseId":"resp_0330c101aa2c61dc016aa39bad5cc887d18032b16237ac4a23","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0330c101aa2c61dc016aa39bb0157c87d1893515a620355feb","type":"reasoning","content":[],"encrypted_content":"gAAAAABqo5u2OjQ_Z3HK_UHfYXXNKJWcOQWrPZFkpDrTTsv10fOXCu_1VH7wIuxeNprs4KlUfYdtxcXrG9MMjtemoeksXUgHdvADMDvbO9FODYYdaY6EGEkywvqJ24CkOFHUkzkV3pURPrlbsMZ4CzM500KMVsGWNihjI4UgDNFns0SyveQ1cDigiWI6cvMPQXSRID1FrnHC1ugyDOQ0_Oh8PD0REoJYaB6sCmtx72oJDgWEH5_Vq-1jx1azppK6iaRRSFMDBcdqSXv_b2jyuds36K4FvvYUVkjd-hrDxXSma2Fgs2xACs6S9qDcq92Ebp8COcPI-Quuwceyy1aujJinnDwAVqOr27sbl4gGLIzF2CeRf2sVMPLOxkaTbMgWxV2HmP8_CU9uKOyRhFsAXYEpDbz7MV--7BRV0iTYc8-px5njQdYXSrXJnYazhSkTx55m8rVA6TGPmszB74JcZR-hiasyXbj6cxc83SRjU_S48wo8Fv2SVKUC9_8AMD2I4Gl3yYIFSZqdPBuePSOE-2SzTepg7ZW_nanp9qMmOHqVyWpcgBQE2Vq6GL9_ybJN7H1BU9IFXWQBU7slv7caESZoDGZ5rIMBzacQ-ReFFDNRWVdG76oqj4hck7KpFC-nuE5oMqWE7IQBoBC-8Zh7FA_noV7-dvapuE3wW9eLhQ2kCfpRy3KJDRR3AbcfRTQLV91XigmnQYsLaq6FWtU6P_gHl5ggmTF-aMau_mA9d43Kzl2REg55EuA-fB_iOIMuoN7m5LqLLnPNBBbdVw9AK2DbiXbSvwjbOGwAgPRPM6Q6JW1Ok_4XL1QTsBvnW5fG-jdYDEFro6Lcd_oIQg0gyesAicTXGwE0bb3BYCt_qE3t0qVkCA_hCCKxYEgVAUAUQpfwb7ZLZrM4v-JWoAW-CcWT3uGKquauAVCaRoPbK3v-OEfQ3t0ed-cZVHZ5M5S5reiFU35-KjzTRHOeNM4yHNG8bcZR4mMbr0Huhm24PLvfiwWaQhxS1EjWFXfC-XKsZxuv_nzFMod5_pdvWE23sApvtl8BJ6kq7GpFrUcv4ks-UwnKcy__FnhTi6LSyZ1rFr-gE8TrYLZ5nxYBcWyPy1M93_Hdd1mL6x8Y2wHy6vwF2T9QgcpebE16TnJTEq32PqWDTHuA5n2ExiHHeryxwEFGf5fFadOiYz3bbugm3h9wjPbup6ikKoU5Wo7RgBHJX4pGtkkWwpOEacCP5xc8uVOrZp6d-kZT5iv_I2pb2fJXFHz2fTlXazF8b8DYCHWF8l0VoOw-Dlh45quRILBY2B6Br8o1dY1Ng-YH55lPArOkVp-yaJzz5gF9Bqw_GG7JHkjJqZ6qMRD5tLIJISYU9Jn0wjRjIllXcQ==","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"summary":[{"type":"summary_text","text":"**Clarifying empty-check ambiguity**"}],"metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bb6703887d19bb901f43040dc1b","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading shared reaper substrate\",\"path\":\"crates/spt/tests/common/reap.rs:1-100\"}","call_id":"call_eMSitTgXsTUnHbvu6os6dBTV","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bb6705087d19b85851db8a4a745","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading shared fixture module\",\"path\":\"crates/spt/tests/common/mod.rs:1-60\"}","call_id":"call_YcHQLNeAMyM2asfYWy7R2A8f","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"read","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bb6705887d1b008e2831dcedb1e","type":"function_call","status":"completed","arguments":"{\"i\":\"Locating guard adoption coverage\",\"pattern\":\"DaemonReaper|common::reap|reap::\",\"path\":\"crates/spt/tests/projindex_writer_e2e.rs;crates/spt/tests/projindex_reader_e2e.rs;crates/spt/tests/brain_split.rs;crates/spt/tests/brain_respawn_rename.rs;crates/spt/tests/endpoint_autostart_e2e.rs\",\"case\":true,\"gitignore\":true,\"skip\":null}","call_id":"call_r5lz1Pm7pQbMxITTa1IT0PmF","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"grep","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}}]},"duration":9446.501199999824,"ttft":3039.3978999992833,"completedAt":1789107128853,"contextSnapshot":{"promptTokens":124866,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"message","id":"fa3742b9","parentId":"a00775c1","timestamp":"2026-09-11T06:12:08.869Z","message":{"role":"toolResult","toolCallId":"call_eMSitTgXsTUnHbvu6os6dBTV|fc_0330c101aa2c61dc016aa39bb6703887d19bb901f43040dc1b","toolName":"read","content":[{"type":"text","text":"//! The AUTHENTICATED breadcrumb reaper shared by the `spt` integration tests.\n//!\n//! An on-disk pid breadcrumb (`<SPT_HOME>/daemon.pid`, the `pid` field of\n//! `brain.ready`) is a NUMBER, not an identity. The process that wrote it exits;\n//! the OS is then free to mint that same number onto something else — measured at\n//! 2.2 s minimum on the Windows gate box, p50 11.7 s under a Phase-A test battery.\n//! A cleanup that reads the breadcrumb and issues `taskkill /PID <n> /F /T` after\n//! the writer is gone therefore tree-kills whatever inherited the number: on a\n//! shared runner that is a CONCURRENT test process, which dies with a bare exit 1\n//! and no panic — nothing to read, nothing to blame (the observed\n//! `worker_lifecycle_e2e` red in golden job 90742055246).\n//!\n//! So every kill here is fail-CLOSED: the pid is reaped only when it still\n//! resolves to the target image this test started, is not the harness itself or\n//! one of its ancestors, and (when the caller observed the process while it was\n//! provably ours) still carries the creation time it was observed with. Anything\n//! else — a freed pid, an unreadable image, a foreign image, no identity oracle —\n//! REFUSES and says so on stderr. A refusal is the correct outcome on the happy\n//! path of a test that already stopped its daemon; these calls are leak insurance\n//! for the failure paths, not the primary teardown.\n//!\n//! Every invocation prints its evidence (pid, image, creation time) and its\n//! verdict BEFORE acting, so a harness that is itself hard-killed still leaves a\n//! diagnosable trail in the captured output.\n//!\n//! `#![allow(dead_code)]`: `tests/common/` compiles into EVERY `spt` integration\n//! test binary, and only the reaping ones call these.\n#![allow(dead_code)]\n\nuse std::path::{Path, PathBuf};\nuse std::process::Command;\n\nuse spt_store::proc::ProcIdentity;\n\n// Windows-only: the `taskkill` child would otherwise flash a console window.\n#[cfg(windows)]\nuse super::CommandNoWindowExt;\n\n/// A process's identity, captured while it was PROVABLY the process this test\n/// started. Pairing the pid with its creation time is what makes a later\n/// \"is this still the same process?\" question answerable at all.\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub struct ProcObservation {\n    pub pid: u32,\n    pub started_at: u64,\n}\n\n/// What the guard decided. `Refused` carries a stable reason token so a CI log\n/// grep can tell \"nothing to reap\" from \"we were about to kill a stranger\".\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\npub enum Verdict {\n    /// The pid authenticated; the kill was issued.\n    Killed,\n    /// No kill was issued. The token names why.\n    Refused(&'static str),\n}\n\n/// Resolve `<home>/daemon.pid` to a number, `None` when absent or unparseable.\npub fn breadcrumb_daemon_pid(home: &Path) -> Option<u32> {\n    std::fs::read_to_string(home.join(\"daemon.pid\"))\n        .ok()\n        .and_then(|txt| txt.trim().parse::<u32>().ok())\n}\n\n/// Capture `pid`'s identity NOW, for a later authenticated reap. Returns `None`\n/// when the platform has no identity oracle or the process is already gone — in\n/// which case the later reap simply runs without the creation-time pin (it still\n/// image-verifies).\npub fn observe(label: &str, pid: u32) -> Option<ProcObservation> {\n    match spt_store::proc::process_identity(pid) {\n        ProcIdentity::Present(started_at) => {\n            eprintln!(\"REAP[{label}]: observed pid={pid} started_at={started_at}\");\n            Some(ProcObservation { pid, started_at })\n        }\n        other => {\n            eprintln!(\"REAP[{label}]: pid={pid} not observable ({other:?}) — no identity pin\");\n            None\n        }\n    }\n}\n\n/// Do two paths name the SAME image?\n///\n/// Canonicalize both sides first: one side comes from the OS (`exe_path`, always\n/// OS-normalized) and the other from the test (`CARGO_BIN_EXE_spt`, spelled\n/// however `CARGO_TARGET_DIR` was spelled), so a bare string compare reads\n/// `…/debug\\spt.exe` and `…\\debug\\spt.exe` as DIFFERENT binaries — a guard that\n/// refuses its own daemon, which is a leak plus a false red, not a safe default.\n/// Windows adds case-insensitivity on top.\npub fn same_image(left: &Path, right: &Path) -> bool {\n    fn canonical(p: &Path) -> PathBuf {\n        std::fs::canonicalize(p).unwrap_or_else(|_| p.to_path_buf())\n    }\n    let (left, right) = (canonical(left), canonical(right));\n    #[cfg(windows)]\n    {\n        left.to_string_lossy()\n            .eq_ignore_ascii_case(&right.to_string_lossy())\n    }\n    #[cfg(not(windows))]\n    {\n        left == right\n    }\n}\n\n[Showing lines 1-103 of 471. Use :104 to continue]"}],"details":{"truncation":{"content":"//! The AUTHENTICATED breadcrumb reaper shared by the `spt` integration tests.\r\n//!\r\n//! An on-disk pid breadcrumb (`<SPT_HOME>/daemon.pid`, the `pid` field of\r\n//! `brain.ready`) is a NUMBER, not an identity. The process that wrote it exits;\r\n//! the OS is then free to mint that same number onto something else — measured at\r\n//! 2.2 s minimum on the Windows gate box, p50 11.7 s under a Phase-A test battery.\r\n//! A cleanup that reads the breadcrumb and issues `taskkill /PID <n> /F /T` after\r\n//! the writer is gone therefore tree-kills whatever inherited the number: on a\r\n//! shared runner that is a CONCURRENT test process, which dies with a bare exit 1\r\n//! and no panic — nothing to read, nothing to blame (the observed\r\n//! `worker_lifecycle_e2e` red in golden job 90742055246).\r\n//!\r\n//! So every kill here is fail-CLOSED: the pid is reaped only when it still\r\n//! resolves to the target image this test started, is not the harness itself or\r\n//! one of its ancestors, and (when the caller observed the process while it was\r\n//! provably ours) still carries the creation time it was observed with. Anything\r\n//! else — a freed pid, an unreadable image, a foreign image, no identity oracle —\r\n//! REFUSES and says so on stderr. A refusal is the correct outcome on the happy\r\n//! path of a test that already stopped its daemon; these calls are leak insurance\r\n//! for the failure paths, not the primary teardown.\r\n//!\r\n//! Every invocation prints its evidence (pid, image, creation time) and its\r\n//! verdict BEFORE acting, so a harness that is itself hard-killed still leaves a\r\n//! diagnosable trail in the captured output.\r\n//!\r\n//! `#![allow(dead_code)]`: `tests/common/` compiles into EVERY `spt` integration\r\n//! test binary, and only the reaping ones call these.\r\n#![allow(dead_code)]\r\n\r\nuse std::path::{Path, PathBuf};\r\nuse std::process::Command;\r\n\r\nuse spt_store::proc::ProcIdentity;\r\n\r\n// Windows-only: the `taskkill` child would otherwise flash a console window.\r\n#[cfg(windows)]\r\nuse super::CommandNoWindowExt;\r\n\r\n/// A process's identity, captured while it was PROVABLY the process this test\r\n/// started. Pairing the pid with its creation time is what makes a later\r\n/// \"is this still the same process?\" question answerable at all.\r\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\r\npub struct ProcObservation {\r\n    pub pid: u32,\r\n    pub started_at: u64,\r\n}\r\n\r\n/// What the guard decided. `Refused` carries a stable reason token so a CI log\r\n/// grep can tell \"nothing to reap\" from \"we were about to kill a stranger\".\r\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\r\npub enum Verdict {\r\n    /// The pid authenticated; the kill was issued.\r\n    Killed,\r\n    /// No kill was issued. The token names why.\r\n    Refused(&'static str),\r\n}\r\n\r\n/// Resolve `<home>/daemon.pid` to a number, `None` when absent or unparseable.\r\npub fn breadcrumb_daemon_pid(home: &Path) -> Option<u32> {\r\n    std::fs::read_to_string(home.join(\"daemon.pid\"))\r\n        .ok()\r\n        .and_then(|txt| txt.trim().parse::<u32>().ok())\r\n}\r\n\r\n/// Capture `pid`'s identity NOW, for a later authenticated reap. Returns `None`\r\n/// when the platform has no identity oracle or the process is already gone — in\r\n/// which case the later reap simply runs without the creation-time pin (it still\r\n/// image-verifies).\r\npub fn observe(label: &str, pid: u32) -> Option<ProcObservation> {\r\n    match spt_store::proc::process_identity(pid) {\r\n        ProcIdentity::Present(started_at) => {\r\n            eprintln!(\"REAP[{label}]: observed pid={pid} started_at={started_at}\");\r\n            Some(ProcObservation { pid, started_at })\r\n        }\r\n        other => {\r\n            eprintln!(\"REAP[{label}]: pid={pid} not observable ({other:?}) — no identity pin\");\r\n            None\r\n        }\r\n    }\r\n}\r\n\r\n/// Do two paths name the SAME image?\r\n///\r\n/// Canonicalize both sides first: one side comes from the OS (`exe_path`, always\r\n/// OS-normalized) and the other from the test (`CARGO_BIN_EXE_spt`, spelled\r\n/// however `CARGO_TARGET_DIR` was spelled), so a bare string compare reads\r\n/// `…/debug\\spt.exe` and `…\\debug\\spt.exe` as DIFFERENT binaries — a guard that\r\n/// refuses its own daemon, which is a leak plus a false red, not a safe default.\r\n/// Windows adds case-insensitivity on top.\r\npub fn same_image(left: &Path, right: &Path) -> bool {\r\n    fn canonical(p: &Path) -> PathBuf {\r\n        std::fs::canonicalize(p).unwrap_or_else(|_| p.to_path_buf())\r\n    }\r\n    let (left, right) = (canonical(left), canonical(right));\r\n    #[cfg(windows)]\r\n    {\r\n        left.to_string_lossy()\r\n            .eq_ignore_ascii_case(&right.to_string_lossy())\r\n    }\r\n    #[cfg(not(windows))]\r\n    {\r\n        left == right\r\n    }\r","truncated":true,"truncatedBy":"lines","totalLines":471,"totalBytes":4711,"outputLines":103,"outputBytes":4711,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":471,"displayContent":{"text":"//! The AUTHENTICATED breadcrumb reaper shared by the `spt` integration tests.\r\n//!\r\n//! An on-disk pid breadcrumb (`<SPT_HOME>/daemon.pid`, the `pid` field of\r\n//! `brain.ready`) is a NUMBER, not an identity. The process that wrote it exits;\r\n//! the OS is then free to mint that same number onto something else — measured at\r\n//! 2.2 s minimum on the Windows gate box, p50 11.7 s under a Phase-A test battery.\r\n//! A cleanup that reads the breadcrumb and issues `taskkill /PID <n> /F /T` after\r\n//! the writer is gone therefore tree-kills whatever inherited the number: on a\r\n//! shared runner that is a CONCURRENT test process, which dies with a bare exit 1\r\n//! and no panic — nothing to read, nothing to blame (the observed\r\n//! `worker_lifecycle_e2e` red in golden job 90742055246).\r\n//!\r\n//! So every kill here is fail-CLOSED: the pid is reaped only when it still\r\n//! resolves to the target image this test started, is not the harness itself or\r\n//! one of its ancestors, and (when the caller observed the process while it was\r\n//! provably ours) still carries the creation time it was observed with. Anything\r\n//! else — a freed pid, an unreadable image, a foreign image, no identity oracle —\r\n//! REFUSES and says so on stderr. A refusal is the correct outcome on the happy\r\n//! path of a test that already stopped its daemon; these calls are leak insurance\r\n//! for the failure paths, not the primary teardown.\r\n//!\r\n//! Every invocation prints its evidence (pid, image, creation time) and its\r\n//! verdict BEFORE acting, so a harness that is itself hard-killed still leaves a\r\n//! diagnosable trail in the captured output.\r\n//!\r\n//! `#![allow(dead_code)]`: `tests/common/` compiles into EVERY `spt` integration\r\n//! test binary, and only the reaping ones call these.\r\n#![allow(dead_code)]\r\n\r\nuse std::path::{Path, PathBuf};\r\nuse std::process::Command;\r\n\r\nuse spt_store::proc::ProcIdentity;\r\n\r\n// Windows-only: the `taskkill` child would otherwise flash a console window.\r\n#[cfg(windows)]\r\nuse super::CommandNoWindowExt;\r\n\r\n/// A process's identity, captured while it was PROVABLY the process this test\r\n/// started. Pairing the pid with its creation time is what makes a later\r\n/// \"is this still the same process?\" question answerable at all.\r\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\r\npub struct ProcObservation {\r\n    pub pid: u32,\r\n    pub started_at: u64,\r\n}\r\n\r\n/// What the guard decided. `Refused` carries a stable reason token so a CI log\r\n/// grep can tell \"nothing to reap\" from \"we were about to kill a stranger\".\r\n#[derive(Clone, Copy, Debug, PartialEq, Eq)]\r\npub enum Verdict {\r\n    /// The pid authenticated; the kill was issued.\r\n    Killed,\r\n    /// No kill was issued. The token names why.\r\n    Refused(&'static str),\r\n}\r\n\r\n/// Resolve `<home>/daemon.pid` to a number, `None` when absent or unparseable.\r\npub fn breadcrumb_daemon_pid(home: &Path) -> Option<u32> {\r\n    std::fs::read_to_string(home.join(\"daemon.pid\"))\r\n        .ok()\r\n        .and_then(|txt| txt.trim().parse::<u32>().ok())\r\n}\r\n\r\n/// Capture `pid`'s identity NOW, for a later authenticated reap. Returns `None`\r\n/// when the platform has no identity oracle or the process is already gone — in\r\n/// which case the later reap simply runs without the creation-time pin (it still\r\n/// image-verifies).\r\npub fn observe(label: &str, pid: u32) -> Option<ProcObservation> {\r\n    match spt_store::proc::process_identity(pid) {\r\n        ProcIdentity::Present(started_at) => {\r\n            eprintln!(\"REAP[{label}]: observed pid={pid} started_at={started_at}\");\r\n            Some(ProcObservation { pid, started_at })\r\n        }\r\n        other => {\r\n            eprintln!(\"REAP[{label}]: pid={pid} not observable ({other:?}) — no identity pin\");\r\n            None\r\n        }\r\n    }\r\n}\r\n\r\n/// Do two paths name the SAME image?\r\n///\r\n/// Canonicalize both sides first: one side comes from the OS (`exe_path`, always\r\n/// OS-normalized) and the other from the test (`CARGO_BIN_EXE_spt`, spelled\r\n/// however `CARGO_TARGET_DIR` was spelled), so a bare string compare reads\r\n/// `…/debug\\spt.exe` and `…\\debug\\spt.exe` as DIFFERENT binaries — a guard that\r\n/// refuses its own daemon, which is a leak plus a false red, not a safe default.\r\n/// Windows adds case-insensitivity on top.\r\npub fn same_image(left: &Path, right: &Path) -> bool {\r\n    fn canonical(p: &Path) -> PathBuf {\r\n        std::fs::canonicalize(p).unwrap_or_else(|_| p.to_path_buf())\r\n    }\r\n    let (left, right) = (canonical(left), canonical(right));\r\n    #[cfg(windows)]\r\n    {\r\n        left.to_string_lossy()\r\n            .eq_ignore_ascii_case(&right.to_string_lossy())\r\n    }\r\n    #[cfg(not(windows))]\r\n    {\r\n        left == right\r\n    }\r\n}","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104]},"fileSize":21487,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\crates\\spt\\tests\\common\\reap.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":471,"totalBytes":4711,"outputLines":103,"outputBytes":4711,"shownRange":{"start":1,"end":103},"nextOffset":104}}},"isError":false,"timestamp":1789107128869}}
{"type":"message","id":"5ac94802","parentId":"fa3742b9","timestamp":"2026-09-11T06:12:08.877Z","message":{"role":"toolResult","toolCallId":"call_YcHQLNeAMyM2asfYWy7R2A8f|fc_0330c101aa2c61dc016aa39bb6705087d19b85851db8a4a745","toolName":"read","content":[{"type":"text","text":"//! Shared test helpers for the `spt` integration tests.\n//!\n//! `tests/common/mod.rs` (a subdirectory module) is NOT compiled as its own test\n//! binary — each test file pulls it in with `mod common;`.\n//!\n//! `#![allow(dead_code)]` for the same reason `common::reap` carries it: this\n//! module compiles into EVERY `spt` integration binary, and a helper only some\n//! of them use is dead code in all the others — a warning that says nothing\n//! about the code and everything about the layout.\n#![allow(dead_code)]\n\nuse std::path::Path;\nuse std::process::{Child, Command, Output, Stdio};\nuse std::time::{Duration, Instant};\n\n/// The authenticated breadcrumb reaper (`common::reap`) — every test that cleans\n/// up a daemon/brain by its on-disk pid breadcrumb kills through it, so a freed\n/// or recycled pid is refused instead of tree-killed.\npub mod reap;\n\n/// MINT an endpoint (U3 / releases#5): `spt endpoint create <id> --adapter <a>`.\n///\n/// The mint and the first session are separate verbs now — this one writes the\n/// skeleton perch, assigns the permanent anchor subnet and records the adapter +\n/// project folder as the endpoint's session defaults; it starts nothing. Every\n/// real-daemon e2e that used to open with a single\n/// `endpoint run --adapter A --id I --start` calls this first, then starts.\n///\n/// Lives here rather than being copied into each test file because it is the\n/// SAME first half everywhere, and a bringup half that drifted per-file is\n/// exactly how an estate stops testing one surface.\n///\n/// PANICS on a failed mint, deliberately: a test whose endpoint was never\n/// created goes on to fail somewhere further down, on an assertion about\n/// something else entirely.\npub fn create_endpoint(spt_bin: &Path, home: &Path, id: &str, adapter: &str) -> Output {\n    let mut cmd = Command::new(spt_bin);\n    cmd.no_window()\n        .args([\"endpoint\", \"create\", id, \"--adapter\", adapter])\n        .env(\"SPT_HOME\", home);\n    let out = output_bounded(cmd, Duration::from_secs(45));\n    assert!(\n        out.status.success(),\n        \"endpoint create {id} --adapter {adapter} must succeed: {}\",\n        String::from_utf8_lossy(&out.stderr)\n    );\n    out\n}\n\n/// Render both daemon stderr channels for an e2e failure panel.\n///\n/// `daemon run` redirects stderr in-process, so the child capture contains only\n/// startup output emitted before redirect installation. The durable sink holds\n/// every later broker/brain diagnostic.\n// [int->REQ-DAEMON-STDERR-PERSIST]\npub fn daemon_stderr_panel(pre_redirect: &Path) -> String {\n    let captured = std::fs::read_to_string(pre_redirect).unwrap_or_else(|error| {\n        format!(\n            \"broker stderr (pre-redirect) ABSENT at {}: {error}\",\n            pre_redirect.display()\n        )\n    });\n    let home = pre_redirect\n        .parent()\n        .expect(\"daemon pre-redirect capture must live beneath SPT_HOME\");\n…\n}\n\n[Showing lines 1-63 of 373. Use :64 to continue]"}],"details":{"truncation":{"content":"//! Shared test helpers for the `spt` integration tests.\r\n//!\r\n//! `tests/common/mod.rs` (a subdirectory module) is NOT compiled as its own test\r\n//! binary — each test file pulls it in with `mod common;`.\r\n//!\r\n//! `#![allow(dead_code)]` for the same reason `common::reap` carries it: this\r\n//! module compiles into EVERY `spt` integration binary, and a helper only some\r\n//! of them use is dead code in all the others — a warning that says nothing\r\n//! about the code and everything about the layout.\r\n#![allow(dead_code)]\r\n\r\nuse std::path::Path;\r\nuse std::process::{Child, Command, Output, Stdio};\r\nuse std::time::{Duration, Instant};\r\n\r\n/// The authenticated breadcrumb reaper (`common::reap`) — every test that cleans\r\n/// up a daemon/brain by its on-disk pid breadcrumb kills through it, so a freed\r\n/// or recycled pid is refused instead of tree-killed.\r\npub mod reap;\r\n\r\n/// MINT an endpoint (U3 / releases#5): `spt endpoint create <id> --adapter <a>`.\r\n///\r\n/// The mint and the first session are separate verbs now — this one writes the\r\n/// skeleton perch, assigns the permanent anchor subnet and records the adapter +\r\n/// project folder as the endpoint's session defaults; it starts nothing. Every\r\n/// real-daemon e2e that used to open with a single\r\n/// `endpoint run --adapter A --id I --start` calls this first, then starts.\r\n///\r\n/// Lives here rather than being copied into each test file because it is the\r\n/// SAME first half everywhere, and a bringup half that drifted per-file is\r\n/// exactly how an estate stops testing one surface.\r\n///\r\n/// PANICS on a failed mint, deliberately: a test whose endpoint was never\r\n/// created goes on to fail somewhere further down, on an assertion about\r\n/// something else entirely.\r\npub fn create_endpoint(spt_bin: &Path, home: &Path, id: &str, adapter: &str) -> Output {\r\n    let mut cmd = Command::new(spt_bin);\r\n    cmd.no_window()\r\n        .args([\"endpoint\", \"create\", id, \"--adapter\", adapter])\r\n        .env(\"SPT_HOME\", home);\r\n    let out = output_bounded(cmd, Duration::from_secs(45));\r\n    assert!(\r\n        out.status.success(),\r\n        \"endpoint create {id} --adapter {adapter} must succeed: {}\",\r\n        String::from_utf8_lossy(&out.stderr)\r\n    );\r\n    out\r\n}\r\n\r\n/// Render both daemon stderr channels for an e2e failure panel.\r\n///\r\n/// `daemon run` redirects stderr in-process, so the child capture contains only\r\n/// startup output emitted before redirect installation. The durable sink holds\r\n/// every later broker/brain diagnostic.\r\n// [int->REQ-DAEMON-STDERR-PERSIST]\r\npub fn daemon_stderr_panel(pre_redirect: &Path) -> String {\r\n    let captured = std::fs::read_to_string(pre_redirect).unwrap_or_else(|error| {\r\n        format!(\r\n            \"broker stderr (pre-redirect) ABSENT at {}: {error}\",\r\n            pre_redirect.display()\r\n        )\r\n    });\r\n    let home = pre_redirect\r","truncated":true,"truncatedBy":"lines","totalLines":373,"totalBytes":2873,"outputLines":63,"outputBytes":2873,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":373,"displayContent":{"text":"//! Shared test helpers for the `spt` integration tests.\r\n//!\r\n//! `tests/common/mod.rs` (a subdirectory module) is NOT compiled as its own test\r\n//! binary — each test file pulls it in with `mod common;`.\r\n//!\r\n//! `#![allow(dead_code)]` for the same reason `common::reap` carries it: this\r\n//! module compiles into EVERY `spt` integration binary, and a helper only some\r\n//! of them use is dead code in all the others — a warning that says nothing\r\n//! about the code and everything about the layout.\r\n#![allow(dead_code)]\r\n\r\nuse std::path::Path;\r\nuse std::process::{Child, Command, Output, Stdio};\r\nuse std::time::{Duration, Instant};\r\n\r\n/// The authenticated breadcrumb reaper (`common::reap`) — every test that cleans\r\n/// up a daemon/brain by its on-disk pid breadcrumb kills through it, so a freed\r\n/// or recycled pid is refused instead of tree-killed.\r\npub mod reap;\r\n\r\n/// MINT an endpoint (U3 / releases#5): `spt endpoint create <id> --adapter <a>`.\r\n///\r\n/// The mint and the first session are separate verbs now — this one writes the\r\n/// skeleton perch, assigns the permanent anchor subnet and records the adapter +\r\n/// project folder as the endpoint's session defaults; it starts nothing. Every\r\n/// real-daemon e2e that used to open with a single\r\n/// `endpoint run --adapter A --id I --start` calls this first, then starts.\r\n///\r\n/// Lives here rather than being copied into each test file because it is the\r\n/// SAME first half everywhere, and a bringup half that drifted per-file is\r\n/// exactly how an estate stops testing one surface.\r\n///\r\n/// PANICS on a failed mint, deliberately: a test whose endpoint was never\r\n/// created goes on to fail somewhere further down, on an assertion about\r\n/// something else entirely.\r\npub fn create_endpoint(spt_bin: &Path, home: &Path, id: &str, adapter: &str) -> Output {\r\n    let mut cmd = Command::new(spt_bin);\r\n    cmd.no_window()\r\n        .args([\"endpoint\", \"create\", id, \"--adapter\", adapter])\r\n        .env(\"SPT_HOME\", home);\r\n    let out = output_bounded(cmd, Duration::from_secs(45));\r\n    assert!(\r\n        out.status.success(),\r\n        \"endpoint create {id} --adapter {adapter} must succeed: {}\",\r\n        String::from_utf8_lossy(&out.stderr)\r\n    );\r\n    out\r\n}\r\n\r\n/// Render both daemon stderr channels for an e2e failure panel.\r\n///\r\n/// `daemon run` redirects stderr in-process, so the child capture contains only\r\n/// startup output emitted before redirect installation. The durable sink holds\r\n/// every later broker/brain diagnostic.\r\n// [int->REQ-DAEMON-STDERR-PERSIST]\r\npub fn daemon_stderr_panel(pre_redirect: &Path) -> String {\r\n    let captured = std::fs::read_to_string(pre_redirect).unwrap_or_else(|error| {\r\n        format!(\r\n            \"broker stderr (pre-redirect) ABSENT at {}: {error}\",\r\n            pre_redirect.display()\r\n        )\r\n    });\r\n    let home = pre_redirect\r\n        .parent()\n        .expect(\"daemon pre-redirect capture must live beneath SPT_HOME\");\n…\n}","startLine":1,"lineNumbers":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,null,77]},"fileSize":16239,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\crates\\spt\\tests\\common\\mod.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":373,"totalBytes":2873,"outputLines":63,"outputBytes":2873,"shownRange":{"start":1,"end":63},"nextOffset":64}}},"isError":false,"timestamp":1789107128877}}
{"type":"message","id":"0981a711","parentId":"5ac94802","timestamp":"2026-09-11T06:12:08.878Z","message":{"role":"toolResult","toolCallId":"call_r5lz1Pm7pQbMxITTa1IT0PmF|fc_0330c101aa2c61dc016aa39bb6705887d1b008e2831dcedb1e","toolName":"grep","content":[{"type":"text","text":"No matches found"}],"details":{"scopePath":"crates/spt/tests/projindex_writer_e2e.rs, crates/spt/tests/projindex_reader_e2e.rs, crates/spt/tests/brain_split.rs, crates/spt/tests/brain_respawn_rename.rs, crates/spt/tests/endpoint_autostart_e2e.rs","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\crates\\spt\\tests","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":0,"fileCount":0,"files":[],"truncated":false},"isError":false,"useless":true,"timestamp":1789107128878}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_gCoHjZMwko5NoUoOP0IkDWnq|fc_0330c101aa2c61dc016aa39bb86c5c87d1bf23d363191bf9c8","toolName":"grep","startedAt":"2026-09-11T06:12:14.121Z","args":{"path":"crates/spt/tests/projindex_writer_e2e.rs;crates/spt/tests/projindex_reader_e2e.rs;crates/spt/tests/brain_split.rs;crates/spt/tests/brain_respawn_rename.rs;crates/spt/tests/endpoint_autostart_e2e.rs"},"intent":"Locating alternative cleanup forms"},"id":"1a28b61b","parentId":"0981a711","timestamp":"2026-09-11T06:12:14.121Z"}
{"type":"message","id":"e3bc1a29","parentId":"1a28b61b","timestamp":"2026-09-11T06:12:14.122Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":""},{"type":"toolCall","id":"call_gCoHjZMwko5NoUoOP0IkDWnq|fc_0330c101aa2c61dc016aa39bb86c5c87d1bf23d363191bf9c8","name":"grep","arguments":{"i":"Locating alternative cleanup forms","pattern":"Drop|Reaper|reap|sweep|kill","path":"crates/spt/tests/projindex_writer_e2e.rs;crates/spt/tests/projindex_reader_e2e.rs;crates/spt/tests/brain_split.rs;crates/spt/tests/brain_respawn_rename.rs;crates/spt/tests/endpoint_autostart_e2e.rs","case":false,"gitignore":true,"skip":null},"intent":"Locating alternative cleanup forms"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":2309,"output":127,"cacheRead":124672,"cacheWrite":0,"totalTokens":127108,"reasoningTokens":7,"cost":{"input":0.023090000000000003,"output":0.006350000000000001,"cacheRead":0.12467199999999999,"cacheWrite":0,"total":0.154112}},"stopReason":"toolUse","timestamp":1789107128919,"responseId":"resp_0330c101aa2c61dc016aa39bb6f67087d1bc3d78c1487a874f","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0330c101aa2c61dc016aa39bb7e5e087d1af2741da3c1426e9","type":"reasoning","content":[],"encrypted_content":"gAAAAABqo5u4ROR7I6pSCzyPOYlzYt5s4utY4a8tC62so2lqTbbxJ_BtGo0SRWff3wNV9hyoq1FIpzJYl_2ueU_xrUtchEcJwSAKI75slHe5cFgLpJ2o6Rkebk-jkolPvprgbPcOBt4G6Z1OGW0O59zAfox7LuPWe2Pjj5Aw2FaR_TCvyZAszNmqVA03Tjhitjeo1WqPkGqM6F7hMmFXkRIDyCJd4pmahe9S2u14QK0ixeUhCoT0zsOiJ4K8L94qzgVPtGo0EYe_u9jOT_58_GPOL4D35DkSJUXCkqvwtAbtc6DrH_z3ZzLr6KW-tCC6b9kUL1USQd5ED6ARtE8oNKA6v1tzrS0B6uKK-2AVOxudfJBMzGkpEYgw7i6FRtvHVrSDc4EQ0nlWEn7hxWfk2d2R_E8Fte_gr7SN7mVnr6vrM4Y0tknz8yAgw9PqyeFmRJ1CcZi7pQQxYIHXBo6gcEitDweSXu2g0iCINq5igpSYyvtiPVVS0blW-AvTxmIaGWJBRgw4nXqHGBUjhOnR7y5IQq_eyMQmXQwF4LLMxT5NHCtPI7OEIjFL8tQo7owCMX6Xqfm00vgtJQSA7-b81ok5XRX5kxdwlY7kj187fLMVXKpy_DkBxQ-SU1d2m5YJ0z1QiOm9Vj3TOpQukgciTReFachfTfbsXarKO2XqJBoFYeEY3dnaL9qNoApnR-PZsCjxT6ZWj8mgzxuKX6EsbFSSmVu3t1vCwYpopWKHnEmZ2CeyUxv3_ISYtCKoG2B6w1uRiEKuqWQptK5SohoH74hOvYgVd4e0jkBNFzLlbBYgQ4cgwnefQHpglY-7f8MeYAZeeXXRd5MK2TsyJBxytE291GjKISmh-PRjNabgs5dR1BzngKwqw6tvZjUJfP9JKjy6eYEjGDibndwNB8C4J1oky66vcZI-cmI0Vd65acV3MtAd5Sc89c5qhyQe_5m43oxwuaGJbIGv_PxOye-JOKWycDBrPblqihOvxVpll2XnmO3wCi22ynIqewKQoPQu-QOXYfva5NbQ6IRVKPfPs9yYV-P1KCB4h0D0ELSOUtNE-0F_0whN9VP3i868FmcwWVMGOYCVuLL070QtKnqFeFBS0CuEXOFrNTXM1-sdoSeu8BGFMkrCBHvTovb-KkkoOI7dRkzJoZdGV6KujbEZnQ3i2peACuI9z-_jzpf89ZHMuDrYk2Je1FLj2i9XcOrN7y0s0g8R5ewMyP41YGSskRj5bplley4E8xTZTkHSr4fa1Yfhjyz8gkvYhN7OW9Y9Q6DcluE76BQEhix4GtTO2_tyNKAFe99Ut_z5FDwWmbybuPYI_A8zE54=","internal_chat_message_metadata_passthrough":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"summary":[],"metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}},{"id":"fc_0330c101aa2c61dc016aa39bb86c5c87d1bf23d363191bf9c8","type":"function_call","status":"completed","arguments":"{\"i\":\"Locating alternative cleanup forms\",\"pattern\":\"Drop|Reaper|reap|sweep|kill\",\"path\":\"crates/spt/tests/projindex_writer_e2e.rs;crates/spt/tests/projindex_reader_e2e.rs;crates/spt/tests/brain_split.rs;crates/spt/tests/brain_respawn_rename.rs;crates/spt/tests/endpoint_autostart_e2e.rs\",\"case\":false,\"gitignore\":true,\"skip\":null}","call_id":"call_gCoHjZMwko5NoUoOP0IkDWnq","internal_chat_message_metadata_passthrough":{"create_time":1789107127.216846,"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"grep","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}}]},"duration":5200.681099999696,"ttft":1330.5465000001714,"completedAt":1789107134120,"contextSnapshot":{"promptTokens":126981,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"message","id":"8ed7cc1b","parentId":"e3bc1a29","timestamp":"2026-09-11T06:12:14.139Z","message":{"role":"toolResult","toolCallId":"call_gCoHjZMwko5NoUoOP0IkDWnq|fc_0330c101aa2c61dc016aa39bb86c5c87d1bf23d363191bf9c8","toolName":"grep","content":[{"type":"text","text":"# crates/spt/tests/\n## projindex_writer_e2e.rs\n 13|//! reconciling each into the published index. Bounded everywhere; every\n*14|//! spawned pid is reaped SCOPED at test end.\n 15|//!\n 16|//! HEAVY at birth (the HEAVY-AT-BIRTH ruling, doyle 2026-07-15,\n 17|//! `.config/nextest.toml`): this spawns a real daemon tree.\n...\n 31|\n*32|/// Scoped pid-tree kill (cleanup) — never machine-wide.\n*33|fn kill_pid(pid: u32) {\n 34|    #[cfg(windows)]\n*35|    let _ = Command::new(\"taskkill\")\n 36|        .no_window()\n 37|        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n 38|        .output();\n 39|    #[cfg(unix)]\n*40|    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n 41|}\n 42|\n 43|/// `(pid, generation)` out of `brain.ready`; `None` until it parses.\n...\n 163|        .unwrap_or_else(|| {\n*164|            let _ = broker.kill();\n 165|            let _ = broker.wait();\n 166|            panic!(\n 167|                \"PRECONDITION: brain never came up.\\n{}\",\n...\n 215|    };\n*216|    kill_pid(brain_pid_1);\n*217|    let _ = broker.kill();\n 218|    let _ = broker.wait();\n 219|    let bytes_before = std::fs::read(&index_path).unwrap();\n 220|    let stats_path = home.path().join(\"index\").join(\"project-index-stats.json\");\n...\n 231|        .unwrap_or_else(|| {\n*232|            let _ = broker2.kill();\n 233|            let _ = broker2.wait();\n 234|            panic!(\n 235|                \"warm brain never came up.\\n{}\",\n...\n 348|\n*349|    // (4e) PURGE through the real CLI verb: the row is dropped, never resurrected.\n 350|    let purge = {\n 351|        let mut cmd = Command::new(&spt_bin);\n 352|        cmd.no_window()\n...\n 361|    );\n*362|    wait_index(&index_path, Duration::from_secs(15), \"purge → row dropped\", |i| {\n 363|        !i.endpoints.contains_key(\"ep2\")\n 364|    });\n 365|\n*366|    // ── (5) Reap SCOPED. ──\n 367|    let _ = {\n 368|        let mut cmd = Command::new(&spt_bin);\n 369|        cmd.no_window()\n...\n 373|    };\n*374|    kill_pid(brain_pid_2);\n*375|    let _ = broker2.kill();\n 376|    let _ = broker2.wait();\n 377|}\n## projindex_reader_e2e.rs\n 13|//! out from under the readers → same verbs stay fast, render `-`, still zero\n*14|//! git. Bounded everywhere; every spawned pid reaped SCOPED.\n 15|//!\n 16|//! HEAVY AT BIRTH (the HEAVY-AT-BIRTH ruling, doyle 2026-07-15,\n 17|//! `.config/nextest.toml`): spawns a real daemon tree.\n...\n 32|\n*33|fn kill_pid(pid: u32) {\n 34|    #[cfg(windows)]\n*35|    let _ = Command::new(\"taskkill\")\n 36|        .no_window()\n 37|        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n 38|        .output();\n 39|    #[cfg(unix)]\n*40|    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n 41|}\n 42|\n 43|\n...\n 275|\n*276|    // ── (7) Reap SCOPED. ──\n 277|    let _ = {\n 278|        let mut cmd = Command::new(&spt_bin);\n 279|        cmd.no_window()\n...\n 283|    };\n*284|    kill_pid(brain_pid);\n*285|    let _ = broker.kill();\n 286|    let _ = broker.wait();\n 287|}\n 288|\n## brain_split.rs\n 12|//! idles; the logic loops stay broker-side until D2. So this test asserts only\n*13|//! the boundary — come-up, survive-brain-kill, respawn — not any logic.\n 14|//!\n 15|//! The full PTY-child + live-QUIC survival across a swap is the D7 `int` E2E\n 16|//! (REQ-UPD-3 re-point); here the process-level boundary is `unit`-tagged.\n...\n 26|\n*27|/// Best-effort cross-platform kill of a pid (mirrors the other E2E helpers).\n*28|fn kill_pid(pid: u32) {\n 29|    #[cfg(windows)]\n*30|    let _ = Command::new(\"taskkill\")\n 31|        .no_window()\n 32|        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n 33|        .output();\n 34|    #[cfg(unix)]\n*35|    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n 36|}\n 37|\n 38|/// Read the `pid` out of a `brain.ready` body. As of restoration D6-1b the\n...\n 98|/// `daemon stop` target) lives in the broker's foreground loop\n*99|/// (`daemon.rs::Daemon::run`), NOT the brain — so killing the brain and watching\n 100|/// the supervisor respawn it must leave `daemon: running` **continuously** true.\n 101|/// If the seed anchor ever rode the brain, this is the test that would catch it\n 102|/// flapping. External `ensure_running`/`is_running`/`daemon stop` behavior is\n...\n 125|    let pid1 = wait_for_ready_pid(&ready, Duration::from_secs(30)).unwrap_or_else(|| {\n*126|        let _ = broker.kill();\n 127|        panic!(\"brain child never signalled ready\");\n 128|    });\n 129|    assert!(\n...\n 133|\n*134|    // Kill the brain; while the supervisor respawns it, the seed anchor (in the\n 135|    // never-restarting broker) must stay continuously up. Sample across the whole\n 136|    // respawn gap — a single not-running read is a failure (the anchor flapped).\n*137|    kill_pid(pid1);\n 138|    let deadline = Instant::now() + Duration::from_secs(30);\n 139|    let mut pid2 = None;\n 140|    while Instant::now() < deadline {\n...\n 142|            daemon_running(&spt_bin, home.path()),\n*143|            \"seed anchor dropped during a brain respawn — it must not ride the brain\"\n 144|        );\n 145|        if let Ok(s) = std::fs::read_to_string(&ready) {\n 146|            if let Some(pid) = ready_pid(&s) {\n...\n 155|    let pid2 = pid2.unwrap_or_else(|| {\n*156|        kill_pid(pid1);\n*157|        let _ = broker.kill();\n 158|        panic!(\"supervisor did not respawn the brain\");\n 159|    });\n 160|    assert_ne!(pid1, pid2, \"the respawned brain is a fresh process\");\n...\n 169|\n*170|    kill_pid(pid2);\n*171|    let _ = broker.kill();\n 172|    let _ = broker.wait();\n 173|}\n 174|\n 175|#[test]\n*176|fn broker_survives_brain_kill_and_respawns_it() {\n 177|    let home = tempfile::tempdir().unwrap();\n 178|    let spt_bin = PathBuf::from(env!(\"CARGO_BIN_EXE_spt\"));\n 179|    let ready = home.path().join(\"brain.ready\");\n...\n 196|    let pid1 = wait_for_ready_pid(&ready, Duration::from_secs(30)).unwrap_or_else(|| {\n*197|        let _ = broker.kill();\n 198|        panic!(\"brain child never signalled ready (no brain.ready breadcrumb)\");\n 199|    });\n 200|    assert!(\n...\n 204|\n*205|    // ── 2. survive-brain-kill + respawn: kill the brain, expect a NEW pid ──────\n*206|    kill_pid(pid1);\n 207|    let pid2 = wait_for_new_pid(&ready, pid1, Duration::from_secs(30)).unwrap_or_else(|| {\n*208|        kill_pid(pid1);\n*209|        let _ = broker.kill();\n## brain_respawn_rename.rs\n 73|\n*74|fn kill_pid(pid: u32) {\n 75|    #[cfg(windows)]\n*76|    let _ = Command::new(\"taskkill\")\n 77|        .no_window()\n 78|        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n 79|        .output();\n 80|    #[cfg(unix)]\n*81|    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n 82|}\n 83|\n 84|#[test]\n...\n 117|    let (pid0, hash0) = wait_ready(&ready, None, Duration::from_secs(45)).unwrap_or_else(|| {\n*118|        let _ = broker.kill();\n 119|        panic!(\"gen-0 brain never signalled ready\");\n 120|    });\n 121|    assert_eq!(\n...\n 143|\n*144|    // ── Trigger a brain respawn (kill the brain; the supervisor respawns it). The\n 145|    //    respawn must land on the APPLIED bytes now at P (the canonical path the\n 146|    //    broker captured at start), NOT the renamed P.old-8. Pre-fix on Linux the\n 147|    //    broker's per-spawn current_exe() (readlink /proc/self/exe) follows the\n...\n 149|    //    spawns the captured P (bytes B). Windows never followed the rename. ──\n*150|    kill_pid(pid0);\n 151|    let (pid1, hash1) = wait_ready(&ready, Some(pid0), Duration::from_secs(45)).unwrap_or_else(|| {\n*152|        kill_pid(pid0);\n*153|        let _ = broker.kill();\n 154|        panic!(\"supervisor never respawned the brain after the rename\");\n 155|    });\n 156|    assert_ne!(pid0, pid1, \"the respawned brain is a fresh process\");\n...\n 164|    // Teardown.\n*165|    kill_pid(pid1);\n*166|    let _ = broker.kill();\n 167|    let _ = broker.wait();\n 168|}\n## endpoint_autostart_e2e.rs\n 19|//!      the entry lands in `<home>/daemon.json`);\n*20|//!   3. daemon A is STOPPED and its harness/psyche reaped — the endpoint is down;\n 21|//!   4. a SECOND daemon (B) starts against the same home with NO bringup;\n 22|//!   5. the boot replay must bring `gwauto` back up FRESH — the keystone is the\n 23|//!      loud `ENDPOINT_AUTOSTART:gwauto` token in daemon B's stderr (emitted only\n...\n 32|//! Own integration binary (own process → no SPT_HOME race); every spawned daemon\n*33|//! / harness / psyche pid reaped SCOPED via a panic-safe guard + explicit\n 34|//! teardown. Timeboxed ≤120s internally.\n 35|//!   cargo test -p spt --test endpoint_autostart_e2e -- --test-threads=1\n 36|\n...\n 46|\n*47|/// Scoped pid-tree kill (cleanup) — never machine-wide.\n*48|fn kill_pid(pid: u32) {\n 49|    #[cfg(windows)]\n*50|    let _ = Command::new(\"taskkill\")\n 51|        .no_window()\n 52|        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n 53|        .output();\n 54|    #[cfg(unix)]\n*55|    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n 56|}\n 57|\n*58|/// Panic-safe reaper: every pid handed to it is taskkill'd on drop, so a panic\n 59|/// anywhere in the body still tears the isolated daemon/harness/psyche tree down\n 60|/// (the restart flow has many more panic points than a single-daemon gate).\n*61|struct Reaper {\n 62|    pids: Mutex<Vec<u32>>,\n 63|}\n*64|impl Reaper {\n 65|    fn new() -> Self {\n*66|        Reaper {\n 67|            pids: Mutex::new(Vec::new()),\n 68|        }\n 69|    }\n...\n 73|}\n*74|impl Drop for Reaper {\n*75|    fn drop(&mut self) {\n 76|        for pid in self.pids.lock().unwrap().iter() {\n*77|            kill_pid(*pid);\n 78|        }\n 79|    }\n 80|}\n...\n 130|/// Everything written since that newline is a fragment of a line the daemon has\n*131|/// not finished writing, and is dropped. This runs BEFORE `read_logs_sink`'s\n 132|/// per-file `'\\n'` push on purpose: that push is the second half of the bug it\n 133|/// fixes — keeping the fragment merely preserved it, but terminating it\n 134|/// PROMOTED it to a complete-looking line that `.lines()` could not distinguish\n...\n 252|fn saved_endpoint_replays_on_daemon_restart() {\n*253|    let reaper = Reaper::new();\n 254|\n 255|    // ── (1) Isolated, NET-LESS SPT_HOME. ──\n 256|    let home = tempfile::tempdir().unwrap();\n...\n 287|    std::fs::copy(&spt_bin, &psyche_bin).expect(\"stage the psyche binary fixture\");\n*288|    let drops = home.path().join(\"drops\");\n*289|    std::fs::create_dir_all(&drops).unwrap();\n*290|    let dir = drops.to_string_lossy().replace('\\\\', \"/\");\n 291|    let manifest_toml = format!(\n 292|        \"[adapter]\\nname=\\\"cc\\\"\\nkind=\\\"harness\\\"\\nversion=\\\"1\\\"\\n\\\n 293|         min_spt_core_version=\\\"0\\\"\\n\\n[session.self]\\ncommand='{self_cmd}'\\n\\n\\\n...\n 319|        .expect(\"spawn daemon A\");\n*320|    reaper.add(broker_a.id());\n 321|    let brain_a = match wait_for_ready_pid(&ready_path, None, Duration::from_secs(120)) {\n 322|        Some(p) => p,\n 323|        None => {\n...\n 329|    };\n*330|    reaper.add(brain_a);\n 331|\n 332|    // ── (4) Mint the endpoint, bring it up, and mark it a startup default.\n 333|    //    Since U3 the auto-start lever is its OWN verb rather than a flag on the"}],"details":{"scopePath":"crates/spt/tests/projindex_writer_e2e.rs, crates/spt/tests/projindex_reader_e2e.rs, crates/spt/tests/brain_split.rs, crates/spt/tests/brain_respawn_rename.rs, crates/spt/tests/endpoint_autostart_e2e.rs","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\crates\\spt\\tests","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":71,"fileCount":5,"files":["crates/spt/tests/projindex_writer_e2e.rs","crates/spt/tests/projindex_reader_e2e.rs","crates/spt/tests/brain_split.rs","crates/spt/tests/brain_respawn_rename.rs","crates/spt/tests/endpoint_autostart_e2e.rs"],"fileMatches":[{"path":"crates/spt/tests/projindex_writer_e2e.rs","count":14},{"path":"crates/spt/tests/projindex_reader_e2e.rs","count":7},{"path":"crates/spt/tests/brain_split.rs","count":20},{"path":"crates/spt/tests/brain_respawn_rename.rs","count":10},{"path":"crates/spt/tests/endpoint_autostart_e2e.rs","count":20}],"truncated":true,"perFileLimitReached":20,"displayContent":"# crates/spt/tests/\n## projindex_writer_e2e.rs\n  13│//! reconciling each into the published index. Bounded everywhere; every\n *14│//! spawned pid is reaped SCOPED at test end.\n  15│//!\n  16│//! HEAVY at birth (the HEAVY-AT-BIRTH ruling, doyle 2026-07-15,\n  17│//! `.config/nextest.toml`): this spawns a real daemon tree.\n    │...\n  31│\n *32│/// Scoped pid-tree kill (cleanup) — never machine-wide.\n *33│fn kill_pid(pid: u32) {\n  34│    #[cfg(windows)]\n *35│    let _ = Command::new(\"taskkill\")\n  36│        .no_window()\n  37│        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n  38│        .output();\n  39│    #[cfg(unix)]\n *40│    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n  41│}\n  42│\n  43│/// `(pid, generation)` out of `brain.ready`; `None` until it parses.\n    │...\n 163│        .unwrap_or_else(|| {\n*164│            let _ = broker.kill();\n 165│            let _ = broker.wait();\n 166│            panic!(\n 167│                \"PRECONDITION: brain never came up.\\n{}\",\n    │...\n 215│    };\n*216│    kill_pid(brain_pid_1);\n*217│    let _ = broker.kill();\n 218│    let _ = broker.wait();\n 219│    let bytes_before = std::fs::read(&index_path).unwrap();\n 220│    let stats_path = home.path().join(\"index\").join(\"project-index-stats.json\");\n    │...\n 231│        .unwrap_or_else(|| {\n*232│            let _ = broker2.kill();\n 233│            let _ = broker2.wait();\n 234│            panic!(\n 235│                \"warm brain never came up.\\n{}\",\n    │...\n 348│\n*349│    // (4e) PURGE through the real CLI verb: the row is dropped, never resurrected.\n 350│    let purge = {\n 351│        let mut cmd = Command::new(&spt_bin);\n 352│        cmd.no_window()\n    │...\n 361│    );\n*362│    wait_index(&index_path, Duration::from_secs(15), \"purge → row dropped\", |i| {\n 363│        !i.endpoints.contains_key(\"ep2\")\n 364│    });\n 365│\n*366│    // ── (5) Reap SCOPED. ──\n 367│    let _ = {\n 368│        let mut cmd = Command::new(&spt_bin);\n 369│        cmd.no_window()\n    │...\n 373│    };\n*374│    kill_pid(brain_pid_2);\n*375│    let _ = broker2.kill();\n 376│    let _ = broker2.wait();\n 377│}\n## projindex_reader_e2e.rs\n  13│//! out from under the readers → same verbs stay fast, render `-`, still zero\n *14│//! git. Bounded everywhere; every spawned pid reaped SCOPED.\n  15│//!\n  16│//! HEAVY AT BIRTH (the HEAVY-AT-BIRTH ruling, doyle 2026-07-15,\n  17│//! `.config/nextest.toml`): spawns a real daemon tree.\n    │...\n  32│\n *33│fn kill_pid(pid: u32) {\n  34│    #[cfg(windows)]\n *35│    let _ = Command::new(\"taskkill\")\n  36│        .no_window()\n  37│        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n  38│        .output();\n  39│    #[cfg(unix)]\n *40│    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n  41│}\n  42│\n  43│\n    │...\n 275│\n*276│    // ── (7) Reap SCOPED. ──\n 277│    let _ = {\n 278│        let mut cmd = Command::new(&spt_bin);\n 279│        cmd.no_window()\n    │...\n 283│    };\n*284│    kill_pid(brain_pid);\n*285│    let _ = broker.kill();\n 286│    let _ = broker.wait();\n 287│}\n 288│\n## brain_split.rs\n  12│//! idles; the logic loops stay broker-side until D2. So this test asserts only\n *13│//! the boundary — come-up, survive-brain-kill, respawn — not any logic.\n  14│//!\n  15│//! The full PTY-child + live-QUIC survival across a swap is the D7 `int` E2E\n  16│//! (REQ-UPD-3 re-point); here the process-level boundary is `unit`-tagged.\n    │...\n  26│\n *27│/// Best-effort cross-platform kill of a pid (mirrors the other E2E helpers).\n *28│fn kill_pid(pid: u32) {\n  29│    #[cfg(windows)]\n *30│    let _ = Command::new(\"taskkill\")\n  31│        .no_window()\n  32│        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n  33│        .output();\n  34│    #[cfg(unix)]\n *35│    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n  36│}\n  37│\n  38│/// Read the `pid` out of a `brain.ready` body. As of restoration D6-1b the\n    │...\n  98│/// `daemon stop` target) lives in the broker's foreground loop\n *99│/// (`daemon.rs::Daemon::run`), NOT the brain — so killing the brain and watching\n 100│/// the supervisor respawn it must leave `daemon: running` **continuously** true.\n 101│/// If the seed anchor ever rode the brain, this is the test that would catch it\n 102│/// flapping. External `ensure_running`/`is_running`/`daemon stop` behavior is\n    │...\n 125│    let pid1 = wait_for_ready_pid(&ready, Duration::from_secs(30)).unwrap_or_else(|| {\n*126│        let _ = broker.kill();\n 127│        panic!(\"brain child never signalled ready\");\n 128│    });\n 129│    assert!(\n    │...\n 133│\n*134│    // Kill the brain; while the supervisor respawns it, the seed anchor (in the\n 135│    // never-restarting broker) must stay continuously up. Sample across the whole\n 136│    // respawn gap — a single not-running read is a failure (the anchor flapped).\n*137│    kill_pid(pid1);\n 138│    let deadline = Instant::now() + Duration::from_secs(30);\n 139│    let mut pid2 = None;\n 140│    while Instant::now() < deadline {\n    │...\n 142│            daemon_running(&spt_bin, home.path()),\n*143│            \"seed anchor dropped during a brain respawn — it must not ride the brain\"\n 144│        );\n 145│        if let Ok(s) = std::fs::read_to_string(&ready) {\n 146│            if let Some(pid) = ready_pid(&s) {\n    │...\n 155│    let pid2 = pid2.unwrap_or_else(|| {\n*156│        kill_pid(pid1);\n*157│        let _ = broker.kill();\n 158│        panic!(\"supervisor did not respawn the brain\");\n 159│    });\n 160│    assert_ne!(pid1, pid2, \"the respawned brain is a fresh process\");\n    │...\n 169│\n*170│    kill_pid(pid2);\n*171│    let _ = broker.kill();\n 172│    let _ = broker.wait();\n 173│}\n 174│\n 175│#[test]\n*176│fn broker_survives_brain_kill_and_respawns_it() {\n 177│    let home = tempfile::tempdir().unwrap();\n 178│    let spt_bin = PathBuf::from(env!(\"CARGO_BIN_EXE_spt\"));\n 179│    let ready = home.path().join(\"brain.ready\");\n    │...\n 196│    let pid1 = wait_for_ready_pid(&ready, Duration::from_secs(30)).unwrap_or_else(|| {\n*197│        let _ = broker.kill();\n 198│        panic!(\"brain child never signalled ready (no brain.ready breadcrumb)\");\n 199│    });\n 200│    assert!(\n    │...\n 204│\n*205│    // ── 2. survive-brain-kill + respawn: kill the brain, expect a NEW pid ──────\n*206│    kill_pid(pid1);\n 207│    let pid2 = wait_for_new_pid(&ready, pid1, Duration::from_secs(30)).unwrap_or_else(|| {\n*208│        kill_pid(pid1);\n*209│        let _ = broker.kill();\n## brain_respawn_rename.rs\n  73│\n *74│fn kill_pid(pid: u32) {\n  75│    #[cfg(windows)]\n *76│    let _ = Command::new(\"taskkill\")\n  77│        .no_window()\n  78│        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n  79│        .output();\n  80│    #[cfg(unix)]\n *81│    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n  82│}\n  83│\n  84│#[test]\n    │...\n 117│    let (pid0, hash0) = wait_ready(&ready, None, Duration::from_secs(45)).unwrap_or_else(|| {\n*118│        let _ = broker.kill();\n 119│        panic!(\"gen-0 brain never signalled ready\");\n 120│    });\n 121│    assert_eq!(\n    │...\n 143│\n*144│    // ── Trigger a brain respawn (kill the brain; the supervisor respawns it). The\n 145│    //    respawn must land on the APPLIED bytes now at P (the canonical path the\n 146│    //    broker captured at start), NOT the renamed P.old-8. Pre-fix on Linux the\n 147│    //    broker's per-spawn current_exe() (readlink /proc/self/exe) follows the\n    │...\n 149│    //    spawns the captured P (bytes B). Windows never followed the rename. ──\n*150│    kill_pid(pid0);\n 151│    let (pid1, hash1) = wait_ready(&ready, Some(pid0), Duration::from_secs(45)).unwrap_or_else(|| {\n*152│        kill_pid(pid0);\n*153│        let _ = broker.kill();\n 154│        panic!(\"supervisor never respawned the brain after the rename\");\n 155│    });\n 156│    assert_ne!(pid0, pid1, \"the respawned brain is a fresh process\");\n    │...\n 164│    // Teardown.\n*165│    kill_pid(pid1);\n*166│    let _ = broker.kill();\n 167│    let _ = broker.wait();\n 168│}\n## endpoint_autostart_e2e.rs\n  19│//!      the entry lands in `<home>/daemon.json`);\n *20│//!   3. daemon A is STOPPED and its harness/psyche reaped — the endpoint is down;\n  21│//!   4. a SECOND daemon (B) starts against the same home with NO bringup;\n  22│//!   5. the boot replay must bring `gwauto` back up FRESH — the keystone is the\n  23│//!      loud `ENDPOINT_AUTOSTART:gwauto` token in daemon B's stderr (emitted only\n    │...\n  32│//! Own integration binary (own process → no SPT_HOME race); every spawned daemon\n *33│//! / harness / psyche pid reaped SCOPED via a panic-safe guard + explicit\n  34│//! teardown. Timeboxed ≤120s internally.\n  35│//!   cargo test -p spt --test endpoint_autostart_e2e -- --test-threads=1\n  36│\n    │...\n  46│\n *47│/// Scoped pid-tree kill (cleanup) — never machine-wide.\n *48│fn kill_pid(pid: u32) {\n  49│    #[cfg(windows)]\n *50│    let _ = Command::new(\"taskkill\")\n  51│        .no_window()\n  52│        .args([\"/PID\", &pid.to_string(), \"/F\", \"/T\"])\n  53│        .output();\n  54│    #[cfg(unix)]\n *55│    let _ = Command::new(\"kill\").args([\"-9\", &pid.to_string()]).output();\n  56│}\n  57│\n *58│/// Panic-safe reaper: every pid handed to it is taskkill'd on drop, so a panic\n  59│/// anywhere in the body still tears the isolated daemon/harness/psyche tree down\n  60│/// (the restart flow has many more panic points than a single-daemon gate).\n *61│struct Reaper {\n  62│    pids: Mutex<Vec<u32>>,\n  63│}\n *64│impl Reaper {\n  65│    fn new() -> Self {\n *66│        Reaper {\n  67│            pids: Mutex::new(Vec::new()),\n  68│        }\n  69│    }\n    │...\n  73│}\n *74│impl Drop for Reaper {\n *75│    fn drop(&mut self) {\n  76│        for pid in self.pids.lock().unwrap().iter() {\n *77│            kill_pid(*pid);\n  78│        }\n  79│    }\n  80│}\n    │...\n 130│/// Everything written since that newline is a fragment of a line the daemon has\n*131│/// not finished writing, and is dropped. This runs BEFORE `read_logs_sink`'s\n 132│/// per-file `'\\n'` push on purpose: that push is the second half of the bug it\n 133│/// fixes — keeping the fragment merely preserved it, but terminating it\n 134│/// PROMOTED it to a complete-looking line that `.lines()` could not distinguish\n    │...\n 252│fn saved_endpoint_replays_on_daemon_restart() {\n*253│    let reaper = Reaper::new();\n 254│\n 255│    // ── (1) Isolated, NET-LESS SPT_HOME. ──\n 256│    let home = tempfile::tempdir().unwrap();\n    │...\n 287│    std::fs::copy(&spt_bin, &psyche_bin).expect(\"stage the psyche binary fixture\");\n*288│    let drops = home.path().join(\"drops\");\n*289│    std::fs::create_dir_all(&drops).unwrap();\n*290│    let dir = drops.to_string_lossy().replace('\\\\', \"/\");\n 291│    let manifest_toml = format!(\n 292│        \"[adapter]\\nname=\\\"cc\\\"\\nkind=\\\"harness\\\"\\nversion=\\\"1\\\"\\n\\\n 293│         min_spt_core_version=\\\"0\\\"\\n\\n[session.self]\\ncommand='{self_cmd}'\\n\\n\\\n    │...\n 319│        .expect(\"spawn daemon A\");\n*320│    reaper.add(broker_a.id());\n 321│    let brain_a = match wait_for_ready_pid(&ready_path, None, Duration::from_secs(120)) {\n 322│        Some(p) => p,\n 323│        None => {\n    │...\n 329│    };\n*330│    reaper.add(brain_a);\n 331│\n 332│    // ── (4) Mint the endpoint, bring it up, and mark it a startup default.\n 333│    //    Since U3 the auto-start lever is its OWN verb rather than a flag on the"},"isError":false,"timestamp":1789107134138}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_6ezvZ1Ev1tB5tPrefAADESjs|fc_0820bf72eb96c0c7016aa39c1764e887d1b5683ad6f058698c","toolName":"yield","startedAt":"2026-09-11T06:16:21.170Z"},"id":"2116369d","parentId":"8ed7cc1b","timestamp":"2026-09-11T06:16:21.170Z"}
{"type":"message","id":"752ad333","parentId":"2116369d","timestamp":"2026-09-11T06:16:21.170Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_6ezvZ1Ev1tB5tPrefAADESjs|fc_0820bf72eb96c0c7016aa39c1764e887d1b5683ad6f058698c","name":"yield","arguments":{"type":null,"data":{"summary":"Complete read-only accounting: 43 assigned entries, IR-55–IR-97 inclusive. Leading lines 3001–3021 are CI-RIDER history belonging to the first scout, not a split IR. Preserve built work; propose driver/capacity prerequisites and narrowly seam-triggered riders for REMOTE-FRICTION, pending operator grill. No commands, edits, builds or tests executed.","files":[{"path":"docs/INFRA-REGISTER.md:3022-5900","description":"All 43 assigned IR bodies, amendments, triggers and residuals read."},{"path":"docs/INFRA-REGISTER.md:1-61","description":"Authoritative prior release-close reconciliation and next-intake composition; supersedes stale historical build/owner prose."},{"path":".spt/preserved/infra-close069-20260911/audit.json","description":"Previous SHA-pinned full-register audit and parent rulings; consulted assigned-range report and implementation receipts."},{"path":"docs/instruments/ir59/STATUS.md","description":"Existing disk-floor instrument, flags, adoption contract and instant-not-headroom limitation."},{"path":"crates/xtask/src/main.rs:69-70","description":"pick-audit and disk-floor already wired; do not dispatch their implementation again."},{"path":"crates/xtask/src/brainread.rs:194-203,295-320","description":"IR-94 still has name-shaped stream predicate and three-file population."},{"path":"crates/spt-store/src/proc.rs:430","description":"kill_pid_tree still accepts bare numeric root; existing tree machinery is not identity-required primitive enforcement."},{"path":"crates/spt-daemon/src/daemon.rs:474-476","description":"Direct pidfile overwrite remains; IR-82 predecessor preservation not built."},{"path":"crates/spt-daemon/src/docshost.rs:90-102","description":"Ephemeral advisory flag still silently returns zero before explicit docs-port resolution."},{"path":"crates/spt/tests/common/reap.rs:1-100","description":"Authenticated breadcrumb reaper substrate already exists, including birth/image checks and refusal semantics."},{"path":"crates/spt/tests/common/mod.rs:1-60","description":"Shared reaper export and existing test support; adoption should reuse this seam."},{"path":"crates/spt/tests/projindex_writer_e2e.rs; crates/spt/tests/projindex_reader_e2e.rs; crates/spt/tests/brain_split.rs; crates/spt/tests/brain_respawn_rename.rs","description":"IR-79 first-wave sites retain local kill helpers and end-of-body teardown; existing authenticated reaper is not equivalent to these sites having adopted lifetime guards."},{"path":"https://github.com/BigscreenVR/spt-bs-releases/issues/304","description":"Current milestone intake explicitly forbids implementation before grill; includes original bag and adjacent RC/serving requests."}],"architecture":"Separate four obligations: built mechanism, caller/driver adoption, box/operator configuration, and incident diagnosis. Broker/brain custody, IO publication, HTTP serving and shared-runner control are different seams. Similar 5–10s or 900s durations do not establish a common cause. Infrastructure remains in the register, even when its remedy touches product code.","report":"## Scope and evidence key\nAssigned population is exactly IR-55, IR-56, IR-57, IR-58, IR-59, IR-60, IR-61, IR-62, IR-63, IR-64, IR-65, IR-66, IR-67, IR-68, IR-69, IR-70, IR-71, IR-72, IR-73, IR-74, IR-75, IR-76, IR-77, IR-78, IR-79, IR-80, IR-81, IR-82, IR-83, IR-84, IR-85, IR-86, IR-87, IR-88, IR-89, IR-90, IR-91, IR-92, IR-93, IR-94, IR-95, IR-96, IR-97: 43 consecutive, unique IDs. First IR opens at 3022. The first scout independently confirmed ownership of continuing CI-RIDER history through 3021. No IR spans the assignment boundary.\n\nFIRED means a qualifying historical event or standing intake opportunity is evidenced, not that #304 has already edited that seam. UNKNOWN means no qualifying new event/source touch established; it is not NOT-FIRED or closure. Prospective #304 seam connections below are explicitly conditional until grill/final wave shape. Prior close record is dated 2026-09-11 and source-pinned e5a2fed9; dates are reported as written. Targeted working-tree reads corroborate several unbuilt residuals but are not runtime acceptance.\n\n## Full compressed enumeration\n| ID / opening line | Status / remaining obligation | Trigger and evidence verdict | Recommended disposition / dependency |\n|---|---|---|---|\n| IR-55 / 3022 | OPEN, ARMED-FOR-CAPTURE; leak unidentified | FIRED standing unfiltered spt-bin battery trigger. Historical wedge twice; nextest 653 pass and five bare 663-pass settles are containment/negative observations, not discharge. No fresh wedge in intake. | Carry armed in lifecycle package; preserve environment + before/during census before cleanup; no new bisect merely because RC freezes. |\n| IR-56 / 3148 | BUILT cross-worktree claim refusal and explicit foreign-pool takeover | FIRED historically, SIGNET build evidence recorded. | Keep built. IR-42 admission adjudication remains separate; no duplicate pool-claim lane. |\n| IR-57 / 3189 | OPEN living assembly procedure; pick-audit BUILT | FIRED historical assemblies, two real LOSS catches. #304 assembly remains future. | Adopt existing command over full pick chain; retain compilation and repaired-suite obligations at actual gate time. Do not rebuild tool. |\n| IR-58 / 3248 | OPEN duplicate-target enumeration check; original nonexistent-bin claim RETRACTED | FIRED prior brainread/xtask work; next xtask check touch remains rider seam. | Tooling rider using Cargo target enumeration, not manifest-stanza grep. Never resurrect withdrawn prose fix. |\n| IR-59 / 3283 | OPEN capacity/adoption; disk-floor BUILT | FIRED gate/CI arc and release-close resource reds: 3167 units passed before END floor refused 15,360,114,688 < 34,359,738,368 B. | Compose driver/capacity adoption with IR-46/76/86/90; pool budget/reclaim per wave. No new instrument, no reboot remedy, no causal attribution to unavailable earlier logs. |\n| IR-60 / 3417 | OPEN truthful producer-status capture | FIRED v0.69 recurrence: wrapper NEXTEST_EXIT=0 measured tail while Cargo returned 101. | Driver rider: capture inside producer shell immediately, write and propagate actual leg status; distinguish raw Summary from missing exit. |\n| IR-61 / 3466 | OPEN accepted duplicated literal-state trackers | UNKNOWN substantive spacerun scanning touch; unrelated xtask work insufficient. | Carry until new skip/literal/tracker change, then unify rather than add third tracker. |\n| IR-62 / 3499 | BUILT docs collision remedy; other bind surfaces residual | FIRED historical second collision, PR158 measured port-held arm and ephemeral fix. | Keep built; retain non-docs co-diagnostic caveat. Not whole-rig network isolation and not #297 TCP admission. |\n| IR-63 / 3540 | OPEN cleanup adopted, producer teardown not closed | FIRED historical rig work/leaked daemon and conhost CWD pins; queued lane not proof of landing. | Compose IR-79/80/97 lifetime/accounting work. Reuse safe reap machinery; historical random victims do not diagnose new stalls. |\n| IR-64 / 3579 | OPEN operator-owned capacity reservoir | FIRED IR-86 in-job floor despite pool discipline, explicitly recorded. New operator ruling UNKNOWN. | Separate operator move/expand/accept-tax decision. Old 845GB bulk is historical census, not current measurement; agents cannot touch it. |\n| IR-65 / 3601 | REMEDIATED-AT-BOX, OPEN reset recheck | UNKNOWN tailscale snap/auditd update or reimage. New Tailscale incident does not establish reset of kitsubito audit configuration. | Carry named recheck triggers; do not rerun box probes or reopen remediation from symptom similarity. |\n| IR-66 / 3627 | CLOSED / BUILT delayed needles | FIRED historical two-platform rider gates; previous close explicitly reconciled. | Keep closed. No redispatch of two test edits. |\n| IR-67 / 3660 | BUILT explicit integration-suite battery template | FIRED historical IO-PARSER waves and intake template adoption. | Keep built; --bins still must never be described as integration coverage. |\n| IR-68 / 3682 | OPEN ingest-cause investigation | UNKNOWN new PSYCHE_INGEST_FAIL sighting/dedicated probe slot. Planted nonempty index locks did not block ingest. | Carry capture-first; COMMUNE_FAIL now names reason. Do not reinstate refuted index-lock attribution. |\n| IR-69 / 3710 | OPEN #243 conversion/generator/zero-recensus and anchored consumers; original emission fix LANDED | FIRED historical residual recensus: 338 cli sites plus 2 main sites missed. | Keep #243 dependency and separate test-side anchored IDLE/DISPATCH/BUSY/BOUND rider. No redo of landed emission or already-converted delivery sites. IO/USER_INPUT work may touch consumer seam, not automatically satisfy entire residual population. |\n| IR-70 / 3802 | OPEN assembly-point enforcement; witnessed publisher correction shipped | UNKNOWN actual IoBus construction/API or sink-registration touch. #300 USER_INPUT integration makes seam plausible, not established. | Conditional #300/IR-92 companion only if construction/sink seam touched; reuse default_bus and real publish path. No assumption all event work fires construction trigger. |\n| IR-71 / 3829 | OPEN persisted controller-release breadcrumb | UNKNOWN actual controller lifecycle/breadcrumb touch or barrier timeout. #302 freezes and added #251 viewer detach do not themselves prove controller-release failure. | Conditional lifecycle rider after RCA/role distinction; record after persisted clear, not merely detach event. |\n| IR-72 / 3853 | OPEN named-perch/seat custody read surface | UNKNOWN actual roster/status read-model change; #299 explicitly opens roster diagnosis but remedy not selected. | Strong conditional #299 rider if read model changes; inspect holder identity/role without new bare-pid oracle. Do not add a broad RC diagnostic product implicitly. |\n| IR-73 / 3887 | CLOSED / BUILT eight post-checkout floor sites plus docs rereads | FIRED and reconciled prior close with source and IR-86 live catch. | Keep closed; sizing/dependency coupling remains IR-86. |\n| IR-74 / 3911 | OPEN /tmp lifetime bounding | FIRED between-milestone audit opportunity; current Linux cleanup/touch UNKNOWN. Historical 21,643 homes not fresh census. | Linux audit rider with counted bounded cleanup/retention; not a Windows reap claim. |\n| IR-75 / 3925 | OPEN Linux treqs install-or-explicit-omit decision | UNKNOWN new Linux driver touch; current audit opportunity available. Recorded leg 127, not green. | Pair IR-74 box audit; verify state before eventual action, install or explicitly use identical-tree Windows scan coverage. Do not reopen unrelated IR-37. |\n| IR-76 / 3940 | OPEN driver enforcement/compiler-load census; quiet-window documentation exists | FIRED historical driver/workflow arc and overlapping loads; no #304 run authorized. | Compose required quiet-window gate, truthful three-state meter, compiler-load census. Reuse docs/GOLDEN-CI contract from prior close, not competing policy. No contention attribution from overlap alone. |\n| IR-77 / 3984 | OPEN child-entry to ready timing | UNKNOWN boot/ready-stamp or named test-family touch. RC hitches on existing local sessions are not proof of boot delay. | Conditional boot/ready instrumentation rider only if RCA opens seam. Do not retune deadlines. |\n| IR-78 / 4016 | OPEN explicit docs-port silently overridden | FIRED historical both-variable incident; fresh #304 docshost touch UNKNOWN. Current docshost:99 returns zero silently. #301 and adjacent #282 make this a natural conditional rider. | Tiny notice naming both inputs if docshost touched; preserve chosen precedence, no redesign or claimed schtasks coverage. |\n| IR-79 / 4044 | OPEN lifetime-guard adoption, not lack of all reaper machinery | UNKNOWN new common-module touch; historical exposure established. Current common/reap.rs has authenticated primitives, while first-wave four still use local kills/end teardown. | Compose guard adoption starting projindex_writer, projindex_reader, brain_split, brain_respawn_rename; arm before work. Must distinguish unwinding from hard process kill: Drop alone cannot guarantee timeout/SIGKILL cleanup. |\n| IR-80 / 4125 | OPEN residual 12-cell leak union; ENV tool and scoped fixture findings already established | FIRED historical free-slot investigation. Brainproc shell-wrapper fixture cause scoped; direct production spawn excludes that specific escalation, not all causes. | Caller/fixture adoption and classify remaining members with identity/tree evidence. Reuse existing tree-kill machinery; LEAK counts are not improvement rates. |\n| IR-81 / 4407 | OPEN primitive-required identity and core script gate; adapter arm CLOSED | FIRED historical proc/xtask opportunity. Current kill_pid_tree(root:u32) remains expressible; previous close says #285 repaired site, not primitive. | Carry product primitive and test/CI gate separately, coordinating IR-79 adoption. Adapter fix remains closed. Do not reopen daemon-death causality. |\n| IR-82 / 4532 | RULED, predecessor record still UNBUILT | FIRED historical #285/lifecycle opportunity; current daemon.rs directly overwrites pidfile. | Carry product-side read-before-write/one-generation/age/liveness record; do not infer completion from #285. No liveness-semantic change. |\n| IR-83 / 4638 | OPEN reverse-direction witness enforcement; old universal LAN-only remedy SUPERSEDED | FIRED historical missing inbound coverage and applied-layer proof. #297 incident resolved as Tailscale config, not this guard proving execution. | Keep independent real reverse witness, never-ran/vacuous/blocked distinctions. No new box changes; do not require LAN universally. Coordinate IR-89 exact-step acceptance. |\n| IR-84 / 4775 | OPEN enforcement residual; missing timestamp emit half BUILT | FIRED historical unstamped arm/filer lane. Extra stall arithmetic not solved by adding stamps; IR-89 later explains its own scoped helper class. | Reuse stamped instrumentation in relevant pump RCA; conditional every-arm stamp enforcement. Do not re-add timestamp or transfer old helper cause to local RC freezes. |\n| IR-85 / 4825 | OPEN diagnostic arm; caps 80/40 mitigation only | FIRED arm1 opportunity; comparable rerun never completed. Operator-specific arms UNKNOWN. Old sha slowdown means head growth not necessary, not apportioned cause. | Defer comparison until IR-90/76/97 prerequisites; alternate AB/BA with timestamps and passing-output margins. No Defender/torrent/disk diagnosis of #299/#302. |\n| IR-86 / 4985 | OPEN start-capacity derivation and independent docs prerequisites | FIRED golden/workflow arc; 67.4GiB historical footprint exceeds 32GiB start floor; live docs gate skipped. | Workflow rider: measured capacity + end reserve, run footprint reporting, docs depend only on real prerequisites. IR-73 reorder/reread already done. |\n| IR-87 / 5024 | OPEN cross-runner rendezvous/queue clock | FIRED exact recurrence: golden's own PR took Windows; B terminal 07:36:16, A starts 07:48:07. | Schedule/barrier rider includes self-PR interference, not only other lanes. Preserve raw job conclusions beside VOID scoring; 900s symptom not firewall diagnosis. |\n| IR-88 / 5077 | OPEN durable teardown recipe adoption; prebuilt method proven | FIRED historical release-after-reap regrowth; next pool/runbook touch is adoption seam. | Adopt prebuilt release before delete. Do not propose guard inside verb as protection against Cargo rebuild that happens before verb starts. |\n| IR-89 / 5106 | BOX APPLIED, WORKFLOW BUILT/LANDED; exact golden-step acceptance OPEN | FIRED next-golden trigger: later goldens exist. Exact probe-step exercised/skipped/failed remains UNKNOWN in prior close and this sweep. | Reconcile retained step receipts, not implement another probe or renew spent operator permission. Box/ACL reset remains future recheck. #297 TCP bootstrap is distinct from CI UDP probe. |\n| IR-90 / 5262 | OPEN rig resource refusal + failure context | FIRED ripe-now historical 0.018GiB incident. Existing disk-floor is substrate, not both requested placements. | Driver/rig prerequisite: actual temp/target volumes plus mid-failure free-space context. No loaded comparisons until adopted. No inference a monotonic last-tick sample proves sustained recovery. |\n| IR-91 / 5351 | CLOSED root scratch classification/preservation | FIRED historically and shipped with entry. | Keep closed; retain cited artifacts at established paths and manifests. No new root cleanup sweep. |\n| IR-92 / 5405 | OPEN successful inject lacks MSG_IN; docs rider shipped only | FIRED prior product/IO intake, carried explicitly by close. #300 USER_INPUT funnel work is adjacent but a different event contract. | Compose successful-inject observation at single chokepoint, refused inject none; keep Path-A publish-before-present, Path-B allowed bounded log wait and exact-once per msg-id separate. Never reinterpret USER_INPUT requirement as MSG_OUT or replace it with MSG_IN repair. |\n| IR-93 / 5537 | OPEN symbol packaging decision | UNKNOWN actual installer/release packaging touch. #297 bootstrap may touch installer but start-only remedy not yet ruled. | Put size/profile/distribution decision before operator during grill if packaging opens; release-build success is not installed matching-PDB evidence. No silent product-diagnostics expansion. |\n| IR-94 / 5566 | OPEN behavioral census/fail-unclassified gate | FIRED newly added brainread gate; current three-file/name-shaped code corroborated. Mandatory before bounded serve_sync carrier migration; #299/#302 may or may not reach it. | Small tooling rider with explicit population; ensure mandatory dependency if RCA chooses carrier change. Independent gate defect, not established sync or RC cause. |\n| IR-95 / 5596 | OPEN selected poll instrumentation + producer trace; census/diagnostic measurements exist, patch not shipped | FIRED releases#294 comparison. Census estimate 317 blind/321 with slop and 15 outside detector, not exact repo-wide floor. | Prioritize touched diagnostic waits for #299/#302 only if meaningful; no bulk 304-site conversion. Separately version exchange-correlated producer create/retire trace if needed. Preserve budgets and quantify instrumentation scope; final filtered snapshot not continuous absence. |\n| IR-96 / 5851 | OPEN cause-unclassified convoy red | NOT-FIRED on supplied intake for its specific new events: no convoy source touch, candidate golden red, or matched candidate local-HEAVY run established. Previous cheap discriminator remains unrun. | Carry scoped diagnostic continuation after IR-97/90/76. 0/1 candidate CI vs 3/3 diagnostic HEAVY does not exonerate product or isolate instrumentation. |\n| IR-97 / 5875 | OPEN enforce between-run accounting | FIRED prior repeated-run experiment: retained cohort 0/6/12 across B1/B2/B3. Future #304 repeated runs not yet designed/authorized. | Mandatory harness census between runs plus identity-scoped cleanup, not retrospective limitation paragraph. Counts are not measured load; 18 seen vs 15 killed does not prove self-exit. |\n\n## Proposed riders and ordering — proposals only\n1. **Required before a new loaded/repeated diagnostic campaign:** carry prior-close driver package IR-59/60/76/86/87/90/97 (join first scout's IR-31/46). Capacity, correct producer verdict, existing quiet-window contract, partner scheduling and between-run identities are separate acceptance obligations, not one generic preflight. IR-88 is proven recipe adoption; IR-64 remains separate operator decision. No execution authorized by intake.\n2. **Most direct #304 seam candidates:** IR-78 alongside #301/#282 if docshost touched; IR-72 alongside #299 if roster read-model changes; IR-94 mandatory if any chosen stall remedy puts serve_sync on a bounded carrier; IR-95 selective margins for newly investigated waits. IR-93 requires explicit packaging decision if #297 touches installer, not automatic PDB approval.\n3. **IO package:** IR-92 is already owed, useful near #300, but USER_INPUT-triggered file intent/provenance and MSG_IN inject observation are distinct. IR-70 only if construction/API/sinks change. IR-69 anchored-consumer rider separate from #243 conversion/generator work. Do not expand into general IO rewrite.\n4. **Lifecycle test package:** IR-55/63/79/80, joining earlier-range lifetime entries. Reuse common authenticated reaper and existing tree kill rather than introduce duplicate primitives; identity-required API IR-81 is separate product obligation, IR-82 predecessor record remains separate unbuilt rider. Hard-death cleanup must not be sold as ordinary Drop coverage.\n5. **Acceptance-only reconciliation:** IR-83/89 reverse direction witness and exact probe step receipts; no box/config changes. IR-56/62/66/67/73/91 built/closed states stand. IR-57/59/84 implemented halves stand; only adoption/enforcement residuals remain.\n6. **Carry deferred/conditional:** IR-61/65/68/71/77 and untriggered IR-96 event; Linux IR-74/75 at box-audit slot; IR-85 diagnostic continuation behind prerequisites. Small tooling IR-58 may compose with first scout's seam-rider package. No offline owner becomes executing from a historic assignment.\n\n## Current intake evidence that constrains the grill\nRead issue304 and original five issues directly. #304 is BACKLOG, explicitly intake-only; comment adds #251/#282/#288/#230/#49/#267, retains #49 joint-ship ruling with #42, excludes #296 and CUT #303. No broad networking cleanup or new RC diagnostics implicitly authorized.\n- #297 comment records operator-confirmed Tailscale incident resolution and independently observed HTTP200. Separately source-verified missing TCP bootstrap admission remains; do not call that the incident cause or reapply IR-89 CI UDP rules.\n- #299 complete byte-identical 2497-byte roster at 3822/10120/10105ms, rc0, is accepted evidence. Network deadline, coordinator contention and local metadata costs remain alternatives; no partial/empty output workaround.\n- #300 operator correction is authoritative: USER_INPUT, not MSG_OUT. Preserve authenticated controller/user-node origin and committed input/path intent, 24h reference, receiving-agent audience, once-per-input/path helper. Raw PTY bytes do not equal USER_INPUT.\n- #301 demands public docs at node root; no requirement for Served Resources landing.\n- #302 occurs both local and remote on v0.69.0, input and PTY stall together then queued input drains. Tailnet-only or remote-network explanation cannot cover the reported local occurrences without further evidence.\n\n## Verification limits\nRead-only file/search/issue tools only. No validation commands, process probes, builds, tests, formatting, git changes, register edits or board mutations. Required orientation entry points read, plus relevant golden ADR. Prior close results are cited as existing evidence, never fresh execution. Full change-history and golden-step receipts not re-audited; exact unknown trigger/acceptance states remain explicit."},"error":null}}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":166,"output":5187,"cacheRead":130432,"cacheWrite":0,"totalTokens":135785,"cost":{"input":0.0016600000000000002,"output":0.25935,"cacheRead":0.130432,"cacheWrite":0,"total":0.391442}},"stopReason":"toolUse","timestamp":1789107134155,"responseId":"resp_0820bf72eb96c0c7016aa39c15c7e887d198e2c838c556d7d7","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0820bf72eb96c0c7016aa39c1764e887d1b5683ad6f058698c","type":"function_call","status":"completed","arguments":"{\"type\":null,\"data\":{\"summary\":\"Complete read-only accounting: 43 assigned entries, IR-55–IR-97 inclusive. Leading lines 3001–3021 are CI-RIDER history belonging to the first scout, not a split IR. Preserve built work; propose driver/capacity prerequisites and narrowly seam-triggered riders for REMOTE-FRICTION, pending operator grill. No commands, edits, builds or tests executed.\",\"files\":[{\"path\":\"docs/INFRA-REGISTER.md:3022-5900\",\"description\":\"All 43 assigned IR bodies, amendments, triggers and residuals read.\"},{\"path\":\"docs/INFRA-REGISTER.md:1-61\",\"description\":\"Authoritative prior release-close reconciliation and next-intake composition; supersedes stale historical build/owner prose.\"},{\"path\":\".spt/preserved/infra-close069-20260911/audit.json\",\"description\":\"Previous SHA-pinned full-register audit and parent rulings; consulted assigned-range report and implementation receipts.\"},{\"path\":\"docs/instruments/ir59/STATUS.md\",\"description\":\"Existing disk-floor instrument, flags, adoption contract and instant-not-headroom limitation.\"},{\"path\":\"crates/xtask/src/main.rs:69-70\",\"description\":\"pick-audit and disk-floor already wired; do not dispatch their implementation again.\"},{\"path\":\"crates/xtask/src/brainread.rs:194-203,295-320\",\"description\":\"IR-94 still has name-shaped stream predicate and three-file population.\"},{\"path\":\"crates/spt-store/src/proc.rs:430\",\"description\":\"kill_pid_tree still accepts bare numeric root; existing tree machinery is not identity-required primitive enforcement.\"},{\"path\":\"crates/spt-daemon/src/daemon.rs:474-476\",\"description\":\"Direct pidfile overwrite remains; IR-82 predecessor preservation not built.\"},{\"path\":\"crates/spt-daemon/src/docshost.rs:90-102\",\"description\":\"Ephemeral advisory flag still silently returns zero before explicit docs-port resolution.\"},{\"path\":\"crates/spt/tests/common/reap.rs:1-100\",\"description\":\"Authenticated breadcrumb reaper substrate already exists, including birth/image checks and refusal semantics.\"},{\"path\":\"crates/spt/tests/common/mod.rs:1-60\",\"description\":\"Shared reaper export and existing test support; adoption should reuse this seam.\"},{\"path\":\"crates/spt/tests/projindex_writer_e2e.rs; crates/spt/tests/projindex_reader_e2e.rs; crates/spt/tests/brain_split.rs; crates/spt/tests/brain_respawn_rename.rs\",\"description\":\"IR-79 first-wave sites retain local kill helpers and end-of-body teardown; existing authenticated reaper is not equivalent to these sites having adopted lifetime guards.\"},{\"path\":\"https://github.com/BigscreenVR/spt-bs-releases/issues/304\",\"description\":\"Current milestone intake explicitly forbids implementation before grill; includes original bag and adjacent RC/serving requests.\"}],\"architecture\":\"Separate four obligations: built mechanism, caller/driver adoption, box/operator configuration, and incident diagnosis. Broker/brain custody, IO publication, HTTP serving and shared-runner control are different seams. Similar 5–10s or 900s durations do not establish a common cause. Infrastructure remains in the register, even when its remedy touches product code.\",\"report\":\"## Scope and evidence key\\nAssigned population is exactly IR-55, IR-56, IR-57, IR-58, IR-59, IR-60, IR-61, IR-62, IR-63, IR-64, IR-65, IR-66, IR-67, IR-68, IR-69, IR-70, IR-71, IR-72, IR-73, IR-74, IR-75, IR-76, IR-77, IR-78, IR-79, IR-80, IR-81, IR-82, IR-83, IR-84, IR-85, IR-86, IR-87, IR-88, IR-89, IR-90, IR-91, IR-92, IR-93, IR-94, IR-95, IR-96, IR-97: 43 consecutive, unique IDs. First IR opens at 3022. The first scout independently confirmed ownership of continuing CI-RIDER history through 3021. No IR spans the assignment boundary.\\n\\nFIRED means a qualifying historical event or standing intake opportunity is evidenced, not that #304 has already edited that seam. UNKNOWN means no qualifying new event/source touch established; it is not NOT-FIRED or closure. Prospective #304 seam connections below are explicitly conditional until grill/final wave shape. Prior close record is dated 2026-09-11 and source-pinned e5a2fed9; dates are reported as written. Targeted working-tree reads corroborate several unbuilt residuals but are not runtime acceptance.\\n\\n## Full compressed enumeration\\n| ID / opening line | Status / remaining obligation | Trigger and evidence verdict | Recommended disposition / dependency |\\n|---|---|---|---|\\n| IR-55 / 3022 | OPEN, ARMED-FOR-CAPTURE; leak unidentified | FIRED standing unfiltered spt-bin battery trigger. Historical wedge twice; nextest 653 pass and five bare 663-pass settles are containment/negative observations, not discharge. No fresh wedge in intake. | Carry armed in lifecycle package; preserve environment + before/during census before cleanup; no new bisect merely because RC freezes. |\\n| IR-56 / 3148 | BUILT cross-worktree claim refusal and explicit foreign-pool takeover | FIRED historically, SIGNET build evidence recorded. | Keep built. IR-42 admission adjudication remains separate; no duplicate pool-claim lane. |\\n| IR-57 / 3189 | OPEN living assembly procedure; pick-audit BUILT | FIRED historical assemblies, two real LOSS catches. #304 assembly remains future. | Adopt existing command over full pick chain; retain compilation and repaired-suite obligations at actual gate time. Do not rebuild tool. |\\n| IR-58 / 3248 | OPEN duplicate-target enumeration check; original nonexistent-bin claim RETRACTED | FIRED prior brainread/xtask work; next xtask check touch remains rider seam. | Tooling rider using Cargo target enumeration, not manifest-stanza grep. Never resurrect withdrawn prose fix. |\\n| IR-59 / 3283 | OPEN capacity/adoption; disk-floor BUILT | FIRED gate/CI arc and release-close resource reds: 3167 units passed before END floor refused 15,360,114,688 < 34,359,738,368 B. | Compose driver/capacity adoption with IR-46/76/86/90; pool budget/reclaim per wave. No new instrument, no reboot remedy, no causal attribution to unavailable earlier logs. |\\n| IR-60 / 3417 | OPEN truthful producer-status capture | FIRED v0.69 recurrence: wrapper NEXTEST_EXIT=0 measured tail while Cargo returned 101. | Driver rider: capture inside producer shell immediately, write and propagate actual leg status; distinguish raw Summary from missing exit. |\\n| IR-61 / 3466 | OPEN accepted duplicated literal-state trackers | UNKNOWN substantive spacerun scanning touch; unrelated xtask work insufficient. | Carry until new skip/literal/tracker change, then unify rather than add third tracker. |\\n| IR-62 / 3499 | BUILT docs collision remedy; other bind surfaces residual | FIRED historical second collision, PR158 measured port-held arm and ephemeral fix. | Keep built; retain non-docs co-diagnostic caveat. Not whole-rig network isolation and not #297 TCP admission. |\\n| IR-63 / 3540 | OPEN cleanup adopted, producer teardown not closed | FIRED historical rig work/leaked daemon and conhost CWD pins; queued lane not proof of landing. | Compose IR-79/80/97 lifetime/accounting work. Reuse safe reap machinery; historical random victims do not diagnose new stalls. |\\n| IR-64 / 3579 | OPEN operator-owned capacity reservoir | FIRED IR-86 in-job floor despite pool discipline, explicitly recorded. New operator ruling UNKNOWN. | Separate operator move/expand/accept-tax decision. Old 845GB bulk is historical census, not current measurement; agents cannot touch it. |\\n| IR-65 / 3601 | REMEDIATED-AT-BOX, OPEN reset recheck | UNKNOWN tailscale snap/auditd update or reimage. New Tailscale incident does not establish reset of kitsubito audit configuration. | Carry named recheck triggers; do not rerun box probes or reopen remediation from symptom similarity. |\\n| IR-66 / 3627 | CLOSED / BUILT delayed needles | FIRED historical two-platform rider gates; previous close explicitly reconciled. | Keep closed. No redispatch of two test edits. |\\n| IR-67 / 3660 | BUILT explicit integration-suite battery template | FIRED historical IO-PARSER waves and intake template adoption. | Keep built; --bins still must never be described as integration coverage. |\\n| IR-68 / 3682 | OPEN ingest-cause investigation | UNKNOWN new PSYCHE_INGEST_FAIL sighting/dedicated probe slot. Planted nonempty index locks did not block ingest. | Carry capture-first; COMMUNE_FAIL now names reason. Do not reinstate refuted index-lock attribution. |\\n| IR-69 / 3710 | OPEN #243 conversion/generator/zero-recensus and anchored consumers; original emission fix LANDED | FIRED historical residual recensus: 338 cli sites plus 2 main sites missed. | Keep #243 dependency and separate test-side anchored IDLE/DISPATCH/BUSY/BOUND rider. No redo of landed emission or already-converted delivery sites. IO/USER_INPUT work may touch consumer seam, not automatically satisfy entire residual population. |\\n| IR-70 / 3802 | OPEN assembly-point enforcement; witnessed publisher correction shipped | UNKNOWN actual IoBus construction/API or sink-registration touch. #300 USER_INPUT integration makes seam plausible, not established. | Conditional #300/IR-92 companion only if construction/sink seam touched; reuse default_bus and real publish path. No assumption all event work fires construction trigger. |\\n| IR-71 / 3829 | OPEN persisted controller-release breadcrumb | UNKNOWN actual controller lifecycle/breadcrumb touch or barrier timeout. #302 freezes and added #251 viewer detach do not themselves prove controller-release failure. | Conditional lifecycle rider after RCA/role distinction; record after persisted clear, not merely detach event. |\\n| IR-72 / 3853 | OPEN named-perch/seat custody read surface | UNKNOWN actual roster/status read-model change; #299 explicitly opens roster diagnosis but remedy not selected. | Strong conditional #299 rider if read model changes; inspect holder identity/role without new bare-pid oracle. Do not add a broad RC diagnostic product implicitly. |\\n| IR-73 / 3887 | CLOSED / BUILT eight post-checkout floor sites plus docs rereads | FIRED and reconciled prior close with source and IR-86 live catch. | Keep closed; sizing/dependency coupling remains IR-86. |\\n| IR-74 / 3911 | OPEN /tmp lifetime bounding | FIRED between-milestone audit opportunity; current Linux cleanup/touch UNKNOWN. Historical 21,643 homes not fresh census. | Linux audit rider with counted bounded cleanup/retention; not a Windows reap claim. |\\n| IR-75 / 3925 | OPEN Linux treqs install-or-explicit-omit decision | UNKNOWN new Linux driver touch; current audit opportunity available. Recorded leg 127, not green. | Pair IR-74 box audit; verify state before eventual action, install or explicitly use identical-tree Windows scan coverage. Do not reopen unrelated IR-37. |\\n| IR-76 / 3940 | OPEN driver enforcement/compiler-load census; quiet-window documentation exists | FIRED historical driver/workflow arc and overlapping loads; no #304 run authorized. | Compose required quiet-window gate, truthful three-state meter, compiler-load census. Reuse docs/GOLDEN-CI contract from prior close, not competing policy. No contention attribution from overlap alone. |\\n| IR-77 / 3984 | OPEN child-entry to ready timing | UNKNOWN boot/ready-stamp or named test-family touch. RC hitches on existing local sessions are not proof of boot delay. | Conditional boot/ready instrumentation rider only if RCA opens seam. Do not retune deadlines. |\\n| IR-78 / 4016 | OPEN explicit docs-port silently overridden | FIRED historical both-variable incident; fresh #304 docshost touch UNKNOWN. Current docshost:99 returns zero silently. #301 and adjacent #282 make this a natural conditional rider. | Tiny notice naming both inputs if docshost touched; preserve chosen precedence, no redesign or claimed schtasks coverage. |\\n| IR-79 / 4044 | OPEN lifetime-guard adoption, not lack of all reaper machinery | UNKNOWN new common-module touch; historical exposure established. Current common/reap.rs has authenticated primitives, while first-wave four still use local kills/end teardown. | Compose guard adoption starting projindex_writer, projindex_reader, brain_split, brain_respawn_rename; arm before work. Must distinguish unwinding from hard process kill: Drop alone cannot guarantee timeout/SIGKILL cleanup. |\\n| IR-80 / 4125 | OPEN residual 12-cell leak union; ENV tool and scoped fixture findings already established | FIRED historical free-slot investigation. Brainproc shell-wrapper fixture cause scoped; direct production spawn excludes that specific escalation, not all causes. | Caller/fixture adoption and classify remaining members with identity/tree evidence. Reuse existing tree-kill machinery; LEAK counts are not improvement rates. |\\n| IR-81 / 4407 | OPEN primitive-required identity and core script gate; adapter arm CLOSED | FIRED historical proc/xtask opportunity. Current kill_pid_tree(root:u32) remains expressible; previous close says #285 repaired site, not primitive. | Carry product primitive and test/CI gate separately, coordinating IR-79 adoption. Adapter fix remains closed. Do not reopen daemon-death causality. |\\n| IR-82 / 4532 | RULED, predecessor record still UNBUILT | FIRED historical #285/lifecycle opportunity; current daemon.rs directly overwrites pidfile. | Carry product-side read-before-write/one-generation/age/liveness record; do not infer completion from #285. No liveness-semantic change. |\\n| IR-83 / 4638 | OPEN reverse-direction witness enforcement; old universal LAN-only remedy SUPERSEDED | FIRED historical missing inbound coverage and applied-layer proof. #297 incident resolved as Tailscale config, not this guard proving execution. | Keep independent real reverse witness, never-ran/vacuous/blocked distinctions. No new box changes; do not require LAN universally. Coordinate IR-89 exact-step acceptance. |\\n| IR-84 / 4775 | OPEN enforcement residual; missing timestamp emit half BUILT | FIRED historical unstamped arm/filer lane. Extra stall arithmetic not solved by adding stamps; IR-89 later explains its own scoped helper class. | Reuse stamped instrumentation in relevant pump RCA; conditional every-arm stamp enforcement. Do not re-add timestamp or transfer old helper cause to local RC freezes. |\\n| IR-85 / 4825 | OPEN diagnostic arm; caps 80/40 mitigation only | FIRED arm1 opportunity; comparable rerun never completed. Operator-specific arms UNKNOWN. Old sha slowdown means head growth not necessary, not apportioned cause. | Defer comparison until IR-90/76/97 prerequisites; alternate AB/BA with timestamps and passing-output margins. No Defender/torrent/disk diagnosis of #299/#302. |\\n| IR-86 / 4985 | OPEN start-capacity derivation and independent docs prerequisites | FIRED golden/workflow arc; 67.4GiB historical footprint exceeds 32GiB start floor; live docs gate skipped. | Workflow rider: measured capacity + end reserve, run footprint reporting, docs depend only on real prerequisites. IR-73 reorder/reread already done. |\\n| IR-87 / 5024 | OPEN cross-runner rendezvous/queue clock | FIRED exact recurrence: golden's own PR took Windows; B terminal 07:36:16, A starts 07:48:07. | Schedule/barrier rider includes self-PR interference, not only other lanes. Preserve raw job conclusions beside VOID scoring; 900s symptom not firewall diagnosis. |\\n| IR-88 / 5077 | OPEN durable teardown recipe adoption; prebuilt method proven | FIRED historical release-after-reap regrowth; next pool/runbook touch is adoption seam. | Adopt prebuilt release before delete. Do not propose guard inside verb as protection against Cargo rebuild that happens before verb starts. |\\n| IR-89 / 5106 | BOX APPLIED, WORKFLOW BUILT/LANDED; exact golden-step acceptance OPEN | FIRED next-golden trigger: later goldens exist. Exact probe-step exercised/skipped/failed remains UNKNOWN in prior close and this sweep. | Reconcile retained step receipts, not implement another probe or renew spent operator permission. Box/ACL reset remains future recheck. #297 TCP bootstrap is distinct from CI UDP probe. |\\n| IR-90 / 5262 | OPEN rig resource refusal + failure context | FIRED ripe-now historical 0.018GiB incident. Existing disk-floor is substrate, not both requested placements. | Driver/rig prerequisite: actual temp/target volumes plus mid-failure free-space context. No loaded comparisons until adopted. No inference a monotonic last-tick sample proves sustained recovery. |\\n| IR-91 / 5351 | CLOSED root scratch classification/preservation | FIRED historically and shipped with entry. | Keep closed; retain cited artifacts at established paths and manifests. No new root cleanup sweep. |\\n| IR-92 / 5405 | OPEN successful inject lacks MSG_IN; docs rider shipped only | FIRED prior product/IO intake, carried explicitly by close. #300 USER_INPUT funnel work is adjacent but a different event contract. | Compose successful-inject observation at single chokepoint, refused inject none; keep Path-A publish-before-present, Path-B allowed bounded log wait and exact-once per msg-id separate. Never reinterpret USER_INPUT requirement as MSG_OUT or replace it with MSG_IN repair. |\\n| IR-93 / 5537 | OPEN symbol packaging decision | UNKNOWN actual installer/release packaging touch. #297 bootstrap may touch installer but start-only remedy not yet ruled. | Put size/profile/distribution decision before operator during grill if packaging opens; release-build success is not installed matching-PDB evidence. No silent product-diagnostics expansion. |\\n| IR-94 / 5566 | OPEN behavioral census/fail-unclassified gate | FIRED newly added brainread gate; current three-file/name-shaped code corroborated. Mandatory before bounded serve_sync carrier migration; #299/#302 may or may not reach it. | Small tooling rider with explicit population; ensure mandatory dependency if RCA chooses carrier change. Independent gate defect, not established sync or RC cause. |\\n| IR-95 / 5596 | OPEN selected poll instrumentation + producer trace; census/diagnostic measurements exist, patch not shipped | FIRED releases#294 comparison. Census estimate 317 blind/321 with slop and 15 outside detector, not exact repo-wide floor. | Prioritize touched diagnostic waits for #299/#302 only if meaningful; no bulk 304-site conversion. Separately version exchange-correlated producer create/retire trace if needed. Preserve budgets and quantify instrumentation scope; final filtered snapshot not continuous absence. |\\n| IR-96 / 5851 | OPEN cause-unclassified convoy red | NOT-FIRED on supplied intake for its specific new events: no convoy source touch, candidate golden red, or matched candidate local-HEAVY run established. Previous cheap discriminator remains unrun. | Carry scoped diagnostic continuation after IR-97/90/76. 0/1 candidate CI vs 3/3 diagnostic HEAVY does not exonerate product or isolate instrumentation. |\\n| IR-97 / 5875 | OPEN enforce between-run accounting | FIRED prior repeated-run experiment: retained cohort 0/6/12 across B1/B2/B3. Future #304 repeated runs not yet designed/authorized. | Mandatory harness census between runs plus identity-scoped cleanup, not retrospective limitation paragraph. Counts are not measured load; 18 seen vs 15 killed does not prove self-exit. |\\n\\n## Proposed riders and ordering — proposals only\\n1. **Required before a new loaded/repeated diagnostic campaign:** carry prior-close driver package IR-59/60/76/86/87/90/97 (join first scout's IR-31/46). Capacity, correct producer verdict, existing quiet-window contract, partner scheduling and between-run identities are separate acceptance obligations, not one generic preflight. IR-88 is proven recipe adoption; IR-64 remains separate operator decision. No execution authorized by intake.\\n2. **Most direct #304 seam candidates:** IR-78 alongside #301/#282 if docshost touched; IR-72 alongside #299 if roster read-model changes; IR-94 mandatory if any chosen stall remedy puts serve_sync on a bounded carrier; IR-95 selective margins for newly investigated waits. IR-93 requires explicit packaging decision if #297 touches installer, not automatic PDB approval.\\n3. **IO package:** IR-92 is already owed, useful near #300, but USER_INPUT-triggered file intent/provenance and MSG_IN inject observation are distinct. IR-70 only if construction/API/sinks change. IR-69 anchored-consumer rider separate from #243 conversion/generator work. Do not expand into general IO rewrite.\\n4. **Lifecycle test package:** IR-55/63/79/80, joining earlier-range lifetime entries. Reuse common authenticated reaper and existing tree kill rather than introduce duplicate primitives; identity-required API IR-81 is separate product obligation, IR-82 predecessor record remains separate unbuilt rider. Hard-death cleanup must not be sold as ordinary Drop coverage.\\n5. **Acceptance-only reconciliation:** IR-83/89 reverse direction witness and exact probe step receipts; no box/config changes. IR-56/62/66/67/73/91 built/closed states stand. IR-57/59/84 implemented halves stand; only adoption/enforcement residuals remain.\\n6. **Carry deferred/conditional:** IR-61/65/68/71/77 and untriggered IR-96 event; Linux IR-74/75 at box-audit slot; IR-85 diagnostic continuation behind prerequisites. Small tooling IR-58 may compose with first scout's seam-rider package. No offline owner becomes executing from a historic assignment.\\n\\n## Current intake evidence that constrains the grill\\nRead issue304 and original five issues directly. #304 is BACKLOG, explicitly intake-only; comment adds #251/#282/#288/#230/#49/#267, retains #49 joint-ship ruling with #42, excludes #296 and CUT #303. No broad networking cleanup or new RC diagnostics implicitly authorized.\\n- #297 comment records operator-confirmed Tailscale incident resolution and independently observed HTTP200. Separately source-verified missing TCP bootstrap admission remains; do not call that the incident cause or reapply IR-89 CI UDP rules.\\n- #299 complete byte-identical 2497-byte roster at 3822/10120/10105ms, rc0, is accepted evidence. Network deadline, coordinator contention and local metadata costs remain alternatives; no partial/empty output workaround.\\n- #300 operator correction is authoritative: USER_INPUT, not MSG_OUT. Preserve authenticated controller/user-node origin and committed input/path intent, 24h reference, receiving-agent audience, once-per-input/path helper. Raw PTY bytes do not equal USER_INPUT.\\n- #301 demands public docs at node root; no requirement for Served Resources landing.\\n- #302 occurs both local and remote on v0.69.0, input and PTY stall together then queued input drains. Tailnet-only or remote-network explanation cannot cover the reported local occurrences without further evidence.\\n\\n## Verification limits\\nRead-only file/search/issue tools only. No validation commands, process probes, builds, tests, formatting, git changes, register edits or board mutations. Required orientation entry points read, plus relevant golden ADR. Prior close results are cited as existing evidence, never fresh execution. Full change-history and golden-step receipts not re-audited; exact unknown trigger/acceptance states remain explicit.\"},\"error\":null}","call_id":"call_6ezvZ1Ev1tB5tPrefAADESjs","internal_chat_message_metadata_passthrough":{"create_time":1789107222.277742,"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"},"name":"yield","metadata":{"turn_id":"22d88b61-f620-49b8-abed-8b7f3a1f67ca"}}]},"duration":246987.54620000068,"ttft":91649.52799999993,"completedAt":1789107381169,"contextSnapshot":{"promptTokens":130598,"nonMessageTokens":10297,"compactionEpoch":0}}}
{"type":"message","id":"30803859","parentId":"752ad333","timestamp":"2026-09-11T06:16:21.172Z","message":{"role":"toolResult","toolCallId":"call_6ezvZ1Ev1tB5tPrefAADESjs|fc_0820bf72eb96c0c7016aa39c1764e887d1b5683ad6f058698c","toolName":"yield","content":[{"type":"text","text":"Result submitted."}],"details":{"data":{"summary":"Complete read-only accounting: 43 assigned entries, IR-55–IR-97 inclusive. Leading lines 3001–3021 are CI-RIDER history belonging to the first scout, not a split IR. Preserve built work; propose driver/capacity prerequisites and narrowly seam-triggered riders for REMOTE-FRICTION, pending operator grill. No commands, edits, builds or tests executed.","files":[{"path":"docs/INFRA-REGISTER.md:3022-5900","description":"All 43 assigned IR bodies, amendments, triggers and residuals read."},{"path":"docs/INFRA-REGISTER.md:1-61","description":"Authoritative prior release-close reconciliation and next-intake composition; supersedes stale historical build/owner prose."},{"path":".spt/preserved/infra-close069-20260911/audit.json","description":"Previous SHA-pinned full-register audit and parent rulings; consulted assigned-range report and implementation receipts."},{"path":"docs/instruments/ir59/STATUS.md","description":"Existing disk-floor instrument, flags, adoption contract and instant-not-headroom limitation."},{"path":"crates/xtask/src/main.rs:69-70","description":"pick-audit and disk-floor already wired; do not dispatch their implementation again."},{"path":"crates/xtask/src/brainread.rs:194-203,295-320","description":"IR-94 still has name-shaped stream predicate and three-file population."},{"path":"crates/spt-store/src/proc.rs:430","description":"kill_pid_tree still accepts bare numeric root; existing tree machinery is not identity-required primitive enforcement."},{"path":"crates/spt-daemon/src/daemon.rs:474-476","description":"Direct pidfile overwrite remains; IR-82 predecessor preservation not built."},{"path":"crates/spt-daemon/src/docshost.rs:90-102","description":"Ephemeral advisory flag still silently returns zero before explicit docs-port resolution."},{"path":"crates/spt/tests/common/reap.rs:1-100","description":"Authenticated breadcrumb reaper substrate already exists, including birth/image checks and refusal semantics."},{"path":"crates/spt/tests/common/mod.rs:1-60","description":"Shared reaper export and existing test support; adoption should reuse this seam."},{"path":"crates/spt/tests/projindex_writer_e2e.rs; crates/spt/tests/projindex_reader_e2e.rs; crates/spt/tests/brain_split.rs; crates/spt/tests/brain_respawn_rename.rs","description":"IR-79 first-wave sites retain local kill helpers and end-of-body teardown; existing authenticated reaper is not equivalent to these sites having adopted lifetime guards."},{"path":"https://github.com/BigscreenVR/spt-bs-releases/issues/304","description":"Current milestone intake explicitly forbids implementation before grill; includes original bag and adjacent RC/serving requests."}],"architecture":"Separate four obligations: built mechanism, caller/driver adoption, box/operator configuration, and incident diagnosis. Broker/brain custody, IO publication, HTTP serving and shared-runner control are different seams. Similar 5–10s or 900s durations do not establish a common cause. Infrastructure remains in the register, even when its remedy touches product code.","report":"## Scope and evidence key\nAssigned population is exactly IR-55, IR-56, IR-57, IR-58, IR-59, IR-60, IR-61, IR-62, IR-63, IR-64, IR-65, IR-66, IR-67, IR-68, IR-69, IR-70, IR-71, IR-72, IR-73, IR-74, IR-75, IR-76, IR-77, IR-78, IR-79, IR-80, IR-81, IR-82, IR-83, IR-84, IR-85, IR-86, IR-87, IR-88, IR-89, IR-90, IR-91, IR-92, IR-93, IR-94, IR-95, IR-96, IR-97: 43 consecutive, unique IDs. First IR opens at 3022. The first scout independently confirmed ownership of continuing CI-RIDER history through 3021. No IR spans the assignment boundary.\n\nFIRED means a qualifying historical event or standing intake opportunity is evidenced, not that #304 has already edited that seam. UNKNOWN means no qualifying new event/source touch established; it is not NOT-FIRED or closure. Prospective #304 seam connections below are explicitly conditional until grill/final wave shape. Prior close record is dated 2026-09-11 and source-pinned e5a2fed9; dates are reported as written. Targeted working-tree reads corroborate several unbuilt residuals but are not runtime acceptance.\n\n## Full compressed enumeration\n| ID / opening line | Status / remaining obligation | Trigger and evidence verdict | Recommended disposition / dependency |\n|---|---|---|---|\n| IR-55 / 3022 | OPEN, ARMED-FOR-CAPTURE; leak unidentified | FIRED standing unfiltered spt-bin battery trigger. Historical wedge twice; nextest 653 pass and five bare 663-pass settles are containment/negative observations, not discharge. No fresh wedge in intake. | Carry armed in lifecycle package; preserve environment + before/during census before cleanup; no new bisect merely because RC freezes. |\n| IR-56 / 3148 | BUILT cross-worktree claim refusal and explicit foreign-pool takeover | FIRED historically, SIGNET build evidence recorded. | Keep built. IR-42 admission adjudication remains separate; no duplicate pool-claim lane. |\n| IR-57 / 3189 | OPEN living assembly procedure; pick-audit BUILT | FIRED historical assemblies, two real LOSS catches. #304 assembly remains future. | Adopt existing command over full pick chain; retain compilation and repaired-suite obligations at actual gate time. Do not rebuild tool. |\n| IR-58 / 3248 | OPEN duplicate-target enumeration check; original nonexistent-bin claim RETRACTED | FIRED prior brainread/xtask work; next xtask check touch remains rider seam. | Tooling rider using Cargo target enumeration, not manifest-stanza grep. Never resurrect withdrawn prose fix. |\n| IR-59 / 3283 | OPEN capacity/adoption; disk-floor BUILT | FIRED gate/CI arc and release-close resource reds: 3167 units passed before END floor refused 15,360,114,688 < 34,359,738,368 B. | Compose driver/capacity adoption with IR-46/76/86/90; pool budget/reclaim per wave. No new instrument, no reboot remedy, no causal attribution to unavailable earlier logs. |\n| IR-60 / 3417 | OPEN truthful producer-status capture | FIRED v0.69 recurrence: wrapper NEXTEST_EXIT=0 measured tail while Cargo returned 101. | Driver rider: capture inside producer shell immediately, write and propagate actual leg status; distinguish raw Summary from missing exit. |\n| IR-61 / 3466 | OPEN accepted duplicated literal-state trackers | UNKNOWN substantive spacerun scanning touch; unrelated xtask work insufficient. | Carry until new skip/literal/tracker change, then unify rather than add third tracker. |\n| IR-62 / 3499 | BUILT docs collision remedy; other bind surfaces residual | FIRED historical second collision, PR158 measured port-held arm and ephemeral fix. | Keep built; retain non-docs co-diagnostic caveat. Not whole-rig network isolation and not #297 TCP admission. |\n| IR-63 / 3540 | OPEN cleanup adopted, producer teardown not closed | FIRED historical rig work/leaked daemon and conhost CWD pins; queued lane not proof of landing. | Compose IR-79/80/97 lifetime/accounting work. Reuse safe reap machinery; historical random victims do not diagnose new stalls. |\n| IR-64 / 3579 | OPEN operator-owned capacity reservoir | FIRED IR-86 in-job floor despite pool discipline, explicitly recorded. New operator ruling UNKNOWN. | Separate operator move/expand/accept-tax decision. Old 845GB bulk is historical census, not current measurement; agents cannot touch it. |\n| IR-65 / 3601 | REMEDIATED-AT-BOX, OPEN reset recheck | UNKNOWN tailscale snap/auditd update or reimage. New Tailscale incident does not establish reset of kitsubito audit configuration. | Carry named recheck triggers; do not rerun box probes or reopen remediation from symptom similarity. |\n| IR-66 / 3627 | CLOSED / BUILT delayed needles | FIRED historical two-platform rider gates; previous close explicitly reconciled. | Keep closed. No redispatch of two test edits. |\n| IR-67 / 3660 | BUILT explicit integration-suite battery template | FIRED historical IO-PARSER waves and intake template adoption. | Keep built; --bins still must never be described as integration coverage. |\n| IR-68 / 3682 | OPEN ingest-cause investigation | UNKNOWN new PSYCHE_INGEST_FAIL sighting/dedicated probe slot. Planted nonempty index locks did not block ingest. | Carry capture-first; COMMUNE_FAIL now names reason. Do not reinstate refuted index-lock attribution. |\n| IR-69 / 3710 | OPEN #243 conversion/generator/zero-recensus and anchored consumers; original emission fix LANDED | FIRED historical residual recensus: 338 cli sites plus 2 main sites missed. | Keep #243 dependency and separate test-side anchored IDLE/DISPATCH/BUSY/BOUND rider. No redo of landed emission or already-converted delivery sites. IO/USER_INPUT work may touch consumer seam, not automatically satisfy entire residual population. |\n| IR-70 / 3802 | OPEN assembly-point enforcement; witnessed publisher correction shipped | UNKNOWN actual IoBus construction/API or sink-registration touch. #300 USER_INPUT integration makes seam plausible, not established. | Conditional #300/IR-92 companion only if construction/sink seam touched; reuse default_bus and real publish path. No assumption all event work fires construction trigger. |\n| IR-71 / 3829 | OPEN persisted controller-release breadcrumb | UNKNOWN actual controller lifecycle/breadcrumb touch or barrier timeout. #302 freezes and added #251 viewer detach do not themselves prove controller-release failure. | Conditional lifecycle rider after RCA/role distinction; record after persisted clear, not merely detach event. |\n| IR-72 / 3853 | OPEN named-perch/seat custody read surface | UNKNOWN actual roster/status read-model change; #299 explicitly opens roster diagnosis but remedy not selected. | Strong conditional #299 rider if read model changes; inspect holder identity/role without new bare-pid oracle. Do not add a broad RC diagnostic product implicitly. |\n| IR-73 / 3887 | CLOSED / BUILT eight post-checkout floor sites plus docs rereads | FIRED and reconciled prior close with source and IR-86 live catch. | Keep closed; sizing/dependency coupling remains IR-86. |\n| IR-74 / 3911 | OPEN /tmp lifetime bounding | FIRED between-milestone audit opportunity; current Linux cleanup/touch UNKNOWN. Historical 21,643 homes not fresh census. | Linux audit rider with counted bounded cleanup/retention; not a Windows reap claim. |\n| IR-75 / 3925 | OPEN Linux treqs install-or-explicit-omit decision | UNKNOWN new Linux driver touch; current audit opportunity available. Recorded leg 127, not green. | Pair IR-74 box audit; verify state before eventual action, install or explicitly use identical-tree Windows scan coverage. Do not reopen unrelated IR-37. |\n| IR-76 / 3940 | OPEN driver enforcement/compiler-load census; quiet-window documentation exists | FIRED historical driver/workflow arc and overlapping loads; no #304 run authorized. | Compose required quiet-window gate, truthful three-state meter, compiler-load census. Reuse docs/GOLDEN-CI contract from prior close, not competing policy. No contention attribution from overlap alone. |\n| IR-77 / 3984 | OPEN child-entry to ready timing | UNKNOWN boot/ready-stamp or named test-family touch. RC hitches on existing local sessions are not proof of boot delay. | Conditional boot/ready instrumentation rider only if RCA opens seam. Do not retune deadlines. |\n| IR-78 / 4016 | OPEN explicit docs-port silently overridden | FIRED historical both-variable incident; fresh #304 docshost touch UNKNOWN. Current docshost:99 returns zero silently. #301 and adjacent #282 make this a natural conditional rider. | Tiny notice naming both inputs if docshost touched; preserve chosen precedence, no redesign or claimed schtasks coverage. |\n| IR-79 / 4044 | OPEN lifetime-guard adoption, not lack of all reaper machinery | UNKNOWN new common-module touch; historical exposure established. Current common/reap.rs has authenticated primitives, while first-wave four still use local kills/end teardown. | Compose guard adoption starting projindex_writer, projindex_reader, brain_split, brain_respawn_rename; arm before work. Must distinguish unwinding from hard process kill: Drop alone cannot guarantee timeout/SIGKILL cleanup. |\n| IR-80 / 4125 | OPEN residual 12-cell leak union; ENV tool and scoped fixture findings already established | FIRED historical free-slot investigation. Brainproc shell-wrapper fixture cause scoped; direct production spawn excludes that specific escalation, not all causes. | Caller/fixture adoption and classify remaining members with identity/tree evidence. Reuse existing tree-kill machinery; LEAK counts are not improvement rates. |\n| IR-81 / 4407 | OPEN primitive-required identity and core script gate; adapter arm CLOSED | FIRED historical proc/xtask opportunity. Current kill_pid_tree(root:u32) remains expressible; previous close says #285 repaired site, not primitive. | Carry product primitive and test/CI gate separately, coordinating IR-79 adoption. Adapter fix remains closed. Do not reopen daemon-death causality. |\n| IR-82 / 4532 | RULED, predecessor record still UNBUILT | FIRED historical #285/lifecycle opportunity; current daemon.rs directly overwrites pidfile. | Carry product-side read-before-write/one-generation/age/liveness record; do not infer completion from #285. No liveness-semantic change. |\n| IR-83 / 4638 | OPEN reverse-direction witness enforcement; old universal LAN-only remedy SUPERSEDED | FIRED historical missing inbound coverage and applied-layer proof. #297 incident resolved as Tailscale config, not this guard proving execution. | Keep independent real reverse witness, never-ran/vacuous/blocked distinctions. No new box changes; do not require LAN universally. Coordinate IR-89 exact-step acceptance. |\n| IR-84 / 4775 | OPEN enforcement residual; missing timestamp emit half BUILT | FIRED historical unstamped arm/filer lane. Extra stall arithmetic not solved by adding stamps; IR-89 later explains its own scoped helper class. | Reuse stamped instrumentation in relevant pump RCA; conditional every-arm stamp enforcement. Do not re-add timestamp or transfer old helper cause to local RC freezes. |\n| IR-85 / 4825 | OPEN diagnostic arm; caps 80/40 mitigation only | FIRED arm1 opportunity; comparable rerun never completed. Operator-specific arms UNKNOWN. Old sha slowdown means head growth not necessary, not apportioned cause. | Defer comparison until IR-90/76/97 prerequisites; alternate AB/BA with timestamps and passing-output margins. No Defender/torrent/disk diagnosis of #299/#302. |\n| IR-86 / 4985 | OPEN start-capacity derivation and independent docs prerequisites | FIRED golden/workflow arc; 67.4GiB historical footprint exceeds 32GiB start floor; live docs gate skipped. | Workflow rider: measured capacity + end reserve, run footprint reporting, docs depend only on real prerequisites. IR-73 reorder/reread already done. |\n| IR-87 / 5024 | OPEN cross-runner rendezvous/queue clock | FIRED exact recurrence: golden's own PR took Windows; B terminal 07:36:16, A starts 07:48:07. | Schedule/barrier rider includes self-PR interference, not only other lanes. Preserve raw job conclusions beside VOID scoring; 900s symptom not firewall diagnosis. |\n| IR-88 / 5077 | OPEN durable teardown recipe adoption; prebuilt method proven | FIRED historical release-after-reap regrowth; next pool/runbook touch is adoption seam. | Adopt prebuilt release before delete. Do not propose guard inside verb as protection against Cargo rebuild that happens before verb starts. |\n| IR-89 / 5106 | BOX APPLIED, WORKFLOW BUILT/LANDED; exact golden-step acceptance OPEN | FIRED next-golden trigger: later goldens exist. Exact probe-step exercised/skipped/failed remains UNKNOWN in prior close and this sweep. | Reconcile retained step receipts, not implement another probe or renew spent operator permission. Box/ACL reset remains future recheck. #297 TCP bootstrap is distinct from CI UDP probe. |\n| IR-90 / 5262 | OPEN rig resource refusal + failure context | FIRED ripe-now historical 0.018GiB incident. Existing disk-floor is substrate, not both requested placements. | Driver/rig prerequisite: actual temp/target volumes plus mid-failure free-space context. No loaded comparisons until adopted. No inference a monotonic last-tick sample proves sustained recovery. |\n| IR-91 / 5351 | CLOSED root scratch classification/preservation | FIRED historically and shipped with entry. | Keep closed; retain cited artifacts at established paths and manifests. No new root cleanup sweep. |\n| IR-92 / 5405 | OPEN successful inject lacks MSG_IN; docs rider shipped only | FIRED prior product/IO intake, carried explicitly by close. #300 USER_INPUT funnel work is adjacent but a different event contract. | Compose successful-inject observation at single chokepoint, refused inject none; keep Path-A publish-before-present, Path-B allowed bounded log wait and exact-once per msg-id separate. Never reinterpret USER_INPUT requirement as MSG_OUT or replace it with MSG_IN repair. |\n| IR-93 / 5537 | OPEN symbol packaging decision | UNKNOWN actual installer/release packaging touch. #297 bootstrap may touch installer but start-only remedy not yet ruled. | Put size/profile/distribution decision before operator during grill if packaging opens; release-build success is not installed matching-PDB evidence. No silent product-diagnostics expansion. |\n| IR-94 / 5566 | OPEN behavioral census/fail-unclassified gate | FIRED newly added brainread gate; current three-file/name-shaped code corroborated. Mandatory before bounded serve_sync carrier migration; #299/#302 may or may not reach it. | Small tooling rider with explicit population; ensure mandatory dependency if RCA chooses carrier change. Independent gate defect, not established sync or RC cause. |\n| IR-95 / 5596 | OPEN selected poll instrumentation + producer trace; census/diagnostic measurements exist, patch not shipped | FIRED releases#294 comparison. Census estimate 317 blind/321 with slop and 15 outside detector, not exact repo-wide floor. | Prioritize touched diagnostic waits for #299/#302 only if meaningful; no bulk 304-site conversion. Separately version exchange-correlated producer create/retire trace if needed. Preserve budgets and quantify instrumentation scope; final filtered snapshot not continuous absence. |\n| IR-96 / 5851 | OPEN cause-unclassified convoy red | NOT-FIRED on supplied intake for its specific new events: no convoy source touch, candidate golden red, or matched candidate local-HEAVY run established. Previous cheap discriminator remains unrun. | Carry scoped diagnostic continuation after IR-97/90/76. 0/1 candidate CI vs 3/3 diagnostic HEAVY does not exonerate product or isolate instrumentation. |\n| IR-97 / 5875 | OPEN enforce between-run accounting | FIRED prior repeated-run experiment: retained cohort 0/6/12 across B1/B2/B3. Future #304 repeated runs not yet designed/authorized. | Mandatory harness census between runs plus identity-scoped cleanup, not retrospective limitation paragraph. Counts are not measured load; 18 seen vs 15 killed does not prove self-exit. |\n\n## Proposed riders and ordering — proposals only\n1. **Required before a new loaded/repeated diagnostic campaign:** carry prior-close driver package IR-59/60/76/86/87/90/97 (join first scout's IR-31/46). Capacity, correct producer verdict, existing quiet-window contract, partner scheduling and between-run identities are separate acceptance obligations, not one generic preflight. IR-88 is proven recipe adoption; IR-64 remains separate operator decision. No execution authorized by intake.\n2. **Most direct #304 seam candidates:** IR-78 alongside #301/#282 if docshost touched; IR-72 alongside #299 if roster read-model changes; IR-94 mandatory if any chosen stall remedy puts serve_sync on a bounded carrier; IR-95 selective margins for newly investigated waits. IR-93 requires explicit packaging decision if #297 touches installer, not automatic PDB approval.\n3. **IO package:** IR-92 is already owed, useful near #300, but USER_INPUT-triggered file intent/provenance and MSG_IN inject observation are distinct. IR-70 only if construction/API/sinks change. IR-69 anchored-consumer rider separate from #243 conversion/generator work. Do not expand into general IO rewrite.\n4. **Lifecycle test package:** IR-55/63/79/80, joining earlier-range lifetime entries. Reuse common authenticated reaper and existing tree kill rather than introduce duplicate primitives; identity-required API IR-81 is separate product obligation, IR-82 predecessor record remains separate unbuilt rider. Hard-death cleanup must not be sold as ordinary Drop coverage.\n5. **Acceptance-only reconciliation:** IR-83/89 reverse direction witness and exact probe step receipts; no box/config changes. IR-56/62/66/67/73/91 built/closed states stand. IR-57/59/84 implemented halves stand; only adoption/enforcement residuals remain.\n6. **Carry deferred/conditional:** IR-61/65/68/71/77 and untriggered IR-96 event; Linux IR-74/75 at box-audit slot; IR-85 diagnostic continuation behind prerequisites. Small tooling IR-58 may compose with first scout's seam-rider package. No offline owner becomes executing from a historic assignment.\n\n## Current intake evidence that constrains the grill\nRead issue304 and original five issues directly. #304 is BACKLOG, explicitly intake-only; comment adds #251/#282/#288/#230/#49/#267, retains #49 joint-ship ruling with #42, excludes #296 and CUT #303. No broad networking cleanup or new RC diagnostics implicitly authorized.\n- #297 comment records operator-confirmed Tailscale incident resolution and independently observed HTTP200. Separately source-verified missing TCP bootstrap admission remains; do not call that the incident cause or reapply IR-89 CI UDP rules.\n- #299 complete byte-identical 2497-byte roster at 3822/10120/10105ms, rc0, is accepted evidence. Network deadline, coordinator contention and local metadata costs remain alternatives; no partial/empty output workaround.\n- #300 operator correction is authoritative: USER_INPUT, not MSG_OUT. Preserve authenticated controller/user-node origin and committed input/path intent, 24h reference, receiving-agent audience, once-per-input/path helper. Raw PTY bytes do not equal USER_INPUT.\n- #301 demands public docs at node root; no requirement for Served Resources landing.\n- #302 occurs both local and remote on v0.69.0, input and PTY stall together then queued input drains. Tailnet-only or remote-network explanation cannot cover the reported local occurrences without further evidence.\n\n## Verification limits\nRead-only file/search/issue tools only. No validation commands, process probes, builds, tests, formatting, git changes, register edits or board mutations. Required orientation entry points read, plus relevant golden ADR. Prior close results are cited as existing evidence, never fresh execution. Full change-history and golden-step receipts not re-audited; exact unknown trigger/acceptance states remain explicit."},"status":"success"},"isError":false,"timestamp":1789107381171}}
{"type":"custom","customType":"session_exit","data":{"reason":"dispose","kind":"normal","recordedAt":"2026-09-11T06:23:21.182Z"},"id":"80f69636","parentId":"30803859","timestamp":"2026-09-11T06:23:21.182Z"}
