{"type":"title","v":1,"title":"","updatedAt":"2026-09-13T10:31:31.966Z","pad":"                                                                                                                                                                              "}
{"type":"session","version":3,"id":"01a09a52-7b7e-7000-bad7-01c30303edf4","timestamp":"2026-09-13T10:31:31.966Z","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core"}
{"type":"model_change","id":"9814a07f","parentId":null,"timestamp":"2026-09-13T10:31:32.062Z","model":"openai-codex/gpt-6-astra","resolvedModelIsFallback":false}
{"type":"session_init","id":"5d5abb40","parentId":"9814a07f","timestamp":"2026-09-13T10:31:32.066Z","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- Bash: `bash`\n- Edit: `edit`\n- Eval: `eval`\n- Glob: `glob`\n- Grep: `grep`\n- Task: `task`\n- Hub: `hub`\n- Web Search: `web_search`\n- Write: `write`\n- Submit Result: `yield`\n# xd:// Tool Devices\nWrite JSON args as `content` to `xd://<tool>` via `write`. Invalid args return schema in error → fix/retry.\n## ast_edit — AST Edit\n\nStructural AST-aware rewrites via ast-grep. Use for codemods where text replace is unsafe. Mixed-language paths are fine: each file is parsed in its own language, and a pattern only rewrites files it parses in.\n\n- Metavariables in `pat` (`$A`, `$$$ARGS`) substitute into `out`.\n- **Patterns match AST structure, not text.** `$NAME` = one node; `$_` = unbound; `$$$NAME` = zero-or-more.\n  - Use `$$$NAME`, NOT `$$NAME` (invalid). Names UPPERCASE, whole node — partial like `prefix$VAR` fails.\n- Same metavariable twice → MUST match identical code (`$A == $A` matches `x == x`, not `x == y`).\n- Rewrite patterns MUST parse as single AST node. Non-standalone → wrap: `class $_ { … }`.\n- TS: tolerate annotations — `async function $NAME($$$ARGS): $_ { $$$BODY }`. Delete with empty `out`: `{\"pat\":\"console.log($$$)\",\"out\":\"\"}`.\n- 1:1 substitution — no splitting/merging captures.\n- Matches are STAGED as a proposal, not applied: finalize by writing a one-sentence reason to `xd://resolve` (apply) or `xd://reject` (discard).\n- Parse issues → malformed rewrite, not clean no-op. For one-off text edits, prefer the Edit tool.\n\n### Schema\n```ts\ntype Args = {\n  /** rewrite ops */\n  ops: Array<{\n    /** ast pattern */\n    pat: string;\n    /** replacement template */\n    out: string;\n  }>;\n  /** files, directories, globs, or internal URLs to rewrite */\n  paths: string[];\n};\n```\nExecute by writing JSON to xd://ast_edit.\n\n## debug — Debug\n\nDebugger access. Prefer over bash for program state, breakpoints, stepping, or thread inspection.\nOnly one active session at a time. `program` is a target path, not a shell command.\nDirectories need a directory-capable adapter (e.g. `dlv`).\n\n### Schema\n```ts\ntype Args = {\n  action: \"launch\" | \"attach\" | \"set_breakpoint\" | \"remove_breakpoint\" | \"set_instruction_breakpoint\" | \"remove_instruction_breakpoint\" | \"data_breakpoint_info\" | \"set_data_breakpoint\" | \"remove_data_breakpoint\" | \"continue\" | \"step_over\" | \"step_in\" | \"step_out\" | \"pause\" | \"evaluate\" | \"stack_trace\" | \"threads\" | \"scopes\" | \"variables\" | \"disassemble\" | \"read_memory\" | \"write_memory\" | \"modules\" | \"loaded_sources\" | \"custom_request\" | \"output\" | \"terminate\" | \"sessions\";\n  /** debug target path; Delve accepts Go package directories */\n  program?: string;\n  /** program arguments */\n  args?: string[];\n  /** configured adapter id (gdb, lldb-dap, debugpy, dlv, rdbg, or dap.json entry) */\n  adapter?: string;\n  cwd?: string;\n  /** source file */\n  file?: string;\n  /** source line */\n  line?: number;\n  /** function name */\n  function?: string;\n  /** variable or data name */\n  name?: string;\n  /** breakpoint condition */\n  condition?: string;\n  hit_condition?: string;\n  /** expression to evaluate */\n  expression?: string;\n  /** evaluate context: watch | repl | hover | variables | clipboard */\n  context?: string;\n  frame_id?: number;\n  /** scope variables reference */\n  scope_id?: number;\n  /** variable reference */\n  variable_ref?: number;\n  /** process id for attach */\n  pid?: number;\n  /** remote attach port */\n  port?: number;\n  /** remote attach host */\n  host?: string;\n  /** max stack frames */\n  levels?: number;\n  /** memory reference or address */\n  memory_reference?: string;\n  instruction_reference?: string;\n  instruction_count?: number;\n  instruction_offset?: number;\n  /** bytes to read */\n  count?: number;\n  /** base64 memory payload */\n  data?: string;\n  /** data breakpoint id */\n  data_id?: string;\n  access_type?: \"read\" | \"write\" | \"readWrite\";\n  /** custom dap request command */\n  command?: string;\n  /** custom request arguments */\n  arguments?: Record<string, unknown>;\n  offset?: number;\n  resolve_symbols?: boolean;\n  allow_partial?: boolean;\n  start_module?: number;\n  module_count?: number;\n  /** per-request timeout seconds */\n  timeout?: number;\n};\n```\nExecute by writing JSON to xd://debug.\n\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- User says `parallel` or `parallelize` → MUST use `task` subagents; parallel tool calls insufficient.\n\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- Surgical edits → `edit`.\n- Create/overwrite → `write`.\n\n- Regex search/target location → `grep`, not shell `grep`, `rg`, `awk`.\n- Structure mapping/globbing → `glob`, not `ls **/*.ext` or `fd`.\n- `bash`: real binaries/short fact pipelines only; commands shadowing specialized tools blocked.\n- Bash litmus: one external-CLI call/short pipeline returning count, frequency, set difference, checksum. For merely moving, paging, trimming fetchable bytes: tool.\n\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\n# AST\nSHOULD use syntax-aware tools before text hacks:\n\n- Codemods → `ast_edit`.\n\n# Delegation\nInline first. Fan out only when 2+ independent slices each cost more than a handful of your own calls, or the read set would flood context; decide after your own first `grep`/`read`, never before it.\n- NEVER open with a scout. Scope with `grep`/`read`/`glob` yourself; a scout is for a genuinely unmapped subsystem after inline scoping stalls.\n- NEVER delegate one slice. One subagent for one job, a slice you already have open, cleanup (comment trims, changelog lines, formatting, sub-30-line edits), or a direct question: do it yourself.\n- NEVER babysit. Spawn → keep working → read the result. Steering a lone agent through `hub` send/wait costs more than the work.\n## Delegation gates\n- **Own decomposition.** Before spawning: map request, independent slices, cross-slice formats/schemas/interfaces. Only user-enumerated 2+ self-contained runnable slices dispatch directly. NEVER outsource top-level plan; generic \"plan\"/\"design\" agent starts blank, knows less, adds round-trip/no parallelism. Slice-local design and requested competing plans/reviews allowed.\n- **Real concurrency.** Fan exactly to genuine decomposition, one `tasks[]` array. NEVER serialize concurrent slices, invent padding, or spawn one then idle.\n- **User intent.** Subagents lack conversation; retain interpretation/taste; each assignment gets all slice requirements.\n- **Cap:** At most 32 subagents concurrently; excess queues. `tasks[]` batch > 32 delays results: stay within cap.\n- **Dependencies only.** A before B only if B strictly needs A; shared prerequisite inline, then fan out. “Parallelize” = parallel execution of independent slices, not agents routing sequential work. Small missing piece: run parallel; B asks A via `hub`!\n\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    - **Web UI** → use `browser.open` to get a tab handle, its direct helpers for common actions, `tab.run` for custom JavaScript, and `tab.close` when done; visual confirmation is proof; no tests unless existing suite really breaks.\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\nWorker agent: delegated tasks.\n\nTools: FULL access (edit, write, bash, grep, read, etc.); MUST use as needed to complete task.\nMUST hyperfocus assigned task; NEVER deviate.\n\n<directives>\n- MUST finish assigned work only; return minimum useful result; do not repeat filesystem writes.\n- SHOULD edit files, run commands, create files when task requires.\n- MUST concise; NEVER filler, repetition, tool transcripts. User cannot see you; result: notes for yourself.\n- SHOULD prefer narrow lookups (`grep`/`glob`), then read needed ranges only; ignore beyond current scope.\n- AVOID full-file reads unless necessary.\n- SHOULD prefer editing existing files over creating new files.\n- NEVER create documentation files (`*.md`) unless explicitly requested.\n- MUST follow assignment and instructions.\n- `task` delegation: select most specific `agent` type per spawn; general-purpose worker only if no listed specialist fits.\n</directives>\n\n§ Context\n# Goal\nImplement releases#300 in C:/Users/decid/Documents/projects/spt-core/.worktrees/300-input-acceptance, branch feat/300-input-acceptance off f4e7635c. Section 8 docs/INPUT-PROVENANCE-CONTRACT.md is authoritative (overrides historical token/adapter draft). Core-only, no adapter changes/tokens. Every USER_INPUT receipt binds broker-owned live remote controller before async work; exact core delivery bytes excluded; payload/session dedup while live reference, no TTL extension; existing live-reference serving 24h/audience, missing file silent, other non-grants named.\n# Constraints\nSkip ALL validation: no build/test/lint/formatter, no commits. Parent runs targeted verification once. Use LSP references before exported changes if possible (currently requests return empty despite known callers; report/fallback). Own only assigned files/regions. Parent is integration owner and handles broker report dispatch, msg.rs, brain.rs, API receipt ingestion, docs/manifest. No source changes outside this worktree. No product fleet commands.\n# Contract\nArchitecture uses EXISTING rc authenticated controller stream, not separate WEB requests. Net protocol owner (RemoteInputServing) defines in spt-net/src/net/attach.rs: InputPathRequest { receipt_id: String, session: String, paths: Vec<String>, received_at_ms: u64 }; InputPathResult { path: String, outcome: InputPathOutcome }; InputPathOutcome enum Registered { url: String, expires_at_ms: u64 }, Missing, Declined { reason: String }; InputPathReply { receipt_id: String, results: Vec<InputPathResult> }; all Serialize Deserialize Clone Debug. Add AttachRecord::InputPaths { request: InputPathRequest } and ::InputPathsReply { reply: InputPathReply }. Broker IPC msg constants parent owns: KIND_USER_INPUT_PATHS = \"user-input-paths\" (envelope payload InputPathRequest), KIND_USER_INPUT_PATHS_REPLY = \"user-input-paths-reply\" (InputPathReply). Parent handles broker routing request only to receipt-bound controller and validates replies. Parent adds Brain::complete_input_paths(&InputPathReply) sending reply IPC; attach serve worker calls it when reply arrives on same stream. Broker detects delivery exclusion via InputWriter::delivery_matches(payload: &[u8]) -> bool method supplied by DeliveryRecording. Parent will NOT edit broker.rs until DeliveryRecording reports done, but may read; msg.rs/brain.rs are parent-owned.\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 `DeliveryRecording`. Currently visible peers:\n- `RemoteInputServing` — task (sub, running)\n- `RemoteServeAuthority` — scout (sub, running): Reading exact stream match\n- `Main` — main (main, running)\n- `DeliveryCustody` — scout (sub, idle)\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- Use `type: string` for a terminal result; if data is omitted, your last assistant turn becomes the raw final result.\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`.\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\nbroker.rs InputRecord/InputWriter, enqueue_text_chunked, drive_one_sequence, injection-worker sequencing sections ONLY; new deliverybytes.rs if needed and lib.rs module declaration only coordinated with parent. Source facts: agent://DeliveryCustody. No report dispatch edits.\n# Change\nImplement actual successful physical delivery-byte custody per hosted session. Distinguish translated delivery Text/Key from controller bytes (dispatch_input and flush_inject_floor) and settle probes. Keep nonblocking bounded FIFO and single physical writer. Tag delivery records, track successful writes, aggregate text chunks per delivery; do not infer from payload shapes. Expose InputWriter::delivery_matches(&self, payload: &[u8])->bool. Exact payload matching may strip only framing YOUR core added or distinguish Key vs Text at source; do not normalize arbitrary reported text. Need track completed/pending text so report triggered by Enter can see actual text already written; failure/drop must not claim full payload landed. Discuss narrow physical-write-completion race honestly. Bound memory without evicting live evidence silently: prefer hashes for completed payloads, session lifetime; if quota, fail closed with named reason rather than origin grant. Capture text-only candidates matching multiline exact reported payload; core key bytes provenance retained or distinguish as controls. All actual delivery sites in current checkout Text/Key, commits, and buffered-controller flush accounted. Add focused behavior regression cells with [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT], no test wording/source assertions. Existing InputWriter tests update only if contract compile breaks.\n# Acceptance\nHuman controller/typeahead never classified as core injection; failed queued writes do not certify omitted bytes; successful split text delivery matches exact report even before logical Commit; unknown human payload does not match; altered same-shape payload does not match. Return exact edits and test names. Skip all validation; parent owns broker.rs after you finish.","tools":["read","bash","edit","eval","glob","grep","task","hub","web_search","write","yield","ast_edit","debug","spt_checkpoint"],"agent":"task","resolvedModel":"openai-codex/gpt-6-astra","readOnly":false,"spawns":"*"}
{"type":"message","id":"857d8066","parentId":"5d5abb40","timestamp":"2026-09-13T10:31:32.161Z","message":{"role":"user","content":[{"type":"text","text":"Complete assignment thoroughly:\n\n# Target\nbroker.rs InputRecord/InputWriter, enqueue_text_chunked, drive_one_sequence, injection-worker sequencing sections ONLY; new deliverybytes.rs if needed and lib.rs module declaration only coordinated with parent. Source facts: agent://DeliveryCustody. No report dispatch edits.\n# Change\nImplement actual successful physical delivery-byte custody per hosted session. Distinguish translated delivery Text/Key from controller bytes (dispatch_input and flush_inject_floor) and settle probes. Keep nonblocking bounded FIFO and single physical writer. Tag delivery records, track successful writes, aggregate text chunks per delivery; do not infer from payload shapes. Expose InputWriter::delivery_matches(&self, payload: &[u8])->bool. Exact payload matching may strip only framing YOUR core added or distinguish Key vs Text at source; do not normalize arbitrary reported text. Need track completed/pending text so report triggered by Enter can see actual text already written; failure/drop must not claim full payload landed. Discuss narrow physical-write-completion race honestly. Bound memory without evicting live evidence silently: prefer hashes for completed payloads, session lifetime; if quota, fail closed with named reason rather than origin grant. Capture text-only candidates matching multiline exact reported payload; core key bytes provenance retained or distinguish as controls. All actual delivery sites in current checkout Text/Key, commits, and buffered-controller flush accounted. Add focused behavior regression cells with [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT], no test wording/source assertions. Existing InputWriter tests update only if contract compile breaks.\n# Acceptance\nHuman controller/typeahead never classified as core injection; failed queued writes do not certify omitted bytes; successful split text delivery matches exact report even before logical Commit; unknown human payload does not match; altered same-shape payload does not match. Return exact edits and test names. Skip all validation; parent owns broker.rs after you finish."}],"attribution":"agent","timestamp":1789295492067}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_QsMYrmRbCFaJSdq7Ij2FRS4V|fc_0b12df87254bb4e6016aa67b862b7887d1909e4d97990d76cd","toolName":"read","startedAt":"2026-09-13T10:31:34.821Z","args":{"path":"agent://DeliveryCustody"},"intent":"Reading source custody findings"},"id":"acbcef98","parentId":"857d8066","timestamp":"2026-09-13T10:31:34.821Z"}
{"type":"message","id":"7830fb42","parentId":"acbcef98","timestamp":"2026-09-13T10:31:34.822Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_QsMYrmRbCFaJSdq7Ij2FRS4V|fc_0b12df87254bb4e6016aa67b862b7887d1909e4d97990d76cd","name":"read","arguments":{"i":"Reading source custody findings","path":"agent://DeliveryCustody"},"intent":"Reading source custody findings"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":17958,"output":28,"cacheRead":0,"cacheWrite":0,"totalTokens":17986,"cost":{"input":0.17958000000000002,"output":0.0014,"cacheRead":0,"cacheWrite":0,"total":0.18098000000000003}},"stopReason":"toolUse","timestamp":1789295492159,"responseId":"resp_0b12df87254bb4e6016aa67b84a06887d1a263d16149b8ec75","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0b12df87254bb4e6016aa67b862b7887d1909e4d97990d76cd","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading source custody findings\",\"path\":\"agent://DeliveryCustody\"}","call_id":"call_QsMYrmRbCFaJSdq7Ij2FRS4V","internal_chat_message_metadata_passthrough":{"create_time":1789295492.886602,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":2658.6668000000063,"ttft":2029.78820000001,"completedAt":1789295494819,"contextSnapshot":{"promptTokens":17958,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"credential_pin","id":"8724d938","parentId":"7830fb42","timestamp":"2026-09-13T10:31:34.822Z","provider":"openai-codex","hash":"1a3c10d7bc41d381cab1511db604bc2637dfcfc63796a890d8b5ee152859e1cb"}
{"type":"message","id":"d6395143","parentId":"8724d938","timestamp":"2026-09-13T10:31:34.867Z","message":{"role":"toolResult","toolCallId":"call_QsMYrmRbCFaJSdq7Ij2FRS4V|fc_0b12df87254bb4e6016aa67b862b7887d1909e4d97990d76cd","toolName":"read","content":[{"type":"text","text":"{\n  \"summary\": \"Own-delivery custody should be attached to the existing per-session InputWriter FIFO and finalized only after successful physical writes, with translation-origin tags applied before enqueue. Current checkout has KeyCmd::Text, not Write, and no separate typeahead/post-commit delivery path. Controller-floor flushes must remain explicitly non-delivery. No files changed or validation commands run.\",\n  \"files\": [\n    {\n      \"path\": \".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs\",\n      \"description\": \"HostedSession/InputWriter and physical writer seam: 4109–4277; controller floor flush: 4588–4598; translation construction: 4630–4697; settle probe: 4757–4783; text chunking: 4843–4859; sequence application: 4884–4944; worker/re-drive: 4952–5182; writer construction: 8314–8320; controller input: 8746–8848.\"\n    },\n    {\n      \"path\": \".worktrees/300-input-acceptance/crates/spt-daemon/src/translation.rs\",\n      \"description\": \"Command forms 64–79; exact key-to-byte mapping 93–155; controller-only InjectFloor state 169–217; stdout JSON decode 276–293; binary stdin write (not PTY delivery) 309–317.\"\n    },\n    {\n      \"path\": \".worktrees/300-input-acceptance/crates/spt-term/src/pty.rs\",\n      \"description\": \"Shared writer handle 191–196 and physical SessionSurface::write_input 236–240 establish locking and success/partial-failure limits.\"\n    },\n    {\n      \"path\": \".worktrees/300-input-acceptance/docs/INPUT-PROVENANCE-CONTRACT.md\",\n      \"description\": \"Section 8 explicitly requires exclusion using bytes core actually wrote, not payload shape.\"\n    }\n  ],\n  \"architecture\": \"Translation commands and controller input share one bounded, nonblocking InputWriter FIFO. The lone broker input_writer drains raw Vec<u8> records into PtySession::write_input; origin and sequence metadata are currently absent. Translation floor buffering separates controller bytes during injection, but does not retain delivery history. The InputWriter survives translation respawn and therefore is the minimal session-lifetime custody owner.\",\n  \"report\": \"## Concrete minimal recording seam\\n\\nChange the internal InputRecord representation from raw Vec<u8> to a tagged record identifying ordinary/controller/control bytes versus translation-delivery bytes, with a per-delivery/attempt identity and sequence boundaries where needed. Keep the existing FIFO and single physical writer. Attach a small session-local shared delivery ledger to InputWriter, accessible through HostedSession.input; do not put it on Translation, because build_translation replaces that child/state on respawn while reusing the existing InputWriter (4630–4697).\\n\\nTag delivery at drive_one_sequence's Key and Text branches. Preserve exact ordered bytes, including text split across chunk records and mapped key bytes; retain Text-versus-Key information so semantic candidates can be related to their actual byte source rather than guessing from event-envelope shape. In input_writer, record successful writes only after SessionSurface::write_input returns Ok. A dropped enqueue, disconnected writer, or failed write must not create a claim that the whole delivery landed. Propagate/retain an attempt-invalid marker if any tagged chunk fails enqueue or write; otherwise later successful chunks must not accidentally certify the omitted full payload. Existing bool enqueue results are currently ignored at all production callsites.\\n\\nA commit marker must be ordered in the same FIFO if used to finalize a full sequence, before flushing controller input. It writes no PTY bytes. Do not silently treat a dropped commit marker as a completed record. However, commit-only publication has a receipt race: Enter can cause USER_INPUT before the binary emits commit or the writer processes its marker. Successful text/submit boundaries need to become visible incrementally rather than relying solely on a future commit. There remains a narrower interval between a physical write making input visible to the harness and the writer publishing successful completion; resolving that without delaying input/receipt is not proven by the existing API. Do not mark enqueued bytes as successful to conceal this interval.\\n\\n## Every production broker enqueue/write site\\n\\n| Location | Bytes | Custody |\\n|---|---|---|\\n| broker.rs:4907–4910, drive_one_sequence Key | key_to_bytes result | Translation delivery; record exact successful bytes with sequence identity. Includes Enter/CR and choreography/control keys. Unknown key emits nothing. |\\n| broker.rs:4912–4916 → 4843–4846, Text / enqueue_text_chunked | UTF-8 text split by chunk_text | Translation delivery; accumulate successful ordered chunks without assuming one chunk equals one submission. |\\n| broker.rs:4923–4926, Commit | None | Logical terminator only; currently any parsed Commit, including commit:false, ends the sequence. Does not establish successful enqueue/write. |\\n| broker.rs:4593, flush_inject_floor | Controller bytes buffered while floor held | Never own delivery. Same helper runs after commit, timeout, disconnect, and event-send failure. |\\n| broker.rs:4769, settle_before_inject | INJECT_SETTLE_PROBE | Core terminal readiness control, not peer-message text; keep separate from delivery candidates. |\\n| broker.rs:8818, dispatch_input journaled branch | Decoded InputReq bytes | Ordinary input, not own translation delivery. Includes human, RC, shell/system and legacy paths. |\\n| broker.rs:8843, dispatch_input unjournaled branch | Decoded InputReq bytes | Same non-delivery classification. |\\n| broker.rs:4274–4277, input_writer | All accepted FIFO records | Only broker physical write call; classify before this convergence, confirm success here. |\\n\\nThe broker's single write_input caller is not the sole physical writer in all of spt-term: PtySession::shared_writer (pty.rs:191–196) is cloned for drain DSR auto-answer. Those terminal replies serialize on the same underlying writer but are not peer-message delivery. Hooking all low-level writer traffic would capture unrelated protocol bytes and lose origin discrimination.\\n\\n## Post-commit, release, typeahead and retry\\n\\nIn this inspected checkout, KeyCmd has Key, Text, Delay, Commit (translation.rs:64–79); there is no Write variant. Targeted search followed by a broader crates search found no typeahead/post_commit implementation. The available equivalent is InjectFloor.buffer: it contains controller-origin input exclusively, taken by take_or_release in a loop and enqueued after the injected commands (translation.rs:169–217; broker.rs:4588–4598). This is human/input custody, not an extension of the core delivery.\\n\\nAfter Commit, drive_one_sequence immediately flushes/releases and returns. It does not apply remaining commands as post-commit delivery. run_inject_worker drains/discards any pending cmd_rx records before the next event (5002–5005). An actual echo retry calls drive_one_sequence again (5019–5068), so instrumenting its two translated byte branches covers re-drive without another write seam. Timed-out/disconnected attempts may already have written bytes; committed status alone does not describe whether a submission occurred. A queued EVENT or successful child.send is even earlier and is not delivery proof.\\n\\n## Existing normalization and state\\n\\nThere is no delivery-to-USER_INPUT normalizer in these target files. Text passes from serde JSON string to text.into_bytes unchanged; chunk_text preserves concatenation exactly. TranslationChild trims the outer JSON line, not the decoded text value (276–293). key_to_bytes trims/lowercases the key name and maps enter/return/cr to CR, newline/lf to LF, named terminal keys to CSI and ctrl chords to control bytes (93–155). These are command decoding rules, not evidence that a reported payload retained terminal framing.\\n\\nBracketed paste wrapping is explicitly deferred in broker.rs:694–696 and 750–754. A broader search finds wrap_bracketed_paste in crates/spt/src/rc.rs:651–667, but that wraps controller clipboard input and is not a delivery normalizer. No existing stripping of ESC[200~/ESC[201~ or CR-to-LF conversion was found in the delivery path. Any new exact-byte-derived report comparison normalization must be stated as an added comparison rule, not reused existing behavior. Do not broadly trim whitespace, strip payload-looking wrappers or match a prefix.\\n\\nThe existing sent_text Vec (4899, 4915; SeqOutcome at 4865–4875) concatenates Text commands before enqueue, excludes all Keys, and is used solely for echo checking. It is therefore neither a complete actual byte record nor proof of successful writes. echo_verified (781–786) checks only a bounded text head in output; echo_verify_after (4812–4835) may assume success when output is absent. Neither is suitable authority for full-byte custody. InputWriter.backpressure only reports queue pressure. InjectFloor holds a boolean and controller Vec. Worker-local respooled_once/strikes serve retry bookkeeping, not provenance.\\n\\n## Lock ordering\\n\\n- dispatch_input clones input/translation/log under sessions, releases sessions, then checks controller under log, releases log, sends the content-free child ping, and separately locks floor for buffer_if_held (8746–8804).\\n- flush_inject_floor calls take_or_release under floor and releases it before enqueue (4588–4598). Preserve this; never record these bytes as delivery just because they were emitted by the inject worker.\\n- drive_one_sequence opens floor under a short lock, releases it before child.send and all enqueue operations. TranslationChild::send holds only its stdin mutex during the binary write.\\n- input_writer currently takes no sessions/log/floor lock. PtySession::write_input takes its private writer mutex, executes write_all and flush, and returns (pty.rs:236–240).\\n- Recommended ledger locking is after the physical call returns and only for short in-memory updates; lookup clones the session's input handle before consulting the ledger. Avoid acquiring sessions/log/floor from the writer and never hold a ledger mutex across a potentially wedged PTY write.\\n\\n## Proof limits\\n\\nThis is static source mapping only, as requested; no builds/tests/validation or runtime experiments were performed. write_input Ok establishes write_all plus flush completed, not that the terminal/harness accepted the same semantic payload. An Err can occur after a partial write, or after write_all succeeded but flush failed; the current Result exposes no committed byte count. Exact custody for those partial/error bytes requires a deeper write-accounting API, not a broker-only assumption. Terminal editing keys, stash/restore, bracketed paste interpretation and downstream text transformations can make raw stream bytes differ from reported submission text. Full command-byte recording preserves evidence but is not a general terminal editor emulator. Byte equality also cannot distinguish a later human deliberately submitting text identical to a prior core delivery; session-local exact-byte exclusion has that intrinsic ceiling. No adapter changes or token mechanism are necessary for the recommended recording seam.\"\n}"}],"details":{"resolvedPath":"C:\\Users\\decid\\.omp\\agent\\sessions\\-Documents-projects-spt-core\\2026-09-13T10-23-45-921Z_01a09a4b-5f01-7000-9118-23ce74a49636\\DeliveryCustody.md","contentType":"text/markdown","totalLines":23,"displayContent":{"text":"{\n  \"summary\": \"Own-delivery custody should be attached to the existing per-session InputWriter FIFO and finalized only after successful physical writes, with translation-origin tags applied before enqueue. Current checkout has KeyCmd::Text, not Write, and no separate typeahead/post-commit delivery path. Controller-floor flushes must remain explicitly non-delivery. No files changed or validation commands run.\",\n  \"files\": [\n    {\n      \"path\": \".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs\",\n      \"description\": \"HostedSession/InputWriter and physical writer seam: 4109–4277; controller floor flush: 4588–4598; translation construction: 4630–4697; settle probe: 4757–4783; text chunking: 4843–4859; sequence application: 4884–4944; worker/re-drive: 4952–5182; writer construction: 8314–8320; controller input: 8746–8848.\"\n    },\n    {\n      \"path\": \".worktrees/300-input-acceptance/crates/spt-daemon/src/translation.rs\",\n      \"description\": \"Command forms 64–79; exact key-to-byte mapping 93–155; controller-only InjectFloor state 169–217; stdout JSON decode 276–293; binary stdin write (not PTY delivery) 309–317.\"\n    },\n    {\n      \"path\": \".worktrees/300-input-acceptance/crates/spt-term/src/pty.rs\",\n      \"description\": \"Shared writer handle 191–196 and physical SessionSurface::write_input 236–240 establish locking and success/partial-failure limits.\"\n    },\n    {\n      \"path\": \".worktrees/300-input-acceptance/docs/INPUT-PROVENANCE-CONTRACT.md\",\n      \"description\": \"Section 8 explicitly requires exclusion using bytes core actually wrote, not payload shape.\"\n    }\n  ],\n  \"architecture\": \"Translation commands and controller input share one bounded, nonblocking InputWriter FIFO. The lone broker input_writer drains raw Vec<u8> records into PtySession::write_input; origin and sequence metadata are currently absent. Translation floor buffering separates controller bytes during injection, but does not retain delivery history. The InputWriter survives translation respawn and therefore is the minimal session-lifetime custody owner.\",\n  \"report\": \"## Concrete minimal recording seam\\n\\nChange the internal InputRecord representation from raw Vec<u8> to a tagged record identifying ordinary/controller/control bytes versus translation-delivery bytes, with a per-delivery/attempt identity and sequence boundaries where needed. Keep the existing FIFO and single physical writer. Attach a small session-local shared delivery ledger to InputWriter, accessible through HostedSession.input; do not put it on Translation, because build_translation replaces that child/state on respawn while reusing the existing InputWriter (4630–4697).\\n\\nTag delivery at drive_one_sequence's Key and Text branches. Preserve exact ordered bytes, including text split across chunk records and mapped key bytes; retain Text-versus-Key information so semantic candidates can be related to their actual byte source rather than guessing from event-envelope shape. In input_writer, record successful writes only after SessionSurface::write_input returns Ok. A dropped enqueue, disconnected writer, or failed write must not create a claim that the whole delivery landed. Propagate/retain an attempt-invalid marker if any tagged chunk fails enqueue or write; otherwise later successful chunks must not accidentally certify the omitted full payload. Existing bool enqueue results are currently ignored at all production callsites.\\n\\nA commit marker must be ordered in the same FIFO if used to finalize a full sequence, before flushing controller input. It writes no PTY bytes. Do not silently treat a dropped commit marker as a completed record. However, commit-only publication has a receipt race: Enter can cause USER_INPUT before the binary emits commit or the writer processes its marker. Successful text/submit boundaries need to become visible incrementally rather than relying solely on a future commit. There remains a narrower interval between a physical write making input visible to the harness and the writer publishing successful completion; resolving that without delaying input/receipt is not proven by the existing API. Do not mark enqueued bytes as successful to conceal this interval.\\n\\n## Every production broker enqueue/write site\\n\\n| Location | Bytes | Custody |\\n|---|---|---|\\n| broker.rs:4907–4910, drive_one_sequence Key | key_to_bytes result | Translation delivery; record exact successful bytes with sequence identity. Includes Enter/CR and choreography/control keys. Unknown key emits nothing. |\\n| broker.rs:4912–4916 → 4843–4846, Text / enqueue_text_chunked | UTF-8 text split by chunk_text | Translation delivery; accumulate successful ordered chunks without assuming one chunk equals one submission. |\\n| broker.rs:4923–4926, Commit | None | Logical terminator only; currently any parsed Commit, including commit:false, ends the sequence. Does not establish successful enqueue/write. |\\n| broker.rs:4593, flush_inject_floor | Controller bytes buffered while floor held | Never own delivery. Same helper runs after commit, timeout, disconnect, and event-send failure. |\\n| broker.rs:4769, settle_before_inject | INJECT_SETTLE_PROBE | Core terminal readiness control, not peer-message text; keep separate from delivery candidates. |\\n| broker.rs:8818, dispatch_input journaled branch | Decoded InputReq bytes | Ordinary input, not own translation delivery. Includes human, RC, shell/system and legacy paths. |\\n| broker.rs:8843, dispatch_input unjournaled branch | Decoded InputReq bytes | Same non-delivery classification. |\\n| broker.rs:4274–4277, input_writer | All accepted FIFO records | Only broker physical write call; classify before this convergence, confirm success here. |\\n\\nThe broker's single write_input caller is not the sole physical writer in all of spt-term: PtySession::shared_writer (pty.rs:191–196) is cloned for drain DSR auto-answer. Those terminal replies serialize on the same underlying writer but are not peer-message delivery. Hooking all low-level writer traffic would capture unrelated protocol bytes and lose origin discrimination.\\n\\n## Post-commit, release, typeahead and retry\\n\\nIn this inspected checkout, KeyCmd has Key, Text, Delay, Commit (translation.rs:64–79); there is no Write variant. Targeted search followed by a broader crates search found no typeahead/post_commit implementation. The available equivalent is InjectFloor.buffer: it contains controller-origin input exclusively, taken by take_or_release in a loop and enqueued after the injected commands (translation.rs:169–217; broker.rs:4588–4598). This is human/input custody, not an extension of the core delivery.\\n\\nAfter Commit, drive_one_sequence immediately flushes/releases and returns. It does not apply remaining commands as post-commit delivery. run_inject_worker drains/discards any pending cmd_rx records before the next event (5002–5005). An actual echo retry calls drive_one_sequence again (5019–5068), so instrumenting its two translated byte branches covers re-drive without another write seam. Timed-out/disconnected attempts may already have written bytes; committed status alone does not describe whether a submission occurred. A queued EVENT or successful child.send is even earlier and is not delivery proof.\\n\\n## Existing normalization and state\\n\\nThere is no delivery-to-USER_INPUT normalizer in these target files. Text passes from serde JSON string to text.into_bytes unchanged; chunk_text preserves concatenation exactly. TranslationChild trims the outer JSON line, not the decoded text value (276–293). key_to_bytes trims/lowercases the key name and maps enter/return/cr to CR, newline/lf to LF, named terminal keys to CSI and ctrl chords to control bytes (93–155). These are command decoding rules, not evidence that a reported payload retained terminal framing.\\n\\nBracketed paste wrapping is explicitly deferred in broker.rs:694–696 and 750–754. A broader search finds wrap_bracketed_paste in crates/spt/src/rc.rs:651–667, but that wraps controller clipboard input and is not a delivery normalizer. No existing stripping of ESC[200~/ESC[201~ or CR-to-LF conversion was found in the delivery path. Any new exact-byte-derived report comparison normalization must be stated as an added comparison rule, not reused existing behavior. Do not broadly trim whitespace, strip payload-looking wrappers or match a prefix.\\n\\nThe existing sent_text Vec (4899, 4915; SeqOutcome at 4865–4875) concatenates Text commands before enqueue, excludes all Keys, and is used solely for echo checking. It is therefore neither a complete actual byte record nor proof of successful writes. echo_verified (781–786) checks only a bounded text head in output; echo_verify_after (4812–4835) may assume success when output is absent. Neither is suitable authority for full-byte custody. InputWriter.backpressure only reports queue pressure. InjectFloor holds a boolean and controller Vec. Worker-local respooled_once/strikes serve retry bookkeeping, not provenance.\\n\\n## Lock ordering\\n\\n- dispatch_input clones input/translation/log under sessions, releases sessions, then checks controller under log, releases log, sends the content-free child ping, and separately locks floor for buffer_if_held (8746–8804).\\n- flush_inject_floor calls take_or_release under floor and releases it before enqueue (4588–4598). Preserve this; never record these bytes as delivery just because they were emitted by the inject worker.\\n- drive_one_sequence opens floor under a short lock, releases it before child.send and all enqueue operations. TranslationChild::send holds only its stdin mutex during the binary write.\\n- input_writer currently takes no sessions/log/floor lock. PtySession::write_input takes its private writer mutex, executes write_all and flush, and returns (pty.rs:236–240).\\n- Recommended ledger locking is after the physical call returns and only for short in-memory updates; lookup clones the session's input handle before consulting the ledger. Avoid acquiring sessions/log/floor from the writer and never hold a ledger mutex across a potentially wedged PTY write.\\n\\n## Proof limits\\n\\nThis is static source mapping only, as requested; no builds/tests/validation or runtime experiments were performed. write_input Ok establishes write_all plus flush completed, not that the terminal/harness accepted the same semantic payload. An Err can occur after a partial write, or after write_all succeeded but flush failed; the current Result exposes no committed byte count. Exact custody for those partial/error bytes requires a deeper write-accounting API, not a broker-only assumption. Terminal editing keys, stash/restore, bracketed paste interpretation and downstream text transformations can make raw stream bytes differ from reported submission text. Full command-byte recording preserves evidence but is not a general terminal editor emulator. Byte equality also cannot distinguish a later human deliberately submitting text identical to a prior core delivery; session-local exact-byte exclusion has that intrinsic ceiling. No adapter changes or token mechanism are necessary for the recommended recording seam.\"\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]},"meta":{"source":{"type":"internal","value":"agent://DeliveryCustody"}}},"isError":false,"timestamp":1789295494865}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_BOsuJ13p3FYbScRSLSr13CV0|fc_0b12df87254bb4e6016aa67b8e602887d1b03c57ba6a748bf5","toolName":"read","startedAt":"2026-09-13T10:31:42.493Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:4100-4305,4580-4605,4750-4785,4840-4960,4952-5190"},"intent":"Reading delivery writer sections"},"id":"99209f88","parentId":"d6395143","timestamp":"2026-09-13T10:31:42.493Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_A4Z9WO2tolSYOyU9XlJhAoK7|fc_0b12df87254bb4e6016aa67b8e603887d19b8b257abeeeeb18","toolName":"grep","startedAt":"2026-09-13T10:31:42.493Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs;.worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml;.worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs"},"intent":"Finding writer tests and hashes"},"id":"62e6c92f","parentId":"99209f88","timestamp":"2026-09-13T10:31:42.493Z"}
{"type":"message","id":"071a5af7","parentId":"62e6c92f","timestamp":"2026-09-13T10:31:42.494Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_BOsuJ13p3FYbScRSLSr13CV0|fc_0b12df87254bb4e6016aa67b8e602887d1b03c57ba6a748bf5","name":"read","arguments":{"i":"Reading delivery writer sections","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:4100-4305,4580-4605,4750-4785,4840-4960,4952-5190"},"intent":"Reading delivery writer sections"},{"type":"toolCall","id":"call_A4Z9WO2tolSYOyU9XlJhAoK7|fc_0b12df87254bb4e6016aa67b8e603887d19b8b257abeeeeb18","name":"grep","arguments":{"i":"Finding writer tests and hashes","pattern":"InputWriter|enqueue_text_chunked|sha2|blake3|mod tests","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs;.worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml;.worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs","case":true,"gitignore":true,"skip":0},"intent":"Finding writer tests and hashes"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":2532,"output":198,"cacheRead":17792,"cacheWrite":0,"totalTokens":20522,"cost":{"input":0.025320000000000002,"output":0.0099,"cacheRead":0.017792,"cacheWrite":0,"total":0.053012000000000004}},"stopReason":"toolUse","timestamp":1789295494901,"responseId":"resp_0b12df87254bb4e6016aa67b872bd887d1b52e823753718b87","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0b12df87254bb4e6016aa67b8e602887d1b03c57ba6a748bf5","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading delivery writer sections\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:4100-4305,4580-4605,4750-4785,4840-4960,4952-5190\"}","call_id":"call_BOsuJ13p3FYbScRSLSr13CV0","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67b8e603887d19b8b257abeeeeb18","type":"function_call","status":"completed","arguments":"{\"i\":\"Finding writer tests and hashes\",\"pattern\":\"InputWriter|enqueue_text_chunked|sha2|blake3|mod tests\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs;.worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml;.worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs\",\"case\":true,\"gitignore\":true,\"skip\":0}","call_id":"call_A4Z9WO2tolSYOyU9XlJhAoK7","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"grep","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":7590.112199999974,"ttft":7499.922900000005,"completedAt":1789295502491,"contextSnapshot":{"promptTokens":20324,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"55356650","parentId":"071a5af7","timestamp":"2026-09-13T10:31:42.516Z","message":{"role":"toolResult","toolCallId":"call_BOsuJ13p3FYbScRSLSr13CV0|fc_0b12df87254bb4e6016aa67b8e602887d1b03c57ba6a748bf5","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#3A1D]\n4096:struct Translation {\n…\n4100:    /// and are driven one-at-a-time so two sequences never interleave.\n4101:    event_tx: Sender<String>,\n4102:    /// The live child — shared so `dispatch_input` fires content-free pings while\n4103:    /// the worker (which also holds an `Arc`) drives events / faults the binary.\n4104:    child: Arc<TranslationChild>,\n4105:    /// Raised by the worker on FAULT (commit-deadline miss / binary death): the\n4106:    /// session's idle inbound then SPOOLS (never raw-injected) and `dispatch_input`\n4107:    /// stops pinging.\n4108:    faulted: Arc<AtomicBool>,\n4109:}\n4110:\n4111:/// A child the broker hosts under a PTY — the §B-owned resources for one\n4112:/// session, plus its gapless-resume output log.\n4113:struct HostedSession {\n4114:    /// The PTY + child (PTY master/writer + spawned child process).\n4115:    session: Arc<PtySession>,\n4116:    /// The session's dedicated PTY input-writer (v0.13.0 P0,\n4117:    /// REQ-HAZARD-PTY-INPUT-WRITER-WEDGE): the SOLE caller of the blocking\n4118:    /// `write_input`. Every dispatch-side write ENQUEUES here and returns at once,\n4119:    /// so a paste burst that fills the harness's input buffer parks only the\n4120:    /// writer thread, never the broker dispatch thread.\n4121:    input: Arc<InputWriter>,\n4122:    /// The output drain pump (kept so teardown can stop it).\n4123:    #[allow(dead_code)] // held for ownership/teardown; not read directly\n4124:    drain: Drain,\n4125:    /// The sequenced, buffered output + current subscriber.\n4126:    log: Arc<Mutex<OutputLog>>,\n4127:    /// The owning endpoint (the spawn's label; empty = unlabeled). The\n4128:    /// inbound dispatcher's gate subject for remote-drive (D9-1).\n4129:    endpoint: String,\n4130:    /// The translation-binary attachment (Layer C), or `None` for a session with\n4131:    /// no `[message-idle-translation-binary]` — then idle inbound delivery SPOOLS\n4132:    /// (no raw PTY inject; ADR-0022 amendment).\n4133:    translation: Option<Arc<Translation>>,\n4134:    /// The resolved translation argv this session was spawned with (F029 C-1) —\n4135:    /// held so a bounded eager respawn after a REAL fault can rebuild the binary\n4136:    /// from the exact same command (`build_translation`) without re-reading the\n4137:    /// manifest (works for a test session with a direct argv AND a production\n4138:    /// session). `None` for a no-translation session. Updated on an adapter-apply\n4139:    /// restart to the swapped-in argv.\n4140:    translation_argv: Option<Vec<String>>,\n4141:    /// The bounded-respawn give-up counter shared with the inject worker (F029 C-1,\n4142:    /// REQ-HAZARD-TRANSLATE-FAULT-PERMANENT-DEATH): the dispatch respawn path\n4143:    /// increments it per rebuild, the worker RESETS it to 0 on a healthy `{commit}`\n4144:    /// (so a recovered binary refreshes the whole budget). At `translate_respawn_\n4145:    /// budget()` the daemon gives up (loud) and leaves the binary dead → spool.\n4146:    translation_respawns: Arc<AtomicU32>,\n4147:    /// The adapter name owning this session (W3a, ADR-0025) — empty for a\n4148:    /// legacy/test/shell spawn. A live adapter update finds every live session\n4149:    /// whose `adapter` matches to cycle its resident children.\n4150:    adapter: String,\n4151:    /// The adapter's install dir for this session (W3a) — `None` if unknown. The\n4152:    /// apply target for a live update's CRC swap.\n4153:    install_dir: Option<std::path::PathBuf>,\n4154:    /// When the session spawned (ADR-0041 decision 6) — the zombie verdict's\n4155:    /// boot-grace anchor: a just-spawned adapter harness has no client chain\n4156:    /// yet and must never read as a dead tree during bringup.\n4157:    // [impl->REQ-ENDPOINT-CYCLE-HONEST]\n4158:    spawned_at: Instant,\n4159:    /// OS birth stamp captured while the newly spawned child is still owned\n4160:    /// and BEFORE any waiter can reap it. Never refreshed from a remembered pid.\n4161:    // [impl->REQ-BROKER-ZOMBIE-IDENTITY]\n4162:    process_started_at: Option<u64>,\n4163:}\n4164:\n4165:/// One record queued to a session's dedicated PTY input-writer thread — the raw\n4166:/// bytes to write (v0.13.0 P0, REQ-HAZARD-PTY-INPUT-WRITER-WEDGE).\n4167:type InputRecord = Vec<u8>;\n4168:\n4169:/// The per-session PTY input FIFO depth (records). Sized for a generous paste —\n4170:/// a wedged harness fills this and then DROPS, never blocking the dispatch\n4171:/// thread. The int gate shrinks it via `SPT_INPUT_QUEUE_DEPTH` so the\n4172:/// DROP+`INPUT_BACKPRESSURE` leg is forced in a handful of records rather than a\n4173:/// few hundred KB of real paste.\n4174:const INPUT_QUEUE_DEPTH: usize = 4096;\n4175:\n4176:/// The effective input FIFO depth: production is [`INPUT_QUEUE_DEPTH`]; the int\n4177:/// gate overrides it (`SPT_INPUT_QUEUE_DEPTH`) to a tiny value to force a\n4178:/// deterministic queue saturation — the depth's PRESENCE (bounded, drop-on-full)\n4179:/// is the invariant, not its exact value.\n4180:fn input_queue_depth() -> usize {\n4181:    match std::env::var(\"SPT_INPUT_QUEUE_DEPTH\") {\n4182:        Ok(n) => n\n4183:            .parse::<usize>()\n4184:            .ok()\n4185:            .filter(|d| *d > 0)\n4186:            .unwrap_or(INPUT_QUEUE_DEPTH),\n4187:        Err(_) => INPUT_QUEUE_DEPTH,\n4188:    }\n4189:}\n4190:\n4191:/// One session's dedicated PTY input-writer (v0.13.0 P0,\n4192:/// REQ-HAZARD-PTY-INPUT-WRITER-WEDGE). The `writer` thread is the SOLE caller of\n4193:/// the blocking [`SessionSurface::write_input`]; every other site enqueues a\n4194:/// record via [`InputWriter::enqueue`] (a non-blocking `try_send`) and returns\n4195:/// immediately. So a paste burst that fills the ConPTY/forkpty input buffer\n4196:/// parks ONLY this thread — the broker dispatch thread, attach-opens, resizes,\n4197:/// and every other session stay fully live (the W1b-deferred fix (2)). Mirrors\n4198:/// the OUTPUT-side [`ViewerSink`]/[`ControllerSink`] writer-thread pattern.\n4199:struct InputWriter {\n4200:    /// The bounded input FIFO to the writer thread. `try_send` only — a full\n4201:    /// queue (a genuinely wedged harness) DROPS, it never blocks.\n4202:    tx: SyncSender<InputRecord>,\n4203:    /// True while the FIFO is saturated and input is being dropped; cleared on\n4204:    /// the next accepted enqueue (heal-on-resume). Mirrored to the perch's\n4205:    /// `input_backpressure` so the operator sees the drop.\n4206:    backpressure: AtomicBool,\n4207:    /// The owning endpoint (the spawn's label; empty = unlabeled / raw test) —\n4208:    /// the perch whose `input_backpressure` this stamps. Empty ⇒ nowhere to record.\n4209:    endpoint: String,\n4210:    /// The writer thread handle (held for ownership; the thread drains until the\n4211:    /// last `tx` clone drops at session teardown, then exits).\n4212:    _writer: JoinHandle<()>,\n4213:}\n4214:\n4215:impl InputWriter {\n4216:    /// Spawn a session's input-writer thread. `session` is the `Arc<PtySession>`\n4217:    /// whose PTY write handle this thread now exclusively owns.\n4218:    fn spawn(session: Arc<PtySession>, endpoint: String) -> Arc<InputWriter> {\n4219:        let (tx, rx) = sync_channel::<InputRecord>(input_queue_depth());\n4220:        let writer = thread::spawn(move || input_writer(session, rx));\n4221:        Arc::new(InputWriter {\n4222:            tx,\n4223:            backpressure: AtomicBool::new(false),\n4224:            endpoint,\n4225:            _writer: writer,\n4226:        })\n4227:    }\n4228:\n4229:    /// Enqueue `bytes` for the PTY write thread — NON-BLOCKING. Returns `true`\n4230:    /// when accepted (ordered, will land), `false` when the FIFO was full and the\n4231:    /// record was DROPPED. A full queue stamps `INPUT_BACKPRESSURE` (once, on the\n4232:    /// rising edge); the next accepted enqueue clears it (heal). The dispatch\n4233:    /// thread never blocks here, however stuck the harness is.\n4234:    // [impl->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\n4235:    fn enqueue(&self, bytes: InputRecord) -> bool {\n4236:        match self.tx.try_send(bytes) {\n4237:            Ok(()) => {\n4238:                // Heal: input is flowing again — clear a prior backpressure stamp.\n4239:                if self.backpressure.swap(false, Ordering::AcqRel) {\n4240:                    self.stamp_backpressure(false);\n4241:                }\n4242:                true\n4243:            }\n4244:            Err(TrySendError::Full(_)) => {\n4245:                // DROP + surface, but stamp only on the rising edge.\n4246:                if !self.backpressure.swap(true, Ordering::AcqRel) {\n4247:                    self.stamp_backpressure(true);\n4248:                }\n4249:                false\n4250:            }\n4251:            // The writer thread is gone (session teardown) — nothing to do.\n4252:            Err(TrySendError::Disconnected(_)) => false,\n4253:        }\n4254:    }\n4255:\n4256:    /// Mirror the input-backpressure signal to the perch's `info.json` (the\n4257:    /// broker is the single writer). Best-effort: a session served without a\n4258:    /// perch (raw broker tests) has nowhere to record.\n4259:    fn stamp_backpressure(&self, dropping: bool) {\n4260:        if self.endpoint.is_empty() {\n4261:            return;\n4262:        }\n4263:        let perch = resolve_perch_path(&self.endpoint, ParentHint::Infer);\n4264:        let _ = spt_store::info::set_input_backpressure(&perch, dropping);\n4265:    }\n4266:}\n4267:\n4268:/// A session's input-writer thread (REQ-HAZARD-PTY-INPUT-WRITER-WEDGE): drain\n4269:/// records from `rx` and apply each via the BLOCKING\n4270:/// [`SessionSurface::write_input`] — the ONE place that touches the PTY writer. A\n4271:/// wedged harness parks this thread (and only this thread); a write error is\n4272:/// swallowed (the same best-effort the inline callers had). The thread exits\n4273:/// when the last `tx` clone drops at session teardown.\n4274:fn input_writer(session: Arc<PtySession>, rx: Receiver<InputRecord>) {\n4275:    while let Ok(bytes) = rx.recv() {\n4276:        let _ = session.write_input(&bytes);\n4277:    }\n4278:}\n4279:\n4280:/// Drain the inject floor's buffered controller input to the PTY **after** an\n4281:/// injected sequence, then release the floor. Each step takes the buffered bytes\n4282:/// OFF the lock before ENQUEUEING it to the lone input-writer (the W1 rule: never\n4283:/// hold a lock across a PTY write — now never block on it either); input arriving\n4284:/// mid-flush keeps buffering, so strict order is preserved until the buffer\n4285:/// drains empty and the floor frees.\n4286:/// Lock the per-session inject floor, RECOVERING a poisoned mutex instead of\n4287:/// panicking (B6, REQ-HAZARD-INJECT-WORKER-POISON). The floor is SHARED by the\n4288:/// inject worker (`run_inject_worker` open / `flush_inject_floor`) and the\n4289:/// controller-input path (`dispatch_input` Layer C `buffer_if_held`). A panic under\n4290:/// the lock on EITHER poisons it; a bare `.lock().unwrap()` at the next site then\n4291:/// panics too — and a panic in the inject WORKER kills its thread WITHOUT reaping\n4292:/// the translation child, ORPHANING a live binary while `event_tx.send` fails, so\n4293:/// force-native delivery reports \"worker-gone\" (delivered=false) FOREVER though the\n4294:/// pid is alive (the F-e mis-diagnosed \"translation-binary liveness decay\").\n4295:/// Recovering the guard (the effect-journal poison-tolerance idiom, bug #16 /\n4296:/// REQ-HAZARD-EFFECT-JOURNAL-PTY-WEDGE) keeps the floor usable so ONE panic cannot\n4297:/// cascade the whole session's delivery dead.\n4298:// [impl->REQ-HAZARD-INJECT-WORKER-POISON]\n4299:fn lock_floor(floor: &Mutex<InjectFloor>) -> std::sync::MutexGuard<'_, InjectFloor> {\n4300:    floor.lock().unwrap_or_else(|p| p.into_inner())\n4301:}\n4302:\n4303:/// Poison-tolerant lock for ANY broker-resident mutex reachable from serve/dispatch\n4304:/// (B-1, REQ-HAZARD-BROKER-FLOOR-LOCK-POISON). A brain-only self-update keeps the\n4305:/// broker process — and every one of its `Mutex`es — ALIVE (REQ-UPD-3), so a single\n…\n4573:fn alert_seal_ceremony_brute_force(subnet: &str, failures: u32) {\n…\n4580:    spt_proto::emit_line_err!(\"SEAL_CEREMONY_BRUTE_FORCE:{subnet}: {body}\");\n4581:    std::thread::spawn(move || {\n4582:        if let Err(e) = raise_engine_room_alert(&subnet, &body) {\n4583:            spt_proto::emit_line_err!(\"SEAL_CEREMONY_ALERT_UNRAISED:{subnet}: {e} — {body}\");\n4584:        }\n4585:    });\n4586:}\n4587:\n4588:fn flush_inject_floor(floor: &Mutex<InjectFloor>, input: &InputWriter) {\n4589:    loop {\n4590:        let chunk = lock_floor(floor).take_or_release();\n4591:        match chunk {\n4592:            Some(bytes) => {\n4593:                input.enqueue(bytes);\n4594:            }\n4595:            None => break,\n4596:        }\n4597:    }\n4598:}\n4599:\n4600:/// The inject worker (W2 Layer C): one thread per translation-bearing session. It\n4601:/// drives inbound `<EVENT>`s through the binary and applies the binary's keystroke\n4602:/// commands to the PTY ATOMICALLY w.r.t. the operator's live controller.\n4603:///\n4604:/// Per queued event: drop any stray pre-event commands, OPEN the floor (operator\n4605:/// input now buffers in `dispatch_input`), feed the binary the `{type:event}`,\n…\n4750:/// session ring to produce output (the child answered / re-rendered → its reader is live).\n4751:/// Re-probe each tick until output appears or the bounded deadline elapses — a genuinely\n4752:/// quiet/dead child never parks the worker (echo-verify + the commit deadline still bound\n4753:/// delivery). No lock is held across a PTY write. Returns `true` iff the probe was\n4754:/// OBSERVED (ring advanced) — the caller uses that to distinguish an echoing PTY (re-settle\n4755:/// every delivery) from a non-echoing ConPTY (settle is useless + costs the full deadline).\n4756:// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n4757:fn settle_before_inject(input: &InputWriter, log: &Mutex<OutputLog>, endpoint: &str) -> bool {\n4758:    let baseline = recover_log(log).high_water();\n4759:    let deadline = Instant::now() + inject_settle_deadline();\n4760:    loop {\n4761:        // Probe: a live reader produces output → the ring advances. On an\n4762:        // echoing PTY the observable is the CPR round-trip: the probe echoes\n4763:        // into the child's OUTPUT, where the drain answers it and STRIPS the\n4764:        // query from the forwarded stream (REQ-DSR-SINGLE-CPR — the echoed\n4765:        // query itself no longer reaches the ring); the CPR written to the\n4766:        // child's input then echoes back as output and advances the ring one\n4767:        // hop later, well within the poll cadence. A re-render works the same\n4768:        // as before; a non-echoing ConPTY stays unobservable (the latch).\n4769:        input.enqueue(INJECT_SETTLE_PROBE.to_vec());\n4770:        thread::sleep(INJECT_SETTLE_POLL);\n4771:        if recover_log(log).high_water() > baseline {\n4772:            return true; // output produced since baseline → the input reader is live\n4773:        }\n4774:        if Instant::now() >= deadline {\n4775:            spt_proto::emit_line_err!(\n4776:                \"INJECT_SETTLE_TIMEOUT:{endpoint}: no PTY readiness echo within {}ms — proceeding (echo-verify guards head loss)\",\n4777:                inject_settle_deadline().as_millis()\n4778:            );\n4779:            return false;\n4780:        }\n4781:    }\n4782:}\n4783:\n4784:/// Decide whether to run the settle-gate for this delivery attempt (Layer 1 re-arm,\n4785:/// REQ-INJECT-MULTILINE-INTEGRITY). The reader-reattach race is NOT startup-only, so an\n…\n4840:/// FIFO, single writer). The reader is already confirmed live by the settle-gate before\n4841:/// the first chunk lands.\n4842:// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n4843:fn enqueue_text_chunked(input: &InputWriter, bytes: Vec<u8>) {\n4844:    chunk_text(&bytes, inject_text_chunk(), |part| {\n4845:        input.enqueue(part.to_vec());\n4846:    });\n4847:}\n4848:\n4849:/// Pure chunk-split core (unit-testable): a payload at or below `chunk` is emitted\n4850:/// whole; a larger one is split into ordered `chunk`-sized parts (last part short).\n4851:/// Reassembling the emitted parts in order yields the original bytes exactly.\n4852:fn chunk_text(bytes: &[u8], chunk: usize, mut emit: impl FnMut(&[u8])) {\n4853:    if bytes.len() <= chunk {\n4854:        emit(bytes);\n4855:        return;\n4856:    }\n4857:    for part in bytes.chunks(chunk) {\n4858:        emit(part);\n4859:    }\n4860:}\n4861:\n4862:/// The outcome of driving ONE inject sequence (feed the event, drain keystroke\n4863:/// commands to `{commit}` / deadline / death). Carries the payload text TYPED this\n4864:/// attempt so Layer 2 can echo-verify it and (on a re-drive) the caller can re-run.\n4865:enum SeqOutcome {\n4866:    /// The binary emitted `{commit}` — a complete sequence. `sent_text` is the\n4867:    /// concatenated payload text typed (keys excluded — they carry no echoable text).\n4868:    Committed { sent_text: Vec<u8> },\n4869:    /// The commit deadline elapsed with the binary still ALIVE (a MISS, not a fault).\n4870:    Missed,\n4871:    /// The binary's stdout closed mid-sequence (a REAL death fault).\n4872:    Disconnected,\n4873:    /// The stdin write to feed the event FAILED — the binary is gone (a REAL fault).\n4874:    SendFailed,\n4875:}\n4876:\n4877:/// Drive one inject sequence for `envelope`: open the floor, feed the event, drain the\n4878:/// binary's `{key}`/`{text}`/`{delay_ms}` commands to the PTY (text paced-chunked under\n4879:/// the settle-gate) until `{commit}` / the commit deadline / stdout death, then flush the\n4880:/// buffered controller input and release the floor in EVERY exit path (the anti-stall\n4881:/// guarantee). Returns the outcome + typed payload text for the caller's echo-verify.\n4882:// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n4883:// [impl->REQ-HAZARD-INJECT-CONTROL-COEXIST]\n4884:fn drive_one_sequence(\n4885:    input: &InputWriter,\n4886:    floor: &Mutex<InjectFloor>,\n4887:    child: &TranslationChild,\n4888:    cmd_rx: &Receiver<KeyCmd>,\n4889:    envelope: String,\n4890:) -> SeqOutcome {\n4891:    lock_floor(floor).open();\n4892:    if child.send(&ToBinary::Event { envelope }).is_err() {\n4893:        flush_inject_floor(floor, input);\n4894:        return SeqOutcome::SendFailed;\n4895:    }\n4896:    let deadline = Instant::now() + inject_commit_deadline();\n4897:    let mut committed = false;\n4898:    let mut disconnected = false;\n4899:    let mut sent_text: Vec<u8> = Vec::new();\n4900:    loop {\n4901:        let now = Instant::now();\n4902:        let remaining = deadline.saturating_duration_since(now);\n4903:        if remaining.is_zero() {\n4904:            break; // deadline → MISS\n4905:        }\n4906:        match cmd_rx.recv_timeout(remaining) {\n4907:            Ok(KeyCmd::Key { key }) => {\n4908:                if let Some(bytes) = key_to_bytes(&key) {\n4909:                    input.enqueue(bytes);\n4910:                }\n4911:            }\n4912:            Ok(KeyCmd::Text { text }) => {\n4913:                // Accumulate the payload for echo-verify, then type it paced-chunked.\n4914:                let bytes = text.into_bytes();\n4915:                sent_text.extend_from_slice(&bytes);\n4916:                enqueue_text_chunked(input, bytes);\n4917:            }\n4918:            Ok(KeyCmd::Delay { delay_ms }) => {\n4919:                let want = Duration::from_millis(delay_ms);\n4920:                let cap = deadline.saturating_duration_since(Instant::now());\n4921:                thread::sleep(want.min(cap));\n4922:            }\n4923:            Ok(KeyCmd::Commit { .. }) => {\n4924:                committed = true;\n4925:                break;\n4926:            }\n4927:            Err(RecvTimeoutError::Timeout) => break,\n4928:            Err(RecvTimeoutError::Disconnected) => {\n4929:                disconnected = true;\n4930:                break;\n4931:            }\n4932:        }\n4933:    }\n4934:    // Flush buffered controller input AFTER the injected bytes + release the floor —\n4935:    // in EVERY exit path (the ANTI-STALL guarantee).\n4936:    flush_inject_floor(floor, input);\n4937:    if disconnected {\n4938:        SeqOutcome::Disconnected\n4939:    } else if committed {\n4940:        SeqOutcome::Committed { sent_text }\n4941:    } else {\n4942:        SeqOutcome::Missed\n4943:    }\n4944:}\n4945:\n4946:// [impl->REQ-MSG-IDLE-TRANSLATION-BINARY]\n4947:// [impl->REQ-HAZARD-INJECT-CONTROL-COEXIST]\n4948:// [impl->REQ-MSG-DELIVERY-AXES]\n4949:// [impl->REQ-TRANSLATE-COMMIT-MISS-TOLERANCE]\n4950:// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n4951:#[allow(clippy::too_many_arguments)] // per-session worker wiring (C-1 added the respawn counter, W5-A the output-log tap); a struct would obscure the call\n4952:fn run_inject_worker(\n4953:    input: Arc<InputWriter>,\n4954:    child: Arc<TranslationChild>,\n4955:    floor: Arc<Mutex<InjectFloor>>,\n4956:    event_rx: Receiver<String>,\n4957:    cmd_rx: Receiver<KeyCmd>,\n4958:    faulted: Arc<AtomicBool>,\n4959:    respawns: Arc<AtomicU32>,\n4960:    log: Arc<Mutex<OutputLog>>,\n4961:    endpoint: String,\n4962:) {\n4963:    // C-1 worker-local state (REQ-TRANSLATE-COMMIT-MISS-TOLERANCE): CONSECUTIVE\n4964:    // commit-deadline misses (reset on any successful `{commit}`), and the set of\n4965:    // envelopes already respooled-once so a repeat miss dead-letters instead of\n4966:    // respooling forever. Both are worker-local: a REAL fault exits the worker, and\n4967:    // a respawn builds a fresh worker with a fresh budget + set.\n4968:    let mut strikes: u32 = 0;\n4969:    let mut respooled_once: HashSet<String> = HashSet::new();\n4970:    // W5-A Layer 1 (re-arm fix): settle before EVERY delivery, not once per worker. The\n4971:    // head-swallow race is NOT startup-only — a mid-session `/clear` re-enters the\n4972:    // harness's raw-mode input reader and re-creates the pre-settle window (field-proven\n4973:    // on 0.29.0: a checkpoint-wake payload injected right after `/clear` lost its head\n4974:    // even though the worker had long since settled at spawn). So an echoing/interactive\n4975:    // PTY re-settles per delivery (cheap: a tick or two once the reader answers). The old\n4976:    // one-shot's ONLY legitimate purpose was sparing a NON-echoing ConPTY the full\n4977:    // settle-deadline on every delivery (its DSR answer never surfaces, and it has no\n4978:    // reader-reattach race to guard). We keep exactly that optimization via a LATCH driven\n4979:    // by the settle's own return value: a settle that TIMES OUT (probe unobservable) sets\n4980:    // this, and thereafter first-attempt settles are skipped; a settle that is OBSERVED\n4981:    // keeps it clear, so the bug-prone class re-settles forever.\n4982:    let mut probe_unobservable = false;\n4983:    // Layer 2 (echo-verify → re-drive → LOUD spool) is a DECLARED CAPABILITY, default\n4984:    // OFF (`SPT_INJECT_VERIFY_ECHO`). It applies ONLY where the harness re-renders typed\n4985:    // input into its observable output (a real TUI's input line does; a bare shell / a\n4986:    // ConPTY programmatic inject / a test echo-child on ConPTY does NOT). Universal\n4987:    // auto-detection is infeasible — a raw-mode TUI does not echo a benign control probe\n4988:    // (so the probe cannot prove text-echo), and incidental output (a prompt, a redraw)\n4989:    // would make a head-prefix check false-read head-loss and spuriously LOUD-spool EVERY\n4990:    // delivery. So an adapter that KNOWS its harness echoes declares the capability\n4991:    // (parallel to the ruling's \"bracketed-paste where the harness declares it\"); Layer 1\n4992:    // (the settle-gate) is the UNCONDITIONAL root fix. The int gate also forces it on\n4993:    // (`SPT_INJECT_FORCE_ECHO_MISS`) to exercise the re-drive/spool wiring on any platform.\n4994:    // AMBIENT env can NOT arm this: both vars are scrubbed at daemon startup\n4995:    // (`spt_runtime::INJECT_ECHO_ENV_VARS`, F-036 env-inheritance class — an inherited\n4996:    // dev-shell export once force-enabled echo-verify host-wide and a false miss RETYPED\n4997:    // sequences into a live session's input). Only an explicit declaration (or an\n4998:    // in-process test broker, which never runs the daemon entrypoints) reaches this read.\n4999:    let echo_capable = std::env::var_os(\"SPT_INJECT_VERIFY_ECHO\").is_some()\n5000:        || std::env::var_os(\"SPT_INJECT_FORCE_ECHO_MISS\").is_some();\n5001:    // `event_rx` blocks here; events queue → one sequence at a time.\n5002:    for envelope in event_rx {\n5003:        // A well-behaved filter only emits in response to an event, but drop any\n5004:        // unsolicited commands left in the channel so they can't be mis-attributed\n5005:        // to this event's sequence.\n5006:        while cmd_rx.try_recv().is_ok() {}\n5007:\n5008:        let envelope_copy = envelope.clone();\n5009:\n5010:        // ── W5-A: run the sequence with a settle-gate (Layer 1) before ANY byte, an\n5011:        // echo-verify (Layer 2) after `{commit}`, and ONE re-drive on a verify miss →\n5012:        // LOUD spool on a second miss (silent+unrecoverable head-loss → recoverable+loud).\n5013:        // The commit-deadline MISS / binary-death / send-fail semantics below are\n5014:        // unchanged (C-1 miss-tolerance).\n5015:        let mut committed = false;\n5016:        let mut disconnected = false;\n5017:        let mut send_failed = false;\n5018:        let mut integrity_lost = false;\n5019:        for attempt in 1..=INJECT_REDRIVE_ATTEMPTS {\n5020:            // Layer 1: settle-gate before the first byte of EVERY delivery on an echoing\n5021:            // PTY (re-arm — a mid-session `/clear` re-creates the reader-reattach race),\n5022:            // and always before a RE-DRIVE (only reached on a swallowed head, so re-confirm\n5023:            // readiness before retyping). Skip only where the probe is known unobservable\n5024:            // (a non-echoing ConPTY — no race to guard, and settling would burn the full\n5025:            // deadline). The latch is driven by the FIRST-ATTEMPT settle's own outcome.\n5026:            if should_settle(attempt, probe_unobservable) {\n5027:                let observed = settle_before_inject(&input, &log, &endpoint);\n5028:                if attempt == 1 {\n5029:                    probe_unobservable = !observed;\n5030:                }\n5031:            }\n5032:            // Snapshot the ring high-water AFTER settling (excludes probe echoes) so\n5033:            // Layer 2 sees only THIS sequence's output.\n5034:            let seq_start = recover_log(&log).high_water();\n5035:            match drive_one_sequence(&input, &floor, &child, &cmd_rx, envelope_copy.clone()) {\n5036:                SeqOutcome::SendFailed => {\n5037:                    send_failed = true;\n5038:                    break;\n5039:                }\n5040:                SeqOutcome::Disconnected => {\n5041:                    disconnected = true;\n5042:                    break;\n5043:                }\n5044:                SeqOutcome::Missed => {\n5045:                    // Commit-deadline miss — leave to the C-1 miss path (not an\n5046:                    // integrity re-drive; the binary never signalled a complete sequence).\n5047:                    break;\n5048:                }\n5049:                SeqOutcome::Committed { sent_text } => {\n5050:                    committed = true;\n5051:                    // Layer 2: verify the typed head echoed back — ONLY where the terminal\n5052:                    // demonstrably echoes (else a non-echoing PTY's incidental output would\n5053:                    // false-read head-loss). Where it does not echo, Layer 1 stands alone.\n5054:                    if !echo_capable || echo_verify_after(&log, seq_start, &sent_text) {\n5055:                        break; // delivered byte-complete (or echo-verify not applicable here)\n5056:                    }\n5057:                    if attempt < INJECT_REDRIVE_ATTEMPTS {\n5058:                        spt_proto::emit_line_err!(\n5059:                            \"INJECT_ECHO_MISS:{endpoint}: typed head did not echo (attempt {attempt}/{INJECT_REDRIVE_ATTEMPTS}) — re-driving once\"\n5060:                        );\n5061:                        committed = false; // re-drive; only a verified commit counts\n5062:                        continue;\n5063:                    }\n5064:                    // Second miss → the head is swallowed even after a re-drive.\n5065:                    integrity_lost = true;\n5066:                    break;\n5067:                }\n5068:            }\n5069:        }\n5070:\n5071:        if send_failed {\n5072:            // stdin write FAILED → the binary is genuinely GONE (a REAL fault): re-spool\n5073:            // the in-flight envelope, stamp + terminate, exit for a bounded respawn.\n5074:            respool_and_fault(\n5075:                &endpoint,\n5076:                envelope_copy,\n5077:                &faulted,\n5078:                &child,\n5079:                \"stdin write failed\",\n5080:            );\n5081:            return;\n5082:        }\n5083:\n5084:        if integrity_lost {\n5085:            // Layer 2 fallback: the typed head never echoed, even after a re-drive.\n5086:            // A live-SENT inject leaves no spool copy, so convert the silent+unrecoverable\n5087:            // truncation into recoverable+loud — re-spool the envelope (idle-eligible,\n5088:            // poll-fed) with a distinct integrity marker. NOT a binary fault (the binary\n5089:            // committed fine; the terminal swallowed the head), so the worker survives.\n5090:            respool_envelope(&endpoint, &envelope_copy);\n5091:            spt_proto::emit_line_err!(\n5092:                \"INJECT_HEAD_LOSS_SPOOL:{endpoint}: typed payload head did not echo after {INJECT_REDRIVE_ATTEMPTS} attempts — re-spooled loud (delivered=false, recoverable); frame integrity NOT confirmed\"\n5093:            );\n5094:            strikes = 0;\n5095:            respawns.store(0, Ordering::Relaxed);\n5096:            respooled_once.remove(&envelope_copy);\n5097:            continue;\n5098:        }\n5099:\n5100:        if committed {\n5101:            // Healthy sequence: reset the strike counter, refresh the respawn budget\n5102:            // (a working binary heals it), and forget any earlier respool of THIS\n5103:            // envelope (it succeeded → a future miss may respool it afresh).\n5104:            strikes = 0;\n5105:            respawns.store(0, Ordering::Relaxed);\n5106:            respooled_once.remove(&envelope_copy);\n5107:            continue;\n5108:        }\n5109:\n5110:        if disconnected {\n5111:            // REAL binary death (stdout closed mid-sequence): re-spool + stamp +\n5112:            // terminate + exit for a bounded respawn.\n5113:            respool_and_fault(\n5114:                &endpoint,\n5115:                envelope_copy,\n5116:                &faulted,\n5117:                &child,\n5118:                \"binary stdout disconnected\",\n5119:            );\n5120:            return;\n5121:        }\n5122:\n5123:        // ── COMMIT-DEADLINE MISS (miss ≠ fault, REQ-TRANSLATE-COMMIT-MISS-TOLERANCE).\n5124:        // The stdin write SUCCEEDED so the binary is ALIVE; the watchdog already did\n5125:        // its ONLY legitimate job (flushed + released the floor above). Do NOT\n5126:        // terminate, do NOT latch `faulted`. The in-memory pending wake survives the\n5127:        // boundary → the v0.12.0 checkpoint post-clear wake works as intended.\n5128:        strikes += 1;\n5129:        match note_miss_respool(&mut respooled_once, &envelope_copy) {\n5130:            MissRespool::Respool => {\n5131:                // First miss of this envelope — respool it ONCE (idle-eligible,\n5132:                // poll-fed) without faulting.\n5133:                respool_envelope(&endpoint, &envelope_copy);\n5134:                spt_proto::emit_line_err!(\n5135:                    \"TRANSLATION_COMMIT_MISS:{endpoint}: no {{commit}} within deadline (strike {strikes}/{}) — binary preserved, envelope respooled once\",\n5136:                    inject_miss_strike_budget()\n5137:                );\n5138:            }\n5139:            MissRespool::DeadLetter => {\n5140:                // A repeat miss of an already-respooled envelope (e.g. the checkpoint\n5141:                // duplicate FIRE looping back on a later drain): DEAD-LETTER it loud —\n5142:                // do NOT respool again (never a silent drop; it still counts as a\n5143:                // strike), REQ-HAZARD-IDLE-SILENT-NONDELIVERY posture.\n5144:                spt_proto::emit_line_err!(\n5145:                    \"TRANSLATION_COMMIT_MISS_DEADLETTER:{endpoint}: envelope missed {{commit}} again after a prior respool (strike {strikes}/{}) — dead-lettered, NOT respooled again (reported non-delivery, not a silent drop)\",\n5146:                    inject_miss_strike_budget()\n5147:                );\n5148:            }\n5149:        }\n5150:\n5151:        if miss_strikes_exhausted(strikes, inject_miss_strike_budget()) {\n5152:            // N CONSECUTIVE misses with no intervening commit → a REAL fault: the\n5153:            // binary is wedged. Stamp + terminate + exit for a bounded respawn. (The\n5154:            // envelope was already respooled/dead-lettered above — no double respool.)\n5155:            fault_translation_stamped(\n5156:                &endpoint,\n5157:                &faulted,\n5158:                &child,\n5159:                \"no {commit} within INJECT_COMMIT_DEADLINE for the strike budget\",\n5160:            );\n5161:            return;\n5162:        }\n5163:        // Miss tolerated (below the budget): the binary survives — continue to the\n5164:        // next queued event through the SAME live binary.\n5165:    }\n5166:    // `event_tx` dropped → session teardown. Reap the child (no zombie).\n5167:    child.terminate();\n5168:}\n5169:\n5170:/// Re-spool the in-flight envelope as non-deferred (idle-eligible) so the\n5171:/// relay/poll can surface it. Used on a commit-deadline MISS (no fault) and,\n5172:/// composed with the fault, on a REAL binary-death fault.\n5173:// [impl->REQ-MSG-DELIVERY-AXES]\n5174:// [impl->REQ-TRANSLATE-COMMIT-MISS-TOLERANCE]\n5175:fn respool_envelope(endpoint: &str, envelope: &str) {\n5176:    let perch_path =\n5177:        spt_store::perch::resolve_perch_path(endpoint, spt_store::perch::ParentHint::Infer);\n5178:    if let Err(e) = spt_store::spool::spool_message_at(&perch_path, \"\", envelope) {\n5179:        spt_proto::emit_line_err!(\n5180:            \"TRANSLATION_FAULT_RESPOOL:{endpoint}: failed to re-spool ({e}) — message dropped\"\n5181:        );\n5182:    }\n5183:}\n5184:\n5185:/// Re-spool the in-flight envelope (a REAL binary-death fault genuinely lost the\n5186:/// in-flight delivery), then stamp the perch + fault the translation binary.\n5187:// [impl->REQ-MSG-DELIVERY-AXES]\n5188:fn respool_and_fault(\n5189:    endpoint: &str,\n5190:    envelope: String,\n…\n5194:) {\n…\n5197:}"}],"details":{"displayContent":{"text":"struct Translation {\n…\n    /// and are driven one-at-a-time so two sequences never interleave.\n    event_tx: Sender<String>,\n    /// The live child — shared so `dispatch_input` fires content-free pings while\n    /// the worker (which also holds an `Arc`) drives events / faults the binary.\n    child: Arc<TranslationChild>,\n    /// Raised by the worker on FAULT (commit-deadline miss / binary death): the\n    /// session's idle inbound then SPOOLS (never raw-injected) and `dispatch_input`\n    /// stops pinging.\n    faulted: Arc<AtomicBool>,\n}\n\n/// A child the broker hosts under a PTY — the §B-owned resources for one\n/// session, plus its gapless-resume output log.\nstruct HostedSession {\n    /// The PTY + child (PTY master/writer + spawned child process).\n    session: Arc<PtySession>,\n    /// The session's dedicated PTY input-writer (v0.13.0 P0,\n    /// REQ-HAZARD-PTY-INPUT-WRITER-WEDGE): the SOLE caller of the blocking\n    /// `write_input`. Every dispatch-side write ENQUEUES here and returns at once,\n    /// so a paste burst that fills the harness's input buffer parks only the\n    /// writer thread, never the broker dispatch thread.\n    input: Arc<InputWriter>,\n    /// The output drain pump (kept so teardown can stop it).\n    #[allow(dead_code)] // held for ownership/teardown; not read directly\n    drain: Drain,\n    /// The sequenced, buffered output + current subscriber.\n    log: Arc<Mutex<OutputLog>>,\n    /// The owning endpoint (the spawn's label; empty = unlabeled). The\n    /// inbound dispatcher's gate subject for remote-drive (D9-1).\n    endpoint: String,\n    /// The translation-binary attachment (Layer C), or `None` for a session with\n    /// no `[message-idle-translation-binary]` — then idle inbound delivery SPOOLS\n    /// (no raw PTY inject; ADR-0022 amendment).\n    translation: Option<Arc<Translation>>,\n    /// The resolved translation argv this session was spawned with (F029 C-1) —\n    /// held so a bounded eager respawn after a REAL fault can rebuild the binary\n    /// from the exact same command (`build_translation`) without re-reading the\n    /// manifest (works for a test session with a direct argv AND a production\n    /// session). `None` for a no-translation session. Updated on an adapter-apply\n    /// restart to the swapped-in argv.\n    translation_argv: Option<Vec<String>>,\n    /// The bounded-respawn give-up counter shared with the inject worker (F029 C-1,\n    /// REQ-HAZARD-TRANSLATE-FAULT-PERMANENT-DEATH): the dispatch respawn path\n    /// increments it per rebuild, the worker RESETS it to 0 on a healthy `{commit}`\n    /// (so a recovered binary refreshes the whole budget). At `translate_respawn_\n    /// budget()` the daemon gives up (loud) and leaves the binary dead → spool.\n    translation_respawns: Arc<AtomicU32>,\n    /// The adapter name owning this session (W3a, ADR-0025) — empty for a\n    /// legacy/test/shell spawn. A live adapter update finds every live session\n    /// whose `adapter` matches to cycle its resident children.\n    adapter: String,\n    /// The adapter's install dir for this session (W3a) — `None` if unknown. The\n    /// apply target for a live update's CRC swap.\n    install_dir: Option<std::path::PathBuf>,\n    /// When the session spawned (ADR-0041 decision 6) — the zombie verdict's\n    /// boot-grace anchor: a just-spawned adapter harness has no client chain\n    /// yet and must never read as a dead tree during bringup.\n    // [impl->REQ-ENDPOINT-CYCLE-HONEST]\n    spawned_at: Instant,\n    /// OS birth stamp captured while the newly spawned child is still owned\n    /// and BEFORE any waiter can reap it. Never refreshed from a remembered pid.\n    // [impl->REQ-BROKER-ZOMBIE-IDENTITY]\n    process_started_at: Option<u64>,\n}\n\n/// One record queued to a session's dedicated PTY input-writer thread — the raw\n/// bytes to write (v0.13.0 P0, REQ-HAZARD-PTY-INPUT-WRITER-WEDGE).\ntype InputRecord = Vec<u8>;\n\n/// The per-session PTY input FIFO depth (records). Sized for a generous paste —\n/// a wedged harness fills this and then DROPS, never blocking the dispatch\n/// thread. The int gate shrinks it via `SPT_INPUT_QUEUE_DEPTH` so the\n/// DROP+`INPUT_BACKPRESSURE` leg is forced in a handful of records rather than a\n/// few hundred KB of real paste.\nconst INPUT_QUEUE_DEPTH: usize = 4096;\n\n/// The effective input FIFO depth: production is [`INPUT_QUEUE_DEPTH`]; the int\n/// gate overrides it (`SPT_INPUT_QUEUE_DEPTH`) to a tiny value to force a\n/// deterministic queue saturation — the depth's PRESENCE (bounded, drop-on-full)\n/// is the invariant, not its exact value.\nfn input_queue_depth() -> usize {\n    match std::env::var(\"SPT_INPUT_QUEUE_DEPTH\") {\n        Ok(n) => n\n            .parse::<usize>()\n            .ok()\n            .filter(|d| *d > 0)\n            .unwrap_or(INPUT_QUEUE_DEPTH),\n        Err(_) => INPUT_QUEUE_DEPTH,\n    }\n}\n\n/// One session's dedicated PTY input-writer (v0.13.0 P0,\n/// REQ-HAZARD-PTY-INPUT-WRITER-WEDGE). The `writer` thread is the SOLE caller of\n/// the blocking [`SessionSurface::write_input`]; every other site enqueues a\n/// record via [`InputWriter::enqueue`] (a non-blocking `try_send`) and returns\n/// immediately. So a paste burst that fills the ConPTY/forkpty input buffer\n/// parks ONLY this thread — the broker dispatch thread, attach-opens, resizes,\n/// and every other session stay fully live (the W1b-deferred fix (2)). Mirrors\n/// the OUTPUT-side [`ViewerSink`]/[`ControllerSink`] writer-thread pattern.\nstruct InputWriter {\n    /// The bounded input FIFO to the writer thread. `try_send` only — a full\n    /// queue (a genuinely wedged harness) DROPS, it never blocks.\n    tx: SyncSender<InputRecord>,\n    /// True while the FIFO is saturated and input is being dropped; cleared on\n    /// the next accepted enqueue (heal-on-resume). Mirrored to the perch's\n    /// `input_backpressure` so the operator sees the drop.\n    backpressure: AtomicBool,\n    /// The owning endpoint (the spawn's label; empty = unlabeled / raw test) —\n    /// the perch whose `input_backpressure` this stamps. Empty ⇒ nowhere to record.\n    endpoint: String,\n    /// The writer thread handle (held for ownership; the thread drains until the\n    /// last `tx` clone drops at session teardown, then exits).\n    _writer: JoinHandle<()>,\n}\n\nimpl InputWriter {\n    /// Spawn a session's input-writer thread. `session` is the `Arc<PtySession>`\n    /// whose PTY write handle this thread now exclusively owns.\n    fn spawn(session: Arc<PtySession>, endpoint: String) -> Arc<InputWriter> {\n        let (tx, rx) = sync_channel::<InputRecord>(input_queue_depth());\n        let writer = thread::spawn(move || input_writer(session, rx));\n        Arc::new(InputWriter {\n            tx,\n            backpressure: AtomicBool::new(false),\n            endpoint,\n            _writer: writer,\n        })\n    }\n\n    /// Enqueue `bytes` for the PTY write thread — NON-BLOCKING. Returns `true`\n    /// when accepted (ordered, will land), `false` when the FIFO was full and the\n    /// record was DROPPED. A full queue stamps `INPUT_BACKPRESSURE` (once, on the\n    /// rising edge); the next accepted enqueue clears it (heal). The dispatch\n    /// thread never blocks here, however stuck the harness is.\n    // [impl->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\n    fn enqueue(&self, bytes: InputRecord) -> bool {\n        match self.tx.try_send(bytes) {\n            Ok(()) => {\n                // Heal: input is flowing again — clear a prior backpressure stamp.\n                if self.backpressure.swap(false, Ordering::AcqRel) {\n                    self.stamp_backpressure(false);\n                }\n                true\n            }\n            Err(TrySendError::Full(_)) => {\n                // DROP + surface, but stamp only on the rising edge.\n                if !self.backpressure.swap(true, Ordering::AcqRel) {\n                    self.stamp_backpressure(true);\n                }\n                false\n            }\n            // The writer thread is gone (session teardown) — nothing to do.\n            Err(TrySendError::Disconnected(_)) => false,\n        }\n    }\n\n    /// Mirror the input-backpressure signal to the perch's `info.json` (the\n    /// broker is the single writer). Best-effort: a session served without a\n    /// perch (raw broker tests) has nowhere to record.\n    fn stamp_backpressure(&self, dropping: bool) {\n        if self.endpoint.is_empty() {\n            return;\n        }\n        let perch = resolve_perch_path(&self.endpoint, ParentHint::Infer);\n        let _ = spt_store::info::set_input_backpressure(&perch, dropping);\n    }\n}\n\n/// A session's input-writer thread (REQ-HAZARD-PTY-INPUT-WRITER-WEDGE): drain\n/// records from `rx` and apply each via the BLOCKING\n/// [`SessionSurface::write_input`] — the ONE place that touches the PTY writer. A\n/// wedged harness parks this thread (and only this thread); a write error is\n/// swallowed (the same best-effort the inline callers had). The thread exits\n/// when the last `tx` clone drops at session teardown.\nfn input_writer(session: Arc<PtySession>, rx: Receiver<InputRecord>) {\n    while let Ok(bytes) = rx.recv() {\n        let _ = session.write_input(&bytes);\n    }\n}\n\n/// Drain the inject floor's buffered controller input to the PTY **after** an\n/// injected sequence, then release the floor. Each step takes the buffered bytes\n/// OFF the lock before ENQUEUEING it to the lone input-writer (the W1 rule: never\n/// hold a lock across a PTY write — now never block on it either); input arriving\n/// mid-flush keeps buffering, so strict order is preserved until the buffer\n/// drains empty and the floor frees.\n/// Lock the per-session inject floor, RECOVERING a poisoned mutex instead of\n/// panicking (B6, REQ-HAZARD-INJECT-WORKER-POISON). The floor is SHARED by the\n/// inject worker (`run_inject_worker` open / `flush_inject_floor`) and the\n/// controller-input path (`dispatch_input` Layer C `buffer_if_held`). A panic under\n/// the lock on EITHER poisons it; a bare `.lock().unwrap()` at the next site then\n/// panics too — and a panic in the inject WORKER kills its thread WITHOUT reaping\n/// the translation child, ORPHANING a live binary while `event_tx.send` fails, so\n/// force-native delivery reports \"worker-gone\" (delivered=false) FOREVER though the\n/// pid is alive (the F-e mis-diagnosed \"translation-binary liveness decay\").\n/// Recovering the guard (the effect-journal poison-tolerance idiom, bug #16 /\n/// REQ-HAZARD-EFFECT-JOURNAL-PTY-WEDGE) keeps the floor usable so ONE panic cannot\n/// cascade the whole session's delivery dead.\n// [impl->REQ-HAZARD-INJECT-WORKER-POISON]\nfn lock_floor(floor: &Mutex<InjectFloor>) -> std::sync::MutexGuard<'_, InjectFloor> {\n    floor.lock().unwrap_or_else(|p| p.into_inner())\n}\n\n/// Poison-tolerant lock for ANY broker-resident mutex reachable from serve/dispatch\n/// (B-1, REQ-HAZARD-BROKER-FLOOR-LOCK-POISON). A brain-only self-update keeps the\n/// broker process — and every one of its `Mutex`es — ALIVE (REQ-UPD-3), so a single\n…\nfn alert_seal_ceremony_brute_force(subnet: &str, failures: u32) {\n…\n    spt_proto::emit_line_err!(\"SEAL_CEREMONY_BRUTE_FORCE:{subnet}: {body}\");\n    std::thread::spawn(move || {\n        if let Err(e) = raise_engine_room_alert(&subnet, &body) {\n            spt_proto::emit_line_err!(\"SEAL_CEREMONY_ALERT_UNRAISED:{subnet}: {e} — {body}\");\n        }\n    });\n}\n\nfn flush_inject_floor(floor: &Mutex<InjectFloor>, input: &InputWriter) {\n    loop {\n        let chunk = lock_floor(floor).take_or_release();\n        match chunk {\n            Some(bytes) => {\n                input.enqueue(bytes);\n            }\n            None => break,\n        }\n    }\n}\n\n/// The inject worker (W2 Layer C): one thread per translation-bearing session. It\n/// drives inbound `<EVENT>`s through the binary and applies the binary's keystroke\n/// commands to the PTY ATOMICALLY w.r.t. the operator's live controller.\n///\n/// Per queued event: drop any stray pre-event commands, OPEN the floor (operator\n/// input now buffers in `dispatch_input`), feed the binary the `{type:event}`,\n…\n/// session ring to produce output (the child answered / re-rendered → its reader is live).\n/// Re-probe each tick until output appears or the bounded deadline elapses — a genuinely\n/// quiet/dead child never parks the worker (echo-verify + the commit deadline still bound\n/// delivery). No lock is held across a PTY write. Returns `true` iff the probe was\n/// OBSERVED (ring advanced) — the caller uses that to distinguish an echoing PTY (re-settle\n/// every delivery) from a non-echoing ConPTY (settle is useless + costs the full deadline).\n// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\nfn settle_before_inject(input: &InputWriter, log: &Mutex<OutputLog>, endpoint: &str) -> bool {\n    let baseline = recover_log(log).high_water();\n    let deadline = Instant::now() + inject_settle_deadline();\n    loop {\n        // Probe: a live reader produces output → the ring advances. On an\n        // echoing PTY the observable is the CPR round-trip: the probe echoes\n        // into the child's OUTPUT, where the drain answers it and STRIPS the\n        // query from the forwarded stream (REQ-DSR-SINGLE-CPR — the echoed\n        // query itself no longer reaches the ring); the CPR written to the\n        // child's input then echoes back as output and advances the ring one\n        // hop later, well within the poll cadence. A re-render works the same\n        // as before; a non-echoing ConPTY stays unobservable (the latch).\n        input.enqueue(INJECT_SETTLE_PROBE.to_vec());\n        thread::sleep(INJECT_SETTLE_POLL);\n        if recover_log(log).high_water() > baseline {\n            return true; // output produced since baseline → the input reader is live\n        }\n        if Instant::now() >= deadline {\n            spt_proto::emit_line_err!(\n                \"INJECT_SETTLE_TIMEOUT:{endpoint}: no PTY readiness echo within {}ms — proceeding (echo-verify guards head loss)\",\n                inject_settle_deadline().as_millis()\n            );\n            return false;\n        }\n    }\n}\n\n/// Decide whether to run the settle-gate for this delivery attempt (Layer 1 re-arm,\n/// REQ-INJECT-MULTILINE-INTEGRITY). The reader-reattach race is NOT startup-only, so an\n…\n/// FIFO, single writer). The reader is already confirmed live by the settle-gate before\n/// the first chunk lands.\n// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\nfn enqueue_text_chunked(input: &InputWriter, bytes: Vec<u8>) {\n    chunk_text(&bytes, inject_text_chunk(), |part| {\n        input.enqueue(part.to_vec());\n    });\n}\n\n/// Pure chunk-split core (unit-testable): a payload at or below `chunk` is emitted\n/// whole; a larger one is split into ordered `chunk`-sized parts (last part short).\n/// Reassembling the emitted parts in order yields the original bytes exactly.\nfn chunk_text(bytes: &[u8], chunk: usize, mut emit: impl FnMut(&[u8])) {\n    if bytes.len() <= chunk {\n        emit(bytes);\n        return;\n    }\n    for part in bytes.chunks(chunk) {\n        emit(part);\n    }\n}\n\n/// The outcome of driving ONE inject sequence (feed the event, drain keystroke\n/// commands to `{commit}` / deadline / death). Carries the payload text TYPED this\n/// attempt so Layer 2 can echo-verify it and (on a re-drive) the caller can re-run.\nenum SeqOutcome {\n    /// The binary emitted `{commit}` — a complete sequence. `sent_text` is the\n    /// concatenated payload text typed (keys excluded — they carry no echoable text).\n    Committed { sent_text: Vec<u8> },\n    /// The commit deadline elapsed with the binary still ALIVE (a MISS, not a fault).\n    Missed,\n    /// The binary's stdout closed mid-sequence (a REAL death fault).\n    Disconnected,\n    /// The stdin write to feed the event FAILED — the binary is gone (a REAL fault).\n    SendFailed,\n}\n\n/// Drive one inject sequence for `envelope`: open the floor, feed the event, drain the\n/// binary's `{key}`/`{text}`/`{delay_ms}` commands to the PTY (text paced-chunked under\n/// the settle-gate) until `{commit}` / the commit deadline / stdout death, then flush the\n/// buffered controller input and release the floor in EVERY exit path (the anti-stall\n/// guarantee). Returns the outcome + typed payload text for the caller's echo-verify.\n// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n// [impl->REQ-HAZARD-INJECT-CONTROL-COEXIST]\nfn drive_one_sequence(\n    input: &InputWriter,\n    floor: &Mutex<InjectFloor>,\n    child: &TranslationChild,\n    cmd_rx: &Receiver<KeyCmd>,\n    envelope: String,\n) -> SeqOutcome {\n    lock_floor(floor).open();\n    if child.send(&ToBinary::Event { envelope }).is_err() {\n        flush_inject_floor(floor, input);\n        return SeqOutcome::SendFailed;\n    }\n    let deadline = Instant::now() + inject_commit_deadline();\n    let mut committed = false;\n    let mut disconnected = false;\n    let mut sent_text: Vec<u8> = Vec::new();\n    loop {\n        let now = Instant::now();\n        let remaining = deadline.saturating_duration_since(now);\n        if remaining.is_zero() {\n            break; // deadline → MISS\n        }\n        match cmd_rx.recv_timeout(remaining) {\n            Ok(KeyCmd::Key { key }) => {\n                if let Some(bytes) = key_to_bytes(&key) {\n                    input.enqueue(bytes);\n                }\n            }\n            Ok(KeyCmd::Text { text }) => {\n                // Accumulate the payload for echo-verify, then type it paced-chunked.\n                let bytes = text.into_bytes();\n                sent_text.extend_from_slice(&bytes);\n                enqueue_text_chunked(input, bytes);\n            }\n            Ok(KeyCmd::Delay { delay_ms }) => {\n                let want = Duration::from_millis(delay_ms);\n                let cap = deadline.saturating_duration_since(Instant::now());\n                thread::sleep(want.min(cap));\n            }\n            Ok(KeyCmd::Commit { .. }) => {\n                committed = true;\n                break;\n            }\n            Err(RecvTimeoutError::Timeout) => break,\n            Err(RecvTimeoutError::Disconnected) => {\n                disconnected = true;\n                break;\n            }\n        }\n    }\n    // Flush buffered controller input AFTER the injected bytes + release the floor —\n    // in EVERY exit path (the ANTI-STALL guarantee).\n    flush_inject_floor(floor, input);\n    if disconnected {\n        SeqOutcome::Disconnected\n    } else if committed {\n        SeqOutcome::Committed { sent_text }\n    } else {\n        SeqOutcome::Missed\n    }\n}\n\n// [impl->REQ-MSG-IDLE-TRANSLATION-BINARY]\n// [impl->REQ-HAZARD-INJECT-CONTROL-COEXIST]\n// [impl->REQ-MSG-DELIVERY-AXES]\n// [impl->REQ-TRANSLATE-COMMIT-MISS-TOLERANCE]\n// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n#[allow(clippy::too_many_arguments)] // per-session worker wiring (C-1 added the respawn counter, W5-A the output-log tap); a struct would obscure the call\nfn run_inject_worker(\n    input: Arc<InputWriter>,\n    child: Arc<TranslationChild>,\n    floor: Arc<Mutex<InjectFloor>>,\n    event_rx: Receiver<String>,\n    cmd_rx: Receiver<KeyCmd>,\n    faulted: Arc<AtomicBool>,\n    respawns: Arc<AtomicU32>,\n    log: Arc<Mutex<OutputLog>>,\n    endpoint: String,\n) {\n    // C-1 worker-local state (REQ-TRANSLATE-COMMIT-MISS-TOLERANCE): CONSECUTIVE\n    // commit-deadline misses (reset on any successful `{commit}`), and the set of\n    // envelopes already respooled-once so a repeat miss dead-letters instead of\n    // respooling forever. Both are worker-local: a REAL fault exits the worker, and\n    // a respawn builds a fresh worker with a fresh budget + set.\n    let mut strikes: u32 = 0;\n    let mut respooled_once: HashSet<String> = HashSet::new();\n    // W5-A Layer 1 (re-arm fix): settle before EVERY delivery, not once per worker. The\n    // head-swallow race is NOT startup-only — a mid-session `/clear` re-enters the\n    // harness's raw-mode input reader and re-creates the pre-settle window (field-proven\n    // on 0.29.0: a checkpoint-wake payload injected right after `/clear` lost its head\n    // even though the worker had long since settled at spawn). So an echoing/interactive\n    // PTY re-settles per delivery (cheap: a tick or two once the reader answers). The old\n    // one-shot's ONLY legitimate purpose was sparing a NON-echoing ConPTY the full\n    // settle-deadline on every delivery (its DSR answer never surfaces, and it has no\n    // reader-reattach race to guard). We keep exactly that optimization via a LATCH driven\n    // by the settle's own return value: a settle that TIMES OUT (probe unobservable) sets\n    // this, and thereafter first-attempt settles are skipped; a settle that is OBSERVED\n    // keeps it clear, so the bug-prone class re-settles forever.\n    let mut probe_unobservable = false;\n    // Layer 2 (echo-verify → re-drive → LOUD spool) is a DECLARED CAPABILITY, default\n    // OFF (`SPT_INJECT_VERIFY_ECHO`). It applies ONLY where the harness re-renders typed\n    // input into its observable output (a real TUI's input line does; a bare shell / a\n    // ConPTY programmatic inject / a test echo-child on ConPTY does NOT). Universal\n    // auto-detection is infeasible — a raw-mode TUI does not echo a benign control probe\n    // (so the probe cannot prove text-echo), and incidental output (a prompt, a redraw)\n    // would make a head-prefix check false-read head-loss and spuriously LOUD-spool EVERY\n    // delivery. So an adapter that KNOWS its harness echoes declares the capability\n    // (parallel to the ruling's \"bracketed-paste where the harness declares it\"); Layer 1\n    // (the settle-gate) is the UNCONDITIONAL root fix. The int gate also forces it on\n    // (`SPT_INJECT_FORCE_ECHO_MISS`) to exercise the re-drive/spool wiring on any platform.\n    // AMBIENT env can NOT arm this: both vars are scrubbed at daemon startup\n    // (`spt_runtime::INJECT_ECHO_ENV_VARS`, F-036 env-inheritance class — an inherited\n    // dev-shell export once force-enabled echo-verify host-wide and a false miss RETYPED\n    // sequences into a live session's input). Only an explicit declaration (or an\n    // in-process test broker, which never runs the daemon entrypoints) reaches this read.\n    let echo_capable = std::env::var_os(\"SPT_INJECT_VERIFY_ECHO\").is_some()\n        || std::env::var_os(\"SPT_INJECT_FORCE_ECHO_MISS\").is_some();\n    // `event_rx` blocks here; events queue → one sequence at a time.\n    for envelope in event_rx {\n        // A well-behaved filter only emits in response to an event, but drop any\n        // unsolicited commands left in the channel so they can't be mis-attributed\n        // to this event's sequence.\n        while cmd_rx.try_recv().is_ok() {}\n\n        let envelope_copy = envelope.clone();\n\n        // ── W5-A: run the sequence with a settle-gate (Layer 1) before ANY byte, an\n        // echo-verify (Layer 2) after `{commit}`, and ONE re-drive on a verify miss →\n        // LOUD spool on a second miss (silent+unrecoverable head-loss → recoverable+loud).\n        // The commit-deadline MISS / binary-death / send-fail semantics below are\n        // unchanged (C-1 miss-tolerance).\n        let mut committed = false;\n        let mut disconnected = false;\n        let mut send_failed = false;\n        let mut integrity_lost = false;\n        for attempt in 1..=INJECT_REDRIVE_ATTEMPTS {\n            // Layer 1: settle-gate before the first byte of EVERY delivery on an echoing\n            // PTY (re-arm — a mid-session `/clear` re-creates the reader-reattach race),\n            // and always before a RE-DRIVE (only reached on a swallowed head, so re-confirm\n            // readiness before retyping). Skip only where the probe is known unobservable\n            // (a non-echoing ConPTY — no race to guard, and settling would burn the full\n            // deadline). The latch is driven by the FIRST-ATTEMPT settle's own outcome.\n            if should_settle(attempt, probe_unobservable) {\n                let observed = settle_before_inject(&input, &log, &endpoint);\n                if attempt == 1 {\n                    probe_unobservable = !observed;\n                }\n            }\n            // Snapshot the ring high-water AFTER settling (excludes probe echoes) so\n            // Layer 2 sees only THIS sequence's output.\n            let seq_start = recover_log(&log).high_water();\n            match drive_one_sequence(&input, &floor, &child, &cmd_rx, envelope_copy.clone()) {\n                SeqOutcome::SendFailed => {\n                    send_failed = true;\n                    break;\n                }\n                SeqOutcome::Disconnected => {\n                    disconnected = true;\n                    break;\n                }\n                SeqOutcome::Missed => {\n                    // Commit-deadline miss — leave to the C-1 miss path (not an\n                    // integrity re-drive; the binary never signalled a complete sequence).\n                    break;\n                }\n                SeqOutcome::Committed { sent_text } => {\n                    committed = true;\n                    // Layer 2: verify the typed head echoed back — ONLY where the terminal\n                    // demonstrably echoes (else a non-echoing PTY's incidental output would\n                    // false-read head-loss). Where it does not echo, Layer 1 stands alone.\n                    if !echo_capable || echo_verify_after(&log, seq_start, &sent_text) {\n                        break; // delivered byte-complete (or echo-verify not applicable here)\n                    }\n                    if attempt < INJECT_REDRIVE_ATTEMPTS {\n                        spt_proto::emit_line_err!(\n                            \"INJECT_ECHO_MISS:{endpoint}: typed head did not echo (attempt {attempt}/{INJECT_REDRIVE_ATTEMPTS}) — re-driving once\"\n                        );\n                        committed = false; // re-drive; only a verified commit counts\n                        continue;\n                    }\n                    // Second miss → the head is swallowed even after a re-drive.\n                    integrity_lost = true;\n                    break;\n                }\n            }\n        }\n\n        if send_failed {\n            // stdin write FAILED → the binary is genuinely GONE (a REAL fault): re-spool\n            // the in-flight envelope, stamp + terminate, exit for a bounded respawn.\n            respool_and_fault(\n                &endpoint,\n                envelope_copy,\n                &faulted,\n                &child,\n                \"stdin write failed\",\n            );\n            return;\n        }\n\n        if integrity_lost {\n            // Layer 2 fallback: the typed head never echoed, even after a re-drive.\n            // A live-SENT inject leaves no spool copy, so convert the silent+unrecoverable\n            // truncation into recoverable+loud — re-spool the envelope (idle-eligible,\n            // poll-fed) with a distinct integrity marker. NOT a binary fault (the binary\n            // committed fine; the terminal swallowed the head), so the worker survives.\n            respool_envelope(&endpoint, &envelope_copy);\n            spt_proto::emit_line_err!(\n                \"INJECT_HEAD_LOSS_SPOOL:{endpoint}: typed payload head did not echo after {INJECT_REDRIVE_ATTEMPTS} attempts — re-spooled loud (delivered=false, recoverable); frame integrity NOT confirmed\"\n            );\n            strikes = 0;\n            respawns.store(0, Ordering::Relaxed);\n            respooled_once.remove(&envelope_copy);\n            continue;\n        }\n\n        if committed {\n            // Healthy sequence: reset the strike counter, refresh the respawn budget\n            // (a working binary heals it), and forget any earlier respool of THIS\n            // envelope (it succeeded → a future miss may respool it afresh).\n            strikes = 0;\n            respawns.store(0, Ordering::Relaxed);\n            respooled_once.remove(&envelope_copy);\n            continue;\n        }\n\n        if disconnected {\n            // REAL binary death (stdout closed mid-sequence): re-spool + stamp +\n            // terminate + exit for a bounded respawn.\n            respool_and_fault(\n                &endpoint,\n                envelope_copy,\n                &faulted,\n                &child,\n                \"binary stdout disconnected\",\n            );\n            return;\n        }\n\n        // ── COMMIT-DEADLINE MISS (miss ≠ fault, REQ-TRANSLATE-COMMIT-MISS-TOLERANCE).\n        // The stdin write SUCCEEDED so the binary is ALIVE; the watchdog already did\n        // its ONLY legitimate job (flushed + released the floor above). Do NOT\n        // terminate, do NOT latch `faulted`. The in-memory pending wake survives the\n        // boundary → the v0.12.0 checkpoint post-clear wake works as intended.\n        strikes += 1;\n        match note_miss_respool(&mut respooled_once, &envelope_copy) {\n            MissRespool::Respool => {\n                // First miss of this envelope — respool it ONCE (idle-eligible,\n                // poll-fed) without faulting.\n                respool_envelope(&endpoint, &envelope_copy);\n                spt_proto::emit_line_err!(\n                    \"TRANSLATION_COMMIT_MISS:{endpoint}: no {{commit}} within deadline (strike {strikes}/{}) — binary preserved, envelope respooled once\",\n                    inject_miss_strike_budget()\n                );\n            }\n            MissRespool::DeadLetter => {\n                // A repeat miss of an already-respooled envelope (e.g. the checkpoint\n                // duplicate FIRE looping back on a later drain): DEAD-LETTER it loud —\n                // do NOT respool again (never a silent drop; it still counts as a\n                // strike), REQ-HAZARD-IDLE-SILENT-NONDELIVERY posture.\n                spt_proto::emit_line_err!(\n                    \"TRANSLATION_COMMIT_MISS_DEADLETTER:{endpoint}: envelope missed {{commit}} again after a prior respool (strike {strikes}/{}) — dead-lettered, NOT respooled again (reported non-delivery, not a silent drop)\",\n                    inject_miss_strike_budget()\n                );\n            }\n        }\n\n        if miss_strikes_exhausted(strikes, inject_miss_strike_budget()) {\n            // N CONSECUTIVE misses with no intervening commit → a REAL fault: the\n            // binary is wedged. Stamp + terminate + exit for a bounded respawn. (The\n            // envelope was already respooled/dead-lettered above — no double respool.)\n            fault_translation_stamped(\n                &endpoint,\n                &faulted,\n                &child,\n                \"no {commit} within INJECT_COMMIT_DEADLINE for the strike budget\",\n            );\n            return;\n        }\n        // Miss tolerated (below the budget): the binary survives — continue to the\n        // next queued event through the SAME live binary.\n    }\n    // `event_tx` dropped → session teardown. Reap the child (no zombie).\n    child.terminate();\n}\n\n/// Re-spool the in-flight envelope as non-deferred (idle-eligible) so the\n/// relay/poll can surface it. Used on a commit-deadline MISS (no fault) and,\n/// composed with the fault, on a REAL binary-death fault.\n// [impl->REQ-MSG-DELIVERY-AXES]\n// [impl->REQ-TRANSLATE-COMMIT-MISS-TOLERANCE]\nfn respool_envelope(endpoint: &str, envelope: &str) {\n    let perch_path =\n        spt_store::perch::resolve_perch_path(endpoint, spt_store::perch::ParentHint::Infer);\n    if let Err(e) = spt_store::spool::spool_message_at(&perch_path, \"\", envelope) {\n        spt_proto::emit_line_err!(\n            \"TRANSLATION_FAULT_RESPOOL:{endpoint}: failed to re-spool ({e}) — message dropped\"\n        );\n    }\n}\n\n/// Re-spool the in-flight envelope (a REAL binary-death fault genuinely lost the\n/// in-flight delivery), then stamp the perch + fault the translation binary.\n// [impl->REQ-MSG-DELIVERY-AXES]\nfn respool_and_fault(\n    endpoint: &str,\n    envelope: String,\n…\n) {\n…\n}","startLine":4096,"lineNumbers":[4096,null,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,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,null,4573,null,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,null,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,null,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,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,null,5194,null,5197]},"fileSize":857503,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\broker.rs"}}},"isError":false,"timestamp":1789295502515}}
{"type":"message","id":"4f244fbb","parentId":"55356650","timestamp":"2026-09-13T10:31:42.536Z","message":{"role":"toolResult","toolCallId":"call_A4Z9WO2tolSYOyU9XlJhAoK7|fc_0b12df87254bb4e6016aa67b8e603887d19b8b257abeeeeb18","toolName":"grep","content":[{"type":"text","text":"# .worktrees/300-input-acceptance/crates/spt-daemon/\n## Cargo.toml#AEA5\n 83:# (artifact digest) so the signature covers the binary, not just the manifest.\n*84:sha2 = \"0.10\"\n 85:# Per-frame link auth on the same-node shell channels (CONTEXT local-link\n 86:# authentication): HMAC-SHA256 over the token-derived link key (M5-D3b).\n 87:hmac = \"0.12\"\n...\n 102:# Both already in the lockfile via spt-store at these exact versions.\n*103:rsa = { version = \"0.9\", default-features = false, features = [\"sha2\"] }\n 104:rand = \"0.8\"\n 105:spt-test-support = { path = \"../spt-test-support\" }\n 106:# TEST-ONLY independent width-aware emulator for the REQ-SCREENGRID-WIDTH\n\n## src/\n### broker.rs#3A1D\n 4120:    /// writer thread, never the broker dispatch thread.\n*4121:    input: Arc<InputWriter>,\n 4122:    /// The output drain pump (kept so teardown can stop it).\n 4123:    #[allow(dead_code)] // held for ownership/teardown; not read directly\n 4124:    drain: Drain,\n...\n 4193:/// the blocking [`SessionSurface::write_input`]; every other site enqueues a\n*4194:/// record via [`InputWriter::enqueue`] (a non-blocking `try_send`) and returns\n 4195:/// immediately. So a paste burst that fills the ConPTY/forkpty input buffer\n 4196:/// parks ONLY this thread — the broker dispatch thread, attach-opens, resizes,\n 4197:/// and every other session stay fully live (the W1b-deferred fix (2)). Mirrors\n 4198:/// the OUTPUT-side [`ViewerSink`]/[`ControllerSink`] writer-thread pattern.\n*4199:struct InputWriter {\n 4200:    /// The bounded input FIFO to the writer thread. `try_send` only — a full\n 4201:    /// queue (a genuinely wedged harness) DROPS, it never blocks.\n 4202:    tx: SyncSender<InputRecord>,\n...\n 4214:\n*4215:impl InputWriter {\n 4216:    /// Spawn a session's input-writer thread. `session` is the `Arc<PtySession>`\n 4217:    /// whose PTY write handle this thread now exclusively owns.\n*4218:    fn spawn(session: Arc<PtySession>, endpoint: String) -> Arc<InputWriter> {\n 4219:        let (tx, rx) = sync_channel::<InputRecord>(input_queue_depth());\n 4220:        let writer = thread::spawn(move || input_writer(session, rx));\n*4221:        Arc::new(InputWriter {\n 4222:            tx,\n 4223:            backpressure: AtomicBool::new(false),\n 4224:            endpoint,\n...\n 4587:\n*4588:fn flush_inject_floor(floor: &Mutex<InjectFloor>, input: &InputWriter) {\n 4589:    loop {\n 4590:        let chunk = lock_floor(floor).take_or_release();\n 4591:        match chunk {\n...\n 4632:    endpoint_id: &str,\n*4633:    input: &Arc<InputWriter>,\n 4634:    respawns: Arc<AtomicU32>,\n 4635:    log: &Arc<Mutex<OutputLog>>,\n 4636:) -> Option<Arc<Translation>> {\n...\n 4756:// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n*4757:fn settle_before_inject(input: &InputWriter, log: &Mutex<OutputLog>, endpoint: &str) -> bool {\n 4758:    let baseline = recover_log(log).high_water();\n 4759:    let deadline = Instant::now() + inject_settle_deadline();\n 4760:    loop {\n...\n 4842:// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n*4843:fn enqueue_text_chunked(input: &InputWriter, bytes: Vec<u8>) {\n 4844:    chunk_text(&bytes, inject_text_chunk(), |part| {\n 4845:        input.enqueue(part.to_vec());\n 4846:    });\n...\n 4884:fn drive_one_sequence(\n*4885:    input: &InputWriter,\n 4886:    floor: &Mutex<InjectFloor>,\n 4887:    child: &TranslationChild,\n 4888:    cmd_rx: &Receiver<KeyCmd>,\n...\n 4915:                sent_text.extend_from_slice(&bytes);\n*4916:                enqueue_text_chunked(input, bytes);\n 4917:            }\n 4918:            Ok(KeyCmd::Delay { delay_ms }) => {\n 4919:                let want = Duration::from_millis(delay_ms);\n...\n 4952:fn run_inject_worker(\n*4953:    input: Arc<InputWriter>,\n 4954:    child: Arc<TranslationChild>,\n 4955:    floor: Arc<Mutex<InjectFloor>>,\n 4956:    event_rx: Receiver<String>,\n...\n 7066:             backend: {}\\n\\\n*7067:             pubkey-sha256: {fingerprint}\\n\\\n 7068:             A member-or-admin code of '{}' admits this enrollment; Esc cancels.\",\n 7069:            req.subnet, req.backend_kind, req.subnet\n 7070:        );\n...\n 8318:        // too, so the lone writer enforces the W2 inject-floor order.\n*8319:        let input = InputWriter::spawn(Arc::clone(&session), req.endpoint.clone());\n 8320:        // releases#199: the span from here to `row_inserted` is the one a 10-way\n 8321:        // contention run put 1427ms into while the ConPTY create took 14ms — the\n 8322:        // child is ALREADY RUNNING through all of it and the row the bring-up poll\n...\n 10055:#[cfg(test)]\n*10056:mod tests {\n 10057:    use super::*;\n 10058:    use crate::msg::KIND_VIEWER_EVICTED;\n 10059:\n...\n 11004:    // ── v0.13.0 P0 — REQ-HAZARD-PTY-INPUT-WRITER-WEDGE: the PTY input\n*11005:    //    single-writer unit kernel. These exercise the REAL `InputWriter::enqueue`\n 11006:    //    against the REAL bounded `sync_channel` + the REAL backpressure atomic,\n 11007:    //    with a CALLER-CONTROLLED consumer (the test owns `rx` and drains by hand).\n 11008:    //    No PTY, no wall-clock in any decision assertion — the whole point of the\n...\n 11010:\n*11011:    /// Build an [`InputWriter`] over a caller-supplied bounded channel so the test\n 11012:    /// controls the consumer precisely. `endpoint` is EMPTY, so `stamp_backpressure`\n 11013:    /// is a no-op (impl: `if self.endpoint.is_empty() { return; }`) — the perch\n 11014:    /// mirror is the int test's job; here we assert the in-crate `backpressure`\n...\n 11017:    /// the ORDER test; here the TEST is the consumer, draining `rx` deterministically.\n*11018:    fn test_input_writer(depth: usize) -> (InputWriter, Receiver<InputRecord>) {\n 11019:        let (tx, rx) = sync_channel::<InputRecord>(depth);\n*11020:        let w = InputWriter {\n 11021:            tx,\n 11022:            backpressure: AtomicBool::new(false),\n 11023:            endpoint: String::new(),\n### lib.rs#EDDC\n 263:pub use release::{\n*264:    current_platform, parse_verifying_key, sha256_hex, verify_artifact, verify_detached,\n 265:    verify_metadata, verify_signature, verify_update_set_artifact, verify_update_set_docs,\n 266:    verify_update_set_metadata,\n 267:    RejectReason,"}],"details":{"scopePath":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs, .worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml, .worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":23,"fileCount":3,"files":[".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs",".worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml",".worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs"],"fileMatches":[{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs","count":20},{"path":".worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml","count":2},{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs","count":1}],"truncated":true,"perFileLimitReached":20,"displayContent":"# .worktrees/300-input-acceptance/crates/spt-daemon/\n## Cargo.toml#AEA5\n  83│# (artifact digest) so the signature covers the binary, not just the manifest.\n *84│sha2 = \"0.10\"\n  85│# Per-frame link auth on the same-node shell channels (CONTEXT local-link\n  86│# authentication): HMAC-SHA256 over the token-derived link key (M5-D3b).\n  87│hmac = \"0.12\"\n    │...\n 102│# Both already in the lockfile via spt-store at these exact versions.\n*103│rsa = { version = \"0.9\", default-features = false, features = [\"sha2\"] }\n 104│rand = \"0.8\"\n 105│spt-test-support = { path = \"../spt-test-support\" }\n 106│# TEST-ONLY independent width-aware emulator for the REQ-SCREENGRID-WIDTH\n\n## src/\n### broker.rs#3A1D\n  4120│    /// writer thread, never the broker dispatch thread.\n *4121│    input: Arc<InputWriter>,\n  4122│    /// The output drain pump (kept so teardown can stop it).\n  4123│    #[allow(dead_code)] // held for ownership/teardown; not read directly\n  4124│    drain: Drain,\n      │...\n  4193│/// the blocking [`SessionSurface::write_input`]; every other site enqueues a\n *4194│/// record via [`InputWriter::enqueue`] (a non-blocking `try_send`) and returns\n  4195│/// immediately. So a paste burst that fills the ConPTY/forkpty input buffer\n  4196│/// parks ONLY this thread — the broker dispatch thread, attach-opens, resizes,\n  4197│/// and every other session stay fully live (the W1b-deferred fix (2)). Mirrors\n  4198│/// the OUTPUT-side [`ViewerSink`]/[`ControllerSink`] writer-thread pattern.\n *4199│struct InputWriter {\n  4200│    /// The bounded input FIFO to the writer thread. `try_send` only — a full\n  4201│    /// queue (a genuinely wedged harness) DROPS, it never blocks.\n  4202│    tx: SyncSender<InputRecord>,\n      │...\n  4214│\n *4215│impl InputWriter {\n  4216│    /// Spawn a session's input-writer thread. `session` is the `Arc<PtySession>`\n  4217│    /// whose PTY write handle this thread now exclusively owns.\n *4218│    fn spawn(session: Arc<PtySession>, endpoint: String) -> Arc<InputWriter> {\n  4219│        let (tx, rx) = sync_channel::<InputRecord>(input_queue_depth());\n  4220│        let writer = thread::spawn(move || input_writer(session, rx));\n *4221│        Arc::new(InputWriter {\n  4222│            tx,\n  4223│            backpressure: AtomicBool::new(false),\n  4224│            endpoint,\n      │...\n  4587│\n *4588│fn flush_inject_floor(floor: &Mutex<InjectFloor>, input: &InputWriter) {\n  4589│    loop {\n  4590│        let chunk = lock_floor(floor).take_or_release();\n  4591│        match chunk {\n      │...\n  4632│    endpoint_id: &str,\n *4633│    input: &Arc<InputWriter>,\n  4634│    respawns: Arc<AtomicU32>,\n  4635│    log: &Arc<Mutex<OutputLog>>,\n  4636│) -> Option<Arc<Translation>> {\n      │...\n  4756│// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n *4757│fn settle_before_inject(input: &InputWriter, log: &Mutex<OutputLog>, endpoint: &str) -> bool {\n  4758│    let baseline = recover_log(log).high_water();\n  4759│    let deadline = Instant::now() + inject_settle_deadline();\n  4760│    loop {\n      │...\n  4842│// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n *4843│fn enqueue_text_chunked(input: &InputWriter, bytes: Vec<u8>) {\n  4844│    chunk_text(&bytes, inject_text_chunk(), |part| {\n  4845│        input.enqueue(part.to_vec());\n  4846│    });\n      │...\n  4884│fn drive_one_sequence(\n *4885│    input: &InputWriter,\n  4886│    floor: &Mutex<InjectFloor>,\n  4887│    child: &TranslationChild,\n  4888│    cmd_rx: &Receiver<KeyCmd>,\n      │...\n  4915│                sent_text.extend_from_slice(&bytes);\n *4916│                enqueue_text_chunked(input, bytes);\n  4917│            }\n  4918│            Ok(KeyCmd::Delay { delay_ms }) => {\n  4919│                let want = Duration::from_millis(delay_ms);\n      │...\n  4952│fn run_inject_worker(\n *4953│    input: Arc<InputWriter>,\n  4954│    child: Arc<TranslationChild>,\n  4955│    floor: Arc<Mutex<InjectFloor>>,\n  4956│    event_rx: Receiver<String>,\n      │...\n  7066│             backend: {}\\n\\\n *7067│             pubkey-sha256: {fingerprint}\\n\\\n  7068│             A member-or-admin code of '{}' admits this enrollment; Esc cancels.\",\n  7069│            req.subnet, req.backend_kind, req.subnet\n  7070│        );\n      │...\n  8318│        // too, so the lone writer enforces the W2 inject-floor order.\n *8319│        let input = InputWriter::spawn(Arc::clone(&session), req.endpoint.clone());\n  8320│        // releases#199: the span from here to `row_inserted` is the one a 10-way\n  8321│        // contention run put 1427ms into while the ConPTY create took 14ms — the\n  8322│        // child is ALREADY RUNNING through all of it and the row the bring-up poll\n      │...\n 10055│#[cfg(test)]\n*10056│mod tests {\n 10057│    use super::*;\n 10058│    use crate::msg::KIND_VIEWER_EVICTED;\n 10059│\n      │...\n 11004│    // ── v0.13.0 P0 — REQ-HAZARD-PTY-INPUT-WRITER-WEDGE: the PTY input\n*11005│    //    single-writer unit kernel. These exercise the REAL `InputWriter::enqueue`\n 11006│    //    against the REAL bounded `sync_channel` + the REAL backpressure atomic,\n 11007│    //    with a CALLER-CONTROLLED consumer (the test owns `rx` and drains by hand).\n 11008│    //    No PTY, no wall-clock in any decision assertion — the whole point of the\n      │...\n 11010│\n*11011│    /// Build an [`InputWriter`] over a caller-supplied bounded channel so the test\n 11012│    /// controls the consumer precisely. `endpoint` is EMPTY, so `stamp_backpressure`\n 11013│    /// is a no-op (impl: `if self.endpoint.is_empty() { return; }`) — the perch\n 11014│    /// mirror is the int test's job; here we assert the in-crate `backpressure`\n      │...\n 11017│    /// the ORDER test; here the TEST is the consumer, draining `rx` deterministically.\n*11018│    fn test_input_writer(depth: usize) -> (InputWriter, Receiver<InputRecord>) {\n 11019│        let (tx, rx) = sync_channel::<InputRecord>(depth);\n*11020│        let w = InputWriter {\n 11021│            tx,\n 11022│            backpressure: AtomicBool::new(false),\n 11023│            endpoint: String::new(),\n### lib.rs#EDDC\n 263│pub use release::{\n*264│    current_platform, parse_verifying_key, sha256_hex, verify_artifact, verify_detached,\n 265│    verify_metadata, verify_signature, verify_update_set_artifact, verify_update_set_docs,\n 266│    verify_update_set_metadata,\n 267│    RejectReason,"},"isError":false,"timestamp":1789295502535}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_RhRViwtbUKclbMSW167BgDRE|fc_0b12df87254bb4e6016aa67ba23e8487d19a29e1eeb641fd36","toolName":"hub","startedAt":"2026-09-13T10:32:04.816Z","intent":"Coordinating delivery ledger contract"},"id":"1fb8b96a","parentId":"4f244fbb","timestamp":"2026-09-13T10:32:04.816Z"}
{"type":"message","id":"0e26cba6","parentId":"1fb8b96a","timestamp":"2026-09-13T10:32:04.817Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Designing bounded hash ledger**\n\n**Refining bounded hash ledger**\n\n**Designing delivery ledger**"},{"type":"toolCall","id":"call_RhRViwtbUKclbMSW167BgDRE|fc_0b12df87254bb4e6016aa67ba23e8487d19a29e1eeb641fd36","name":"hub","arguments":{"i":"Coordinating delivery ledger contract","op":"send","to":"Main","message":"Implementing new deliverybytes.rs private module (please add `mod deliverybytes;` in lib.rs). InputWriter::delivery_matches exact SHA-256 successful Text aggregates; Keys/control input source-distinguished. Bounded session-life digest set (no eviction); adding InputWriter::delivery_unavailable_reason() -> Option<&'static str> returning `delivery-evidence-capacity` once quota exhausted: report dispatch MUST decline named reason before any origin grant. Pending record metadata uses bounded streaming hash state; hashes published after successful final chunk of each Text command, before following Enter write. Narrow physical completion/publication race remains documented."},"intent":"Coordinating delivery ledger contract"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":11493,"output":636,"cacheRead":20224,"cacheWrite":0,"totalTokens":32353,"reasoningTokens":476,"cost":{"input":0.11493,"output":0.0318,"cacheRead":0.020224,"cacheWrite":0,"total":0.166954}},"stopReason":"toolUse","timestamp":1789295502563,"responseId":"resp_0b12df87254bb4e6016aa67b8ec82087d185df6dac5a67d6a6","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67b91b09487d19f82dd3f5af95d08","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnuisp7OQKC-GZayGunJYs0OM_2wYocNi-IxCDivIgpihqYa_-A2MRRLdCAqxVL-w7HexvtxQ1rh4THmK5GhgtfWCzhfHOup8LurKmhqvxn9kBxO-TJ3r3OoK-99wSYEvrCOCBjAn0ijriYvfVvsUmbOQzu6kW46FHWAryZxjZnhwTc2Pa6iLfIpk5OSQnSr7HtdXdqa6-9Pcmh-v1aB6by7l6KY0TJkw6hgHEPlbwLmP7KiF-zXhmgDrv16GoTpvziUgmXWb8Ws8H8pdIlZTdqSuQlCdyQbXckxdejtwT9FnhkUKpetlZ2dXVtJ76n0Zosc57UVE4XQT2G4z-owPzOL44IX1nLgkwj4WezSgjkN8RoOXs2VTpxZmAzU-_JbxnHMDBgA-IvaSYTu1hSbtZR8obYqbJc58YSvFQD7TzTby2X0UdmxElIB34NahT08gXXQlKjPurL7nSVJNkWWvvfgyPhJnUMbQ18-NWtWDC67zUMQk59LHKUnn5nZG9UC94xJKRcxlQL4DVMdYEk36nPmyZqHoqcRrANDZYi7l4R0XhSA5i-XX9uZ02YQHrYg8xs5MkTRB2DkhjhtGn-HU4nf3T_JjGZJIupobJ9QLglt2iM7Wsjedd7KUv-SsRjtYhKD1NUcS3R9rT44RHo6WbR73f93g5J-77LHhKAwKtcdOmmzGKewT-uOAOJdcCi6mhsNV1ofXmFrij81IELu3hIhjGoiYrIYlNmWtHi_o4TUkTxcRi5qxaevKbKKYVhmlXDHGSBMhv5cPWzZ8gA5rEvBcMIpGZ_Ym3ib7-k6ZMutRVk1pM1RQDv_17M6xQO-R4JSiUjizlZ7hM6MO2zWsq4LROxk99DcZUJQa5265yzRq6QrtkYi1F81jliltRoW0fURXGp7481vJKkFMZhd3Feek33sQ3BnL2-X3kTpPhpZbUlmLIfWMlztKaO8xJ2tx5uQQlHrMK66NuyAJ79iEIcoVPxEB2JHWGmslRVJHogFwchlEAeBHcqIDBTUH1eT09-_FfdKL8dprFkMlVJs08qp7uHNRqX45559HgQQl-tNYpN_OknCmqhwWVzpWRZT6wQHedFFkwqM-jly_jlj7A_9m5tEdn8-4K67EodE7WGFtjUWoNbbKm2NyGutIn0mipaKiprhQeUKPRuQC6MXk_pLwtM9RueupXLwywGYI1MMlEwT0YxTXbTc3n54UEWNDxzrej0eGJXW8rwoUeDvwn5rv7so6NP3kVQy-7-wi9GVFYYjh-E7KPvQF9qgT3aIoBN5OE0LGFgIrqahd289ut4u2vr1F0d2J9hUK_D6N5Ra3Cki8F3A0fwbRoeih7txsuqXoAT5rewHn2bgop5gnOAextwhRF0onrRdH2tATMB2v9GWBKWMhq6n_5w1iDoZH44T9LIFBm-kAtDceEkdOMUoqdLQMEMoeYPSaE5-B8s1Ejnt9KmLxnyCYDOl6cXUyHwzPb_KTidzsQBUN9KRbSKi1JAdBKjCKM15pj4FtDSQSaCa2fIZKHQ9B-EEJVDWclDLpG-vpl2uvIQsMmFVRI3DM-tG7a-pTNN1-OCLTSAmtSge7UtsEACqj0KAbNSS5-7XW8koRBRQf6sHHmdexFyuC6RSJSsXJv5UdRxoTsqck9Lq6OgYUDv8NRGU1Zheoduzb-Lc7-k3bk04X1pT5ay7J1uX2AtGus4_EnpSqgcEQ3vHhC-Q8MXvlZB5TN-RNXB_B_52Fec4bE2GZrH4xh6FHvL_oT4siwT_npcdl2VobInw9aWbuyki64OVWYF-CwWDwzlJD5WdbGdrblvEm53SwUGnmja-RY-MIPofUSg4jKd3nkmafwDYB1sKHPn9q-PEZHAoFfpYcfVzBcrwDFYnDUEbWkIwzhtfdbnPxzqim5vMWcKQSGcpypqdakApwhZgttotSv2F2r8UZoQWwVZaNmHUudqyERCH57yn6EgUqli0xmkKN1163-Zh2SNF5ScCRBkpukIh4_oWjoV-pNFqfCj5k1g0qgjg6SX_xhRJ4Va42X7b84EjrhV5dUNb6s5XmNN8n6JF66WsDrsYzhFEBsQhyTWTF2HBP4j4a_1pkYbq92Zm9owsjqMZuNq64RahhyFKAuXwmXqdX5SYy5nASgyUolA7HmT2YKJ22u4-IB5d0n3j7n3NvuHHw8lF0RgbQCD5Cj1NVhmc6iraQNAzjbQgbPZ00ThuErq7YZR2jcgGVQxl8I-I5o75kQd21iX6W_4V1S4E_-3o2gok8_qBRVh5QwUAz3Rt9lLG0Hwm4g03UjnyfQvOdYVB-EJLLDxfNEAKTEjyqJjEcgoEQDcdi6eLJLbjxH0DeAA7vQyxRGTsJbNCHd_N4TdBmXsjN7MMUxETOYq1PZE_z9eWG5imUL5rcSEU-FyVaoWIaWt7y2JzHTRkZ99CsCfZwjOAJvoBwUM48CgT8ocYb_Aq9Ill0Ki5fiJVuqc76HQpNGXj8hoU79rXIqs19kkMsSUL52SWQRweNssF2sJ64BzZGMdoNrDmvU3ZHwIKKlLFf-DBNKuZ4XHSUxUIue6NIFr8rozNtPn0qD3Rt55UHGPkG8YTqgrpC-5V2RFl1LAeSqQLbFl1h7Rh0cJaKyEe4dQ2kVPtwq52tyd-KvsO8ibFarFoWtcfJvGz2PdaUXzNZogrN96upYJPQFjnBu5CvxQKMdeP5ruwibyw2R8jNeXF5hIZlvRNlvuhQ1cl3I_IpjLoY75__XI4X6U6xtPZHNP5GAbiPJdwa_VmAikzHYnKtyTBXiDUrllIzpwalzByudx7shpM1LsgBT_qqFbQ4J9NvmVpRtN4OgDpf0UQ6rxUzO4nsn76pcomuJUc7nTU98WdmN_vit_LEybbGnjRPkDFlRafGmmI4yffxwgQVGJH_cJRx9jIOJY4fOucyDnWA6kGuINi4f3gULh31IGvYFH9g8vOaQpRmrMiPlusmtX1lOqWA4r8QxR0AC-jqYPsDwaf0KfuImcHMiTV4XKbWt0oh9wFIeUKUjThdOSoEypVNeUJm-5zC9W1CINWeYVC0XYXNESG83IrAqPZ9QJY25ssJPwJ4mQWOU6NcvLN2ovhhXN0xKgvkImOBbuv9zH2X2abd-uaallcTngP_szoVYKMPiEgavusonBCe-xIIv1ARQWQfsrsc5Ov_UgkCZu3cOR6hAcJkD22uHpvI81jmLlpxnu7LX8e19IIgJOToDm8l3CxmGIw2zy-Fwcb77fIhk9ojhHD8pxYHqZ4tAOG76M46yMnJGHpYkw96AlFXuRSJziBJa4TAFoQnNV755aAtoHZU2uP97lq9zsfO7FOYsXQGVL3yu2M6Xn28QapX6YVER79IdjLTmPcGzZ4Ho3Av2qxqiMD0ZP_WQcVl9ibMpYKLJe4--5EMnqncuRxYGMWam8FgM2HCBvR14IHGaOcTsUai6tTbvWnwuz9suRAxtQ4yvMKCYqWsEhJYj2JUjftcrzLqzvKFVDekoIlb8YKwdjEMkOxPOc-r_cZxX5KyTiSyABSHbca4XsuiQwPsxhYBo-LD2ocWEYuz1Xpf2OLjhUXi93MEnQHqil1aY169C9r1Y1L-o-AhV7lXA4RdTccKfE0e4lrSnbYrBJaRV5cPrb6XWgHXpcyaRTAfzI9i-0jFRLHmpKnxBkKZixDYsPIm-22jSv5VYQHOqlk8_1COcRsBe5yJUb0I8P1XOtFf8mwuoskmQpbY96DbUn2RrM6eJcMg8H_43596kD6wVfqtRH_WL6HcObhxtV4PD52gZ95ZXAVPzYJKGSNqj1nQtd9YwYXMcd2V-MX72hEHghJVHfHhwH-yjq8gg3ADHJUySUKJcBxhuWFBOTonevkOPZRlN8AUiNN1IXbjnmViZDHny1htKHYpeSF9CzHmA21MLVWZc_muZbWtO17jxWVNSUUoETU7u8aWlY5soTLJQaT6AQi9j8bSPX02HB0uv_fSDrLypcU1gtGOF1_DEmJxZ572jSo5_pzpc5e87VkDg5jBx5yzdIIQ1K1_JIdbU_XNPCvUFFSe7Svuf6WS6zvQ5JfsnApFAWAb2eR_p-LP0Vs3ZT_7ifvD7FpRQw88UxVYwJJF_az5utQXJqOkRoFxItB5Fs1AZN51YxFIDK0lBE9XEvbVE2-Cqek6KvvLuCv1QZ81WKV8pl0S5QMWifhoqaEl3ES9z4AeIiNjNKQlHJy3dVaiGPcA_AC9ZIDqb-lnqMeJtvBGQc97-MgPk8S_BK4tmAOqfWxccFaQYmLvlzlT7Z0sLQ1woZF1YBQgBxb3oPdwSeJEjA9N5VLfrdV8tru9MVVScLCEKzoxIZWz3JKsbAmn_dtcqiSw4XetRC-MqfUSCe_xkwbnVhzy9ieNeBez0uQ1kzT3L1P9AfXg-kgd3uCiLa6EIwrl8EsTVsVFdnZi_EiTB5zwBC-7fTR_ipaRk6b0miDWTN5jJDUAlpwrBeDPftGq4k1V8j4iYNcDaCUu3_AL_1HsVQLQIjTRr52XEFhjJZEZgkJL-EDWiPoSjUx32LcSc_HTQSG3_iGEfgsQXIaonlccy164at4XCzxR5XCG8EYY7Y0EVOj0eVIOGdvlN3Sj7KiTf6wtrPUXYMBd08ppuD12moB544HBpyRFWg4rciYB8euZe4vAOhW1X0s0ui6HfJJYIukd3KrjefWtdGNIWosY6lDd-4LnDo91L5xVV9BuyIG0mYrgokddCKbkkAOP__2FmNyM3JltPhrUl9YUr8POdfF02jsDCm3IYCasA0sNXyTc_RL5g5KjXf5Zpo=","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Designing bounded hash ledger**"},{"type":"summary_text","text":"**Refining bounded hash ledger**"},{"type":"summary_text","text":"**Designing delivery ledger**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67ba23e8487d19a29e1eeb641fd36","type":"function_call","status":"completed","arguments":"{\"i\":\"Coordinating delivery ledger contract\",\"op\":\"send\",\"to\":\"Main\",\"message\":\"Implementing new deliverybytes.rs private module (please add `mod deliverybytes;` in lib.rs). InputWriter::delivery_matches exact SHA-256 successful Text aggregates; Keys/control input source-distinguished. Bounded session-life digest set (no eviction); adding InputWriter::delivery_unavailable_reason() -> Option<&'static str> returning `delivery-evidence-capacity` once quota exhausted: report dispatch MUST decline named reason before any origin grant. Pending record metadata uses bounded streaming hash state; hashes published after successful final chunk of each Text command, before following Enter write. Narrow physical completion/publication race remains documented.\"}","call_id":"call_RhRViwtbUKclbMSW167BgDRE","internal_chat_message_metadata_passthrough":{"create_time":1789295502.935016,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"hub","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":22240.248900000006,"ttft":3144.908999999985,"completedAt":1789295524814,"contextSnapshot":{"promptTokens":31717,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"4d649413","parentId":"0e26cba6","timestamp":"2026-09-13T10:32:04.820Z","message":{"role":"toolResult","toolCallId":"call_RhRViwtbUKclbMSW167BgDRE|fc_0b12df87254bb4e6016aa67ba23e8487d19a29e1eeb641fd36","toolName":"hub","content":[{"type":"text","text":"Delivered to 1 peer(s):\n- Main: injected"}],"details":{"op":"send","from":"DeliveryRecording","to":"Main","receipts":[{"to":"Main","outcome":"injected"}]},"isError":false,"timestamp":1789295524818}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_KDzAAKLmcrVXc1zLbIySBwD6|fc_0b12df87254bb4e6016aa67baa801487d1b9cd3ae0d9002623","toolName":"read","startedAt":"2026-09-13T10:32:10.595Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:11004-11220"},"intent":"Reading existing writer tests"},"id":"4b40532c","parentId":"4d649413","timestamp":"2026-09-13T10:32:10.595Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_LmXtcH1LjPzaQr5rzHWmGFC5|fc_0b12df87254bb4e6016aa67baa802487d1b97d4099c0f473d3","toolName":"read","startedAt":"2026-09-13T10:32:10.595Z","args":{"path":".worktrees/300-input-acceptance/docs/INPUT-PROVENANCE-CONTRACT.md:220-"},"intent":"Reading authoritative provenance contract"},"id":"aa30be79","parentId":"4b40532c","timestamp":"2026-09-13T10:32:10.595Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_e1c1CEvseL9n8SBnkHJUUNXa|fc_0b12df87254bb4e6016aa67baa802c87d1a7676a1f8e5149db","toolName":"read","startedAt":"2026-09-13T10:32:10.595Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs:1-90"},"intent":"Reading daemon module conventions"},"id":"5081e31d","parentId":"aa30be79","timestamp":"2026-09-13T10:32:10.595Z"}
{"type":"message","id":"ee1fc67e","parentId":"5081e31d","timestamp":"2026-09-13T10:32:10.595Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_KDzAAKLmcrVXc1zLbIySBwD6|fc_0b12df87254bb4e6016aa67baa801487d1b9cd3ae0d9002623","name":"read","arguments":{"i":"Reading existing writer tests","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:11004-11220"},"intent":"Reading existing writer tests"},{"type":"toolCall","id":"call_LmXtcH1LjPzaQr5rzHWmGFC5|fc_0b12df87254bb4e6016aa67baa802487d1b97d4099c0f473d3","name":"read","arguments":{"i":"Reading authoritative provenance contract","path":".worktrees/300-input-acceptance/docs/INPUT-PROVENANCE-CONTRACT.md:220-"},"intent":"Reading authoritative provenance contract"},{"type":"toolCall","id":"call_e1c1CEvseL9n8SBnkHJUUNXa|fc_0b12df87254bb4e6016aa67baa802c87d1a7676a1f8e5149db","name":"read","arguments":{"i":"Reading daemon module conventions","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs:1-90"},"intent":"Reading daemon module conventions"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":759,"output":146,"cacheRead":31616,"cacheWrite":0,"totalTokens":32521,"cost":{"input":0.00759,"output":0.0073,"cacheRead":0.031616,"cacheWrite":0,"total":0.046506}},"stopReason":"toolUse","timestamp":1789295524829,"responseId":"resp_0b12df87254bb4e6016aa67ba50e6087d1bf2018a96b521db4","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0b12df87254bb4e6016aa67baa801487d1b9cd3ae0d9002623","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading existing writer tests\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:11004-11220\"}","call_id":"call_KDzAAKLmcrVXc1zLbIySBwD6","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67baa802487d1b97d4099c0f473d3","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading authoritative provenance contract\",\"path\":\".worktrees/300-input-acceptance/docs/INPUT-PROVENANCE-CONTRACT.md:220-\"}","call_id":"call_LmXtcH1LjPzaQr5rzHWmGFC5","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67baa802c87d1a7676a1f8e5149db","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading daemon module conventions\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs:1-90\"}","call_id":"call_e1c1CEvseL9n8SBnkHJUUNXa","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":5764.473800000036,"ttft":5694.656799999997,"completedAt":1789295530594,"contextSnapshot":{"promptTokens":32375,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"8a11be95","parentId":"ee1fc67e","timestamp":"2026-09-13T10:32:10.604Z","message":{"role":"toolResult","toolCallId":"call_e1c1CEvseL9n8SBnkHJUUNXa|fc_0b12df87254bb4e6016aa67baa802c87d1a7676a1f8e5149db","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/lib.rs#EDDC]\n1://! `spt-daemon` — the per-machine broker/brain supervisor (M3b).\n2://!\n3://! ADR-0004 splits the logical daemon into two implementation layers so a\n4://! routine self-update swaps the logic without disturbing live endpoints:\n5://!\n6://! - a **broker** (stable kernel) holds *only* the un-transferable resources a\n7://!   live consumer would lose continuity on if the logic restarted — PTY\n8://!   masters (from [`spt_term`]), spawned harness children, accepted/listening\n9://!   sockets — and runs no logic;\n10://! - a **brain** (restartable logic) holds routing, registry, manifest parse,\n11://!   and the re-hosted [`spt_live`] lifecycle, attaching to the broker over a\n12://!   **versioned local IPC** so a *newer brain talks to an older broker*.\n13://!\n14://! **B0 (this commit)** lands the crate's layer position plus that versioned\n15://! IPC seam — the load-bearing contract everything else rides:\n16://!\n17://! - [`frame`] — the forward-compatible [`Envelope`] schema + the version\n18://!   [`Hello`] handshake (KNOWN-HAZARDS 2.3, [`REQ-HAZARD-HANDOFF-ARGV-COMPAT`]);\n19://! - [`codec`] — length-prefixed JSON framing over any [`std::io::Read`]/`Write`;\n20://! - [`transport`] — the OS-split carrier (named pipe / UDS) behind one\n21://!   [`DaemonTransport`] trait, mirroring `spt-term`'s `SessionSurface`.\n22://!\n23://! **B1 (this commit)** adds the **broker kernel** ([`broker`]) — the stable\n24://! half that hosts a real `spt-term` PTY child and relays its output/input over\n25://! the IPC, holding only the ADR-0004 §B resources and no logic — plus the\n26://! broker↔brain message catalog ([`msg`]).\n27://!\n28://! **B3 (this commit)** consolidates the interim no-daemon model into the brain:\n29://! the `api listen` pulse / Psyche / drop-ingest loops become scheduled\n30://! in-process loops ([`lifecycle::BrainLifecycle`]) paced by a durable,\n31://! configurable period ([`config::DaemonConfig`]) instead of the interim 5s\n32://! constant; the only residue left in the harness-hosted session is the thin,\n33://! stateless [`relay::Relay`]. The `spt` binary's `LiveHost` becomes a shim over\n34://! `BrainLifecycle` (re-host, not rewrite) ([`REQ-DAEMON-1`]).\n35://!\n36://! **B5 (this commit)** makes the broker↔brain boundary **exactly-once across a\n37://! brain crash** ([`effect::EffectJournal`]): an idempotent `input` carries a\n38://! durable `op_id`, and the broker dedups at the effect keyed by that id over a\n39://! broker-owned recovery anchor (KNOWN-HAZARDS 7.2, [`REQ-HAZARD-RESTART-IDEMPOTENT`];\n40://! Spike #6's two constraints — broker-owned anchor, dedup-at-effect-by-id —\n41://! instantiated on the real PTY-write boundary).\n42://!\n43://! **C0 (this commit)** opens M3c — the self-update engine ([`update`]): the\n44://! ADR-0004 §A update-class taxonomy ([`UpdateClass`] + [`classify`]) and the\n45://! **brain-only zero-interruption swap** ([`apply_brain_only`], [`REQ-UPD-3`]).\n46://! The brain-only apply *triggers* a handoff over the B2 substrate — snapshot →\n47://! drop → re-attach — so the live PTY child + its output stream survive the logic\n48://! swap untouched; it never re-implements the handoff and never touches a broker\n49://! resource.\n50://!\n51://! **C1 (this commit)** adds the verify-before-handoff gate ([`release`]): a\n52://! release is signature-verified ([`REQ-UPD-2`]) and hardened against rollback\n53://! ([`REQ-HAZARD-UPDATE-ROLLBACK`]) — Ed25519 over signed metadata, key\n54://! trust/revocation, channel pinning, metadata expiry, monotonic version, and a\n55://! SHA-256 binding the signature to the actual binary bytes. [`plan_verified`] is\n56://! the front door: it produces an [`UpdatePlan`] *only* for a release that passes\n57://! every check, so an unverified binary can never reach [`apply_brain_only`].\n58://!\n59://! **C3 (this commit)** conducts the **adapter ripple** ([`adapter_update`]):\n60://! after self-update, spt-core updates each registered adapter via its manifest\n61://! `[update]` avenue ([`REQ-UPD-5`], [`REQ-SEAM-UPDATE`]). `file_pull` payloads\n62://! are verified against the **adapter's own** key (manifest-declared) + SHA-256\n63://! (adapter content signing, ADR-0004 §D); `delegated` updaters are opaque, so\n64://! spt-core delegates the trust only when the adapter attests `self_verifies`,\n65://! else skips them as unverifiable.\n66://!\n67://! **D4b (this commit)** makes broker-held QUIC streams survive brain restarts\n68://! **gaplessly and exactly-once** (Spike #3 invariants A–D as real tests): each\n69://! stream's reads are buffered in a sequenced ring (the B2 `OutputLog`\n70://! discipline) a brain subscribes to with a resume cursor; sends/opens carry\n71://! durable `op_id`s journaled at the broker, so a restarted brain's re-drive\n72://! dedups instead of double-writing the wire.\n73://!\n74://! **D4a (this commit)** moves the node's network presence into the broker\n75://! ([`nethost::NetHost`], ADR-0004 §B): a dedicated tokio runtime hosts the\n76://! iroh endpoint + every accepted/dialed QUIC connection, so a brain restart\n77://! never interrupts a cross-node connection. The brain drives net operations\n78://! (endpoint-status, dial) over new IPC frames in the same forward-compatible\n79://! catalog; an `op_id`-carrying dial is exactly-once through the B5\n80://! [`effect::EffectJournal`]. The endpoint binds as the durable node identity\n81://! (`spt-store`'s `node.key`), with the relay stance from `daemon.json`.\n82://!\n83://! **D5a (this commit)** puts WAN message delivery on the D4 substrate: a\n84://! [`WanMessage`](spt_net::net::wanmsg::WanMessage) NDJSON feed over a\n85://! broker-owned QUIC stream funnels through [`wan::receive_wan`] — the ADR-0009\n86://! access-gate seam ([`access`], handshake-proven origin only, KNOWN-HAZARDS\n87://! 7.5) plus durable op-id dedup (7.2, wire-fed) — into the existing local\n88://! REQ-MSG delivery path.\n89://!\n90://! **D5b (this commit)** adds remote terminal attach ([`attach`], REQ-INST-8):\n91://! a byte-stream viewport onto a local session for an operator daemon on\n92://! another node — session output pumped as sequenced\n93://! [`AttachRecord`](spt_net::net::attach::AttachRecord)s (deduped at the\n\n[Showing lines 1-93 of 294. Use :94 to continue]"}],"details":{"truncation":{"content":"//! `spt-daemon` — the per-machine broker/brain supervisor (M3b).\r\n//!\r\n//! ADR-0004 splits the logical daemon into two implementation layers so a\r\n//! routine self-update swaps the logic without disturbing live endpoints:\r\n//!\r\n//! - a **broker** (stable kernel) holds *only* the un-transferable resources a\r\n//!   live consumer would lose continuity on if the logic restarted — PTY\r\n//!   masters (from [`spt_term`]), spawned harness children, accepted/listening\r\n//!   sockets — and runs no logic;\r\n//! - a **brain** (restartable logic) holds routing, registry, manifest parse,\r\n//!   and the re-hosted [`spt_live`] lifecycle, attaching to the broker over a\r\n//!   **versioned local IPC** so a *newer brain talks to an older broker*.\r\n//!\r\n//! **B0 (this commit)** lands the crate's layer position plus that versioned\r\n//! IPC seam — the load-bearing contract everything else rides:\r\n//!\r\n//! - [`frame`] — the forward-compatible [`Envelope`] schema + the version\r\n//!   [`Hello`] handshake (KNOWN-HAZARDS 2.3, [`REQ-HAZARD-HANDOFF-ARGV-COMPAT`]);\r\n//! - [`codec`] — length-prefixed JSON framing over any [`std::io::Read`]/`Write`;\r\n//! - [`transport`] — the OS-split carrier (named pipe / UDS) behind one\r\n//!   [`DaemonTransport`] trait, mirroring `spt-term`'s `SessionSurface`.\r\n//!\r\n//! **B1 (this commit)** adds the **broker kernel** ([`broker`]) — the stable\r\n//! half that hosts a real `spt-term` PTY child and relays its output/input over\r\n//! the IPC, holding only the ADR-0004 §B resources and no logic — plus the\r\n//! broker↔brain message catalog ([`msg`]).\r\n//!\r\n//! **B3 (this commit)** consolidates the interim no-daemon model into the brain:\r\n//! the `api listen` pulse / Psyche / drop-ingest loops become scheduled\r\n//! in-process loops ([`lifecycle::BrainLifecycle`]) paced by a durable,\r\n//! configurable period ([`config::DaemonConfig`]) instead of the interim 5s\r\n//! constant; the only residue left in the harness-hosted session is the thin,\r\n//! stateless [`relay::Relay`]. The `spt` binary's `LiveHost` becomes a shim over\r\n//! `BrainLifecycle` (re-host, not rewrite) ([`REQ-DAEMON-1`]).\r\n//!\r\n//! **B5 (this commit)** makes the broker↔brain boundary **exactly-once across a\r\n//! brain crash** ([`effect::EffectJournal`]): an idempotent `input` carries a\r\n//! durable `op_id`, and the broker dedups at the effect keyed by that id over a\r\n//! broker-owned recovery anchor (KNOWN-HAZARDS 7.2, [`REQ-HAZARD-RESTART-IDEMPOTENT`];\r\n//! Spike #6's two constraints — broker-owned anchor, dedup-at-effect-by-id —\r\n//! instantiated on the real PTY-write boundary).\r\n//!\r\n//! **C0 (this commit)** opens M3c — the self-update engine ([`update`]): the\r\n//! ADR-0004 §A update-class taxonomy ([`UpdateClass`] + [`classify`]) and the\r\n//! **brain-only zero-interruption swap** ([`apply_brain_only`], [`REQ-UPD-3`]).\r\n//! The brain-only apply *triggers* a handoff over the B2 substrate — snapshot →\r\n//! drop → re-attach — so the live PTY child + its output stream survive the logic\r\n//! swap untouched; it never re-implements the handoff and never touches a broker\r\n//! resource.\r\n//!\r\n//! **C1 (this commit)** adds the verify-before-handoff gate ([`release`]): a\r\n//! release is signature-verified ([`REQ-UPD-2`]) and hardened against rollback\r\n//! ([`REQ-HAZARD-UPDATE-ROLLBACK`]) — Ed25519 over signed metadata, key\r\n//! trust/revocation, channel pinning, metadata expiry, monotonic version, and a\r\n//! SHA-256 binding the signature to the actual binary bytes. [`plan_verified`] is\r\n//! the front door: it produces an [`UpdatePlan`] *only* for a release that passes\r\n//! every check, so an unverified binary can never reach [`apply_brain_only`].\r\n//!\r\n//! **C3 (this commit)** conducts the **adapter ripple** ([`adapter_update`]):\r\n//! after self-update, spt-core updates each registered adapter via its manifest\r\n//! `[update]` avenue ([`REQ-UPD-5`], [`REQ-SEAM-UPDATE`]). `file_pull` payloads\r\n//! are verified against the **adapter's own** key (manifest-declared) + SHA-256\r\n//! (adapter content signing, ADR-0004 §D); `delegated` updaters are opaque, so\r\n//! spt-core delegates the trust only when the adapter attests `self_verifies`,\r\n//! else skips them as unverifiable.\r\n//!\r\n//! **D4b (this commit)** makes broker-held QUIC streams survive brain restarts\r\n//! **gaplessly and exactly-once** (Spike #3 invariants A–D as real tests): each\r\n//! stream's reads are buffered in a sequenced ring (the B2 `OutputLog`\r\n//! discipline) a brain subscribes to with a resume cursor; sends/opens carry\r\n//! durable `op_id`s journaled at the broker, so a restarted brain's re-drive\r\n//! dedups instead of double-writing the wire.\r\n//!\r\n//! **D4a (this commit)** moves the node's network presence into the broker\r\n//! ([`nethost::NetHost`], ADR-0004 §B): a dedicated tokio runtime hosts the\r\n//! iroh endpoint + every accepted/dialed QUIC connection, so a brain restart\r\n//! never interrupts a cross-node connection. The brain drives net operations\r\n//! (endpoint-status, dial) over new IPC frames in the same forward-compatible\r\n//! catalog; an `op_id`-carrying dial is exactly-once through the B5\r\n//! [`effect::EffectJournal`]. The endpoint binds as the durable node identity\r\n//! (`spt-store`'s `node.key`), with the relay stance from `daemon.json`.\r\n//!\r\n//! **D5a (this commit)** puts WAN message delivery on the D4 substrate: a\r\n//! [`WanMessage`](spt_net::net::wanmsg::WanMessage) NDJSON feed over a\r\n//! broker-owned QUIC stream funnels through [`wan::receive_wan`] — the ADR-0009\r\n//! access-gate seam ([`access`], handshake-proven origin only, KNOWN-HAZARDS\r\n//! 7.5) plus durable op-id dedup (7.2, wire-fed) — into the existing local\r\n//! REQ-MSG delivery path.\r\n//!\r\n//! **D5b (this commit)** adds remote terminal attach ([`attach`], REQ-INST-8):\r\n//! a byte-stream viewport onto a local session for an operator daemon on\r\n//! another node — session output pumped as sequenced\r\n//! [`AttachRecord`](spt_net::net::attach::AttachRecord)s (deduped at the\r","truncated":true,"truncatedBy":"lines","totalLines":294,"totalBytes":6023,"outputLines":93,"outputBytes":6023,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":294,"displayContent":{"text":"//! `spt-daemon` — the per-machine broker/brain supervisor (M3b).\r\n//!\r\n//! ADR-0004 splits the logical daemon into two implementation layers so a\r\n//! routine self-update swaps the logic without disturbing live endpoints:\r\n//!\r\n//! - a **broker** (stable kernel) holds *only* the un-transferable resources a\r\n//!   live consumer would lose continuity on if the logic restarted — PTY\r\n//!   masters (from [`spt_term`]), spawned harness children, accepted/listening\r\n//!   sockets — and runs no logic;\r\n//! - a **brain** (restartable logic) holds routing, registry, manifest parse,\r\n//!   and the re-hosted [`spt_live`] lifecycle, attaching to the broker over a\r\n//!   **versioned local IPC** so a *newer brain talks to an older broker*.\r\n//!\r\n//! **B0 (this commit)** lands the crate's layer position plus that versioned\r\n//! IPC seam — the load-bearing contract everything else rides:\r\n//!\r\n//! - [`frame`] — the forward-compatible [`Envelope`] schema + the version\r\n//!   [`Hello`] handshake (KNOWN-HAZARDS 2.3, [`REQ-HAZARD-HANDOFF-ARGV-COMPAT`]);\r\n//! - [`codec`] — length-prefixed JSON framing over any [`std::io::Read`]/`Write`;\r\n//! - [`transport`] — the OS-split carrier (named pipe / UDS) behind one\r\n//!   [`DaemonTransport`] trait, mirroring `spt-term`'s `SessionSurface`.\r\n//!\r\n//! **B1 (this commit)** adds the **broker kernel** ([`broker`]) — the stable\r\n//! half that hosts a real `spt-term` PTY child and relays its output/input over\r\n//! the IPC, holding only the ADR-0004 §B resources and no logic — plus the\r\n//! broker↔brain message catalog ([`msg`]).\r\n//!\r\n//! **B3 (this commit)** consolidates the interim no-daemon model into the brain:\r\n//! the `api listen` pulse / Psyche / drop-ingest loops become scheduled\r\n//! in-process loops ([`lifecycle::BrainLifecycle`]) paced by a durable,\r\n//! configurable period ([`config::DaemonConfig`]) instead of the interim 5s\r\n//! constant; the only residue left in the harness-hosted session is the thin,\r\n//! stateless [`relay::Relay`]. The `spt` binary's `LiveHost` becomes a shim over\r\n//! `BrainLifecycle` (re-host, not rewrite) ([`REQ-DAEMON-1`]).\r\n//!\r\n//! **B5 (this commit)** makes the broker↔brain boundary **exactly-once across a\r\n//! brain crash** ([`effect::EffectJournal`]): an idempotent `input` carries a\r\n//! durable `op_id`, and the broker dedups at the effect keyed by that id over a\r\n//! broker-owned recovery anchor (KNOWN-HAZARDS 7.2, [`REQ-HAZARD-RESTART-IDEMPOTENT`];\r\n//! Spike #6's two constraints — broker-owned anchor, dedup-at-effect-by-id —\r\n//! instantiated on the real PTY-write boundary).\r\n//!\r\n//! **C0 (this commit)** opens M3c — the self-update engine ([`update`]): the\r\n//! ADR-0004 §A update-class taxonomy ([`UpdateClass`] + [`classify`]) and the\r\n//! **brain-only zero-interruption swap** ([`apply_brain_only`], [`REQ-UPD-3`]).\r\n//! The brain-only apply *triggers* a handoff over the B2 substrate — snapshot →\r\n//! drop → re-attach — so the live PTY child + its output stream survive the logic\r\n//! swap untouched; it never re-implements the handoff and never touches a broker\r\n//! resource.\r\n//!\r\n//! **C1 (this commit)** adds the verify-before-handoff gate ([`release`]): a\r\n//! release is signature-verified ([`REQ-UPD-2`]) and hardened against rollback\r\n//! ([`REQ-HAZARD-UPDATE-ROLLBACK`]) — Ed25519 over signed metadata, key\r\n//! trust/revocation, channel pinning, metadata expiry, monotonic version, and a\r\n//! SHA-256 binding the signature to the actual binary bytes. [`plan_verified`] is\r\n//! the front door: it produces an [`UpdatePlan`] *only* for a release that passes\r\n//! every check, so an unverified binary can never reach [`apply_brain_only`].\r\n//!\r\n//! **C3 (this commit)** conducts the **adapter ripple** ([`adapter_update`]):\r\n//! after self-update, spt-core updates each registered adapter via its manifest\r\n//! `[update]` avenue ([`REQ-UPD-5`], [`REQ-SEAM-UPDATE`]). `file_pull` payloads\r\n//! are verified against the **adapter's own** key (manifest-declared) + SHA-256\r\n//! (adapter content signing, ADR-0004 §D); `delegated` updaters are opaque, so\r\n//! spt-core delegates the trust only when the adapter attests `self_verifies`,\r\n//! else skips them as unverifiable.\r\n//!\r\n//! **D4b (this commit)** makes broker-held QUIC streams survive brain restarts\r\n//! **gaplessly and exactly-once** (Spike #3 invariants A–D as real tests): each\r\n//! stream's reads are buffered in a sequenced ring (the B2 `OutputLog`\r\n//! discipline) a brain subscribes to with a resume cursor; sends/opens carry\r\n//! durable `op_id`s journaled at the broker, so a restarted brain's re-drive\r\n//! dedups instead of double-writing the wire.\r\n//!\r\n//! **D4a (this commit)** moves the node's network presence into the broker\r\n//! ([`nethost::NetHost`], ADR-0004 §B): a dedicated tokio runtime hosts the\r\n//! iroh endpoint + every accepted/dialed QUIC connection, so a brain restart\r\n//! never interrupts a cross-node connection. The brain drives net operations\r\n//! (endpoint-status, dial) over new IPC frames in the same forward-compatible\r\n//! catalog; an `op_id`-carrying dial is exactly-once through the B5\r\n//! [`effect::EffectJournal`]. The endpoint binds as the durable node identity\r\n//! (`spt-store`'s `node.key`), with the relay stance from `daemon.json`.\r\n//!\r\n//! **D5a (this commit)** puts WAN message delivery on the D4 substrate: a\r\n//! [`WanMessage`](spt_net::net::wanmsg::WanMessage) NDJSON feed over a\r\n//! broker-owned QUIC stream funnels through [`wan::receive_wan`] — the ADR-0009\r\n//! access-gate seam ([`access`], handshake-proven origin only, KNOWN-HAZARDS\r\n//! 7.5) plus durable op-id dedup (7.2, wire-fed) — into the existing local\r\n//! REQ-MSG delivery path.\r\n//!\r\n//! **D5b (this commit)** adds remote terminal attach ([`attach`], REQ-INST-8):\r\n//! a byte-stream viewport onto a local session for an operator daemon on\r\n//! another node — session output pumped as sequenced\r\n//! [`AttachRecord`](spt_net::net::attach::AttachRecord)s (deduped at the\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,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]},"fileSize":13171,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\lib.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":294,"totalBytes":6023,"outputLines":93,"outputBytes":6023,"shownRange":{"start":1,"end":93},"nextOffset":94}}},"isError":false,"timestamp":1789295530603}}
{"type":"message","id":"eda75c8a","parentId":"8a11be95","timestamp":"2026-09-13T10:32:10.606Z","message":{"role":"toolResult","toolCallId":"call_LmXtcH1LjPzaQr5rzHWmGFC5|fc_0b12df87254bb4e6016aa67baa802487d1b97d4099c0f473d3","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/docs/INPUT-PROVENANCE-CONTRACT.md#250A]\n1:# Submission-bound input provenance — the public harness contract\n…\n215:## 5. The question for adapter owners\n…\n219:1. Does your harness have an **acceptance surface** as defined in §2 — a point where a submission is\n220:   committed by the user and is not yet queued?\n221:2. **The ordering question — this replaces the old buffered-authorship question, which is now\n222:   settled.** Do NOT answer about who typed the characters: under the submitter rule the token current\n223:   at acceptance is correct by definition, even if someone else typed the text. Answer instead about\n224:   your QUEUE: does your acceptance point sit at **enqueue** (the submission is captured as it enters\n225:   the queue) or at **dequeue** (captured as the harness takes it off for processing)? If it is\n226:   dequeue, what can change the seat between the two, and can your adapter reach the enqueue point at\n227:   all?\n228:2b. **Machine-injected input.** Can input reach that same acceptance surface WITHOUT a human pressing\n229:   send — hooks, replayed or scripted input, automation writing into the same path, a resumed session\n230:   re-submitting? Can your adapter tell that case apart from a human submission, and what does it\n231:   currently capture for it? A machine injection that captures the seat-holder's token would attribute\n232:   a machine's submission to a person, which is a mechanism question this contract has NOT resolved.\n233:3. At that point, can the adapter **read and store** a value, and keep it associated with that exact\n234:   submission through any queueing the harness performs? Can the harness EDIT or SPLIT the text after\n235:   acceptance, and if so can your adapter OBSERVE that it did (§3.2)? Answer what you can observe, not\n236:   what you would like to guarantee: if there is no post-acceptance observation, say so — an adapter\n237:   that cannot see later edits must not promise to detect them, and reporting the limitation is the\n238:   answer this contract wants.\n239:4. When the submission is reported, can the adapter include the stored value, its own submission id,\n240:   and the **exact committed payload text** in the same report?\n241:5. If any of those is impossible, **what precisely is missing** — a hook that does not exist, a hook\n242:   that fires too late, a buffer the adapter cannot see behind, an association the harness drops, a\n243:   payload the harness rewrites?\n244:\n245:Answer (5) concretely if it applies. A named limitation is the useful answer and the one that gets a\n246:decision; \"probably fine\" is not, and neither is a workaround that samples the current controller.\n247:**An answer here is feasibility input, not approval**: doyle holds the approval, and the clauses marked\n248:unresolved below are not guarantees an adapter may build against yet.\n249:\n250:## 6. Known open items, so nobody assumes they are settled\n251:\n252:- **CLOSED, recorded so nobody reopens it:** \"which controller's text is this, if one typed and\n253:  another sent\" is SETTLED by Reavo's decision — the sender's computer, full stop. Earlier revisions of\n254:  this document carried it as the biggest open question; it is not one. Re-raising it is out of scope,\n255:  and an adapter must not build attribution machinery to answer it.\n256:- **Enqueue-versus-dequeue ordering is a MECHANISM question, still open** (doyle, B7ZLOLBZ). Where the\n257:  acceptance point sits relative to the queue decides whether \"the token current at acceptance\" is the\n258:  submitter's token in practice. Adapter answers to §5.2 are the input to that ruling. It does not\n259:  reopen the experience.\n260:- **ORIGIN SIGNALING IS AN UNRESOLVED REQUIREMENT, not an adapter chore** (doyle). Machine-injected\n261:  submissions were MEASURED indistinguishable from human ones at the harness level (§7), and the only\n262:  separator in the field today is an adapter recognising its own transport's payload shapes — a\n263:  heuristic that establishes \"this looks like something spt sent\", never \"a person submitted this\".\n264:  Recognizing payload shapes is not authenticated human provenance. What is missing is a trustworthy\n265:  origin signal; until one exists such submissions report with no token, which is a floor and not a\n266:  solution. Adapter answers to §5.2b describe the gap; they do not close it.\n267:- **A resumed session re-submitting and externally scripted input are SEPARATE, both uncharacterised**,\n268:  and external automation is **not** equivalent to a resumed session — neither answer follows from the\n269:  other.\n270:- **What makes a sender \"unreliable\" (§4.4) is UNDEFINED here** and is deliberately not the adapter's\n271:  to decide. The adopted safety rule says no automatic share in that case; the threshold is core-side\n272:  and gate-side.\n273:- **The post-handoff grace period (§4.5) is a PROPOSAL, not an authorized guarantee.** The submitter\n274:  rule reduces its urgency — the submitter is by definition whoever held the seat at acceptance — but\n275:  it is still unruled, and its bound still has **no value**; it must be justified, not picked.\n276:- **§4.2's split of responsibility is deliberate**: the association is the adapter's to establish and\n277:  core cannot verify it independently. Nothing in this contract is core-side proof of authorship.\n278:- Whether the token is readable through an existing authenticated read verb, or needs a new surface,\n279:  is **not decided** and is deliberately absent from this contract — it is an implementation question\n280:  and adapter owners should not need it to answer §5.\n281:- Acceptance criteria for #300 live on the issue (comment 5645159945) and are proposed, not granted.\n282:- If no shipped adapter can satisfy §3.1, that is a concrete limitation for an operator decision via\n283:  lia, not a licence to reduce the behaviour.\n284:- The **silent skip** (§4.3) is the one non-grant that emits nothing. It is easy to misread as a bug\n285:  report waiting to happen — \"the file didn't get shared and nothing said why\" — and it is deliberate.\n286:  If experience shows users need a signal, that is a new operator decision, not a contract correction.\n287:\n288:## 7. Adapter answers on record\n289:\n290:### claude-spt (perri, 2026-09-12) — answered against this frame, with measurements\n291:\n292:**§5.1 acceptance surface: YES.** `UserPromptSubmit` fires when a submission is committed, before the\n293:model sees it, carrying the exact committed text and session id, and can block.\n294:\n295:**Two holes, and they are TWO SEPARATE POPULATIONS** — perri's precision fix, kept apart here because\n296:they need different contract language and merging them states something false about both:\n297:\n298:- **All submissions: 302 audited, 227 hook-covered.** The 75 misses are harness-synthesised transcript\n299:  entries OR built-in local slash commands (`/compact`, `/reload-plugins` mid-session are the clean\n300:  cases). This is a **surface gap the adapter cannot close**.\n301:- **PTY-typed submissions only: 133 audited, 103 covered.** All 30 misses are safe-mode sessions, where\n302:  hooks are off BY DESIGN. That is **configuration, not a defect** — a session that legitimately has no\n303:  adapter at all.\n304:\n305:Both land on \"no token\", by different routes. **Consequence for this contract: \"no token\" is a\n306:FIRST-CLASS outcome, not an edge case** (§3.4), and any design that treats a missing token as anomalous\n307:is wrong on this harness.\n308:\n309:**Instrument limit, carried with the numbers:** the audit observes hook OUTPUT in the transcript, not\n310:hook INVOCATION, so a hook that fired and emitted nothing is invisible to the count. The positive\n311:controls are the coverage figures themselves — 227/302 and 103/133 — so it is an instrument that counts\n312:rather than a detector that can never fire.\n313:\n314:**§5.2 ordering: ENQUEUE, measured, n=3.** With a turn demonstrably still executing, submissions typed\n315:into the input box fired the hook at **+0.5s, +0.9s and +1.0s** after Enter — exactly one fire each,\n316:with **no second fire** when the harness later folded the text into the running turn. Capture therefore\n317:sits at enqueue, ahead of what the harness does next, and §3.1 is satisfiable **for the cases\n318:exercised**.\n319:\n320:**Three observations are evidence about those three cases, not universal coverage** — a distinction the\n321:measurer drew first and this document keeps in its own voice. They establish that enqueue capture\n322:happens on this path; they do not establish that every submission on this harness takes it.\n323:\n324:**The three caveats are recorded WITH the result, not summarised past it** (perri's own framing, and\n325:they are the reason to trust the number): the submissions were PTY-typed by spt rather than by a human,\n326:on the same keystroke path into the same input box; the endpoint was forced idle to take that route,\n327:which changes spt's routing decision and not the harness's queueing; and **one narrower window remains\n328:unmeasured** — a submission typed into the Stop-to-next-turn boundary, which an in-tree comment claims\n329:is folded into the running turn with no hook at all. That claim is neither confirmed nor refuted and is\n330:asserted in neither direction here.\n331:\n332:**§5.2b machine injection: INDISTINGUISHABLE AT THE HARNESS LEVEL — and the probe above was itself a\n333:machine submission.** Core PTY-typed the text and pressed Enter with no human involved, and the hook\n334:fired identically to a human submission. This is spt's own normal delivery path to a busy agent, not a\n335:hypothetical. The adapter can separate them **only by recognising its own transport's payload shapes**,\n336:a discriminator that already exists for an adjacent reason: reporting a delivered peer message back as\n337:user input would launder a peer's shortform tags into an ingest edge. For such a submission the adapter\n338:captures **nothing** and reports with no token, per §3.4.\n339:\n340:**What this actually exposes is an UNRESOLVED ORIGIN-SIGNALING REQUIREMENT, not an adapter chore**\n341:(doyle's correction to an earlier draft of mine, which framed it as a maintenance obligation on core to\n342:announce every injection shape). **Recognizing payload shapes is not authenticated human provenance.**\n343:A pattern list is a heuristic over today's formats: it can be wrong, it can go stale, and even when it\n344:is right it establishes only \"this looks like something spt sent\", never \"a person submitted this\".\n345:\n346:So the gap is not that adapters must track core's injection formats — it is that **nothing in this\n347:system currently signals origin in a way an adapter could trust.** That mechanism does not exist yet,\n348:and this contract does not pretend an adapter's shape-matching substitutes for it. Until it does,\n349:machine-injected submissions report with no token (§3.4), which is correct but is a floor rather than\n350:a solution.\n351:\n352:Two further injection sources — a resumed session re-submitting, and scripted input originating outside\n353:spt — are **uncharacterised** and reach the same surface. They are deliberately not guessed at, and\n354:**external automation is not equivalent to a resumed session**: they are separate origins whose answers\n355:do not follow from one another.\n356:\n357:**§5.3 carry: satisfied, and for a better reason than diligence.** Capture and report happen inside the\n358:SAME hook invocation, so nothing has to survive a queue at all. **Edit/split detection: CANNOT BE DONE.**\n359:The adapter sees a submission exactly once and never again — no post-acceptance event, no rewrite\n360:signal, nothing to diff against. It binds only the bytes it saw, which is exactly what §3.2 requires —\n361:authorization is of the ORIGINAL ACCEPTED BYTES — but it **cannot NOTICE a rewrite**. Under the\n362:corrected §3.2 that is not a failure to satisfy the clause: the adapter reports the limitation instead\n363:of promising detection it cannot deliver, and the capture of the accepted bytes stands. What it does\n364:mean is that a path introduced by a later rewrite could not be refused BY THE ADAPTER; it is refused by\n365:the contract, since authorization never extended to it.\n366:\n367:**§5.4 report: yes** — adapter-minted submission id, token, and exact committed bytes in one call at\n368:acceptance. Two operational facts: the hook runs against a ~5s deadline (measured p99 4835ms on that\n369:node) so **a report can be lost to a kill** — which is an argument FOR §3.5's same-id-same-payload\n370:retry, not merely a tolerance of it; and 99.4% of the hook's wall time is serial `spt` process spawns,\n371:so **the token read must fold into a call the hook already makes** rather than adding a spawn on the\n372:deadline-critical path. Noted for the implementation question this contract deliberately leaves open:\n373:reading the token from inside `UserPromptSubmit` IS the acceptance-time read, and is a forbidden sample\n374:only when taken at report time.\n375:\n376:**Named limitations (§5.5):** no queued-vs-immediate flag and no sat-time on the hook input; no\n377:post-acceptance observation, so rewrites are undetectable; the surface is neither universal nor\n378:guaranteed enabled; the hook is deadline-killed under load, so reports must be idempotent and\n379:loss-tolerant; and machine-injected submissions are separable only by the adapter's recognition of\n380:shapes it has been told about.\n381:\n382:### omp-spt (emphasys, 2026-09-13, message 4II3N2NA) — answered from public upstream declarations, not a runtime measurement\n383:\n384:**No submission-bound carrier.** `InputEvent` carries `type`, `text`, optional `images`, and\n385:`source: \"interactive\" | \"rpc\" | \"extension\"` — no submission id, no attachment identity, no\n386:core-issued value. `BeforeAgentStartEvent` carries `prompt`/`images`/`systemPrompt`, nothing more.\n387:**`InputEventResult` may replace text/images**, so observed text is not guaranteed to be the committed\n388:payload after later extensions run. `sendUserMessage` permits programmatic prompts and queued streaming.\n389:\n390:**§5.2 ordering: UNVERIFIED.** The declarations do not establish a pre-enqueue acceptance boundary;\n391:emphasys inspected upstream `main` declarations only and will not promise ordering or byte preservation.\n392:\n393:**§5.2b origin: `source` names a ROUTE, not a person.** `source === \"interactive\"` distinguishes input\n394:routes from one another, not an authenticated controller from automation using the same route; no\n395:replay/resume discriminator exists.\n396:\n397:Scope carried with the answer: no experiment, no installed-runtime measurement, no core-source inspection.\n398:\n399:## 8. RULING (doyle, 2026-09-13; RE-CUT the same day on the operator's direction) — core-only; no token, nothing asked of adapters\n400:\n401:**Operator, 2026-09-13, direct:** \"#300 needs to be developed entirely independently of harness adapters.\n402:spt-core does not concern itself with harness adapter integration. omp-spt and/or claude-spt should not\n403:have anything to do with #300. they already submit USER_INPUT kind event hooks, and that's all spt-core\n404:should be asking of them.\"\n405:\n406:That strikes the whole adapter half of this contract — §3's obligations, the token, and the first cut of\n407:this ruling (a manifest declaration plus a submission id, retracted within the hour). What remains is\n408:what core can do with what it ALREADY receives: a session-authenticated USER_INPUT report carrying the\n409:exact payload, at whatever moment the harness reports it.\n410:\n411:1. **Core binds origin at RECEIPT of every USER_INPUT report** — the session's current authenticated\n412:   REMOTE controller seat (the broker-owned `driven_by`). Local seat, viewer, or no seat ⇒ no origin ⇒\n413:   nothing served, named on the declined line. No adapter declares anything; no adapter is asked when it\n414:   reports.\n415:2. **Own-injection exclusion.** Core delivers peer messages by writing into the session's PTY itself. A\n416:   USER_INPUT whose payload is a delivery core wrote into that session binds no origin — recognised by\n417:   the bytes core wrote, never by payload shape. This is core's origin signal for the one injection\n418:   source it owns; resumed-session re-submission and external automation stay uncharacterised and bind\n419:   the seat as the submitter rule says.\n420:3. **Dedup is core-side, keyed on the report:** a repeat of the same payload within the same session\n421:   while its reference is live re-registers nothing, emits no second helper notice, and extends no TTL.\n422:   No adapter-minted id exists.\n423:4. **Serving semantics unchanged from #17 / ADR-0058 Am.1:** submitter's machine, 24h TTL, audience the\n424:   receiving endpoint, helper notice once per submission and path. A path that names no file on the\n425:   submitter's machine is SILENTLY SKIPPED (§4.3); every other non-grant is named (§4.7).\n426:5. **The stated ceiling, instead of an adapter promise.** The report lags acceptance by whatever the\n427:   harness's own path costs (claude-spt: 0.5–1.0 s measured, n=3; omp-spt: unmeasured). A cross-operator\n428:   Take inside that lag attributes the submission to the NEW holder, whose own file is then served to the\n429:   agent that holder now controls. Core states this; it does not ask adapters to shrink it. §1's\n430:   prohibition on sampling stands for anything core might build LATER than receipt — receipt is the\n431:   earliest moment core has the payload, and it is the moment used.\n432:6. **§4.1 token issuance and §4.5 grace period: STRUCK.** §7's adapter answers stay on record as\n433:   measurements of the ceiling in (5), not as obligations.\n434:\n435:**Build:** `REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT` (traceable-reqs.toml, minted unactivated). Product\n436:lane: todlando. Adapter side: NONE."}],"details":{"totalLines":436,"displayContent":{"text":"# Submission-bound input provenance — the public harness contract\n…\n## 5. The question for adapter owners\n…\n1. Does your harness have an **acceptance surface** as defined in §2 — a point where a submission is\r\n   committed by the user and is not yet queued?\r\n2. **The ordering question — this replaces the old buffered-authorship question, which is now\r\n   settled.** Do NOT answer about who typed the characters: under the submitter rule the token current\r\n   at acceptance is correct by definition, even if someone else typed the text. Answer instead about\r\n   your QUEUE: does your acceptance point sit at **enqueue** (the submission is captured as it enters\r\n   the queue) or at **dequeue** (captured as the harness takes it off for processing)? If it is\r\n   dequeue, what can change the seat between the two, and can your adapter reach the enqueue point at\r\n   all?\r\n2b. **Machine-injected input.** Can input reach that same acceptance surface WITHOUT a human pressing\r\n   send — hooks, replayed or scripted input, automation writing into the same path, a resumed session\r\n   re-submitting? Can your adapter tell that case apart from a human submission, and what does it\r\n   currently capture for it? A machine injection that captures the seat-holder's token would attribute\r\n   a machine's submission to a person, which is a mechanism question this contract has NOT resolved.\r\n3. At that point, can the adapter **read and store** a value, and keep it associated with that exact\r\n   submission through any queueing the harness performs? Can the harness EDIT or SPLIT the text after\r\n   acceptance, and if so can your adapter OBSERVE that it did (§3.2)? Answer what you can observe, not\r\n   what you would like to guarantee: if there is no post-acceptance observation, say so — an adapter\r\n   that cannot see later edits must not promise to detect them, and reporting the limitation is the\r\n   answer this contract wants.\r\n4. When the submission is reported, can the adapter include the stored value, its own submission id,\r\n   and the **exact committed payload text** in the same report?\r\n5. If any of those is impossible, **what precisely is missing** — a hook that does not exist, a hook\r\n   that fires too late, a buffer the adapter cannot see behind, an association the harness drops, a\r\n   payload the harness rewrites?\r\n\r\nAnswer (5) concretely if it applies. A named limitation is the useful answer and the one that gets a\r\ndecision; \"probably fine\" is not, and neither is a workaround that samples the current controller.\r\n**An answer here is feasibility input, not approval**: doyle holds the approval, and the clauses marked\r\nunresolved below are not guarantees an adapter may build against yet.\r\n\r\n## 6. Known open items, so nobody assumes they are settled\r\n\r\n- **CLOSED, recorded so nobody reopens it:** \"which controller's text is this, if one typed and\r\n  another sent\" is SETTLED by Reavo's decision — the sender's computer, full stop. Earlier revisions of\r\n  this document carried it as the biggest open question; it is not one. Re-raising it is out of scope,\r\n  and an adapter must not build attribution machinery to answer it.\r\n- **Enqueue-versus-dequeue ordering is a MECHANISM question, still open** (doyle, B7ZLOLBZ). Where the\r\n  acceptance point sits relative to the queue decides whether \"the token current at acceptance\" is the\r\n  submitter's token in practice. Adapter answers to §5.2 are the input to that ruling. It does not\r\n  reopen the experience.\r\n- **ORIGIN SIGNALING IS AN UNRESOLVED REQUIREMENT, not an adapter chore** (doyle). Machine-injected\r\n  submissions were MEASURED indistinguishable from human ones at the harness level (§7), and the only\r\n  separator in the field today is an adapter recognising its own transport's payload shapes — a\r\n  heuristic that establishes \"this looks like something spt sent\", never \"a person submitted this\".\r\n  Recognizing payload shapes is not authenticated human provenance. What is missing is a trustworthy\r\n  origin signal; until one exists such submissions report with no token, which is a floor and not a\r\n  solution. Adapter answers to §5.2b describe the gap; they do not close it.\r\n- **A resumed session re-submitting and externally scripted input are SEPARATE, both uncharacterised**,\r\n  and external automation is **not** equivalent to a resumed session — neither answer follows from the\r\n  other.\r\n- **What makes a sender \"unreliable\" (§4.4) is UNDEFINED here** and is deliberately not the adapter's\r\n  to decide. The adopted safety rule says no automatic share in that case; the threshold is core-side\r\n  and gate-side.\r\n- **The post-handoff grace period (§4.5) is a PROPOSAL, not an authorized guarantee.** The submitter\r\n  rule reduces its urgency — the submitter is by definition whoever held the seat at acceptance — but\r\n  it is still unruled, and its bound still has **no value**; it must be justified, not picked.\r\n- **§4.2's split of responsibility is deliberate**: the association is the adapter's to establish and\r\n  core cannot verify it independently. Nothing in this contract is core-side proof of authorship.\r\n- Whether the token is readable through an existing authenticated read verb, or needs a new surface,\r\n  is **not decided** and is deliberately absent from this contract — it is an implementation question\r\n  and adapter owners should not need it to answer §5.\r\n- Acceptance criteria for #300 live on the issue (comment 5645159945) and are proposed, not granted.\r\n- If no shipped adapter can satisfy §3.1, that is a concrete limitation for an operator decision via\r\n  lia, not a licence to reduce the behaviour.\r\n- The **silent skip** (§4.3) is the one non-grant that emits nothing. It is easy to misread as a bug\r\n  report waiting to happen — \"the file didn't get shared and nothing said why\" — and it is deliberate.\r\n  If experience shows users need a signal, that is a new operator decision, not a contract correction.\r\n\r\n## 7. Adapter answers on record\r\n\r\n### claude-spt (perri, 2026-09-12) — answered against this frame, with measurements\r\n\r\n**§5.1 acceptance surface: YES.** `UserPromptSubmit` fires when a submission is committed, before the\r\nmodel sees it, carrying the exact committed text and session id, and can block.\r\n\r\n**Two holes, and they are TWO SEPARATE POPULATIONS** — perri's precision fix, kept apart here because\r\nthey need different contract language and merging them states something false about both:\r\n\r\n- **All submissions: 302 audited, 227 hook-covered.** The 75 misses are harness-synthesised transcript\r\n  entries OR built-in local slash commands (`/compact`, `/reload-plugins` mid-session are the clean\r\n  cases). This is a **surface gap the adapter cannot close**.\r\n- **PTY-typed submissions only: 133 audited, 103 covered.** All 30 misses are safe-mode sessions, where\r\n  hooks are off BY DESIGN. That is **configuration, not a defect** — a session that legitimately has no\r\n  adapter at all.\r\n\r\nBoth land on \"no token\", by different routes. **Consequence for this contract: \"no token\" is a\r\nFIRST-CLASS outcome, not an edge case** (§3.4), and any design that treats a missing token as anomalous\r\nis wrong on this harness.\r\n\r\n**Instrument limit, carried with the numbers:** the audit observes hook OUTPUT in the transcript, not\r\nhook INVOCATION, so a hook that fired and emitted nothing is invisible to the count. The positive\r\ncontrols are the coverage figures themselves — 227/302 and 103/133 — so it is an instrument that counts\r\nrather than a detector that can never fire.\r\n\r\n**§5.2 ordering: ENQUEUE, measured, n=3.** With a turn demonstrably still executing, submissions typed\r\ninto the input box fired the hook at **+0.5s, +0.9s and +1.0s** after Enter — exactly one fire each,\r\nwith **no second fire** when the harness later folded the text into the running turn. Capture therefore\r\nsits at enqueue, ahead of what the harness does next, and §3.1 is satisfiable **for the cases\r\nexercised**.\r\n\r\n**Three observations are evidence about those three cases, not universal coverage** — a distinction the\r\nmeasurer drew first and this document keeps in its own voice. They establish that enqueue capture\r\nhappens on this path; they do not establish that every submission on this harness takes it.\r\n\r\n**The three caveats are recorded WITH the result, not summarised past it** (perri's own framing, and\r\nthey are the reason to trust the number): the submissions were PTY-typed by spt rather than by a human,\r\non the same keystroke path into the same input box; the endpoint was forced idle to take that route,\r\nwhich changes spt's routing decision and not the harness's queueing; and **one narrower window remains\r\nunmeasured** — a submission typed into the Stop-to-next-turn boundary, which an in-tree comment claims\r\nis folded into the running turn with no hook at all. That claim is neither confirmed nor refuted and is\r\nasserted in neither direction here.\r\n\r\n**§5.2b machine injection: INDISTINGUISHABLE AT THE HARNESS LEVEL — and the probe above was itself a\r\nmachine submission.** Core PTY-typed the text and pressed Enter with no human involved, and the hook\r\nfired identically to a human submission. This is spt's own normal delivery path to a busy agent, not a\r\nhypothetical. The adapter can separate them **only by recognising its own transport's payload shapes**,\r\na discriminator that already exists for an adjacent reason: reporting a delivered peer message back as\r\nuser input would launder a peer's shortform tags into an ingest edge. For such a submission the adapter\r\ncaptures **nothing** and reports with no token, per §3.4.\r\n\r\n**What this actually exposes is an UNRESOLVED ORIGIN-SIGNALING REQUIREMENT, not an adapter chore**\r\n(doyle's correction to an earlier draft of mine, which framed it as a maintenance obligation on core to\r\nannounce every injection shape). **Recognizing payload shapes is not authenticated human provenance.**\r\nA pattern list is a heuristic over today's formats: it can be wrong, it can go stale, and even when it\r\nis right it establishes only \"this looks like something spt sent\", never \"a person submitted this\".\r\n\r\nSo the gap is not that adapters must track core's injection formats — it is that **nothing in this\r\nsystem currently signals origin in a way an adapter could trust.** That mechanism does not exist yet,\r\nand this contract does not pretend an adapter's shape-matching substitutes for it. Until it does,\r\nmachine-injected submissions report with no token (§3.4), which is correct but is a floor rather than\r\na solution.\r\n\r\nTwo further injection sources — a resumed session re-submitting, and scripted input originating outside\r\nspt — are **uncharacterised** and reach the same surface. They are deliberately not guessed at, and\r\n**external automation is not equivalent to a resumed session**: they are separate origins whose answers\r\ndo not follow from one another.\r\n\r\n**§5.3 carry: satisfied, and for a better reason than diligence.** Capture and report happen inside the\r\nSAME hook invocation, so nothing has to survive a queue at all. **Edit/split detection: CANNOT BE DONE.**\r\nThe adapter sees a submission exactly once and never again — no post-acceptance event, no rewrite\r\nsignal, nothing to diff against. It binds only the bytes it saw, which is exactly what §3.2 requires —\r\nauthorization is of the ORIGINAL ACCEPTED BYTES — but it **cannot NOTICE a rewrite**. Under the\r\ncorrected §3.2 that is not a failure to satisfy the clause: the adapter reports the limitation instead\r\nof promising detection it cannot deliver, and the capture of the accepted bytes stands. What it does\r\nmean is that a path introduced by a later rewrite could not be refused BY THE ADAPTER; it is refused by\r\nthe contract, since authorization never extended to it.\r\n\r\n**§5.4 report: yes** — adapter-minted submission id, token, and exact committed bytes in one call at\r\nacceptance. Two operational facts: the hook runs against a ~5s deadline (measured p99 4835ms on that\r\nnode) so **a report can be lost to a kill** — which is an argument FOR §3.5's same-id-same-payload\r\nretry, not merely a tolerance of it; and 99.4% of the hook's wall time is serial `spt` process spawns,\r\nso **the token read must fold into a call the hook already makes** rather than adding a spawn on the\r\ndeadline-critical path. Noted for the implementation question this contract deliberately leaves open:\r\nreading the token from inside `UserPromptSubmit` IS the acceptance-time read, and is a forbidden sample\r\nonly when taken at report time.\r\n\r\n**Named limitations (§5.5):** no queued-vs-immediate flag and no sat-time on the hook input; no\r\npost-acceptance observation, so rewrites are undetectable; the surface is neither universal nor\r\nguaranteed enabled; the hook is deadline-killed under load, so reports must be idempotent and\r\nloss-tolerant; and machine-injected submissions are separable only by the adapter's recognition of\r\nshapes it has been told about.\r\n\r\n### omp-spt (emphasys, 2026-09-13, message 4II3N2NA) — answered from public upstream declarations, not a runtime measurement\r\n\r\n**No submission-bound carrier.** `InputEvent` carries `type`, `text`, optional `images`, and\r\n`source: \"interactive\" | \"rpc\" | \"extension\"` — no submission id, no attachment identity, no\r\ncore-issued value. `BeforeAgentStartEvent` carries `prompt`/`images`/`systemPrompt`, nothing more.\r\n**`InputEventResult` may replace text/images**, so observed text is not guaranteed to be the committed\r\npayload after later extensions run. `sendUserMessage` permits programmatic prompts and queued streaming.\r\n\r\n**§5.2 ordering: UNVERIFIED.** The declarations do not establish a pre-enqueue acceptance boundary;\r\nemphasys inspected upstream `main` declarations only and will not promise ordering or byte preservation.\r\n\r\n**§5.2b origin: `source` names a ROUTE, not a person.** `source === \"interactive\"` distinguishes input\r\nroutes from one another, not an authenticated controller from automation using the same route; no\r\nreplay/resume discriminator exists.\r\n\r\nScope carried with the answer: no experiment, no installed-runtime measurement, no core-source inspection.\r\n\r\n## 8. RULING (doyle, 2026-09-13; RE-CUT the same day on the operator's direction) — core-only; no token, nothing asked of adapters\r\n\r\n**Operator, 2026-09-13, direct:** \"#300 needs to be developed entirely independently of harness adapters.\r\nspt-core does not concern itself with harness adapter integration. omp-spt and/or claude-spt should not\r\nhave anything to do with #300. they already submit USER_INPUT kind event hooks, and that's all spt-core\r\nshould be asking of them.\"\r\n\r\nThat strikes the whole adapter half of this contract — §3's obligations, the token, and the first cut of\r\nthis ruling (a manifest declaration plus a submission id, retracted within the hour). What remains is\r\nwhat core can do with what it ALREADY receives: a session-authenticated USER_INPUT report carrying the\r\nexact payload, at whatever moment the harness reports it.\r\n\r\n1. **Core binds origin at RECEIPT of every USER_INPUT report** — the session's current authenticated\r\n   REMOTE controller seat (the broker-owned `driven_by`). Local seat, viewer, or no seat ⇒ no origin ⇒\r\n   nothing served, named on the declined line. No adapter declares anything; no adapter is asked when it\r\n   reports.\r\n2. **Own-injection exclusion.** Core delivers peer messages by writing into the session's PTY itself. A\r\n   USER_INPUT whose payload is a delivery core wrote into that session binds no origin — recognised by\r\n   the bytes core wrote, never by payload shape. This is core's origin signal for the one injection\r\n   source it owns; resumed-session re-submission and external automation stay uncharacterised and bind\r\n   the seat as the submitter rule says.\r\n3. **Dedup is core-side, keyed on the report:** a repeat of the same payload within the same session\r\n   while its reference is live re-registers nothing, emits no second helper notice, and extends no TTL.\r\n   No adapter-minted id exists.\r\n4. **Serving semantics unchanged from #17 / ADR-0058 Am.1:** submitter's machine, 24h TTL, audience the\r\n   receiving endpoint, helper notice once per submission and path. A path that names no file on the\r\n   submitter's machine is SILENTLY SKIPPED (§4.3); every other non-grant is named (§4.7).\r\n5. **The stated ceiling, instead of an adapter promise.** The report lags acceptance by whatever the\r\n   harness's own path costs (claude-spt: 0.5–1.0 s measured, n=3; omp-spt: unmeasured). A cross-operator\r\n   Take inside that lag attributes the submission to the NEW holder, whose own file is then served to the\r\n   agent that holder now controls. Core states this; it does not ask adapters to shrink it. §1's\r\n   prohibition on sampling stands for anything core might build LATER than receipt — receipt is the\r\n   earliest moment core has the payload, and it is the moment used.\r\n6. **§4.1 token issuance and §4.5 grace period: STRUCK.** §7's adapter answers stay on record as\r\n   measurements of the ceiling in (5), not as obligations.\r\n\r\n**Build:** `REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT` (traceable-reqs.toml, minted unactivated). Product\r\nlane: todlando. Adapter side: NONE.\r","startLine":1,"lineNumbers":[1,null,215,null,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436]},"fileSize":33503,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\docs\\INPUT-PROVENANCE-CONTRACT.md"}}},"isError":false,"timestamp":1789295530606}}
{"type":"message","id":"c7eda496","parentId":"eda75c8a","timestamp":"2026-09-13T10:32:10.613Z","message":{"role":"toolResult","toolCallId":"call_KDzAAKLmcrVXc1zLbIySBwD6|fc_0b12df87254bb4e6016aa67baa801487d1b9cd3ae0d9002623","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#3A1D]\n11003:\n11004:    // ── v0.13.0 P0 — REQ-HAZARD-PTY-INPUT-WRITER-WEDGE: the PTY input\n11005:    //    single-writer unit kernel. These exercise the REAL `InputWriter::enqueue`\n11006:    //    against the REAL bounded `sync_channel` + the REAL backpressure atomic,\n11007:    //    with a CALLER-CONTROLLED consumer (the test owns `rx` and drains by hand).\n11008:    //    No PTY, no wall-clock in any decision assertion — the whole point of the\n11009:    //    fix is that the enqueue decision is non-blocking and clock-free. ──────────\n11010:\n11011:    /// Build an [`InputWriter`] over a caller-supplied bounded channel so the test\n11012:    /// controls the consumer precisely. `endpoint` is EMPTY, so `stamp_backpressure`\n11013:    /// is a no-op (impl: `if self.endpoint.is_empty() { return; }`) — the perch\n11014:    /// mirror is the int test's job; here we assert the in-crate `backpressure`\n11015:    /// atomic directly. The `_writer` handle is a trivial no-op thread: the REAL\n11016:    /// drain (`input_writer`) is the trivial FIFO `recv` loop, separately covered by\n11017:    /// the ORDER test; here the TEST is the consumer, draining `rx` deterministically.\n11018:    fn test_input_writer(depth: usize) -> (InputWriter, Receiver<InputRecord>) {\n11019:        let (tx, rx) = sync_channel::<InputRecord>(depth);\n11020:        let w = InputWriter {\n11021:            tx,\n11022:            backpressure: AtomicBool::new(false),\n11023:            endpoint: String::new(),\n11024:            _writer: thread::spawn(|| {}),\n11025:        };\n11026:        (w, rx)\n11027:    }\n11028:\n11029:    /// Drain ORDER: records enqueued in sequence reach the sole writer in strict\n11030:    /// FIFO order. We drive the REAL `enqueue` into the REAL channel, then drain it\n11031:    /// through a single consumer that applies each record to a stub `SessionSurface`\n11032:    /// recording the bytes it receives — EXACTLY mirroring the production\n11033:    /// `input_writer` loop (`while let Ok(b) = rx.recv() { surface.write_input(&b) }`).\n11034:    /// One FIFO + one writer ⇒ exact input order. Non-vacuous: a reorder/LIFO/dedup\n11035:    /// mutation of the single-writer contract makes the recorded sequence diverge.\n11036:    // [unit->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\n11037:    #[test]\n11038:    fn input_writer_preserves_strict_fifo_order_through_the_sole_writer() {\n11039:        use spt_term::surface::{SessionSurface, SurfaceError, SurfaceSize};\n11040:\n11041:        /// A stub PTY write seam: appends every `write_input` to a shared Vec, in\n11042:        /// the order the sole writer applied them. (`resize` is never exercised.)\n11043:        struct RecordingSurface(Arc<Mutex<Vec<Vec<u8>>>>);\n11044:        impl SessionSurface for RecordingSurface {\n11045:            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n11046:                self.0.lock().unwrap().push(bytes.to_vec());\n11047:                Ok(())\n11048:            }\n11049:            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> {\n11050:                Ok(())\n11051:            }\n11052:        }\n11053:\n11054:        // Generous depth so nothing drops — this test is about ORDER, not the bound.\n11055:        let (w, rx) = test_input_writer(256);\n11056:        let written = Arc::new(Mutex::new(Vec::<Vec<u8>>::new()));\n11057:        let surface = RecordingSurface(Arc::clone(&written));\n11058:\n11059:        // Enqueue a distinguishable, NON-monotonic sequence (so any sort/reorder\n11060:        // mutation is caught, not just a reverse): paste-shaped multi-byte records\n11061:        // interleaved with single keystrokes.\n11062:        let inputs: Vec<Vec<u8>> = vec![\n11063:            b\"first\".to_vec(),\n11064:            b\"\\x03\".to_vec(),       // Ctrl-C\n11065:            b\"PASTE-BLOCK-AAAA\".to_vec(),\n11066:            b\"z\".to_vec(),\n11067:            b\"\\r\".to_vec(),         // Enter\n11068:            b\"PASTE-BLOCK-BBBB\".to_vec(),\n11069:            b\"last\".to_vec(),\n11070:        ];\n11071:        for rec in &inputs {\n11072:            assert!(w.enqueue(rec.clone()), \"depth 256: every enqueue is accepted\");\n11073:        }\n11074:        // Close the FIFO so the drain loop terminates, then drain through the SOLE\n11075:        // writer exactly as `input_writer` does.\n11076:        drop(w);\n11077:        while let Ok(bytes) = rx.recv() {\n11078:            surface.write_input(&bytes).unwrap();\n11079:        }\n11080:\n11081:        assert_eq!(\n11082:            *written.lock().unwrap(),\n11083:            inputs,\n11084:            \"the single FIFO + single writer must preserve strict enqueue order \\\n11085:             end-to-end (REQ-HAZARD-PTY-INPUT-WRITER-WEDGE — keystroke order is the \\\n11086:             paste-correctness invariant)\"\n11087:        );\n11088:    }\n11089:\n11090:    /// Bounded-queue DROP/HEAL decision, the heart of the fix. With a TINY capacity\n11091:    /// and a consumer that is NOT draining: the first N enqueues are accepted, the\n11092:    /// overflowing enqueue is DROPPED (returns false) and flips `backpressure` true;\n11093:    /// once the consumer drains one slot, the next enqueue is accepted again and\n11094:    /// CLEARS backpressure (heal-on-resume). Asserted purely on the in-crate\n11095:    /// `backpressure` atomic + the bool return — INJECTED channel, ZERO wall-clock.\n11096:    ///\n11097:    /// Mutation-proof: swap the Full/Ok arms (always-accept) and the DROP assert +\n11098:    /// the `backpressure==true` assert fail; drop the heal `swap(false)` and the\n11099:    /// post-drain clear fails; widen the bound and the saturation assert fails.\n11100:    // [unit->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\n11101:    #[test]\n11102:    fn input_enqueue_drops_and_stamps_on_full_then_heals_on_drain() {\n11103:        const DEPTH: usize = 3;\n11104:        // Consumer is the test; it does NOT drain until we say so → the queue fills.\n11105:        let (w, rx) = test_input_writer(DEPTH);\n11106:\n11107:        // The first DEPTH enqueues fit (accepted, no backpressure yet).\n11108:        for i in 0..DEPTH {\n11109:            assert!(w.enqueue(vec![i as u8]), \"enqueue {i} fits within the bound\");\n11110:        }\n11111:        assert!(\n11112:            !w.backpressure.load(Ordering::Acquire),\n11113:            \"a full-but-not-overflowed queue has NOT signalled backpressure\"\n11114:        );\n11115:\n11116:        // The overflowing enqueue (queue full, consumer stalled) is DROPPED and\n11117:        // stamps backpressure on the rising edge.\n11118:        assert!(\n11119:            !w.enqueue(b\"OVERFLOW\".to_vec()),\n11120:            \"an enqueue into a full FIFO is DROPPED (returns false) — never blocks \\\n11121:             the dispatch thread (the wedge cure)\"\n11122:        );\n11123:        assert!(\n11124:            w.backpressure.load(Ordering::Acquire),\n11125:            \"a DROP must stamp input_backpressure true (operator-visible signal)\"\n11126:        );\n11127:        // A second overflow while still saturated stays dropped + backpressured (the\n11128:        // stamp is rising-edge-only, but the STATE remains true — no flap to false).\n11129:        assert!(!w.enqueue(b\"OVERFLOW-2\".to_vec()), \"still dropping while full\");\n11130:        assert!(\n11131:            w.backpressure.load(Ordering::Acquire),\n11132:            \"backpressure stays asserted while the queue remains saturated\"\n11133:        );\n11134:\n11135:        // The consumer drains ONE slot → a slot frees. The next enqueue is accepted\n11136:        // and HEALS (clears backpressure) — input resumes, the slow harness recovers.\n11137:        let _ = rx.recv().expect(\"drain one record to free a slot\");\n11138:        assert!(\n11139:            w.enqueue(b\"AFTER-DRAIN\".to_vec()),\n11140:            \"with a freed slot the next enqueue is ACCEPTED again\"\n11141:        );\n11142:        assert!(\n11143:            !w.backpressure.load(Ordering::Acquire),\n11144:            \"the first accepted enqueue after a drain HEALS — clears input_backpressure \\\n11145:             (heal-on-resume; a merely-slow harness self-recovers, never a hard wedge)\"\n11146:        );\n11147:    }\n11148:\n11149:    // [unit->REQ-HAZARD-INJECT-WORKER-POISON] B6 leg (i): the per-session inject\n11150:    // floor lock RECOVERS from a poison instead of panicking. The floor is shared by\n11151:    // the inject worker and the controller-input path; a panic under it on either\n11152:    // poisons it. `lock_floor` (the fix) returns a usable guard so the worker's next\n11153:    // open()/flush and the controller's buffer_if_held all survive — one panic can no\n11154:    // longer cascade the whole session's delivery dead (\"worker-gone\" force-native\n11155:    // refusal against a still-live binary). RED-FIRST: swap `lock_floor` back to a bare\n11156:    // `floor.lock().unwrap()` and this PANICS on the poisoned mutex.\n11157:    #[test]\n11158:    fn lock_floor_recovers_a_poisoned_inject_floor() {\n11159:        let floor = Arc::new(Mutex::new(InjectFloor::default()));\n11160:        // Poison it exactly as a panic-while-holding-the-floor-lock does.\n11161:        let f = Arc::clone(&floor);\n11162:        let _ = thread::spawn(move || {\n11163:            let _g = f.lock().unwrap();\n11164:            panic!(\"poison the inject floor\");\n11165:        })\n11166:        .join();\n11167:        assert!(floor.is_poisoned(), \"precondition: the floor mutex is poisoned\");\n11168:        // The fix: the recovered guard is fully usable — open() takes, is_held reads.\n11169:        lock_floor(&floor).open();\n11170:        assert!(\n11171:            lock_floor(&floor).is_held(),\n11172:            \"a poison-recovered floor stays usable (the worker's lock survives a poison)\"\n11173:        );\n11174:    }\n11175:\n11176:    // [unit->REQ-HAZARD-BROKER-FLOOR-LOCK-POISON] B-1 (i): a broker-resident map lock\n11177:    // (the SESSIONS class — sessions/pair_holds) RECOVERS from a poison instead of\n11178:    // panicking. Brain-only self-update keeps the broker + this lock alive; a panic\n11179:    // under it during attach churn would poison it permanently → EVERY subsequent\n11180:    // attach (serve/dispatch locks sessions) panics its reply thread and deadlines\n11181:    // (\"brain IPC read deadline elapsed\") forever. `recover` (the fix) hands back a\n11182:    // usable guard so the NEXT attach-path op still runs. RED-FIRST: swap `recover`\n11183:    // back to a bare `.lock().unwrap()` and the post-poison access PANICS.\n11184:    #[test]\n11185:    fn recover_reopens_a_poisoned_sessions_map() {\n11186:        let sessions: Arc<Mutex<HashMap<u64, u64>>> = Arc::new(Mutex::new(HashMap::new()));\n11187:        recover(&sessions).insert(7, 70); // a pre-poison \"session\" row\n11188:        let s = Arc::clone(&sessions);\n11189:        let _ = thread::spawn(move || {\n11190:            let _g = s.lock().unwrap();\n11191:            panic!(\"poison the sessions map mid-attach\");\n11192:        })\n11193:        .join();\n11194:        assert!(sessions.is_poisoned(), \"precondition: the sessions mutex is poisoned\");\n11195:        // The fix: the recovered guard is fully usable — the prior row survives and a\n11196:        // NEW attach can still insert/look up (no permanent wedge).\n11197:        assert_eq!(recover(&sessions).get(&7).copied(), Some(70), \"prior state survives recovery\");\n11198:        recover(&sessions).insert(9, 90);\n11199:        assert_eq!(recover(&sessions).get(&9).copied(), Some(90), \"the next attach still opens\");\n11200:    }\n11201:\n11202:    /// The physical screen a FRESH client terminal shows after applying the log's\n11203:    /// synthesized cold-attach repaint — rendered through `avt`, an INDEPENDENT\n11204:    /// width-aware emulator. The resize units below assert against THIS, never\n11205:    /// against ScreenGrid's own model: a placement defect in the grid would be\n11206:    /// shared by both sides of a self-comparison and pass vacuously (the standing\n11207:    /// oracle rule from the REQ-SCREENGRID-WIDTH spec).\n11208:    fn repaint_screen(log: &OutputLog) -> Vec<String> {\n11209:        let (rows, cols) = log.grid.geometry();\n11210:        let repaint = log.grid.render_repaint();\n11211:        let mut vt = avt::Vt::new(cols as usize, rows as usize);\n11212:        vt.feed_str(std::str::from_utf8(&repaint).expect(\"the repaint is valid UTF-8\"));\n11213:        vt.view().map(|l| l.text().trim_end().to_string()).collect()\n11214:    }\n11215:\n11216:    // [unit->REQ-RC-RESIZE-GEOMETRY-EPOCH] THE SHRINK CASE, which discriminates\n11217:    // BOTH wrong answers at once — that is the point of its shape:\n11218:    //\n11219:    //   * pre-issue output (emitted at the OLD, WIDER 20 columns) must be parsed\n11220:    //     at 20 and then TRUNCATED by the top-left-preserving resize. Parsing it\n11221:    //     at the new narrow width — what the REJECTED \"set the grid geometry\n11222:    //     first\" reorder does — wraps `KLMNO` onto row 2, where nothing later\n11223:    //     addresses it, and it survives as interior debris.\n\n[Showing lines 11003-11223 of 16479. Use :11224 to continue]"}],"details":{"truncation":{"content":"\r\n    // ── v0.13.0 P0 — REQ-HAZARD-PTY-INPUT-WRITER-WEDGE: the PTY input\r\n    //    single-writer unit kernel. These exercise the REAL `InputWriter::enqueue`\r\n    //    against the REAL bounded `sync_channel` + the REAL backpressure atomic,\r\n    //    with a CALLER-CONTROLLED consumer (the test owns `rx` and drains by hand).\r\n    //    No PTY, no wall-clock in any decision assertion — the whole point of the\r\n    //    fix is that the enqueue decision is non-blocking and clock-free. ──────────\r\n\r\n    /// Build an [`InputWriter`] over a caller-supplied bounded channel so the test\r\n    /// controls the consumer precisely. `endpoint` is EMPTY, so `stamp_backpressure`\r\n    /// is a no-op (impl: `if self.endpoint.is_empty() { return; }`) — the perch\r\n    /// mirror is the int test's job; here we assert the in-crate `backpressure`\r\n    /// atomic directly. The `_writer` handle is a trivial no-op thread: the REAL\r\n    /// drain (`input_writer`) is the trivial FIFO `recv` loop, separately covered by\r\n    /// the ORDER test; here the TEST is the consumer, draining `rx` deterministically.\r\n    fn test_input_writer(depth: usize) -> (InputWriter, Receiver<InputRecord>) {\r\n        let (tx, rx) = sync_channel::<InputRecord>(depth);\r\n        let w = InputWriter {\r\n            tx,\r\n            backpressure: AtomicBool::new(false),\r\n            endpoint: String::new(),\r\n            _writer: thread::spawn(|| {}),\r\n        };\r\n        (w, rx)\r\n    }\r\n\r\n    /// Drain ORDER: records enqueued in sequence reach the sole writer in strict\r\n    /// FIFO order. We drive the REAL `enqueue` into the REAL channel, then drain it\r\n    /// through a single consumer that applies each record to a stub `SessionSurface`\r\n    /// recording the bytes it receives — EXACTLY mirroring the production\r\n    /// `input_writer` loop (`while let Ok(b) = rx.recv() { surface.write_input(&b) }`).\r\n    /// One FIFO + one writer ⇒ exact input order. Non-vacuous: a reorder/LIFO/dedup\r\n    /// mutation of the single-writer contract makes the recorded sequence diverge.\r\n    // [unit->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\r\n    #[test]\r\n    fn input_writer_preserves_strict_fifo_order_through_the_sole_writer() {\r\n        use spt_term::surface::{SessionSurface, SurfaceError, SurfaceSize};\r\n\r\n        /// A stub PTY write seam: appends every `write_input` to a shared Vec, in\r\n        /// the order the sole writer applied them. (`resize` is never exercised.)\r\n        struct RecordingSurface(Arc<Mutex<Vec<Vec<u8>>>>);\r\n        impl SessionSurface for RecordingSurface {\r\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\r\n                self.0.lock().unwrap().push(bytes.to_vec());\r\n                Ok(())\r\n            }\r\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> {\r\n                Ok(())\r\n            }\r\n        }\r\n\r\n        // Generous depth so nothing drops — this test is about ORDER, not the bound.\r\n        let (w, rx) = test_input_writer(256);\r\n        let written = Arc::new(Mutex::new(Vec::<Vec<u8>>::new()));\r\n        let surface = RecordingSurface(Arc::clone(&written));\r\n\r\n        // Enqueue a distinguishable, NON-monotonic sequence (so any sort/reorder\r\n        // mutation is caught, not just a reverse): paste-shaped multi-byte records\r\n        // interleaved with single keystrokes.\r\n        let inputs: Vec<Vec<u8>> = vec![\r\n            b\"first\".to_vec(),\r\n            b\"\\x03\".to_vec(),       // Ctrl-C\r\n            b\"PASTE-BLOCK-AAAA\".to_vec(),\r\n            b\"z\".to_vec(),\r\n            b\"\\r\".to_vec(),         // Enter\r\n            b\"PASTE-BLOCK-BBBB\".to_vec(),\r\n            b\"last\".to_vec(),\r\n        ];\r\n        for rec in &inputs {\r\n            assert!(w.enqueue(rec.clone()), \"depth 256: every enqueue is accepted\");\r\n        }\r\n        // Close the FIFO so the drain loop terminates, then drain through the SOLE\r\n        // writer exactly as `input_writer` does.\r\n        drop(w);\r\n        while let Ok(bytes) = rx.recv() {\r\n            surface.write_input(&bytes).unwrap();\r\n        }\r\n\r\n        assert_eq!(\r\n            *written.lock().unwrap(),\r\n            inputs,\r\n            \"the single FIFO + single writer must preserve strict enqueue order \\\r\n             end-to-end (REQ-HAZARD-PTY-INPUT-WRITER-WEDGE — keystroke order is the \\\r\n             paste-correctness invariant)\"\r\n        );\r\n    }\r\n\r\n    /// Bounded-queue DROP/HEAL decision, the heart of the fix. With a TINY capacity\r\n    /// and a consumer that is NOT draining: the first N enqueues are accepted, the\r\n    /// overflowing enqueue is DROPPED (returns false) and flips `backpressure` true;\r\n    /// once the consumer drains one slot, the next enqueue is accepted again and\r\n    /// CLEARS backpressure (heal-on-resume). Asserted purely on the in-crate\r\n    /// `backpressure` atomic + the bool return — INJECTED channel, ZERO wall-clock.\r\n    ///\r\n    /// Mutation-proof: swap the Full/Ok arms (always-accept) and the DROP assert +\r\n    /// the `backpressure==true` assert fail; drop the heal `swap(false)` and the\r\n    /// post-drain clear fails; widen the bound and the saturation assert fails.\r\n    // [unit->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\r\n    #[test]\r\n    fn input_enqueue_drops_and_stamps_on_full_then_heals_on_drain() {\r\n        const DEPTH: usize = 3;\r\n        // Consumer is the test; it does NOT drain until we say so → the queue fills.\r\n        let (w, rx) = test_input_writer(DEPTH);\r\n\r\n        // The first DEPTH enqueues fit (accepted, no backpressure yet).\r\n        for i in 0..DEPTH {\r\n            assert!(w.enqueue(vec![i as u8]), \"enqueue {i} fits within the bound\");\r\n        }\r\n        assert!(\r\n            !w.backpressure.load(Ordering::Acquire),\r\n            \"a full-but-not-overflowed queue has NOT signalled backpressure\"\r\n        );\r\n\r\n        // The overflowing enqueue (queue full, consumer stalled) is DROPPED and\r\n        // stamps backpressure on the rising edge.\r\n        assert!(\r\n            !w.enqueue(b\"OVERFLOW\".to_vec()),\r\n            \"an enqueue into a full FIFO is DROPPED (returns false) — never blocks \\\r\n             the dispatch thread (the wedge cure)\"\r\n        );\r\n        assert!(\r\n            w.backpressure.load(Ordering::Acquire),\r\n            \"a DROP must stamp input_backpressure true (operator-visible signal)\"\r\n        );\r\n        // A second overflow while still saturated stays dropped + backpressured (the\r\n        // stamp is rising-edge-only, but the STATE remains true — no flap to false).\r\n        assert!(!w.enqueue(b\"OVERFLOW-2\".to_vec()), \"still dropping while full\");\r\n        assert!(\r\n            w.backpressure.load(Ordering::Acquire),\r\n            \"backpressure stays asserted while the queue remains saturated\"\r\n        );\r\n\r\n        // The consumer drains ONE slot → a slot frees. The next enqueue is accepted\r\n        // and HEALS (clears backpressure) — input resumes, the slow harness recovers.\r\n        let _ = rx.recv().expect(\"drain one record to free a slot\");\r\n        assert!(\r\n            w.enqueue(b\"AFTER-DRAIN\".to_vec()),\r\n            \"with a freed slot the next enqueue is ACCEPTED again\"\r\n        );\r\n        assert!(\r\n            !w.backpressure.load(Ordering::Acquire),\r\n            \"the first accepted enqueue after a drain HEALS — clears input_backpressure \\\r\n             (heal-on-resume; a merely-slow harness self-recovers, never a hard wedge)\"\r\n        );\r\n    }\r\n\r\n    // [unit->REQ-HAZARD-INJECT-WORKER-POISON] B6 leg (i): the per-session inject\r\n    // floor lock RECOVERS from a poison instead of panicking. The floor is shared by\r\n    // the inject worker and the controller-input path; a panic under it on either\r\n    // poisons it. `lock_floor` (the fix) returns a usable guard so the worker's next\r\n    // open()/flush and the controller's buffer_if_held all survive — one panic can no\r\n    // longer cascade the whole session's delivery dead (\"worker-gone\" force-native\r\n    // refusal against a still-live binary). RED-FIRST: swap `lock_floor` back to a bare\r\n    // `floor.lock().unwrap()` and this PANICS on the poisoned mutex.\r\n    #[test]\r\n    fn lock_floor_recovers_a_poisoned_inject_floor() {\r\n        let floor = Arc::new(Mutex::new(InjectFloor::default()));\r\n        // Poison it exactly as a panic-while-holding-the-floor-lock does.\r\n        let f = Arc::clone(&floor);\r\n        let _ = thread::spawn(move || {\r\n            let _g = f.lock().unwrap();\r\n            panic!(\"poison the inject floor\");\r\n        })\r\n        .join();\r\n        assert!(floor.is_poisoned(), \"precondition: the floor mutex is poisoned\");\r\n        // The fix: the recovered guard is fully usable — open() takes, is_held reads.\r\n        lock_floor(&floor).open();\r\n        assert!(\r\n            lock_floor(&floor).is_held(),\r\n            \"a poison-recovered floor stays usable (the worker's lock survives a poison)\"\r\n        );\r\n    }\r\n\r\n    // [unit->REQ-HAZARD-BROKER-FLOOR-LOCK-POISON] B-1 (i): a broker-resident map lock\r\n    // (the SESSIONS class — sessions/pair_holds) RECOVERS from a poison instead of\r\n    // panicking. Brain-only self-update keeps the broker + this lock alive; a panic\r\n    // under it during attach churn would poison it permanently → EVERY subsequent\r\n    // attach (serve/dispatch locks sessions) panics its reply thread and deadlines\r\n    // (\"brain IPC read deadline elapsed\") forever. `recover` (the fix) hands back a\r\n    // usable guard so the NEXT attach-path op still runs. RED-FIRST: swap `recover`\r\n    // back to a bare `.lock().unwrap()` and the post-poison access PANICS.\r\n    #[test]\r\n    fn recover_reopens_a_poisoned_sessions_map() {\r\n        let sessions: Arc<Mutex<HashMap<u64, u64>>> = Arc::new(Mutex::new(HashMap::new()));\r\n        recover(&sessions).insert(7, 70); // a pre-poison \"session\" row\r\n        let s = Arc::clone(&sessions);\r\n        let _ = thread::spawn(move || {\r\n            let _g = s.lock().unwrap();\r\n            panic!(\"poison the sessions map mid-attach\");\r\n        })\r\n        .join();\r\n        assert!(sessions.is_poisoned(), \"precondition: the sessions mutex is poisoned\");\r\n        // The fix: the recovered guard is fully usable — the prior row survives and a\r\n        // NEW attach can still insert/look up (no permanent wedge).\r\n        assert_eq!(recover(&sessions).get(&7).copied(), Some(70), \"prior state survives recovery\");\r\n        recover(&sessions).insert(9, 90);\r\n        assert_eq!(recover(&sessions).get(&9).copied(), Some(90), \"the next attach still opens\");\r\n    }\r\n\r\n    /// The physical screen a FRESH client terminal shows after applying the log's\r\n    /// synthesized cold-attach repaint — rendered through `avt`, an INDEPENDENT\r\n    /// width-aware emulator. The resize units below assert against THIS, never\r\n    /// against ScreenGrid's own model: a placement defect in the grid would be\r\n    /// shared by both sides of a self-comparison and pass vacuously (the standing\r\n    /// oracle rule from the REQ-SCREENGRID-WIDTH spec).\r\n    fn repaint_screen(log: &OutputLog) -> Vec<String> {\r\n        let (rows, cols) = log.grid.geometry();\r\n        let repaint = log.grid.render_repaint();\r\n        let mut vt = avt::Vt::new(cols as usize, rows as usize);\r\n        vt.feed_str(std::str::from_utf8(&repaint).expect(\"the repaint is valid UTF-8\"));\r\n        vt.view().map(|l| l.text().trim_end().to_string()).collect()\r\n    }\r\n\r\n    // [unit->REQ-RC-RESIZE-GEOMETRY-EPOCH] THE SHRINK CASE, which discriminates\r\n    // BOTH wrong answers at once — that is the point of its shape:\r\n    //\r\n    //   * pre-issue output (emitted at the OLD, WIDER 20 columns) must be parsed\r\n    //     at 20 and then TRUNCATED by the top-left-preserving resize. Parsing it\r\n    //     at the new narrow width — what the REJECTED \"set the grid geometry\r\n    //     first\" reorder does — wraps `KLMNO` onto row 2, where nothing later\r\n    //     addresses it, and it survives as interior debris.\r","truncated":true,"truncatedBy":"lines","totalLines":5477,"totalBytes":11960,"outputLines":221,"outputBytes":11960,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":16479,"displayContent":{"text":"\r\n    // ── v0.13.0 P0 — REQ-HAZARD-PTY-INPUT-WRITER-WEDGE: the PTY input\r\n    //    single-writer unit kernel. These exercise the REAL `InputWriter::enqueue`\r\n    //    against the REAL bounded `sync_channel` + the REAL backpressure atomic,\r\n    //    with a CALLER-CONTROLLED consumer (the test owns `rx` and drains by hand).\r\n    //    No PTY, no wall-clock in any decision assertion — the whole point of the\r\n    //    fix is that the enqueue decision is non-blocking and clock-free. ──────────\r\n\r\n    /// Build an [`InputWriter`] over a caller-supplied bounded channel so the test\r\n    /// controls the consumer precisely. `endpoint` is EMPTY, so `stamp_backpressure`\r\n    /// is a no-op (impl: `if self.endpoint.is_empty() { return; }`) — the perch\r\n    /// mirror is the int test's job; here we assert the in-crate `backpressure`\r\n    /// atomic directly. The `_writer` handle is a trivial no-op thread: the REAL\r\n    /// drain (`input_writer`) is the trivial FIFO `recv` loop, separately covered by\r\n    /// the ORDER test; here the TEST is the consumer, draining `rx` deterministically.\r\n    fn test_input_writer(depth: usize) -> (InputWriter, Receiver<InputRecord>) {\r\n        let (tx, rx) = sync_channel::<InputRecord>(depth);\r\n        let w = InputWriter {\r\n            tx,\r\n            backpressure: AtomicBool::new(false),\r\n            endpoint: String::new(),\r\n            _writer: thread::spawn(|| {}),\r\n        };\r\n        (w, rx)\r\n    }\r\n\r\n    /// Drain ORDER: records enqueued in sequence reach the sole writer in strict\r\n    /// FIFO order. We drive the REAL `enqueue` into the REAL channel, then drain it\r\n    /// through a single consumer that applies each record to a stub `SessionSurface`\r\n    /// recording the bytes it receives — EXACTLY mirroring the production\r\n    /// `input_writer` loop (`while let Ok(b) = rx.recv() { surface.write_input(&b) }`).\r\n    /// One FIFO + one writer ⇒ exact input order. Non-vacuous: a reorder/LIFO/dedup\r\n    /// mutation of the single-writer contract makes the recorded sequence diverge.\r\n    // [unit->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\r\n    #[test]\r\n    fn input_writer_preserves_strict_fifo_order_through_the_sole_writer() {\r\n        use spt_term::surface::{SessionSurface, SurfaceError, SurfaceSize};\r\n\r\n        /// A stub PTY write seam: appends every `write_input` to a shared Vec, in\r\n        /// the order the sole writer applied them. (`resize` is never exercised.)\r\n        struct RecordingSurface(Arc<Mutex<Vec<Vec<u8>>>>);\r\n        impl SessionSurface for RecordingSurface {\r\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\r\n                self.0.lock().unwrap().push(bytes.to_vec());\r\n                Ok(())\r\n            }\r\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> {\r\n                Ok(())\r\n            }\r\n        }\r\n\r\n        // Generous depth so nothing drops — this test is about ORDER, not the bound.\r\n        let (w, rx) = test_input_writer(256);\r\n        let written = Arc::new(Mutex::new(Vec::<Vec<u8>>::new()));\r\n        let surface = RecordingSurface(Arc::clone(&written));\r\n\r\n        // Enqueue a distinguishable, NON-monotonic sequence (so any sort/reorder\r\n        // mutation is caught, not just a reverse): paste-shaped multi-byte records\r\n        // interleaved with single keystrokes.\r\n        let inputs: Vec<Vec<u8>> = vec![\r\n            b\"first\".to_vec(),\r\n            b\"\\x03\".to_vec(),       // Ctrl-C\r\n            b\"PASTE-BLOCK-AAAA\".to_vec(),\r\n            b\"z\".to_vec(),\r\n            b\"\\r\".to_vec(),         // Enter\r\n            b\"PASTE-BLOCK-BBBB\".to_vec(),\r\n            b\"last\".to_vec(),\r\n        ];\r\n        for rec in &inputs {\r\n            assert!(w.enqueue(rec.clone()), \"depth 256: every enqueue is accepted\");\r\n        }\r\n        // Close the FIFO so the drain loop terminates, then drain through the SOLE\r\n        // writer exactly as `input_writer` does.\r\n        drop(w);\r\n        while let Ok(bytes) = rx.recv() {\r\n            surface.write_input(&bytes).unwrap();\r\n        }\r\n\r\n        assert_eq!(\r\n            *written.lock().unwrap(),\r\n            inputs,\r\n            \"the single FIFO + single writer must preserve strict enqueue order \\\r\n             end-to-end (REQ-HAZARD-PTY-INPUT-WRITER-WEDGE — keystroke order is the \\\r\n             paste-correctness invariant)\"\r\n        );\r\n    }\r\n\r\n    /// Bounded-queue DROP/HEAL decision, the heart of the fix. With a TINY capacity\r\n    /// and a consumer that is NOT draining: the first N enqueues are accepted, the\r\n    /// overflowing enqueue is DROPPED (returns false) and flips `backpressure` true;\r\n    /// once the consumer drains one slot, the next enqueue is accepted again and\r\n    /// CLEARS backpressure (heal-on-resume). Asserted purely on the in-crate\r\n    /// `backpressure` atomic + the bool return — INJECTED channel, ZERO wall-clock.\r\n    ///\r\n    /// Mutation-proof: swap the Full/Ok arms (always-accept) and the DROP assert +\r\n    /// the `backpressure==true` assert fail; drop the heal `swap(false)` and the\r\n    /// post-drain clear fails; widen the bound and the saturation assert fails.\r\n    // [unit->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\r\n    #[test]\r\n    fn input_enqueue_drops_and_stamps_on_full_then_heals_on_drain() {\r\n        const DEPTH: usize = 3;\r\n        // Consumer is the test; it does NOT drain until we say so → the queue fills.\r\n        let (w, rx) = test_input_writer(DEPTH);\r\n\r\n        // The first DEPTH enqueues fit (accepted, no backpressure yet).\r\n        for i in 0..DEPTH {\r\n            assert!(w.enqueue(vec![i as u8]), \"enqueue {i} fits within the bound\");\r\n        }\r\n        assert!(\r\n            !w.backpressure.load(Ordering::Acquire),\r\n            \"a full-but-not-overflowed queue has NOT signalled backpressure\"\r\n        );\r\n\r\n        // The overflowing enqueue (queue full, consumer stalled) is DROPPED and\r\n        // stamps backpressure on the rising edge.\r\n        assert!(\r\n            !w.enqueue(b\"OVERFLOW\".to_vec()),\r\n            \"an enqueue into a full FIFO is DROPPED (returns false) — never blocks \\\r\n             the dispatch thread (the wedge cure)\"\r\n        );\r\n        assert!(\r\n            w.backpressure.load(Ordering::Acquire),\r\n            \"a DROP must stamp input_backpressure true (operator-visible signal)\"\r\n        );\r\n        // A second overflow while still saturated stays dropped + backpressured (the\r\n        // stamp is rising-edge-only, but the STATE remains true — no flap to false).\r\n        assert!(!w.enqueue(b\"OVERFLOW-2\".to_vec()), \"still dropping while full\");\r\n        assert!(\r\n            w.backpressure.load(Ordering::Acquire),\r\n            \"backpressure stays asserted while the queue remains saturated\"\r\n        );\r\n\r\n        // The consumer drains ONE slot → a slot frees. The next enqueue is accepted\r\n        // and HEALS (clears backpressure) — input resumes, the slow harness recovers.\r\n        let _ = rx.recv().expect(\"drain one record to free a slot\");\r\n        assert!(\r\n            w.enqueue(b\"AFTER-DRAIN\".to_vec()),\r\n            \"with a freed slot the next enqueue is ACCEPTED again\"\r\n        );\r\n        assert!(\r\n            !w.backpressure.load(Ordering::Acquire),\r\n            \"the first accepted enqueue after a drain HEALS — clears input_backpressure \\\r\n             (heal-on-resume; a merely-slow harness self-recovers, never a hard wedge)\"\r\n        );\r\n    }\r\n\r\n    // [unit->REQ-HAZARD-INJECT-WORKER-POISON] B6 leg (i): the per-session inject\r\n    // floor lock RECOVERS from a poison instead of panicking. The floor is shared by\r\n    // the inject worker and the controller-input path; a panic under it on either\r\n    // poisons it. `lock_floor` (the fix) returns a usable guard so the worker's next\r\n    // open()/flush and the controller's buffer_if_held all survive — one panic can no\r\n    // longer cascade the whole session's delivery dead (\"worker-gone\" force-native\r\n    // refusal against a still-live binary). RED-FIRST: swap `lock_floor` back to a bare\r\n    // `floor.lock().unwrap()` and this PANICS on the poisoned mutex.\r\n    #[test]\r\n    fn lock_floor_recovers_a_poisoned_inject_floor() {\r\n        let floor = Arc::new(Mutex::new(InjectFloor::default()));\r\n        // Poison it exactly as a panic-while-holding-the-floor-lock does.\r\n        let f = Arc::clone(&floor);\r\n        let _ = thread::spawn(move || {\r\n            let _g = f.lock().unwrap();\r\n            panic!(\"poison the inject floor\");\r\n        })\r\n        .join();\r\n        assert!(floor.is_poisoned(), \"precondition: the floor mutex is poisoned\");\r\n        // The fix: the recovered guard is fully usable — open() takes, is_held reads.\r\n        lock_floor(&floor).open();\r\n        assert!(\r\n            lock_floor(&floor).is_held(),\r\n            \"a poison-recovered floor stays usable (the worker's lock survives a poison)\"\r\n        );\r\n    }\r\n\r\n    // [unit->REQ-HAZARD-BROKER-FLOOR-LOCK-POISON] B-1 (i): a broker-resident map lock\r\n    // (the SESSIONS class — sessions/pair_holds) RECOVERS from a poison instead of\r\n    // panicking. Brain-only self-update keeps the broker + this lock alive; a panic\r\n    // under it during attach churn would poison it permanently → EVERY subsequent\r\n    // attach (serve/dispatch locks sessions) panics its reply thread and deadlines\r\n    // (\"brain IPC read deadline elapsed\") forever. `recover` (the fix) hands back a\r\n    // usable guard so the NEXT attach-path op still runs. RED-FIRST: swap `recover`\r\n    // back to a bare `.lock().unwrap()` and the post-poison access PANICS.\r\n    #[test]\r\n    fn recover_reopens_a_poisoned_sessions_map() {\r\n        let sessions: Arc<Mutex<HashMap<u64, u64>>> = Arc::new(Mutex::new(HashMap::new()));\r\n        recover(&sessions).insert(7, 70); // a pre-poison \"session\" row\r\n        let s = Arc::clone(&sessions);\r\n        let _ = thread::spawn(move || {\r\n            let _g = s.lock().unwrap();\r\n            panic!(\"poison the sessions map mid-attach\");\r\n        })\r\n        .join();\r\n        assert!(sessions.is_poisoned(), \"precondition: the sessions mutex is poisoned\");\r\n        // The fix: the recovered guard is fully usable — the prior row survives and a\r\n        // NEW attach can still insert/look up (no permanent wedge).\r\n        assert_eq!(recover(&sessions).get(&7).copied(), Some(70), \"prior state survives recovery\");\r\n        recover(&sessions).insert(9, 90);\r\n        assert_eq!(recover(&sessions).get(&9).copied(), Some(90), \"the next attach still opens\");\r\n    }\r\n\r\n    /// The physical screen a FRESH client terminal shows after applying the log's\r\n    /// synthesized cold-attach repaint — rendered through `avt`, an INDEPENDENT\r\n    /// width-aware emulator. The resize units below assert against THIS, never\r\n    /// against ScreenGrid's own model: a placement defect in the grid would be\r\n    /// shared by both sides of a self-comparison and pass vacuously (the standing\r\n    /// oracle rule from the REQ-SCREENGRID-WIDTH spec).\r\n    fn repaint_screen(log: &OutputLog) -> Vec<String> {\r\n        let (rows, cols) = log.grid.geometry();\r\n        let repaint = log.grid.render_repaint();\r\n        let mut vt = avt::Vt::new(cols as usize, rows as usize);\r\n        vt.feed_str(std::str::from_utf8(&repaint).expect(\"the repaint is valid UTF-8\"));\r\n        vt.view().map(|l| l.text().trim_end().to_string()).collect()\r\n    }\r\n\r\n    // [unit->REQ-RC-RESIZE-GEOMETRY-EPOCH] THE SHRINK CASE, which discriminates\r\n    // BOTH wrong answers at once — that is the point of its shape:\r\n    //\r\n    //   * pre-issue output (emitted at the OLD, WIDER 20 columns) must be parsed\r\n    //     at 20 and then TRUNCATED by the top-left-preserving resize. Parsing it\r\n    //     at the new narrow width — what the REJECTED \"set the grid geometry\r\n    //     first\" reorder does — wraps `KLMNO` onto row 2, where nothing later\r\n    //     addresses it, and it survives as interior debris.\r","startLine":11003,"lineNumbers":[11003,11004,11005,11006,11007,11008,11009,11010,11011,11012,11013,11014,11015,11016,11017,11018,11019,11020,11021,11022,11023,11024,11025,11026,11027,11028,11029,11030,11031,11032,11033,11034,11035,11036,11037,11038,11039,11040,11041,11042,11043,11044,11045,11046,11047,11048,11049,11050,11051,11052,11053,11054,11055,11056,11057,11058,11059,11060,11061,11062,11063,11064,11065,11066,11067,11068,11069,11070,11071,11072,11073,11074,11075,11076,11077,11078,11079,11080,11081,11082,11083,11084,11085,11086,11087,11088,11089,11090,11091,11092,11093,11094,11095,11096,11097,11098,11099,11100,11101,11102,11103,11104,11105,11106,11107,11108,11109,11110,11111,11112,11113,11114,11115,11116,11117,11118,11119,11120,11121,11122,11123,11124,11125,11126,11127,11128,11129,11130,11131,11132,11133,11134,11135,11136,11137,11138,11139,11140,11141,11142,11143,11144,11145,11146,11147,11148,11149,11150,11151,11152,11153,11154,11155,11156,11157,11158,11159,11160,11161,11162,11163,11164,11165,11166,11167,11168,11169,11170,11171,11172,11173,11174,11175,11176,11177,11178,11179,11180,11181,11182,11183,11184,11185,11186,11187,11188,11189,11190,11191,11192,11193,11194,11195,11196,11197,11198,11199,11200,11201,11202,11203,11204,11205,11206,11207,11208,11209,11210,11211,11212,11213,11214,11215,11216,11217,11218,11219,11220,11221,11222,11223]},"fileSize":857503,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\broker.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":16479,"totalBytes":11960,"outputLines":221,"outputBytes":11960,"shownRange":{"start":11003,"end":11223},"nextOffset":11224}}},"isError":false,"timestamp":1789295530612}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_v7sIZB8QvfmVqXmA1KLHViex|fc_0b12df87254bb4e6016aa67bbc412887d186007a717c31a3c9","toolName":"write","startedAt":"2026-09-13T10:33:40.370Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs"},"intent":"Creating delivery custody ledger"},"id":"55b6ddd7","parentId":"c7eda496","timestamp":"2026-09-13T10:33:40.370Z"}
{"type":"message","id":"35fb1e6e","parentId":"55b6ddd7","timestamp":"2026-09-13T10:33:40.371Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Designing writer records**\n\n**Designing InputRecord**"},{"type":"toolCall","id":"call_v7sIZB8QvfmVqXmA1KLHViex|fc_0b12df87254bb4e6016aa67bbc412887d186007a717c31a3c9","name":"write","arguments":{"i":"Creating delivery custody ledger","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs","content":"//! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\n\nuse sha2::{Digest, Sha256};\nuse spt_term::surface::SessionSurface;\nuse std::collections::HashSet;\nuse std::sync::{Arc, Mutex};\n\n// Digests, not retained payloads. Never evict evidence from a live hosted session:\n// exhaustion disables origin grants with a named reason instead.\nconst MAX_DELIVERY_DIGESTS: usize = 65_536;\n\n#[derive(Default)]\npub(crate) struct DeliveryBytes {\n    completed: Mutex<Completed>,\n}\n\n#[derive(Default)]\nstruct Completed {\n    digests: HashSet<[u8; 32]>,\n    exhausted: bool,\n}\n\nimpl DeliveryBytes {\n    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\n        let digest: [u8; 32] = Sha256::digest(payload).into();\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .digests\n            .contains(&digest)\n    }\n\n    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .exhausted\n            .then_some(\"delivery-evidence-capacity\")\n    }\n\n    fn remember(&self, digest: [u8; 32]) {\n        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n    }\n\n    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        if completed.digests.contains(&digest) {\n            return;\n        }\n        if completed.digests.len() >= limit {\n            completed.exhausted = true;\n        } else {\n            completed.digests.insert(digest);\n        }\n    }\n}\n\n/// One translation attempt; queued records keep its constant-size streaming state\n/// alive until the lone writer has processed them, independently of logical Commit.\n#[derive(Default)]\npub(crate) struct DeliveryAttempt {\n    text: Mutex<AttemptText>,\n}\n\n#[derive(Default)]\nstruct AttemptText {\n    hash: Sha256,\n    has_text: bool,\n    failed: bool,\n}\n\n#[derive(Clone, Copy)]\npub(crate) enum DeliveryPart {\n    Text { end: bool },\n    Key,\n}\n\nimpl DeliveryAttempt {\n    fn failed(&self) {\n        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\n    }\n\n    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\n        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\n        if text.failed {\n            return;\n        }\n        if let DeliveryPart::Text { end } = part {\n            text.hash.update(bytes);\n            text.has_text |= !bytes.is_empty();\n            if end && text.has_text {\n                // Publish each complete Text command's cumulative text, including\n                // exact embedded newlines. Keys are source-tagged controls, never\n                // guessed framing stripped from the reported payload.\n                ledger.remember(text.hash.clone().finalize().into());\n            }\n        }\n    }\n}\n\npub(crate) struct InputRecord {\n    bytes: Vec<u8>,\n    origin: InputOrigin,\n}\n\nenum InputOrigin {\n    Controller,\n    Probe,\n    Delivery {\n        attempt: Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    },\n}\n\nimpl InputRecord {\n    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Controller }\n    }\n\n    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Probe }\n    }\n\n    pub(crate) fn delivery(\n        bytes: Vec<u8>,\n        attempt: &Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    ) -> Self {\n        Self {\n            bytes,\n            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\n        }\n    }\n\n    pub(crate) fn dropped(&self) {\n        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\n            attempt.failed();\n        }\n    }\n\n    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n        // Never hold a custody lock across a potentially wedged physical write.\n        // Ok proves write_all + flush, not harness interpretation. Err may follow\n        // a partial write, whose byte count this API does not expose: do not guess.\n        let success = surface.write_input(&self.bytes).is_ok();\n        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n            if success {\n                attempt.written(&self.bytes, *part, ledger);\n            } else {\n                attempt.failed();\n            }\n        }\n        // A report caused by a separate Enter sees the preceding Text's published\n        // evidence before Enter is written (one FIFO, one writer). A report caused\n        // by Text itself can race between physical completion and this publication;\n        // enqueued bytes cannot honestly close that narrower window.\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use spt_term::surface::{SurfaceError, SurfaceSize};\n\n    struct Sink;\n    impl SessionSurface for Sink {\n        fn write_input(&self, _: &[u8]) -> Result<(), SurfaceError> { Ok(()) }\n        fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn split_multiline_delivery_matches_before_commit_without_normalizing() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        let first = InputRecord::delivery(b\"<EVENT>\\n C:/a\".to_vec(), &attempt, DeliveryPart::Text { end: false });\n        let last = InputRecord::delivery(b\"\\n</EVENT> \".to_vec(), &attempt, DeliveryPart::Text { end: true });\n        let payload = b\"<EVENT>\\n C:/a\\n</EVENT> \";\n        assert!(!ledger.matches(payload));\n        first.write_to(&Sink, &ledger);\n        assert!(!ledger.matches(payload));\n        last.write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        InputRecord::delivery(b\"\\r\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/b\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/a\\n</EVENT>\"));\n        assert!(!ledger.matches(b\"<EVENT>\\r\\n C:/a\\r\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"\\r\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n        let ledger = DeliveryBytes::default();\n        InputRecord::controller(b\"human C:/private\".to_vec()).write_to(&Sink, &ledger);\n        InputRecord::probe(b\"\\x1b[6n\".to_vec()).write_to(&Sink, &ledger);\n        assert!(!ledger.matches(b\"human C:/private\"));\n        assert!(!ledger.matches(b\"\\x1b[6n\"));\n        assert!(!ledger.matches(b\"unknown human payload\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"one\\ntwo\"));\n        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n        let next_attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"three\"));\n        assert!(!ledger.matches(b\"one\\ntwothree\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\n        let ledger = DeliveryBytes::default();\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        assert_eq!(ledger.unavailable_reason(), None);\n        ledger.remember_with_limit(Sha256::digest(b\"second\").into(), 1);\n        assert!(ledger.matches(b\"first\"));\n        assert!(!ledger.matches(b\"second\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-evidence-capacity\"));\n    }\n}\n"},"intent":"Creating delivery custody ledger"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":9991,"output":2928,"cacheRead":32256,"cacheWrite":0,"totalTokens":45175,"reasoningTokens":516,"cost":{"input":0.09991000000000001,"output":0.1464,"cacheRead":0.032256,"cacheWrite":0,"total":0.27856600000000004}},"stopReason":"toolUse","timestamp":1789295530642,"responseId":"resp_0b12df87254bb4e6016aa67baadd5887d199240fe636f83d67","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67bac757887d1b2dfd1f38f035e13","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnu8l8_EJPkAAsqHVXP3lnpaxB7BTA7YHDmJEI-0snQXhHrG8ByN1z6SalhsT7NqUcbQWgGl4kAM8CTQcEkW39apki-1qd0qzJDGid67auV9_OeojYPlhOdio-16voo3ox1L0HVcBhhGODriZaDj1G44cxU1QpRWBEPo7tAmfHUCEHRW3ISWae4qtYWeNepbTDwohu8dlQLCixg1QCqH6CmtvI3jPSK3e89Rz8GK4AsBhCptCF0Uul4GYm4H4Gi4-sfopSr1Y4eNfTbIf6alsAbVOfyCXQ22u6Bi8FCcAuKaCzgjZDDv_ggjAInx_3Hfk0bQ_KWQ2cpvObXvnYEY_M-3tYcFZlhC03VNN9AiTfe6HOMEizyKa-t795nTmc5_6h1hsovctiDE-eyWAqC71s9kxWXErmOGIUUH2AmvvZP6g1w_lLlmPahsAIpa4dGDNuKt5DOHPbKojFnZPwDvBYC29Q1qZog_zTQfbGeIo7upk8rkKZQD0Ocjb-GAY1_isGr1HBrlOUlYFuPHIOhsD2AVJCO3OPtpTayUUwxIdYzZzcJXdjgsYTKgZpAxRhp5HsNbDTHxaSxaTUhSKG-P7aVKxiKYOEYUBGp-s-pf62zy9wyawmeNUsqR_g4C7ZVXkuUREWPErxlkK3Phwu-L0AQs89-clISmIrn4kqOuU3kv9dJBpoGhtkaMgf_fvxlSgSUtbOsoTHlaPb60y6VdJLmL0qxBDwIVAqpzPbFV8B7h6ut9TM3ejyVMZhs4md98NBrSdeuUdlwc4h5X7PWMZ3nttocBb4PpFuf6p8QgpOeSCjIgnbW1M-lYPL3NL8uWEq5Svy7jh-yh7E9f1gEiL04kSEyKqhQKAzQWXjzGBTJtFAVcXniGgAnXATKjdHstvTqj-Z-TtcW69PXKOFB8iNwjUG7cosIMC0ZAQdxmRhF2ljL7LTm_9XGZkqhrCJ8D7K3vU3lINlVrF5qWV4KNFRuidfbsEOj8ovgXLBq5qkgLboKqkpuiByJrJ43XIiuj0I9nvN1yf-pMK26BJXL_-kZJV-UgdzV543jlOFtaJOrLdhOxQqsEMFWn66O33_cYuuSGrPjBaNgVdjUupAvkVtPIMwmNWT0md9DznYs7KY1u57D47NrrAAsBjc_t6uC3OUuSZyLq2MrbcdRz0J1MI710l6WbgIUJuTvsap-YDOw09f0p8FfvQdmvv2IMVFbJJm5pumE81cq4X8t214guAzJIGW1XHA4fGzVgjSdMWzDB7rEoOH-TgJLtjcq21J70pp7Pr-2kInqbKDweE8vVW1joo39H-B6rJaDwzS2p_nEa5rLfeDTkzDZN7LbdAjFwfzsq6qr7hBJsltvBJom46_VYnkzRA-fhY39I124HjZfxXiLjxcQN-UEaRmCyEpWlDUbFQ-YBldZSg45VCVdim35tFN0DzfxHKghFP6zUxUrADT4W6vA4KPmk8tLtrLoc5sh52QXY5LoFUpf0aSpRRr-yExjKWigAIvNhY-Li5Dyz6o1T6_M-hrik4nPGh-xZ_oQRgPCgTyFW6tIQEurd60KfASoLUwGnP3VZCblHfN-zhC24dUYbYTNbquB3PHAo2p1vvUI4N4NGTM5YyStBRIzNS7-cD38rObAcFZT-mdhrNj2grK-nZL3uwyj990rDfC03xM1KiymvpYQ3r_wPkAg4-H74NxqsJjSOfMXIdQMz-y3WM8N7iUF7ZEZpVkIiRXxNoorxT5TpKvpzNCUJEMWO4HqDJ7QqsCDZwZdumDcOdzmpY98ttJ7Lu7yaIz6WLcrCtmkZaqhTxRF-7BCv80BAz_h7ai9vYhqPRyH2C7_DmZzNoiLEh5IDA1paQnu0NVuLXc_RyoIqlgpxzeGOxCH6TnL3tXLO_VkPrAE8XfHR5Q-5DkNecFAAIuYHkOYoUAf27ZVOVtSGxB2BAm4vYYKapLzBk96Cq0jMwOsAhRsB_ZxTGWKAiiz_p_cLcrxeujVATWqE5-oADFsIqpHPfXhGSJ2LWEQyncRmi-wLO2DrkUqBszmdHOH50vRMGReZISzlAoJfq43SDOgCLV2GtL1SSChdg4V66s6WfJGqkHjutY7kOg-Bn-dkNtoKbELNlE1pv-jO74lB1KeM3SJgUKPeldtARIeOd0Bd2iBNVp8pPD0xECjYtluqy6tyAKWZsKFqiZDk4PrI_HetDf84xlW5yl1e_OhnwzeAUj2-ioqb0HUpSO7c1wsGtFiyV-4lJZ0bbeud5icXylYwVeX5E72ExlpoqgZabA1KV-Sy2fcIDieMh9DEnDxvMRL1RMsiDs8_qdxi-qucRLwi6oF-g2EJBxVv4jctzik01CsubwWv3Gk4Asaq4bOOUEgIZnP4-Z3EuMsfLnu9mFY2qf127qgRO9nI0y63xXT6IBDSkAsCDIDdzhw5058kvnLzhI8jsxvRTEAmROWK5lwZsBOuzOpAAiPSkjVJWSlsmPaC5fDEMT2AbPQj3DkpiBS_9LOP2reDoj4cao7zEvPiTOLgB-MZhhp5XzfGVUnW7ckgq3ZmyWxW204E2oecO1daQDfhfZWdQyeRiCTcnnAl0-hJk9QjnAm192osR2ZmlzJjjYcCiFhqG3czWDj9L9OYaSES8Doas9XweVj6tHo7BEBoOo28N23ZMyo05WVvyfajTbjwEjwoN-vt0pUWnuQYfwDG8Oo0FH7Hh8rXApnD39TBFREtc3Ylb7yu24m00cdtw7Iv11olT552RoKwWr5VyhXTHXo7L9LUmPDH2yfXYwZRLny6dlmyuUDjNu6WF-YNSwMnTG_GXMfzSF2OGUeeDIx0pVnKYrm4uTpMMaM0MybADhqmcim_Z4Sy_AgoNKJJScDky8RyAWw5iVefk3HV77GNmY_RCj-8vM59TaOsUDo6UiSe_hMOYakDdHfm1VCs6rgHKfq0GBLFfPYBEr68_IvBJ00zZwVanxQ6yjPqXGooO3fump08tnP83UViQUQCde_Jfl2dJU4IVuYgK5v-mzYoy9z80Rz4VqpR_KrK4BAu-aAcmQxo9j50k-zojJtqP75tRiiVQJWqUaKdS18nyEk8pRcxbTdFTAZw02CFTl0EIMR6CVADc4NZa76adNKzLCxdN6RAuSpALJI-5tjNOxTQMoTH7aJYhrVdb5bb7ODMw4jzOn4TzOPkckx9FUCsWpQmcbgbnJWz5FRnZmPsOd7RDHFbKQzWiRBzC44KzkThtoyqtFPDjda3OPNmqnorgjNiVcKYsXFEtEW127EXfHVHbAh3kSZ75gWiouzumFEh4iu1MEOhlnl7OvJJn-3x2by1hpexR0TMfB6ULT-Mwfi3f9l15YcQpXUCuwI9FKMVFdpyAXeJ3sNJTGT8KZ8MW_ggqqQqmBv3tctOk5On3Hcu6_zhhJkUpR1ubeM3dOMc7eZxDzy3J_GNNgZqAAghGMTPzXPh0hCSh1E2FkJkFDQyLKFemYFGpKy2FL6LxQNIrCHdPr10Rcb0FqOuOvqjlNO3f2KKOamtj1xGxpfT5p-sEeN5S3Mb8J__vZAiBdItD3SidSyK83z1unpVuwxb4MwH0LSJbuVbz3XNpNo3m-z0Klc67I3myT5HZDQc_4BpLt8HCvrQLxDdSjRJbJU7FUL3n1TfSHHySInYa5fgeYjU5B41aBLKFazbeFmxrSnS6LvVSh8wcHs-qJ7VquLdqPqCpsuj-Pn8YXW7ujg4A1old2JXpaUzhIIg5xOAbQ_kYzdVbww2lUL3Ji6E3NV3W0F29nCXCqNPN1N7BAUCZstU5j9VLNti5-uq_6YM8rThRn6-yeoJ-q1lcy4BYCGdvnRi5HwXxFjIjT92pLDWiVZvnoN2HGCcadn8GoU2muVkCmvbUKYWBPN0lgt0VA3Fha4r39t0vO6ldoWoeOarx1FkVjgCoj6sjYlF9G9b_PS5_QRGx04x7AHPYt6cIA0lF1hwAEQwjY8gWtbCzZdbiM4DSGdwXPv8dXI3U5yTRxRev5MeNuhKmXTN9zYrIfeeYOeV35BkBXxoyjnTFGiwaf6-qFdNBgcxVGY3HI1M-7QYlnP0gcs6HnFzZkVbXw37sjPSiibG5pppbY9GDVAvC6LbqYNG9O0417jEj7_MIF22AVYd4FMZATR0RwfUqrDRaRCpSrhHsJ4KuVvvtos8v5R1KLffvUh7HPCzloSxrEgwGJENaVDwU81wbY5hMuNYu-gCHeb3xUbz-Oq-wloNwp9_-qclWuHgNdOap-AHB-tT7y4dsI5VVxQZfgzhG9D7hk5hag3Da7RF67hp4Cu3g9Oc0EswrKJjAhpUJRzddYeGLw6HIPVA_QIyzL3NlxePiAPXForJmQwfKeLsPwR5xQqxdtOr_l9sQgQbChHzqYY7iLpfJYTOx08zmpFlpiBCyPMJ6SeXlIxTJIh1xUl2TKR4SIp8sRR1xdpVumVHGzyAetpaXnwmypnDnR65OE9-7xn3rNtOFbkd49Aa7a-L5RxmpwYmSb3al1-qtq-Dg9Tfh8WbXNtnDV2TGHbY6CO4Eyfzhn0pCi-BiK19RLtQlCS12ifT2zyMDAwKUmvFNWSKUSk2iC_SrgvIzwA_R80DmHWxJPXh8smhoSKNHNsveAPaFfoyZhcNkVDUgvhUVB8J-vD8lDI49mwgVkl945RWHHH2Jld3njykpJugGAVEaqteHTCsOvRaxdtzIM1-rUHU__XBHeQ6MDRsFDjRHovi6GoLnyK-8AhtjtHQYISbddCApMhXI3_FWsBuZ1Y3F1JDblL1FA==","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Designing writer records**"},{"type":"summary_text","text":"**Designing InputRecord**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67bbc412887d186007a717c31a3c9","type":"function_call","status":"completed","arguments":"{\"i\":\"Creating delivery custody ledger\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs\",\"content\":\"//! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\\n\\nuse sha2::{Digest, Sha256};\\nuse spt_term::surface::SessionSurface;\\nuse std::collections::HashSet;\\nuse std::sync::{Arc, Mutex};\\n\\n// Digests, not retained payloads. Never evict evidence from a live hosted session:\\n// exhaustion disables origin grants with a named reason instead.\\nconst MAX_DELIVERY_DIGESTS: usize = 65_536;\\n\\n#[derive(Default)]\\npub(crate) struct DeliveryBytes {\\n    completed: Mutex<Completed>,\\n}\\n\\n#[derive(Default)]\\nstruct Completed {\\n    digests: HashSet<[u8; 32]>,\\n    exhausted: bool,\\n}\\n\\nimpl DeliveryBytes {\\n    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\\n        let digest: [u8; 32] = Sha256::digest(payload).into();\\n        self.completed\\n            .lock()\\n            .unwrap_or_else(|p| p.into_inner())\\n            .digests\\n            .contains(&digest)\\n    }\\n\\n    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\\n        self.completed\\n            .lock()\\n            .unwrap_or_else(|p| p.into_inner())\\n            .exhausted\\n            .then_some(\\\"delivery-evidence-capacity\\\")\\n    }\\n\\n    fn remember(&self, digest: [u8; 32]) {\\n        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\\n    }\\n\\n    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\\n        if completed.digests.contains(&digest) {\\n            return;\\n        }\\n        if completed.digests.len() >= limit {\\n            completed.exhausted = true;\\n        } else {\\n            completed.digests.insert(digest);\\n        }\\n    }\\n}\\n\\n/// One translation attempt; queued records keep its constant-size streaming state\\n/// alive until the lone writer has processed them, independently of logical Commit.\\n#[derive(Default)]\\npub(crate) struct DeliveryAttempt {\\n    text: Mutex<AttemptText>,\\n}\\n\\n#[derive(Default)]\\nstruct AttemptText {\\n    hash: Sha256,\\n    has_text: bool,\\n    failed: bool,\\n}\\n\\n#[derive(Clone, Copy)]\\npub(crate) enum DeliveryPart {\\n    Text { end: bool },\\n    Key,\\n}\\n\\nimpl DeliveryAttempt {\\n    fn failed(&self) {\\n        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\\n    }\\n\\n    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\\n        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\\n        if text.failed {\\n            return;\\n        }\\n        if let DeliveryPart::Text { end } = part {\\n            text.hash.update(bytes);\\n            text.has_text |= !bytes.is_empty();\\n            if end && text.has_text {\\n                // Publish each complete Text command's cumulative text, including\\n                // exact embedded newlines. Keys are source-tagged controls, never\\n                // guessed framing stripped from the reported payload.\\n                ledger.remember(text.hash.clone().finalize().into());\\n            }\\n        }\\n    }\\n}\\n\\npub(crate) struct InputRecord {\\n    bytes: Vec<u8>,\\n    origin: InputOrigin,\\n}\\n\\nenum InputOrigin {\\n    Controller,\\n    Probe,\\n    Delivery {\\n        attempt: Arc<DeliveryAttempt>,\\n        part: DeliveryPart,\\n    },\\n}\\n\\nimpl InputRecord {\\n    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\\n        Self { bytes, origin: InputOrigin::Controller }\\n    }\\n\\n    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\\n        Self { bytes, origin: InputOrigin::Probe }\\n    }\\n\\n    pub(crate) fn delivery(\\n        bytes: Vec<u8>,\\n        attempt: &Arc<DeliveryAttempt>,\\n        part: DeliveryPart,\\n    ) -> Self {\\n        Self {\\n            bytes,\\n            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\\n        }\\n    }\\n\\n    pub(crate) fn dropped(&self) {\\n        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\\n            attempt.failed();\\n        }\\n    }\\n\\n    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\\n    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\\n        // Never hold a custody lock across a potentially wedged physical write.\\n        // Ok proves write_all + flush, not harness interpretation. Err may follow\\n        // a partial write, whose byte count this API does not expose: do not guess.\\n        let success = surface.write_input(&self.bytes).is_ok();\\n        if let InputOrigin::Delivery { attempt, part } = &self.origin {\\n            if success {\\n                attempt.written(&self.bytes, *part, ledger);\\n            } else {\\n                attempt.failed();\\n            }\\n        }\\n        // A report caused by a separate Enter sees the preceding Text's published\\n        // evidence before Enter is written (one FIFO, one writer). A report caused\\n        // by Text itself can race between physical completion and this publication;\\n        // enqueued bytes cannot honestly close that narrower window.\\n    }\\n}\\n\\n#[cfg(test)]\\nmod tests {\\n    use super::*;\\n    use spt_term::surface::{SurfaceError, SurfaceSize};\\n\\n    struct Sink;\\n    impl SessionSurface for Sink {\\n        fn write_input(&self, _: &[u8]) -> Result<(), SurfaceError> { Ok(()) }\\n        fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\\n    }\\n\\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\\n    #[test]\\n    fn split_multiline_delivery_matches_before_commit_without_normalizing() {\\n        let ledger = DeliveryBytes::default();\\n        let attempt = Arc::new(DeliveryAttempt::default());\\n        let first = InputRecord::delivery(b\\\"<EVENT>\\\\n C:/a\\\".to_vec(), &attempt, DeliveryPart::Text { end: false });\\n        let last = InputRecord::delivery(b\\\"\\\\n</EVENT> \\\".to_vec(), &attempt, DeliveryPart::Text { end: true });\\n        let payload = b\\\"<EVENT>\\\\n C:/a\\\\n</EVENT> \\\";\\n        assert!(!ledger.matches(payload));\\n        first.write_to(&Sink, &ledger);\\n        assert!(!ledger.matches(payload));\\n        last.write_to(&Sink, &ledger);\\n        assert!(ledger.matches(payload));\\n        InputRecord::delivery(b\\\"\\\\r\\\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\\n        assert!(ledger.matches(payload));\\n        assert!(!ledger.matches(b\\\"<EVENT>\\\\n C:/b\\\\n</EVENT> \\\"));\\n        assert!(!ledger.matches(b\\\"<EVENT>\\\\n C:/a\\\\n</EVENT>\\\"));\\n        assert!(!ledger.matches(b\\\"<EVENT>\\\\r\\\\n C:/a\\\\r\\\\n</EVENT> \\\"));\\n        assert!(!ledger.matches(b\\\"\\\\r\\\"));\\n    }\\n\\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\\n    #[test]\\n    fn controller_and_probe_bytes_never_become_delivery_evidence() {\\n        let ledger = DeliveryBytes::default();\\n        InputRecord::controller(b\\\"human C:/private\\\".to_vec()).write_to(&Sink, &ledger);\\n        InputRecord::probe(b\\\"\\\\x1b[6n\\\".to_vec()).write_to(&Sink, &ledger);\\n        assert!(!ledger.matches(b\\\"human C:/private\\\"));\\n        assert!(!ledger.matches(b\\\"\\\\x1b[6n\\\"));\\n        assert!(!ledger.matches(b\\\"unknown human payload\\\"));\\n    }\\n\\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\\n    #[test]\\n    fn successful_text_commands_aggregate_without_key_bytes() {\\n        let ledger = DeliveryBytes::default();\\n        let attempt = Arc::new(DeliveryAttempt::default());\\n        InputRecord::delivery(b\\\"one\\\\n\\\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\\n        InputRecord::delivery(b\\\"\\\\x1b[A\\\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\\n        InputRecord::delivery(b\\\"two\\\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\\n        assert!(ledger.matches(b\\\"one\\\\ntwo\\\"));\\n        assert!(!ledger.matches(b\\\"one\\\\n\\\\x1b[Atwo\\\"));\\n        let next_attempt = Arc::new(DeliveryAttempt::default());\\n        InputRecord::delivery(b\\\"three\\\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\\n        assert!(ledger.matches(b\\\"three\\\"));\\n        assert!(!ledger.matches(b\\\"one\\\\ntwothree\\\"));\\n    }\\n\\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\\n    #[test]\\n    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\\n        let ledger = DeliveryBytes::default();\\n        ledger.remember_with_limit(Sha256::digest(b\\\"first\\\").into(), 1);\\n        ledger.remember_with_limit(Sha256::digest(b\\\"first\\\").into(), 1);\\n        assert_eq!(ledger.unavailable_reason(), None);\\n        ledger.remember_with_limit(Sha256::digest(b\\\"second\\\").into(), 1);\\n        assert!(ledger.matches(b\\\"first\\\"));\\n        assert!(!ledger.matches(b\\\"second\\\"));\\n        assert_eq!(ledger.unavailable_reason(), Some(\\\"delivery-evidence-capacity\\\"));\\n    }\\n}\\n\"}","call_id":"call_v7sIZB8QvfmVqXmA1KLHViex","internal_chat_message_metadata_passthrough":{"create_time":1789295531.032906,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"write","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":89721.26890000002,"ttft":1845.6493000000482,"completedAt":1789295620366,"contextSnapshot":{"promptTokens":42247,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"76598b45","parentId":"35fb1e6e","timestamp":"2026-09-13T10:33:40.418Z","message":{"role":"toolResult","toolCallId":"call_v7sIZB8QvfmVqXmA1KLHViex|fc_0b12df87254bb4e6016aa67bbc412887d186007a717c31a3c9","toolName":"write","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#4717]\nSuccessfully wrote 8430 bytes to .worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs"}],"details":{"resolvedPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\deliverybytes.rs"},"isError":false,"timestamp":1789295620416}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_H9Oo37FaDWxRRUxtqhL2imVZ|fc_0b12df87254bb4e6016aa67c09d7b087d1bd6f74d7b5a2d119","toolName":"read","startedAt":"2026-09-13T10:33:45.939Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-term/src/surface.rs:1-125"},"intent":"Reading surface error variants"},"id":"dfb2a8c1","parentId":"76598b45","timestamp":"2026-09-13T10:33:45.939Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_7hirf0ITXtSW1mCQcQfZo3WG|fc_0b12df87254bb4e6016aa67c09d7c087d1ba0f88b81c5c5b9e","toolName":"grep","startedAt":"2026-09-13T10:33:45.940Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon"},"intent":"Finding all input record consumers"},"id":"6867ed64","parentId":"dfb2a8c1","timestamp":"2026-09-13T10:33:45.940Z"}
{"type":"message","id":"5a2f698d","parentId":"6867ed64","timestamp":"2026-09-13T10:33:45.940Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Reading SurfaceError enum**"},{"type":"toolCall","id":"call_H9Oo37FaDWxRRUxtqhL2imVZ|fc_0b12df87254bb4e6016aa67c09d7b087d1bd6f74d7b5a2d119","name":"read","arguments":{"i":"Reading surface error variants","path":".worktrees/300-input-acceptance/crates/spt-term/src/surface.rs:1-125"},"intent":"Reading surface error variants"},{"type":"toolCall","id":"call_7hirf0ITXtSW1mCQcQfZo3WG|fc_0b12df87254bb4e6016aa67c09d7c087d1ba0f88b81c5c5b9e","name":"grep","arguments":{"i":"Finding all input record consumers","pattern":"InputRecord|input_writer\\(|enqueue_text_chunked\\(","path":".worktrees/300-input-acceptance/crates/spt-daemon","case":true,"gitignore":true,"skip":0},"intent":"Finding all input record consumers"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":3125,"output":139,"cacheRead":42112,"cacheWrite":0,"totalTokens":45376,"reasoningTokens":12,"cost":{"input":0.03125,"output":0.0069500000000000004,"cacheRead":0.042112,"cacheWrite":0,"total":0.080312}},"stopReason":"toolUse","timestamp":1789295620464,"responseId":"resp_0b12df87254bb4e6016aa67c04b19887d1a23d4414590e1d64","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c05ae7887d1a5384d25eaa7f1c9","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnwJ8NgmhW8tfBNOWRUXa1bk1GFqYB6g6gXMT3Q5TBomDdtAEAcdp-OJeSOAZfBH-DIrbPbrpBrDp3P6ahBqZOBXIZNeb9Ui2CtbaseNWdoTBVzgxxpWq5NbDg-CCzAY7mbvlHvQiCT1P6oN1roSu-1JW55hmHHDsOrPV5ADOuPIxR4L2BsPWcO-pKU9GpgfTXdyc6DxxAE5leNBTVPev6bbZnGHnDwRXXTpWu_ba0DgbUsU6fzs5QZ0Q8bhq3v7EVBDdfRHHvu3Ip0sgbTwZKQ07zrqcQzGqbpdcGOwXWDRRHnWBgMp68gik7ad0-Z0ygDigmaE9H_Y0OXa7jTr-NPR4hzQ6-sPg0JaXZbiYNyaT5UOMEHLizqQCf7Be9BjKOU9Dy01Pf2LGenyITH4Y5jzg0b9eT-SCCmYFwX7xvMj9bj34GjpQlDEQWREeUa4hnM-n0b4oig2n5B0O_GxTQfy1FC5cvujlSv7OA15JL9sWKVHNAAGAfYRed_VDih4fHbcZYnGUWWDZZZvmOM7ZHtpqSrTOOcA3--h5FDqPwYjHLUbIcB9HBixgpAOEdlbbtZAhp4o6N_jaUIO6HKJ7YesKBorOS6ZU--zKCT9C-ayBbsC3CvmGjsd9Gt4f5wzFqpHEYFoTvXWcsElwY-NFKuSlVvgPjTUtWoXZl1__HrQkobnJKcZz-x2BbReKY0rkvT8qlPq2yROFYZ9iT86O5OoMtzef2mZuhyZ_U1ZXONa7STZs2hKWp7Kq1de5h9vfZT2GozDC38yzRwgynUDhuYjNflE798ufdrSDJhjS3tWsx63qhwPeXIxJuvENi86tyfbFWK_HdMRdYdIfOrVe3bcwHVTgx-cDi8Y27SNJrf9wWnyKOIpc3YBhg_0nHeiJZRCJ-hzS7yuksGaO9vZ_WIZ3s-MfRQb_fyNhLtljkejve9nKs92TJwgiZUhWojhV6lBYvsFD6sHdXDY3LXhFRXNHKyZhEB_IUw-y6g3QusYo6lqUo0HUTJrc9H8nc8yT6CIiF32JUlWLFGh7N7CKqkaTvGX0Nu0LlMPX4z8NBNQ_WupjTIdowacr2xLSwc04YhmtOdCdJ_sDbgrhpc_2lW37cQ2Eb3j0kVp1V4mZnvtM5Q0k-lFFjEn6M8Ep0XxgXrtwoz-6LvzG2wvdjjR84h-1cdP5b_8ifGDfB9FX-v0k7D2Etj54QcCI17Uhn-G9YRKMwlxQumJLscCihxY9An9X-X4p5Xg5NmNpBfOfDvMx6Am563hGn26u24n-GkjMXhr9JsqwnEmxB0h69QbX8iOnRP9WA08FFuYQu21TjHZ2kWlxIaCt_pBJ3EKZpU2ssQM","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Reading SurfaceError enum**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67c09d7b087d1bd6f74d7b5a2d119","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading surface error variants\",\"path\":\".worktrees/300-input-acceptance/crates/spt-term/src/surface.rs:1-125\"}","call_id":"call_H9Oo37FaDWxRRUxtqhL2imVZ","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67c09d7c087d1ba0f88b81c5c5b9e","type":"function_call","status":"completed","arguments":"{\"i\":\"Finding all input record consumers\",\"pattern\":\"InputRecord|input_writer\\\\(|enqueue_text_chunked\\\\(\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon\",\"case\":true,\"gitignore\":true,\"skip\":0}","call_id":"call_7hirf0ITXtSW1mCQcQfZo3WG","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"grep","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":5472.185100000002,"ttft":1250.4135999999708,"completedAt":1789295625937,"contextSnapshot":{"promptTokens":45237,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"18ec3d1d","parentId":"5a2f698d","timestamp":"2026-09-13T10:33:45.955Z","message":{"role":"toolResult","toolCallId":"call_H9Oo37FaDWxRRUxtqhL2imVZ|fc_0b12df87254bb4e6016aa67c09d7b087d1bd6f74d7b5a2d119","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-term/src/surface.rs#E316]\n1://! The OS-neutral session-surface contract.\n2://!\n3://! A [`SessionSurface`] is \"anything you can write input to and read output\n4://! from\" — the abstraction every hosted agent session is driven through. The\n5://! native PTY backend ([`crate::pty::PtySession`]) is the M3a implementation;\n6://! M4's network-attached surface and the GUI text pane slot in behind the same\n7://! trait later.\n8://!\n9://! **OS stream-contract neutrality (Spike #4 / #5, binding):** the surface is\n10://! modeled as a byte stream with explicit, OS-independent attach/replay\n11://! semantics. The trait deliberately exposes *write input* + *resize* only and\n12://! says nothing about whether the underlying output is a raw ordered pipe\n13://! (`forkpty`) or a repaint-on-resize screen buffer (ConPTY) — output streaming\n14://! is a separate, equally OS-neutral concern (A4, [`crate::pty::PtySession`]'s\n15://! reader). No backend's stream semantics leak through this contract.\n16:\n17:use portable_pty::PtySize;\n18:\n19:/// Window geometry for a surface — OS-neutral (`rows × cols` plus optional pixel\n20:/// hints some backends fill and others ignore). Mirrors `portable_pty::PtySize`\n21:/// without leaking the dependency into the trait's public shape.\n22:#[derive(Debug, Clone, Copy, PartialEq, Eq)]\n23:pub struct SurfaceSize {\n24:    /// Number of text rows.\n25:    pub rows: u16,\n26:    /// Number of text columns.\n27:    pub cols: u16,\n28:    /// Cell width in pixels (0 = unset; many systems ignore this).\n29:    pub pixel_width: u16,\n30:    /// Cell height in pixels (0 = unset; many systems ignore this).\n31:    pub pixel_height: u16,\n32:}\n33:\n34:impl SurfaceSize {\n35:    /// A `rows × cols` geometry with pixel hints left unset.\n36:    pub const fn new(rows: u16, cols: u16) -> Self {\n37:        Self {\n38:            rows,\n39:            cols,\n40:            pixel_width: 0,\n41:            pixel_height: 0,\n42:        }\n43:    }\n44:}\n45:\n46:impl Default for SurfaceSize {\n47:    /// The conventional 24×80 terminal.\n48:    fn default() -> Self {\n49:        Self::new(24, 80)\n50:    }\n51:}\n52:\n53:impl From<SurfaceSize> for PtySize {\n54:    fn from(s: SurfaceSize) -> Self {\n55:        PtySize {\n56:            rows: s.rows,\n57:            cols: s.cols,\n58:            pixel_width: s.pixel_width,\n59:            pixel_height: s.pixel_height,\n60:        }\n61:    }\n62:}\n63:\n64:/// A session-surface failure. Carries an operator-facing message; never panics.\n65:#[derive(Debug)]\n66:pub enum SurfaceError {\n67:    /// The OS refused to allocate a PTY pair.\n68:    OpenPty(String),\n69:    /// The OS refused to spawn the child under the PTY.\n70:    Spawn(String),\n71:    /// An I/O operation on the surface failed (read/write/resize).\n72:    Io(std::io::Error),\n73:    /// The single writer handle was already taken (PTY writers are once-only).\n74:    WriterTaken,\n75:    /// The single reader handle was already taken.\n76:    ReaderTaken,\n77:}\n78:\n79:impl std::fmt::Display for SurfaceError {\n80:    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n81:        match self {\n82:            SurfaceError::OpenPty(e) => write!(f, \"failed to open a pty: {e}\"),\n83:            SurfaceError::Spawn(e) => write!(f, \"failed to spawn a child under the pty: {e}\"),\n84:            SurfaceError::Io(e) => write!(f, \"surface i/o failed: {e}\"),\n85:            SurfaceError::WriterTaken => write!(f, \"the surface writer was already taken\"),\n86:            SurfaceError::ReaderTaken => write!(f, \"the surface reader was already taken\"),\n87:        }\n88:    }\n89:}\n90:\n91:impl std::error::Error for SurfaceError {}\n92:\n93:/// Anything a hosted session can be driven through: input goes in, output comes\n94:/// out, geometry can change. See the module docs for the OS-neutrality contract.\n95:///\n96:/// `Send + Sync` so the M3b broker can host the surface behind a shared handle\n97:/// and drive `write_input` / `resize` from its IPC thread while a separate\n98:/// reader thread drains output.\n99://\n100:// [impl->REQ-TERM-1]\n101:pub trait SessionSurface: Send + Sync {\n102:    /// Write raw bytes to the child's input. Escape sequences pass through\n103:    /// verbatim (the cooked/raw `send_line` / `send_keys` distinction lands on\n104:    /// the concrete surface in A3). Flushed on return.\n105:    fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError>;\n106:\n107:    /// Inform the surface (and thus the child) of a new window geometry. On a\n108:    /// real PTY this updates the kernel winsize and raises `SIGWINCH`.\n109:    fn resize(&self, size: SurfaceSize) -> Result<(), SurfaceError>;\n110:\n111:    /// **send-keys** — raw keystroke injection. Bytes go to the child verbatim,\n112:    /// including control bytes and escape sequences (e.g. `Ctrl-C` = `0x03`, an\n113:    /// arrow key = `ESC [ C`). A semantic alias of [`SessionSurface::write_input`]\n114:    /// for the \"type these exact keys\" intent. Ordering is preserved: each call\n115:    /// is one serialized write.\n116:    //\n117:    // [impl->REQ-TERM-2]\n118:    fn send_keys(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n119:        self.write_input(bytes)\n120:    }\n121:\n122:    /// **send-line** — cooked line submission. Appends a carriage return (`\\r`,\n123:    /// the byte a real Enter keypress emits; the slave line discipline maps it\n124:    /// to newline where applicable) and writes the whole line in one serialized\n125:    /// flush, so a concurrent injector can never split the line.\n126:    //\n127:    // [impl->REQ-TERM-2]\n128:    fn send_line(&self, line: &str) -> Result<(), SurfaceError> {\n…\n133:    }\n134:}\n\n[Showing lines 1-128 of 134. Use :129 to continue]"}],"details":{"truncation":{"content":"//! The OS-neutral session-surface contract.\r\n//!\r\n//! A [`SessionSurface`] is \"anything you can write input to and read output\r\n//! from\" — the abstraction every hosted agent session is driven through. The\r\n//! native PTY backend ([`crate::pty::PtySession`]) is the M3a implementation;\r\n//! M4's network-attached surface and the GUI text pane slot in behind the same\r\n//! trait later.\r\n//!\r\n//! **OS stream-contract neutrality (Spike #4 / #5, binding):** the surface is\r\n//! modeled as a byte stream with explicit, OS-independent attach/replay\r\n//! semantics. The trait deliberately exposes *write input* + *resize* only and\r\n//! says nothing about whether the underlying output is a raw ordered pipe\r\n//! (`forkpty`) or a repaint-on-resize screen buffer (ConPTY) — output streaming\r\n//! is a separate, equally OS-neutral concern (A4, [`crate::pty::PtySession`]'s\r\n//! reader). No backend's stream semantics leak through this contract.\r\n\r\nuse portable_pty::PtySize;\r\n\r\n/// Window geometry for a surface — OS-neutral (`rows × cols` plus optional pixel\r\n/// hints some backends fill and others ignore). Mirrors `portable_pty::PtySize`\r\n/// without leaking the dependency into the trait's public shape.\r\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\r\npub struct SurfaceSize {\r\n    /// Number of text rows.\r\n    pub rows: u16,\r\n    /// Number of text columns.\r\n    pub cols: u16,\r\n    /// Cell width in pixels (0 = unset; many systems ignore this).\r\n    pub pixel_width: u16,\r\n    /// Cell height in pixels (0 = unset; many systems ignore this).\r\n    pub pixel_height: u16,\r\n}\r\n\r\nimpl SurfaceSize {\r\n    /// A `rows × cols` geometry with pixel hints left unset.\r\n    pub const fn new(rows: u16, cols: u16) -> Self {\r\n        Self {\r\n            rows,\r\n            cols,\r\n            pixel_width: 0,\r\n            pixel_height: 0,\r\n        }\r\n    }\r\n}\r\n\r\nimpl Default for SurfaceSize {\r\n    /// The conventional 24×80 terminal.\r\n    fn default() -> Self {\r\n        Self::new(24, 80)\r\n    }\r\n}\r\n\r\nimpl From<SurfaceSize> for PtySize {\r\n    fn from(s: SurfaceSize) -> Self {\r\n        PtySize {\r\n            rows: s.rows,\r\n            cols: s.cols,\r\n            pixel_width: s.pixel_width,\r\n            pixel_height: s.pixel_height,\r\n        }\r\n    }\r\n}\r\n\r\n/// A session-surface failure. Carries an operator-facing message; never panics.\r\n#[derive(Debug)]\r\npub enum SurfaceError {\r\n    /// The OS refused to allocate a PTY pair.\r\n    OpenPty(String),\r\n    /// The OS refused to spawn the child under the PTY.\r\n    Spawn(String),\r\n    /// An I/O operation on the surface failed (read/write/resize).\r\n    Io(std::io::Error),\r\n    /// The single writer handle was already taken (PTY writers are once-only).\r\n    WriterTaken,\r\n    /// The single reader handle was already taken.\r\n    ReaderTaken,\r\n}\r\n\r\nimpl std::fmt::Display for SurfaceError {\r\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\r\n        match self {\r\n            SurfaceError::OpenPty(e) => write!(f, \"failed to open a pty: {e}\"),\r\n            SurfaceError::Spawn(e) => write!(f, \"failed to spawn a child under the pty: {e}\"),\r\n            SurfaceError::Io(e) => write!(f, \"surface i/o failed: {e}\"),\r\n            SurfaceError::WriterTaken => write!(f, \"the surface writer was already taken\"),\r\n            SurfaceError::ReaderTaken => write!(f, \"the surface reader was already taken\"),\r\n        }\r\n    }\r\n}\r\n\r\nimpl std::error::Error for SurfaceError {}\r\n\r\n/// Anything a hosted session can be driven through: input goes in, output comes\r\n/// out, geometry can change. See the module docs for the OS-neutrality contract.\r\n///\r\n/// `Send + Sync` so the M3b broker can host the surface behind a shared handle\r\n/// and drive `write_input` / `resize` from its IPC thread while a separate\r\n/// reader thread drains output.\r\n//\r\n// [impl->REQ-TERM-1]\r\npub trait SessionSurface: Send + Sync {\r\n    /// Write raw bytes to the child's input. Escape sequences pass through\r\n    /// verbatim (the cooked/raw `send_line` / `send_keys` distinction lands on\r\n    /// the concrete surface in A3). Flushed on return.\r\n    fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError>;\r\n\r\n    /// Inform the surface (and thus the child) of a new window geometry. On a\r\n    /// real PTY this updates the kernel winsize and raises `SIGWINCH`.\r\n    fn resize(&self, size: SurfaceSize) -> Result<(), SurfaceError>;\r\n\r\n    /// **send-keys** — raw keystroke injection. Bytes go to the child verbatim,\r\n    /// including control bytes and escape sequences (e.g. `Ctrl-C` = `0x03`, an\r\n    /// arrow key = `ESC [ C`). A semantic alias of [`SessionSurface::write_input`]\r\n    /// for the \"type these exact keys\" intent. Ordering is preserved: each call\r\n    /// is one serialized write.\r\n    //\r\n    // [impl->REQ-TERM-2]\r\n    fn send_keys(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\r\n        self.write_input(bytes)\r\n    }\r\n\r\n    /// **send-line** — cooked line submission. Appends a carriage return (`\\r`,\r\n    /// the byte a real Enter keypress emits; the slave line discipline maps it\r\n    /// to newline where applicable) and writes the whole line in one serialized\r\n    /// flush, so a concurrent injector can never split the line.\r\n    //\r\n    // [impl->REQ-TERM-2]\r\n    fn send_line(&self, line: &str) -> Result<(), SurfaceError> {\r","truncated":true,"truncatedBy":"lines","totalLines":134,"totalBytes":5313,"outputLines":128,"outputBytes":5313,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":134,"displayContent":{"text":"//! The OS-neutral session-surface contract.\r\n//!\r\n//! A [`SessionSurface`] is \"anything you can write input to and read output\r\n//! from\" — the abstraction every hosted agent session is driven through. The\r\n//! native PTY backend ([`crate::pty::PtySession`]) is the M3a implementation;\r\n//! M4's network-attached surface and the GUI text pane slot in behind the same\r\n//! trait later.\r\n//!\r\n//! **OS stream-contract neutrality (Spike #4 / #5, binding):** the surface is\r\n//! modeled as a byte stream with explicit, OS-independent attach/replay\r\n//! semantics. The trait deliberately exposes *write input* + *resize* only and\r\n//! says nothing about whether the underlying output is a raw ordered pipe\r\n//! (`forkpty`) or a repaint-on-resize screen buffer (ConPTY) — output streaming\r\n//! is a separate, equally OS-neutral concern (A4, [`crate::pty::PtySession`]'s\r\n//! reader). No backend's stream semantics leak through this contract.\r\n\r\nuse portable_pty::PtySize;\r\n\r\n/// Window geometry for a surface — OS-neutral (`rows × cols` plus optional pixel\r\n/// hints some backends fill and others ignore). Mirrors `portable_pty::PtySize`\r\n/// without leaking the dependency into the trait's public shape.\r\n#[derive(Debug, Clone, Copy, PartialEq, Eq)]\r\npub struct SurfaceSize {\r\n    /// Number of text rows.\r\n    pub rows: u16,\r\n    /// Number of text columns.\r\n    pub cols: u16,\r\n    /// Cell width in pixels (0 = unset; many systems ignore this).\r\n    pub pixel_width: u16,\r\n    /// Cell height in pixels (0 = unset; many systems ignore this).\r\n    pub pixel_height: u16,\r\n}\r\n\r\nimpl SurfaceSize {\r\n    /// A `rows × cols` geometry with pixel hints left unset.\r\n    pub const fn new(rows: u16, cols: u16) -> Self {\r\n        Self {\r\n            rows,\r\n            cols,\r\n            pixel_width: 0,\r\n            pixel_height: 0,\r\n        }\r\n    }\r\n}\r\n\r\nimpl Default for SurfaceSize {\r\n    /// The conventional 24×80 terminal.\r\n    fn default() -> Self {\r\n        Self::new(24, 80)\r\n    }\r\n}\r\n\r\nimpl From<SurfaceSize> for PtySize {\r\n    fn from(s: SurfaceSize) -> Self {\r\n        PtySize {\r\n            rows: s.rows,\r\n            cols: s.cols,\r\n            pixel_width: s.pixel_width,\r\n            pixel_height: s.pixel_height,\r\n        }\r\n    }\r\n}\r\n\r\n/// A session-surface failure. Carries an operator-facing message; never panics.\r\n#[derive(Debug)]\r\npub enum SurfaceError {\r\n    /// The OS refused to allocate a PTY pair.\r\n    OpenPty(String),\r\n    /// The OS refused to spawn the child under the PTY.\r\n    Spawn(String),\r\n    /// An I/O operation on the surface failed (read/write/resize).\r\n    Io(std::io::Error),\r\n    /// The single writer handle was already taken (PTY writers are once-only).\r\n    WriterTaken,\r\n    /// The single reader handle was already taken.\r\n    ReaderTaken,\r\n}\r\n\r\nimpl std::fmt::Display for SurfaceError {\r\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\r\n        match self {\r\n            SurfaceError::OpenPty(e) => write!(f, \"failed to open a pty: {e}\"),\r\n            SurfaceError::Spawn(e) => write!(f, \"failed to spawn a child under the pty: {e}\"),\r\n            SurfaceError::Io(e) => write!(f, \"surface i/o failed: {e}\"),\r\n            SurfaceError::WriterTaken => write!(f, \"the surface writer was already taken\"),\r\n            SurfaceError::ReaderTaken => write!(f, \"the surface reader was already taken\"),\r\n        }\r\n    }\r\n}\r\n\r\nimpl std::error::Error for SurfaceError {}\r\n\r\n/// Anything a hosted session can be driven through: input goes in, output comes\r\n/// out, geometry can change. See the module docs for the OS-neutrality contract.\r\n///\r\n/// `Send + Sync` so the M3b broker can host the surface behind a shared handle\r\n/// and drive `write_input` / `resize` from its IPC thread while a separate\r\n/// reader thread drains output.\r\n//\r\n// [impl->REQ-TERM-1]\r\npub trait SessionSurface: Send + Sync {\r\n    /// Write raw bytes to the child's input. Escape sequences pass through\r\n    /// verbatim (the cooked/raw `send_line` / `send_keys` distinction lands on\r\n    /// the concrete surface in A3). Flushed on return.\r\n    fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError>;\r\n\r\n    /// Inform the surface (and thus the child) of a new window geometry. On a\r\n    /// real PTY this updates the kernel winsize and raises `SIGWINCH`.\r\n    fn resize(&self, size: SurfaceSize) -> Result<(), SurfaceError>;\r\n\r\n    /// **send-keys** — raw keystroke injection. Bytes go to the child verbatim,\r\n    /// including control bytes and escape sequences (e.g. `Ctrl-C` = `0x03`, an\r\n    /// arrow key = `ESC [ C`). A semantic alias of [`SessionSurface::write_input`]\r\n    /// for the \"type these exact keys\" intent. Ordering is preserved: each call\r\n    /// is one serialized write.\r\n    //\r\n    // [impl->REQ-TERM-2]\r\n    fn send_keys(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\r\n        self.write_input(bytes)\r\n    }\r\n\r\n    /// **send-line** — cooked line submission. Appends a carriage return (`\\r`,\r\n    /// the byte a real Enter keypress emits; the slave line discipline maps it\r\n    /// to newline where applicable) and writes the whole line in one serialized\r\n    /// flush, so a concurrent injector can never split the line.\r\n    //\r\n    // [impl->REQ-TERM-2]\r\n    fn send_line(&self, line: &str) -> Result<(), SurfaceError> {\r\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,84,85,86,87,88,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,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,null,133,134]},"fileSize":5490,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-term\\src\\surface.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":134,"totalBytes":5313,"outputLines":128,"outputBytes":5313,"shownRange":{"start":1,"end":128},"nextOffset":129}}},"isError":false,"timestamp":1789295625954}}
{"type":"message","id":"9c0edf94","parentId":"18ec3d1d","timestamp":"2026-09-13T10:33:47.913Z","message":{"role":"toolResult","toolCallId":"call_7hirf0ITXtSW1mCQcQfZo3WG|fc_0b12df87254bb4e6016aa67c09d7c087d1ba0f88b81c5c5b9e","toolName":"grep","content":[{"type":"text","text":"# .worktrees/300-input-acceptance/crates/spt-daemon/src/\n## broker.rs#3A1D\n 4166:/// bytes to write (v0.13.0 P0, REQ-HAZARD-PTY-INPUT-WRITER-WEDGE).\n*4167:type InputRecord = Vec<u8>;\n 4168:\n 4169:/// The per-session PTY input FIFO depth (records). Sized for a generous paste —\n 4170:/// a wedged harness fills this and then DROPS, never blocking the dispatch\n...\n 4201:    /// queue (a genuinely wedged harness) DROPS, it never blocks.\n*4202:    tx: SyncSender<InputRecord>,\n 4203:    /// True while the FIFO is saturated and input is being dropped; cleared on\n 4204:    /// the next accepted enqueue (heal-on-resume). Mirrored to the perch's\n 4205:    /// `input_backpressure` so the operator sees the drop.\n...\n 4218:    fn spawn(session: Arc<PtySession>, endpoint: String) -> Arc<InputWriter> {\n*4219:        let (tx, rx) = sync_channel::<InputRecord>(input_queue_depth());\n*4220:        let writer = thread::spawn(move || input_writer(session, rx));\n 4221:        Arc::new(InputWriter {\n 4222:            tx,\n 4223:            backpressure: AtomicBool::new(false),\n...\n 4234:    // [impl->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\n*4235:    fn enqueue(&self, bytes: InputRecord) -> bool {\n 4236:        match self.tx.try_send(bytes) {\n 4237:            Ok(()) => {\n 4238:                // Heal: input is flowing again — clear a prior backpressure stamp.\n...\n 4273:/// when the last `tx` clone drops at session teardown.\n*4274:fn input_writer(session: Arc<PtySession>, rx: Receiver<InputRecord>) {\n 4275:    while let Ok(bytes) = rx.recv() {\n 4276:        let _ = session.write_input(&bytes);\n 4277:    }\n...\n 4842:// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n*4843:fn enqueue_text_chunked(input: &InputWriter, bytes: Vec<u8>) {\n 4844:    chunk_text(&bytes, inject_text_chunk(), |part| {\n 4845:        input.enqueue(part.to_vec());\n 4846:    });\n...\n 4915:                sent_text.extend_from_slice(&bytes);\n*4916:                enqueue_text_chunked(input, bytes);\n 4917:            }\n 4918:            Ok(KeyCmd::Delay { delay_ms }) => {\n 4919:                let want = Duration::from_millis(delay_ms);\n...\n 11017:    /// the ORDER test; here the TEST is the consumer, draining `rx` deterministically.\n*11018:    fn test_input_writer(depth: usize) -> (InputWriter, Receiver<InputRecord>) {\n*11019:        let (tx, rx) = sync_channel::<InputRecord>(depth);\n 11020:        let w = InputWriter {\n 11021:            tx,\n 11022:            backpressure: AtomicBool::new(false),\n...\n 11054:        // Generous depth so nothing drops — this test is about ORDER, not the bound.\n*11055:        let (w, rx) = test_input_writer(256);\n 11056:        let written = Arc::new(Mutex::new(Vec::<Vec<u8>>::new()));\n 11057:        let surface = RecordingSurface(Arc::clone(&written));\n 11058:\n...\n 11104:        // Consumer is the test; it does NOT drain until we say so → the queue fills.\n*11105:        let (w, rx) = test_input_writer(DEPTH);\n 11106:\n 11107:        // The first DEPTH enqueues fit (accepted, no backpressure yet).\n 11108:        for i in 0..DEPTH {\n...\n 12126:        let journal = EffectJournal::open(dir.path().join(\"effects.log\")).unwrap();\n*12127:        let (w, rx) = test_input_writer(16);\n 12128:        let key = EffectKey {\n 12129:            class: 1,\n 12130:            minter: Minter::Rc,\n## deliverybytes.rs#4717\n 100:\n*101:pub(crate) struct InputRecord {\n 102:    bytes: Vec<u8>,\n 103:    origin: InputOrigin,\n 104:}\n...\n 114:\n*115:impl InputRecord {\n 116:    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n 117:        Self { bytes, origin: InputOrigin::Controller }\n 118:    }\n...\n 176:        let attempt = Arc::new(DeliveryAttempt::default());\n*177:        let first = InputRecord::delivery(b\"<EVENT>\\n C:/a\".to_vec(), &attempt, DeliveryPart::Text { end: false });\n*178:        let last = InputRecord::delivery(b\"\\n</EVENT> \".to_vec(), &attempt, DeliveryPart::Text { end: true });\n 179:        let payload = b\"<EVENT>\\n C:/a\\n</EVENT> \";\n 180:        assert!(!ledger.matches(payload));\n 181:        first.write_to(&Sink, &ledger);\n...\n 184:        assert!(ledger.matches(payload));\n*185:        InputRecord::delivery(b\"\\r\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n 186:        assert!(ledger.matches(payload));\n 187:        assert!(!ledger.matches(b\"<EVENT>\\n C:/b\\n</EVENT> \"));\n 188:        assert!(!ledger.matches(b\"<EVENT>\\n C:/a\\n</EVENT>\"));\n...\n 196:        let ledger = DeliveryBytes::default();\n*197:        InputRecord::controller(b\"human C:/private\".to_vec()).write_to(&Sink, &ledger);\n*198:        InputRecord::probe(b\"\\x1b[6n\".to_vec()).write_to(&Sink, &ledger);\n 199:        assert!(!ledger.matches(b\"human C:/private\"));\n 200:        assert!(!ledger.matches(b\"\\x1b[6n\"));\n 201:        assert!(!ledger.matches(b\"unknown human payload\"));\n...\n 208:        let attempt = Arc::new(DeliveryAttempt::default());\n*209:        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n*210:        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n*211:        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n 212:        assert!(ledger.matches(b\"one\\ntwo\"));\n 213:        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n 214:        let next_attempt = Arc::new(DeliveryAttempt::default());\n*215:        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n 216:        assert!(ledger.matches(b\"three\"));\n 217:        assert!(!ledger.matches(b\"one\\ntwothree\"));\n 218:    }"}],"details":{"scopePath":".worktrees/300-input-acceptance/crates/spt-daemon","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":24,"fileCount":2,"files":[".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs",".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs"],"fileMatches":[{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs","count":13},{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs","count":11}],"truncated":false,"displayContent":"# .worktrees/300-input-acceptance/crates/spt-daemon/src/\n## broker.rs#3A1D\n  4166│/// bytes to write (v0.13.0 P0, REQ-HAZARD-PTY-INPUT-WRITER-WEDGE).\n *4167│type InputRecord = Vec<u8>;\n  4168│\n  4169│/// The per-session PTY input FIFO depth (records). Sized for a generous paste —\n  4170│/// a wedged harness fills this and then DROPS, never blocking the dispatch\n      │...\n  4201│    /// queue (a genuinely wedged harness) DROPS, it never blocks.\n *4202│    tx: SyncSender<InputRecord>,\n  4203│    /// True while the FIFO is saturated and input is being dropped; cleared on\n  4204│    /// the next accepted enqueue (heal-on-resume). Mirrored to the perch's\n  4205│    /// `input_backpressure` so the operator sees the drop.\n      │...\n  4218│    fn spawn(session: Arc<PtySession>, endpoint: String) -> Arc<InputWriter> {\n *4219│        let (tx, rx) = sync_channel::<InputRecord>(input_queue_depth());\n *4220│        let writer = thread::spawn(move || input_writer(session, rx));\n  4221│        Arc::new(InputWriter {\n  4222│            tx,\n  4223│            backpressure: AtomicBool::new(false),\n      │...\n  4234│    // [impl->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\n *4235│    fn enqueue(&self, bytes: InputRecord) -> bool {\n  4236│        match self.tx.try_send(bytes) {\n  4237│            Ok(()) => {\n  4238│                // Heal: input is flowing again — clear a prior backpressure stamp.\n      │...\n  4273│/// when the last `tx` clone drops at session teardown.\n *4274│fn input_writer(session: Arc<PtySession>, rx: Receiver<InputRecord>) {\n  4275│    while let Ok(bytes) = rx.recv() {\n  4276│        let _ = session.write_input(&bytes);\n  4277│    }\n      │...\n  4842│// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n *4843│fn enqueue_text_chunked(input: &InputWriter, bytes: Vec<u8>) {\n  4844│    chunk_text(&bytes, inject_text_chunk(), |part| {\n  4845│        input.enqueue(part.to_vec());\n  4846│    });\n      │...\n  4915│                sent_text.extend_from_slice(&bytes);\n *4916│                enqueue_text_chunked(input, bytes);\n  4917│            }\n  4918│            Ok(KeyCmd::Delay { delay_ms }) => {\n  4919│                let want = Duration::from_millis(delay_ms);\n      │...\n 11017│    /// the ORDER test; here the TEST is the consumer, draining `rx` deterministically.\n*11018│    fn test_input_writer(depth: usize) -> (InputWriter, Receiver<InputRecord>) {\n*11019│        let (tx, rx) = sync_channel::<InputRecord>(depth);\n 11020│        let w = InputWriter {\n 11021│            tx,\n 11022│            backpressure: AtomicBool::new(false),\n      │...\n 11054│        // Generous depth so nothing drops — this test is about ORDER, not the bound.\n*11055│        let (w, rx) = test_input_writer(256);\n 11056│        let written = Arc::new(Mutex::new(Vec::<Vec<u8>>::new()));\n 11057│        let surface = RecordingSurface(Arc::clone(&written));\n 11058│\n      │...\n 11104│        // Consumer is the test; it does NOT drain until we say so → the queue fills.\n*11105│        let (w, rx) = test_input_writer(DEPTH);\n 11106│\n 11107│        // The first DEPTH enqueues fit (accepted, no backpressure yet).\n 11108│        for i in 0..DEPTH {\n      │...\n 12126│        let journal = EffectJournal::open(dir.path().join(\"effects.log\")).unwrap();\n*12127│        let (w, rx) = test_input_writer(16);\n 12128│        let key = EffectKey {\n 12129│            class: 1,\n 12130│            minter: Minter::Rc,\n## deliverybytes.rs#4717\n 100│\n*101│pub(crate) struct InputRecord {\n 102│    bytes: Vec<u8>,\n 103│    origin: InputOrigin,\n 104│}\n    │...\n 114│\n*115│impl InputRecord {\n 116│    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n 117│        Self { bytes, origin: InputOrigin::Controller }\n 118│    }\n    │...\n 176│        let attempt = Arc::new(DeliveryAttempt::default());\n*177│        let first = InputRecord::delivery(b\"<EVENT>\\n C:/a\".to_vec(), &attempt, DeliveryPart::Text { end: false });\n*178│        let last = InputRecord::delivery(b\"\\n</EVENT> \".to_vec(), &attempt, DeliveryPart::Text { end: true });\n 179│        let payload = b\"<EVENT>\\n C:/a\\n</EVENT> \";\n 180│        assert!(!ledger.matches(payload));\n 181│        first.write_to(&Sink, &ledger);\n    │...\n 184│        assert!(ledger.matches(payload));\n*185│        InputRecord::delivery(b\"\\r\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n 186│        assert!(ledger.matches(payload));\n 187│        assert!(!ledger.matches(b\"<EVENT>\\n C:/b\\n</EVENT> \"));\n 188│        assert!(!ledger.matches(b\"<EVENT>\\n C:/a\\n</EVENT>\"));\n    │...\n 196│        let ledger = DeliveryBytes::default();\n*197│        InputRecord::controller(b\"human C:/private\".to_vec()).write_to(&Sink, &ledger);\n*198│        InputRecord::probe(b\"\\x1b[6n\".to_vec()).write_to(&Sink, &ledger);\n 199│        assert!(!ledger.matches(b\"human C:/private\"));\n 200│        assert!(!ledger.matches(b\"\\x1b[6n\"));\n 201│        assert!(!ledger.matches(b\"unknown human payload\"));\n    │...\n 208│        let attempt = Arc::new(DeliveryAttempt::default());\n*209│        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n*210│        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n*211│        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n 212│        assert!(ledger.matches(b\"one\\ntwo\"));\n 213│        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n 214│        let next_attempt = Arc::new(DeliveryAttempt::default());\n*215│        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n 216│        assert!(ledger.matches(b\"three\"));\n 217│        assert!(!ledger.matches(b\"one\\ntwothree\"));\n 218│    }"},"isError":false,"timestamp":1789295627912}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_FI1oky1yehhmrPMkILeBuHA7|fc_0b12df87254bb4e6016aa67c12973c87d19aaf7c8e5f152327","toolName":"read","startedAt":"2026-09-13T10:33:54.768Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:12108-12218"},"intent":"Reading journal queue assertions"},"id":"befc8b63","parentId":"9c0edf94","timestamp":"2026-09-13T10:33:54.768Z"}
{"type":"message","id":"ee49ac0d","parentId":"befc8b63","timestamp":"2026-09-13T10:33:54.769Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Preparing exact test input**"},{"type":"toolCall","id":"call_FI1oky1yehhmrPMkILeBuHA7|fc_0b12df87254bb4e6016aa67c12973c87d19aaf7c8e5f152327","name":"read","arguments":{"i":"Reading journal queue assertions","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:12108-12218"},"intent":"Reading journal queue assertions"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":3547,"output":65,"cacheRead":45056,"cacheWrite":0,"totalTokens":48668,"reasoningTokens":15,"cost":{"input":0.03547,"output":0.0032500000000000003,"cacheRead":0.045056,"cacheWrite":0,"total":0.083776}},"stopReason":"toolUse","timestamp":1789295627947,"responseId":"resp_0b12df87254bb4e6016aa67c0c225087d192595926b91db004","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c0fa01087d181e65780d36a41bf","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnwSuJSm2jNvK9hKV26mJMvxs1FwXlCurdWqr79L1gC29O1KoA9mZNa9lF7sRAzaarNWYm4OEaga-0hz13ZmnfWC6jM2eeAU1Cdrtvh_usN4Xf6iPkJZ5jxbJaH_0wXxdqlAZA4QAeYMLXqHviEYOSMTEQd9gwLJrBOwR9xFWr9yooJfK6dnK86YDKkOifhV4hArcoFHuZ0_z7mofQ6361VQVIG1nmBY-Ud40NQxgOw-BYL4U1SpQsH0o6bt8FgVsHH8M3UC1wS9KrzSLVTIclJpQxl7-RPPVw3vGhtXvMgUumegR41eQ9RWs-htIlH6sA9ywH626T5rNUKSs8kQX89l7CRnXBpgZ-mBGwi1feUfcNzVTvAW79JShFzzSeZM5atwmvhhtQvXnBSIg7MtWNlbeQmcLb87tF-oFzW2j9Hn-6smJVjVCxH_CeCRkqGWo6CvthywRzWKszOnAnYkU-mn4oW9ziGHFnGZqQ7SzjiX6MtKuFkkI18ToRGOj2Cq6b86nylaAg_jkUOBpKu0xBDDWSNbdbJHLzh0SmiaXHe9jYmD_V4xsZk_f81ZFR3CNTTFp3c7Ub_XRfrNlsVU5ucliGqijlKlRpD-v3U01bQYXwE78vISwT5_s8jMco3jL7ODACuOqUkIjH7WKnxXSfXKpE8G4YopHE3NodrlMrRS-kOPw5z32c3jwUiMKUNouSKgLoOyNGpCOq-o73M_5SmzHlz0s6JYzXzzrDiZrc9mhd-1zF_0oCSSN0UHbQZh6--obpuSpIKBRvwqwfJjHbp7NUrFXgb62WP47OwbAMJyaXJzFunxmoIsHM4SGV0q0kZh5GgaZC1EsrZWbg_olzHfAvxhyBV0i0uVCKWfJObUnBHV8xTGUaAF5mAczGv8w6anLsZFE0a3QqgX4ZatGq_HaKj08vL30bi7jNlU041xO8Z18rl8IvRYtWfSy4L-fhWi-70mxnNLfxAPO5DP6iwHM_-r7xmQe8-7mkORCUr4i6FxlH3XseMKh7YdIXGwhYH0pLyokVVUDAkjfXacLMidpo-iiK8zzPihGeSyUX3S4Pd4gmhBAAR1Jm7G1znTGOkxy4r7M7fkInZIRo-FFsNPlFG59ZRoXr587ZqQpKg-xomouwzzliFzNTjgXQyJI2xu47rljfieA-e4b6E_ezr4i6W0hhMVJsh57HxTVyD6N_ttbmmbPZvCSznbtoaLJNhu_SUXjRy4xzlwQUW3-N52oF0Fz7PdN8serYddYhPdCSp9gHXAZrGLAyV4jY3gvq3lH9RQe2z2nsfS8VCllt19QC540hG7I7gwShueyCj2DmVNFAFRGLbibNydjmSXde50WXr480xOyzhJWf1CC6tTKw==","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Preparing exact test input**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67c12973c87d19aaf7c8e5f152327","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading journal queue assertions\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:12108-12218\"}","call_id":"call_FI1oky1yehhmrPMkILeBuHA7","internal_chat_message_metadata_passthrough":{"create_time":1789295628.29931,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":6819.936299999943,"ttft":3696.4244999999646,"completedAt":1789295634768,"contextSnapshot":{"promptTokens":48603,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"d31edc0e","parentId":"ee49ac0d","timestamp":"2026-09-13T10:33:54.858Z","message":{"role":"toolResult","toolCallId":"call_FI1oky1yehhmrPMkILeBuHA7|fc_0b12df87254bb4e6016aa67c12973c87d19aaf7c8e5f152327","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#3A1D]\n12059:    fn supervised_worker_panic_faults_and_reaps_child() {\n…\n12105:        if !dead {\n…\n12107:        }\n12108:        assert!(\n12109:            dead,\n12110:            \"the panicked worker's child is REAPED, not orphaned (no live pid + worker-gone)\"\n12111:        );\n12112:    }\n12113:\n12114:    /// Exactly-once enqueue under the journal: `apply_once((sid,op), PtyWrite, enqueue)`\n12115:    /// runs the enqueue effect once; a REPLAY of the SAME key dedups (does NOT enqueue\n12116:    /// again). Both outcomes ack (\"accepted + ordered\"). We assert the writer received\n12117:    /// the bytes EXACTLY ONCE by counting records drained from the real FIFO. This is\n12118:    /// the broker-side wiring of the `effect.rs` ephemeral-PtyWrite dedup\n12119:    /// (PtyWrite reserve → enqueue → Applied) — order + exactly-once preserved.\n12120:    // [unit->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\n12121:    #[test]\n12122:    fn apply_once_enqueues_ptywrite_exactly_once_and_dedups_replay() {\n12123:        use crate::effect::{EffectJournal, EffectKey, EffectKind, Minter, Outcome};\n12124:\n12125:        let dir = tempfile::tempdir().unwrap();\n12126:        let journal = EffectJournal::open(dir.path().join(\"effects.log\")).unwrap();\n12127:        let (w, rx) = test_input_writer(16);\n12128:        let key = EffectKey {\n12129:            class: 1,\n12130:            minter: Minter::Rc,\n12131:            op: 1,\n12132:        };\n12133:        let bytes = b\"paste-burst\".to_vec();\n12134:\n12135:        // First apply: the PtyWrite effect = the non-blocking enqueue → Applied.\n12136:        let o1 = journal\n12137:            .apply_once(key, EffectKind::PtyWrite, || {\n12138:                w.enqueue(bytes.clone());\n12139:                Ok(())\n12140:            })\n12141:            .unwrap();\n12142:        // Replay the SAME key (a re-driven op / a dup op_id): must DEDUP — the\n12143:        // enqueue effect must NOT run again (no double keystroke landing on the PTY).\n12144:        let o2 = journal\n12145:            .apply_once(key, EffectKind::PtyWrite, || {\n12146:                w.enqueue(bytes.clone());\n12147:                Ok(())\n12148:            })\n12149:            .unwrap();\n12150:\n12151:        assert_eq!(o1, Outcome::Applied, \"the first PtyWrite enqueue applies\");\n12152:        assert_eq!(\n12153:            o2,\n12154:            Outcome::Deduped,\n12155:            \"a replay of the same key is deduped — the enqueue effect does not re-run\"\n12156:        );\n12157:\n12158:        // Drain the FIFO: the bytes were enqueued EXACTLY ONCE despite two apply_once\n12159:        // calls (a re-driven keystroke must not double-type into the paste).\n12160:        drop(w);\n12161:        let drained: Vec<Vec<u8>> = std::iter::from_fn(|| rx.recv().ok()).collect();\n12162:        assert_eq!(\n12163:            drained,\n12164:            vec![bytes],\n12165:            \"the writer received the PtyWrite bytes exactly once across the apply + \\\n12166:             the deduped replay (exactly-once preserved at enqueue — \\\n12167:             REQ-HAZARD-PTY-INPUT-WRITER-WEDGE)\"\n12168:        );\n12169:    }\n12170:\n12171:    // ── v0.13.0 P1c — REQ-HAZARD-CONTROLLER-WRITER-REORDER: the epoch-gated\n12172:    //    single-live-writer-per-connection kernel. WHITE-BOX unit: build a real\n12173:    //    `OutputLog` over a real connected local socket (the transport unit\n12174:    //    harness, `local_socket_handshake_and_frame_round_trip`) and call the\n12175:    //    private `become_controller` directly — TWICE on the SAME `SharedSend` —\n12176:    //    to reproduce the pre-fix handoff(from_seq=1)+re-serve(from_seq=0)\n12177:    //    double-registration on ONE brain connection, with NO forkpty/PTY (so it\n12178:    //    is platform-agnostic on this Windows dev box; it drives become_controller\n12179:    //    directly, not a PTY child). BAR (doyle): deterministically GREEN\n12180:    //    post-fix; the in-lock epoch gate is the load-bearing line (neuter the\n12181:    //    `if controller_epoch.load(Acquire) != epoch { return; }` inside\n12182:    //    `controller_writer`'s `send.lock()` arm → RED). ──────────────────────────\n12183:\n12184:    /// A connected local-socket pair for the unit: bind a listener, connect a\n12185:    /// client `Stream`, accept the server `Stream`. Returns the SERVER send half\n12186:    /// wrapped as a `SharedSend` (the broker side a `become_controller` writes\n12187:    /// through) plus the CLIENT `Stream` (the brain side we read the wire off) and\n12188:    /// the unused server RECV half (held so the server fd stays open while we\n12189:    /// read). Mirrors `LocalSocketTransport`'s own round-trip test + `handle_conn`'s\n12190:    /// `conn.split()`.\n12191:    fn controller_socket_pair() -> (SharedSend, Stream, interprocess::local_socket::RecvHalf) {\n12192:        use std::sync::atomic::AtomicU32;\n12193:        // A process-unique pipe/UDS name so parallel test threads never collide.\n12194:        static SEQ: AtomicU32 = AtomicU32::new(0);\n12195:        let name = format!(\n12196:            \"spt-daemon-p1c-{}-{}.sock\",\n12197:            std::process::id(),\n12198:            SEQ.fetch_add(1, Ordering::Relaxed)\n12199:        );\n12200:        let listener = LocalSocketTransport::bind(&name).expect(\"bind listener\");\n12201:        let client = LocalSocketTransport::connect(&name).expect(\"connect client\");\n12202:        let server = listener.accept().expect(\"accept server side\");\n12203:        let (recv, send) = server.split();\n12204:        (\n12205:            Arc::new(BrokerConn::new(send, brain_write_deadline())),\n12206:            client,\n12207:            recv,\n12208:        )\n12209:    }\n12210:\n12211:    /// Read exactly `n` framed `output` envelopes off the wire and return their\n12212:    /// `seq`s in arrival order. A blocking `read_frame` per frame — the writer\n12213:    /// threads push them; the test runner's own timeout catches a genuine stall\n12214:    /// (no per-read deadline: Windows named pipes reject I/O timeouts).\n12215:    fn drain_output_seqs(client: &mut Stream, n: usize) -> Vec<u64> {\n12216:        let mut seqs = Vec::with_capacity(n);\n12217:        while seqs.len() < n {\n12218:            let env = read_frame(client).expect(\"output frame on the wire\");\n12219:            if env.kind == crate::msg::KIND_OUTPUT {\n12220:                let ev: crate::msg::OutputEvent =\n12221:                    serde_json::from_value(env.payload).expect(\"output payload\");\n…\n12223:            }\n12224:        }\n…\n12226:    }\n\n[Showing lines 12107-12221 of 16479. Use :12222 to continue]"}],"details":{"truncation":{"content":"        }\r\n        assert!(\r\n            dead,\r\n            \"the panicked worker's child is REAPED, not orphaned (no live pid + worker-gone)\"\r\n        );\r\n    }\r\n\r\n    /// Exactly-once enqueue under the journal: `apply_once((sid,op), PtyWrite, enqueue)`\r\n    /// runs the enqueue effect once; a REPLAY of the SAME key dedups (does NOT enqueue\r\n    /// again). Both outcomes ack (\"accepted + ordered\"). We assert the writer received\r\n    /// the bytes EXACTLY ONCE by counting records drained from the real FIFO. This is\r\n    /// the broker-side wiring of the `effect.rs` ephemeral-PtyWrite dedup\r\n    /// (PtyWrite reserve → enqueue → Applied) — order + exactly-once preserved.\r\n    // [unit->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\r\n    #[test]\r\n    fn apply_once_enqueues_ptywrite_exactly_once_and_dedups_replay() {\r\n        use crate::effect::{EffectJournal, EffectKey, EffectKind, Minter, Outcome};\r\n\r\n        let dir = tempfile::tempdir().unwrap();\r\n        let journal = EffectJournal::open(dir.path().join(\"effects.log\")).unwrap();\r\n        let (w, rx) = test_input_writer(16);\r\n        let key = EffectKey {\r\n            class: 1,\r\n            minter: Minter::Rc,\r\n            op: 1,\r\n        };\r\n        let bytes = b\"paste-burst\".to_vec();\r\n\r\n        // First apply: the PtyWrite effect = the non-blocking enqueue → Applied.\r\n        let o1 = journal\r\n            .apply_once(key, EffectKind::PtyWrite, || {\r\n                w.enqueue(bytes.clone());\r\n                Ok(())\r\n            })\r\n            .unwrap();\r\n        // Replay the SAME key (a re-driven op / a dup op_id): must DEDUP — the\r\n        // enqueue effect must NOT run again (no double keystroke landing on the PTY).\r\n        let o2 = journal\r\n            .apply_once(key, EffectKind::PtyWrite, || {\r\n                w.enqueue(bytes.clone());\r\n                Ok(())\r\n            })\r\n            .unwrap();\r\n\r\n        assert_eq!(o1, Outcome::Applied, \"the first PtyWrite enqueue applies\");\r\n        assert_eq!(\r\n            o2,\r\n            Outcome::Deduped,\r\n            \"a replay of the same key is deduped — the enqueue effect does not re-run\"\r\n        );\r\n\r\n        // Drain the FIFO: the bytes were enqueued EXACTLY ONCE despite two apply_once\r\n        // calls (a re-driven keystroke must not double-type into the paste).\r\n        drop(w);\r\n        let drained: Vec<Vec<u8>> = std::iter::from_fn(|| rx.recv().ok()).collect();\r\n        assert_eq!(\r\n            drained,\r\n            vec![bytes],\r\n            \"the writer received the PtyWrite bytes exactly once across the apply + \\\r\n             the deduped replay (exactly-once preserved at enqueue — \\\r\n             REQ-HAZARD-PTY-INPUT-WRITER-WEDGE)\"\r\n        );\r\n    }\r\n\r\n    // ── v0.13.0 P1c — REQ-HAZARD-CONTROLLER-WRITER-REORDER: the epoch-gated\r\n    //    single-live-writer-per-connection kernel. WHITE-BOX unit: build a real\r\n    //    `OutputLog` over a real connected local socket (the transport unit\r\n    //    harness, `local_socket_handshake_and_frame_round_trip`) and call the\r\n    //    private `become_controller` directly — TWICE on the SAME `SharedSend` —\r\n    //    to reproduce the pre-fix handoff(from_seq=1)+re-serve(from_seq=0)\r\n    //    double-registration on ONE brain connection, with NO forkpty/PTY (so it\r\n    //    is platform-agnostic on this Windows dev box; it drives become_controller\r\n    //    directly, not a PTY child). BAR (doyle): deterministically GREEN\r\n    //    post-fix; the in-lock epoch gate is the load-bearing line (neuter the\r\n    //    `if controller_epoch.load(Acquire) != epoch { return; }` inside\r\n    //    `controller_writer`'s `send.lock()` arm → RED). ──────────────────────────\r\n\r\n    /// A connected local-socket pair for the unit: bind a listener, connect a\r\n    /// client `Stream`, accept the server `Stream`. Returns the SERVER send half\r\n    /// wrapped as a `SharedSend` (the broker side a `become_controller` writes\r\n    /// through) plus the CLIENT `Stream` (the brain side we read the wire off) and\r\n    /// the unused server RECV half (held so the server fd stays open while we\r\n    /// read). Mirrors `LocalSocketTransport`'s own round-trip test + `handle_conn`'s\r\n    /// `conn.split()`.\r\n    fn controller_socket_pair() -> (SharedSend, Stream, interprocess::local_socket::RecvHalf) {\r\n        use std::sync::atomic::AtomicU32;\r\n        // A process-unique pipe/UDS name so parallel test threads never collide.\r\n        static SEQ: AtomicU32 = AtomicU32::new(0);\r\n        let name = format!(\r\n            \"spt-daemon-p1c-{}-{}.sock\",\r\n            std::process::id(),\r\n            SEQ.fetch_add(1, Ordering::Relaxed)\r\n        );\r\n        let listener = LocalSocketTransport::bind(&name).expect(\"bind listener\");\r\n        let client = LocalSocketTransport::connect(&name).expect(\"connect client\");\r\n        let server = listener.accept().expect(\"accept server side\");\r\n        let (recv, send) = server.split();\r\n        (\r\n            Arc::new(BrokerConn::new(send, brain_write_deadline())),\r\n            client,\r\n            recv,\r\n        )\r\n    }\r\n\r\n    /// Read exactly `n` framed `output` envelopes off the wire and return their\r\n    /// `seq`s in arrival order. A blocking `read_frame` per frame — the writer\r\n    /// threads push them; the test runner's own timeout catches a genuine stall\r\n    /// (no per-read deadline: Windows named pipes reject I/O timeouts).\r\n    fn drain_output_seqs(client: &mut Stream, n: usize) -> Vec<u64> {\r\n        let mut seqs = Vec::with_capacity(n);\r\n        while seqs.len() < n {\r\n            let env = read_frame(client).expect(\"output frame on the wire\");\r\n            if env.kind == crate::msg::KIND_OUTPUT {\r\n                let ev: crate::msg::OutputEvent =\r\n                    serde_json::from_value(env.payload).expect(\"output payload\");\r","truncated":true,"truncatedBy":"lines","totalLines":4373,"totalBytes":5869,"outputLines":115,"outputBytes":5869,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":16479,"displayContent":{"text":"    fn supervised_worker_panic_faults_and_reaps_child() {\n…\n        if !dead {\n…\n        }\r\n        assert!(\r\n            dead,\r\n            \"the panicked worker's child is REAPED, not orphaned (no live pid + worker-gone)\"\r\n        );\r\n    }\r\n\r\n    /// Exactly-once enqueue under the journal: `apply_once((sid,op), PtyWrite, enqueue)`\r\n    /// runs the enqueue effect once; a REPLAY of the SAME key dedups (does NOT enqueue\r\n    /// again). Both outcomes ack (\"accepted + ordered\"). We assert the writer received\r\n    /// the bytes EXACTLY ONCE by counting records drained from the real FIFO. This is\r\n    /// the broker-side wiring of the `effect.rs` ephemeral-PtyWrite dedup\r\n    /// (PtyWrite reserve → enqueue → Applied) — order + exactly-once preserved.\r\n    // [unit->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\r\n    #[test]\r\n    fn apply_once_enqueues_ptywrite_exactly_once_and_dedups_replay() {\r\n        use crate::effect::{EffectJournal, EffectKey, EffectKind, Minter, Outcome};\r\n\r\n        let dir = tempfile::tempdir().unwrap();\r\n        let journal = EffectJournal::open(dir.path().join(\"effects.log\")).unwrap();\r\n        let (w, rx) = test_input_writer(16);\r\n        let key = EffectKey {\r\n            class: 1,\r\n            minter: Minter::Rc,\r\n            op: 1,\r\n        };\r\n        let bytes = b\"paste-burst\".to_vec();\r\n\r\n        // First apply: the PtyWrite effect = the non-blocking enqueue → Applied.\r\n        let o1 = journal\r\n            .apply_once(key, EffectKind::PtyWrite, || {\r\n                w.enqueue(bytes.clone());\r\n                Ok(())\r\n            })\r\n            .unwrap();\r\n        // Replay the SAME key (a re-driven op / a dup op_id): must DEDUP — the\r\n        // enqueue effect must NOT run again (no double keystroke landing on the PTY).\r\n        let o2 = journal\r\n            .apply_once(key, EffectKind::PtyWrite, || {\r\n                w.enqueue(bytes.clone());\r\n                Ok(())\r\n            })\r\n            .unwrap();\r\n\r\n        assert_eq!(o1, Outcome::Applied, \"the first PtyWrite enqueue applies\");\r\n        assert_eq!(\r\n            o2,\r\n            Outcome::Deduped,\r\n            \"a replay of the same key is deduped — the enqueue effect does not re-run\"\r\n        );\r\n\r\n        // Drain the FIFO: the bytes were enqueued EXACTLY ONCE despite two apply_once\r\n        // calls (a re-driven keystroke must not double-type into the paste).\r\n        drop(w);\r\n        let drained: Vec<Vec<u8>> = std::iter::from_fn(|| rx.recv().ok()).collect();\r\n        assert_eq!(\r\n            drained,\r\n            vec![bytes],\r\n            \"the writer received the PtyWrite bytes exactly once across the apply + \\\r\n             the deduped replay (exactly-once preserved at enqueue — \\\r\n             REQ-HAZARD-PTY-INPUT-WRITER-WEDGE)\"\r\n        );\r\n    }\r\n\r\n    // ── v0.13.0 P1c — REQ-HAZARD-CONTROLLER-WRITER-REORDER: the epoch-gated\r\n    //    single-live-writer-per-connection kernel. WHITE-BOX unit: build a real\r\n    //    `OutputLog` over a real connected local socket (the transport unit\r\n    //    harness, `local_socket_handshake_and_frame_round_trip`) and call the\r\n    //    private `become_controller` directly — TWICE on the SAME `SharedSend` —\r\n    //    to reproduce the pre-fix handoff(from_seq=1)+re-serve(from_seq=0)\r\n    //    double-registration on ONE brain connection, with NO forkpty/PTY (so it\r\n    //    is platform-agnostic on this Windows dev box; it drives become_controller\r\n    //    directly, not a PTY child). BAR (doyle): deterministically GREEN\r\n    //    post-fix; the in-lock epoch gate is the load-bearing line (neuter the\r\n    //    `if controller_epoch.load(Acquire) != epoch { return; }` inside\r\n    //    `controller_writer`'s `send.lock()` arm → RED). ──────────────────────────\r\n\r\n    /// A connected local-socket pair for the unit: bind a listener, connect a\r\n    /// client `Stream`, accept the server `Stream`. Returns the SERVER send half\r\n    /// wrapped as a `SharedSend` (the broker side a `become_controller` writes\r\n    /// through) plus the CLIENT `Stream` (the brain side we read the wire off) and\r\n    /// the unused server RECV half (held so the server fd stays open while we\r\n    /// read). Mirrors `LocalSocketTransport`'s own round-trip test + `handle_conn`'s\r\n    /// `conn.split()`.\r\n    fn controller_socket_pair() -> (SharedSend, Stream, interprocess::local_socket::RecvHalf) {\r\n        use std::sync::atomic::AtomicU32;\r\n        // A process-unique pipe/UDS name so parallel test threads never collide.\r\n        static SEQ: AtomicU32 = AtomicU32::new(0);\r\n        let name = format!(\r\n            \"spt-daemon-p1c-{}-{}.sock\",\r\n            std::process::id(),\r\n            SEQ.fetch_add(1, Ordering::Relaxed)\r\n        );\r\n        let listener = LocalSocketTransport::bind(&name).expect(\"bind listener\");\r\n        let client = LocalSocketTransport::connect(&name).expect(\"connect client\");\r\n        let server = listener.accept().expect(\"accept server side\");\r\n        let (recv, send) = server.split();\r\n        (\r\n            Arc::new(BrokerConn::new(send, brain_write_deadline())),\r\n            client,\r\n            recv,\r\n        )\r\n    }\r\n\r\n    /// Read exactly `n` framed `output` envelopes off the wire and return their\r\n    /// `seq`s in arrival order. A blocking `read_frame` per frame — the writer\r\n    /// threads push them; the test runner's own timeout catches a genuine stall\r\n    /// (no per-read deadline: Windows named pipes reject I/O timeouts).\r\n    fn drain_output_seqs(client: &mut Stream, n: usize) -> Vec<u64> {\r\n        let mut seqs = Vec::with_capacity(n);\r\n        while seqs.len() < n {\r\n            let env = read_frame(client).expect(\"output frame on the wire\");\r\n            if env.kind == crate::msg::KIND_OUTPUT {\r\n                let ev: crate::msg::OutputEvent =\r\n                    serde_json::from_value(env.payload).expect(\"output payload\");\r\n…\n            }\n        }\n…\n    }","startLine":12059,"lineNumbers":[12059,null,12105,null,12107,12108,12109,12110,12111,12112,12113,12114,12115,12116,12117,12118,12119,12120,12121,12122,12123,12124,12125,12126,12127,12128,12129,12130,12131,12132,12133,12134,12135,12136,12137,12138,12139,12140,12141,12142,12143,12144,12145,12146,12147,12148,12149,12150,12151,12152,12153,12154,12155,12156,12157,12158,12159,12160,12161,12162,12163,12164,12165,12166,12167,12168,12169,12170,12171,12172,12173,12174,12175,12176,12177,12178,12179,12180,12181,12182,12183,12184,12185,12186,12187,12188,12189,12190,12191,12192,12193,12194,12195,12196,12197,12198,12199,12200,12201,12202,12203,12204,12205,12206,12207,12208,12209,12210,12211,12212,12213,12214,12215,12216,12217,12218,12219,12220,12221,null,12223,12224,null,12226]},"fileSize":857503,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\broker.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":16479,"totalBytes":5869,"outputLines":115,"outputBytes":5869,"shownRange":{"start":12107,"end":12221},"nextOffset":12222}}},"isError":false,"timestamp":1789295634858}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_29XSeQy7BVPUakPZbKn1qcAf|ctc_0b12df87254bb4e6016aa67c188c0887d1b4819b8d9c9432e8","toolName":"edit","startedAt":"2026-09-13T10:34:26.037Z"},"id":"827191ce","parentId":"d31edc0e","timestamp":"2026-09-13T10:34:26.038Z"}
{"type":"message","id":"05e3f083","parentId":"827191ce","timestamp":"2026-09-13T10:34:26.038Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Adding test byte helper**"},{"type":"toolCall","id":"call_29XSeQy7BVPUakPZbKn1qcAf|ctc_0b12df87254bb4e6016aa67c188c0887d1b4819b8d9c9432e8","name":"edit","arguments":{"input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#3A1D]\nPUT 4165.=4167:\n+/// Source-tagged records retain delivery custody through the single physical writer.\n+use crate::deliverybytes::{DeliveryAttempt, DeliveryBytes, DeliveryPart, InputRecord};\nPUT >4202:\n+    /// Successful delivery evidence survives translation respawn for this session.\n+    deliveries: Arc<DeliveryBytes>,\nPUT 4220.=4220:\n+        let deliveries = Arc::new(DeliveryBytes::default());\n+        let writer_deliveries = Arc::clone(&deliveries);\n+        let writer = thread::spawn(move || input_writer(session, rx, writer_deliveries));\nPUT >4222:\n+            deliveries,\nPUT 4229.=4230:\n+    /// Enqueue controller bytes for the PTY write thread — NON-BLOCKING. Returns\n+    /// `true` when accepted (ordered, not yet physically written), `false` when the\nPUT 4235.=4236:\n+    fn enqueue(&self, bytes: Vec<u8>) -> bool {\n+        self.enqueue_record(InputRecord::controller(bytes))\n+    }\n+\n+    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    fn delivery_matches(&self, payload: &[u8]) -> bool {\n+        self.deliveries.matches(payload)\n+    }\n+\n+    fn delivery_unavailable_reason(&self) -> Option<&'static str> {\n+        self.deliveries.unavailable_reason()\n+    }\n+\n+    fn enqueue_record(&self, record: InputRecord) -> bool {\n+        match self.tx.try_send(record) {\nPUT 4244.=4244:\n+            Err(TrySendError::Full(record)) => {\n+                record.dropped();\nPUT 4252.=4252:\n+            Err(TrySendError::Disconnected(record)) => {\n+                record.dropped();\n+                false\n+            }\nPUT 4271.=4277:\n+/// wedged harness parks this thread (and only this thread). A failed write cannot\n+/// certify delivery bytes; the thread exits after all senders drop at teardown.\n+fn input_writer(\n+    session: Arc<PtySession>,\n+    rx: Receiver<InputRecord>,\n+    deliveries: Arc<DeliveryBytes>,\n+) {\n+    while let Ok(record) = rx.recv() {\n+        record.write_to(session.as_ref(), &deliveries);\n+    }\nPUT 4769.=4769:\n+        input.enqueue_record(InputRecord::probe(INJECT_SETTLE_PROBE.to_vec()));\nPUT 4843.=4845:\n+fn enqueue_text_chunked(input: &InputWriter, attempt: &Arc<DeliveryAttempt>, bytes: Vec<u8>) {\n+    let mut remaining = bytes.len();\n+    chunk_text(&bytes, inject_text_chunk(), |part| {\n+        remaining -= part.len();\n+        input.enqueue_record(InputRecord::delivery(\n+            part.to_vec(),\n+            attempt,\n+            DeliveryPart::Text { end: remaining == 0 },\n+        ));\nPUT >4899:\n+    let delivery = Arc::new(DeliveryAttempt::default());\nPUT 4909.=4909:\n+                    input.enqueue_record(InputRecord::delivery(\n+                        bytes,\n+                        &delivery,\n+                        DeliveryPart::Key,\n+                    ));\nPUT 4916.=4916:\n+                enqueue_text_chunked(input, &delivery, bytes);\nPUT >4933:\n+    // Logical Commit (or timeout/death) does not certify queued bytes. Each\n+    // record retains this attempt until the physical writer confirms it.\nPUT >11021:\n+            deliveries: Arc::new(DeliveryBytes::default()),\nPUT 11033.=11033:\n+    /// `input_writer` loop via the same source-tagged record's `write_to` seam.\nPUT 11077.=11078:\n+        let deliveries = DeliveryBytes::default();\n+        while let Ok(record) = rx.recv() {\n+            record.write_to(&surface, &deliveries);\nPUT 12161.=12161:\n+        let drained: Vec<Vec<u8>> = std::iter::from_fn(|| rx.recv().ok())\n+            .map(InputRecord::into_bytes)\n+            .collect();\n*** End Patch\n"},"customWireName":"edit"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":1999,"output":983,"cacheRead":48512,"cacheWrite":0,"totalTokens":51494,"reasoningTokens":56,"cost":{"input":0.01999,"output":0.04915,"cacheRead":0.048512,"cacheWrite":0,"total":0.117652}},"stopReason":"toolUse","timestamp":1789295634893,"responseId":"resp_0b12df87254bb4e6016aa67c13235887d1bfeb3abcd5c16db5","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c14809087d1b241de6a3421b497","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnwYpTRBj8dlMalI7CHUmuz7jMiSJwaqWvabglp1Tw4GdsRR0Ns-CZ3qyDMCShFHxeFdZVAwxGDc11xXUGu-8R3UX1ZXoCikidvmrTA3tMiKr2nYjsS03cRe28Lfm4R2JN7dlp1VLhh9NpD3KKpNu2tFYupAhiLMBbuu-sz9fFxzA5sFpsTcCGofEUa8rcSYwuehMtqD8TeEU_PrDoatuL6m6osxs_9Odl_zJ7Oenoy_QoJcHDUb8bTLFE0LV5gdQ5fAqHRDTrNDKCjVxjXEpV2V6IuhUL7rh5yPWDAT4yR26jlGe17QOJy7gFkzA-KhlWfg5IWFkaz4xmHx5K4N1Y_e9hb5Ff2Nko0RWuRFPDQnLw8xk8EES4hSPk0bxqAT_UQ_Bv0zpfCGxyEvzbO-oA5dh-FOeYGvIn7xowKl48xeDxg7lvNX3fZ5VVuCunfwwZHMjlZwxMmimFFqVFIkGaORgWibNF4XmSJ5N38my5L9qnMKX_SQKpCsTRTjD-l4-JvrOkUQO-1OdGmrqu0URG7wknhsv5K8UkR11s8olq8sMVZgt-9TwuaktnjWyJA5zghONWIsrB27sFovZlodRy9PQh9y-N0302BKSbwJ3AV6n255SuTyu6B8cD2BUjLfb2Q4AH2-_lR4xqvbqILOuB3EvO74GoEdsqmowrLqdr2ooUjQAt8TYcGPXTEwZ09U1oG4rD3cBxKmKMOjOmON9ytG5bCDY4CmesGF3FnLbzcHIUr9pSnvaTkeGe9Q1pdq_mRqDWEWq1Xq8zpEcM0rAqCIpi7M9YKJpvUt8psDKqe4k_3H7VU8PHByAUwsxeiE9daRowD5ca7O1Wca2E5HqbqJQILmAY76lV3s8eLI1_GvVXoSSN2kwjafUQ5xzhqkKDzF2E0tWUUOCdg7jfXy2fiUaZYZRbqnzYu-tPDHMfk-71yo1VuZ-dUZqs-h7qSnMglQsAT4JiWmwnCvIRaKwV8Om7Y9BFr2HI5TyvcYvraNTILibq2L9qitH-kYbt8S-MYSdRZTV8MLzKN6wahvSQocCUif1hdXvupRsmxatbzotEcW8KE2ji7I_hHuhmoHNzrklINvjiqw9pU11ujOgPzn17cuqTbnSJRz_s2oeSvQCUxTCgQOHeYeB7vB3rklEO8LEvfVEUM0DUYl5uJDYBbVLy0CfHfoBCz_o0PaZcgYlsXia-OhffwBm9_qE-uZlQ1SSJniB7k0QH1AK_mksvvMO8VOtrfn16j3xp8V5kvBJz9rUAuBc8cT8dlQqdwNO26sCpwJbg37E5T7glybIOnuXHHe1lN5LnvvmgGZZ3b0zg0_55mZw-8ZOGCzn60cmhQeDPRLbJm08jNOjdCODVfWxqqtxWUrRnjMH9QDWYhenYPyZxul6tRxgkQ0i9BvpPjVcAaxr9Z4qs439aYKMPEH40H5CdW7reEDQzZ4FXXYeVJ51xeqYdnGlivxwi1yTI_be8DqO392BVsLoXYJVZZ-C2HLBGegE8apGsAEQe67eagXLsri8Q_X8cvf5-WkKrhYsUHU4ya9lZvDALQcDIivGVJ7yrHJvqX3B2d2plyA-GobT0tBiNeA-yoKmGuI78JzF0mXhK1J-O_2fYuWJwz40w==","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Adding test byte helper**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"ctc_0b12df87254bb4e6016aa67c188c0887d1b4819b8d9c9432e8","type":"custom_tool_call","status":"completed","call_id":"call_29XSeQy7BVPUakPZbKn1qcAf","input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#3A1D]\nPUT 4165.=4167:\n+/// Source-tagged records retain delivery custody through the single physical writer.\n+use crate::deliverybytes::{DeliveryAttempt, DeliveryBytes, DeliveryPart, InputRecord};\nPUT >4202:\n+    /// Successful delivery evidence survives translation respawn for this session.\n+    deliveries: Arc<DeliveryBytes>,\nPUT 4220.=4220:\n+        let deliveries = Arc::new(DeliveryBytes::default());\n+        let writer_deliveries = Arc::clone(&deliveries);\n+        let writer = thread::spawn(move || input_writer(session, rx, writer_deliveries));\nPUT >4222:\n+            deliveries,\nPUT 4229.=4230:\n+    /// Enqueue controller bytes for the PTY write thread — NON-BLOCKING. Returns\n+    /// `true` when accepted (ordered, not yet physically written), `false` when the\nPUT 4235.=4236:\n+    fn enqueue(&self, bytes: Vec<u8>) -> bool {\n+        self.enqueue_record(InputRecord::controller(bytes))\n+    }\n+\n+    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    fn delivery_matches(&self, payload: &[u8]) -> bool {\n+        self.deliveries.matches(payload)\n+    }\n+\n+    fn delivery_unavailable_reason(&self) -> Option<&'static str> {\n+        self.deliveries.unavailable_reason()\n+    }\n+\n+    fn enqueue_record(&self, record: InputRecord) -> bool {\n+        match self.tx.try_send(record) {\nPUT 4244.=4244:\n+            Err(TrySendError::Full(record)) => {\n+                record.dropped();\nPUT 4252.=4252:\n+            Err(TrySendError::Disconnected(record)) => {\n+                record.dropped();\n+                false\n+            }\nPUT 4271.=4277:\n+/// wedged harness parks this thread (and only this thread). A failed write cannot\n+/// certify delivery bytes; the thread exits after all senders drop at teardown.\n+fn input_writer(\n+    session: Arc<PtySession>,\n+    rx: Receiver<InputRecord>,\n+    deliveries: Arc<DeliveryBytes>,\n+) {\n+    while let Ok(record) = rx.recv() {\n+        record.write_to(session.as_ref(), &deliveries);\n+    }\nPUT 4769.=4769:\n+        input.enqueue_record(InputRecord::probe(INJECT_SETTLE_PROBE.to_vec()));\nPUT 4843.=4845:\n+fn enqueue_text_chunked(input: &InputWriter, attempt: &Arc<DeliveryAttempt>, bytes: Vec<u8>) {\n+    let mut remaining = bytes.len();\n+    chunk_text(&bytes, inject_text_chunk(), |part| {\n+        remaining -= part.len();\n+        input.enqueue_record(InputRecord::delivery(\n+            part.to_vec(),\n+            attempt,\n+            DeliveryPart::Text { end: remaining == 0 },\n+        ));\nPUT >4899:\n+    let delivery = Arc::new(DeliveryAttempt::default());\nPUT 4909.=4909:\n+                    input.enqueue_record(InputRecord::delivery(\n+                        bytes,\n+                        &delivery,\n+                        DeliveryPart::Key,\n+                    ));\nPUT 4916.=4916:\n+                enqueue_text_chunked(input, &delivery, bytes);\nPUT >4933:\n+    // Logical Commit (or timeout/death) does not certify queued bytes. Each\n+    // record retains this attempt until the physical writer confirms it.\nPUT >11021:\n+            deliveries: Arc::new(DeliveryBytes::default()),\nPUT 11033.=11033:\n+    /// `input_writer` loop via the same source-tagged record's `write_to` seam.\nPUT 11077.=11078:\n+        let deliveries = DeliveryBytes::default();\n+        while let Ok(record) = rx.recv() {\n+            record.write_to(&surface, &deliveries);\nPUT 12161.=12161:\n+        let drained: Vec<Vec<u8>> = std::iter::from_fn(|| rx.recv().ok())\n+            .map(InputRecord::into_bytes)\n+            .collect();\n*** End Patch\n","internal_chat_message_metadata_passthrough":{"create_time":1789295635.299628,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"edit","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":31140.2831,"ttft":1629.8908999999985,"completedAt":1789295666035,"contextSnapshot":{"promptTokens":50511,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"27f628ff","parentId":"05e3f083","timestamp":"2026-09-13T10:34:26.286Z","message":{"role":"toolResult","toolCallId":"call_29XSeQy7BVPUakPZbKn1qcAf|ctc_0b12df87254bb4e6016aa67c188c0887d1b4819b8d9c9432e8","toolName":"edit","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#8B20]\n4113:struct HostedSession {\n\n4163:}\n4164:\n4165:/// Source-tagged records retain delivery custody through the single physical writer.\n4166:use crate::deliverybytes::{DeliveryAttempt, DeliveryBytes, DeliveryPart, InputRecord};\n4167:\n4168:/// The per-session PTY input FIFO depth (records). Sized for a generous paste —\n4200:    /// queue (a genuinely wedged harness) DROPS, it never blocks.\n4201:    tx: SyncSender<InputRecord>,\n4202:    /// Successful delivery evidence survives translation respawn for this session.\n4203:    deliveries: Arc<DeliveryBytes>,\n4204:    /// True while the FIFO is saturated and input is being dropped; cleared on\n4205:    /// the next accepted enqueue (heal-on-resume). Mirrored to the perch's\n4219:    fn spawn(session: Arc<PtySession>, endpoint: String) -> Arc<InputWriter> {\n4220:        let (tx, rx) = sync_channel::<InputRecord>(input_queue_depth());\n4221:        let deliveries = Arc::new(DeliveryBytes::default());\n4222:        let writer_deliveries = Arc::clone(&deliveries);\n4223:        let writer = thread::spawn(move || input_writer(session, rx, writer_deliveries));\n4224:        Arc::new(InputWriter {\n4225:            tx,\n4226:            deliveries,\n4227:            backpressure: AtomicBool::new(false),\n4228:            endpoint,\n\n4230:        })\n4231:    }\n4232:\n4233:    /// Enqueue controller bytes for the PTY write thread — NON-BLOCKING. Returns\n4234:    /// `true` when accepted (ordered, not yet physically written), `false` when the\n4235:    /// record was DROPPED. A full queue stamps `INPUT_BACKPRESSURE` (once, on the\n4236:    /// rising edge); the next accepted enqueue clears it (heal). The dispatch\n4237:    /// thread never blocks here, however stuck the harness is.\n4238:    // [impl->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\n4239:    fn enqueue(&self, bytes: Vec<u8>) -> bool {\n4240:        self.enqueue_record(InputRecord::controller(bytes))\n…\n4252:    fn enqueue_record(&self, record: InputRecord) -> bool {\n4253:        match self.tx.try_send(record) {\n4254:            Ok(()) => {\n4255:                // Heal: input is flowing again — clear a prior backpressure stamp.\n4259:                true\n4260:            }\n4261:            Err(TrySendError::Full(record)) => {\n4262:                record.dropped();\n4263:                // DROP + surface, but stamp only on the rising edge.\n4264:                if !self.backpressure.swap(true, Ordering::AcqRel) {\n\n4266:                }\n\n4268:            }\n4269:            // The writer thread is gone (session teardown) — nothing to do.\n4270:            Err(TrySendError::Disconnected(record)) => {\n4271:                record.dropped();\n4272:                false\n4273:            }\n4274:        }\n4275:    }\n4290:/// records from `rx` and apply each via the BLOCKING\n4291:/// [`SessionSurface::write_input`] — the ONE place that touches the PTY writer. A\n4292:/// wedged harness parks this thread (and only this thread). A failed write cannot\n4293:/// certify delivery bytes; the thread exits after all senders drop at teardown.\n…\n4299:    while let Ok(record) = rx.recv() {\n4300:        record.write_to(session.as_ref(), &deliveries);\n4301:    }\n4302:}\n4791:        // hop later, well within the poll cadence. A re-render works the same\n4792:        // as before; a non-echoing ConPTY stays unobservable (the latch).\n4793:        input.enqueue_record(InputRecord::probe(INJECT_SETTLE_PROBE.to_vec()));\n4794:        thread::sleep(INJECT_SETTLE_POLL);\n4795:        if recover_log(log).high_water() > baseline {\n\n4797:        }\n\n4865:/// the first chunk lands.\n4866:// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n4867:fn enqueue_text_chunked(input: &InputWriter, attempt: &Arc<DeliveryAttempt>, bytes: Vec<u8>) {\n4868:    let mut remaining = bytes.len();\n4869:    chunk_text(&bytes, inject_text_chunk(), |part| {\n4870:        remaining -= part.len();\n4871:        input.enqueue_record(InputRecord::delivery(\n…\n4874:            DeliveryPart::Text { end: remaining == 0 },\n4875:        ));\n4876:    });\n4877:}\n4928:    let mut disconnected = false;\n4929:    let mut sent_text: Vec<u8> = Vec::new();\n4930:    let delivery = Arc::new(DeliveryAttempt::default());\n4931:    loop {\n4932:        let now = Instant::now();\n\n4937:        match cmd_rx.recv_timeout(remaining) {\n4938:            Ok(KeyCmd::Key { key }) => {\n4939:                if let Some(bytes) = key_to_bytes(&key) {\n4940:                    input.enqueue_record(InputRecord::delivery(\n4941:                        bytes,\n4942:                        &delivery,\n4943:                        DeliveryPart::Key,\n4944:                    ));\n4945:                }\n4946:            }\n4947:            Ok(KeyCmd::Text { text }) => {\n\n4949:                let bytes = text.into_bytes();\n4950:                sent_text.extend_from_slice(&bytes);\n4951:                enqueue_text_chunked(input, &delivery, bytes);\n4952:            }\n4953:            Ok(KeyCmd::Delay { delay_ms }) => {\n\n4957:            }\n\n4967:        }\n4968:    }\n4969:    // Logical Commit (or timeout/death) does not certify queued bytes. Each\n4970:    // record retains this attempt until the physical writer confirms it.\n4971:    // Flush buffered controller input AFTER the injected bytes + release the floor —\n4972:    // in EVERY exit path (the ANTI-STALL guarantee).\n11057:        let w = InputWriter {\n11058:            tx,\n11059:            deliveries: Arc::new(DeliveryBytes::default()),\n11060:            backpressure: AtomicBool::new(false),\n11061:            endpoint: String::new(),\n\n11063:        };\n\n11069:    /// through a single consumer that applies each record to a stub `SessionSurface`\n11070:    /// recording the bytes it receives — EXACTLY mirroring the production\n11071:    /// `input_writer` loop via the same source-tagged record's `write_to` seam.\n11072:    /// One FIFO + one writer ⇒ exact input order. Non-vacuous: a reorder/LIFO/dedup\n11073:    /// mutation of the single-writer contract makes the recorded sequence diverge.\n11113:        // writer exactly as `input_writer` does.\n11114:        drop(w);\n11115:        let deliveries = DeliveryBytes::default();\n11116:        while let Ok(record) = rx.recv() {\n11117:            record.write_to(&surface, &deliveries);\n11118:        }\n11119:\n12198:        // calls (a re-driven keystroke must not double-type into the paste).\n12199:        drop(w);\n12200:        let drained: Vec<Vec<u8>> = std::iter::from_fn(|| rx.recv().ok())\n12201:            .map(InputRecord::into_bytes)\n12202:            .collect();\n12203:        assert_eq!(\n12204:            drained,\n\n12209:        );"}],"details":{"diff":" 4113|struct HostedSession {\n\n 4163|}\n 4164|\n-4165|/// One record queued to a session's dedicated PTY input-writer thread — the raw\n-4166|/// bytes to write (v0.13.0 P0, REQ-HAZARD-PTY-INPUT-WRITER-WEDGE).\n-4167|type InputRecord = Vec<u8>;\n+4165|/// Source-tagged records retain delivery custody through the single physical writer.\n+4166|use crate::deliverybytes::{DeliveryAttempt, DeliveryBytes, DeliveryPart, InputRecord};\n 4168|\n 4169|/// The per-session PTY input FIFO depth (records). Sized for a generous paste —\n 4201|    /// queue (a genuinely wedged harness) DROPS, it never blocks.\n 4202|    tx: SyncSender<InputRecord>,\n+4202|    /// Successful delivery evidence survives translation respawn for this session.\n+4203|    deliveries: Arc<DeliveryBytes>,\n 4203|    /// True while the FIFO is saturated and input is being dropped; cleared on\n 4204|    /// the next accepted enqueue (heal-on-resume). Mirrored to the perch's\n 4218|    fn spawn(session: Arc<PtySession>, endpoint: String) -> Arc<InputWriter> {\n 4219|        let (tx, rx) = sync_channel::<InputRecord>(input_queue_depth());\n-4220|        let writer = thread::spawn(move || input_writer(session, rx));\n+4221|        let deliveries = Arc::new(DeliveryBytes::default());\n+4222|        let writer_deliveries = Arc::clone(&deliveries);\n+4223|        let writer = thread::spawn(move || input_writer(session, rx, writer_deliveries));\n 4221|        Arc::new(InputWriter {\n 4222|            tx,\n+4226|            deliveries,\n 4223|            backpressure: AtomicBool::new(false),\n 4224|            endpoint,\n\n 4226|        })\n 4227|    }\n 4228|\n-4229|    /// Enqueue `bytes` for the PTY write thread — NON-BLOCKING. Returns `true`\n-4230|    /// when accepted (ordered, will land), `false` when the FIFO was full and the\n+4233|    /// Enqueue controller bytes for the PTY write thread — NON-BLOCKING. Returns\n+4234|    /// `true` when accepted (ordered, not yet physically written), `false` when the\n 4231|    /// record was DROPPED. A full queue stamps `INPUT_BACKPRESSURE` (once, on the\n 4232|    /// rising edge); the next accepted enqueue clears it (heal). The dispatch\n 4233|    /// thread never blocks here, however stuck the harness is.\n 4234|    // [impl->REQ-HAZARD-PTY-INPUT-WRITER-WEDGE]\n-4235|    fn enqueue(&self, bytes: InputRecord) -> bool {\n-4236|        match self.tx.try_send(bytes) {\n+4239|    fn enqueue(&self, bytes: Vec<u8>) -> bool {\n+4240|        self.enqueue_record(InputRecord::controller(bytes))\n+4241|    }\n+4242|\n+4243|    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+4244|    fn delivery_matches(&self, payload: &[u8]) -> bool {\n+4245|        self.deliveries.matches(payload)\n+4246|    }\n+4247|\n+4248|    fn delivery_unavailable_reason(&self) -> Option<&'static str> {\n+4249|        self.deliveries.unavailable_reason()\n+4250|    }\n+4251|\n+4252|    fn enqueue_record(&self, record: InputRecord) -> bool {\n+4253|        match self.tx.try_send(record) {\n 4237|            Ok(()) => {\n 4238|                // Heal: input is flowing again — clear a prior backpressure stamp.\n 4242|                true\n 4243|            }\n-4244|            Err(TrySendError::Full(_)) => {\n+4261|            Err(TrySendError::Full(record)) => {\n+4262|                record.dropped();\n 4245|                // DROP + surface, but stamp only on the rising edge.\n 4246|                if !self.backpressure.swap(true, Ordering::AcqRel) {\n\n 4248|                }\n\n 4250|            }\n 4251|            // The writer thread is gone (session teardown) — nothing to do.\n-4252|            Err(TrySendError::Disconnected(_)) => false,\n+4270|            Err(TrySendError::Disconnected(record)) => {\n+4271|                record.dropped();\n+4272|                false\n+4273|            }\n 4253|        }\n 4254|    }\n 4269|/// records from `rx` and apply each via the BLOCKING\n 4270|/// [`SessionSurface::write_input`] — the ONE place that touches the PTY writer. A\n-4271|/// wedged harness parks this thread (and only this thread); a write error is\n-4272|/// swallowed (the same best-effort the inline callers had). The thread exits\n-4273|/// when the last `tx` clone drops at session teardown.\n-4274|fn input_writer(session: Arc<PtySession>, rx: Receiver<InputRecord>) {\n-4275|    while let Ok(bytes) = rx.recv() {\n-4276|        let _ = session.write_input(&bytes);\n+4292|/// wedged harness parks this thread (and only this thread). A failed write cannot\n+4293|/// certify delivery bytes; the thread exits after all senders drop at teardown.\n+4294|fn input_writer(\n+4295|    session: Arc<PtySession>,\n+4296|    rx: Receiver<InputRecord>,\n+4297|    deliveries: Arc<DeliveryBytes>,\n+4298|) {\n+4299|    while let Ok(record) = rx.recv() {\n+4300|        record.write_to(session.as_ref(), &deliveries);\n 4277|    }\n 4278|}\n 4767|        // hop later, well within the poll cadence. A re-render works the same\n 4768|        // as before; a non-echoing ConPTY stays unobservable (the latch).\n-4769|        input.enqueue(INJECT_SETTLE_PROBE.to_vec());\n+4793|        input.enqueue_record(InputRecord::probe(INJECT_SETTLE_PROBE.to_vec()));\n 4770|        thread::sleep(INJECT_SETTLE_POLL);\n 4771|        if recover_log(log).high_water() > baseline {\n\n 4773|        }\n\n 4841|/// the first chunk lands.\n 4842|// [impl->REQ-INJECT-MULTILINE-INTEGRITY]\n-4843|fn enqueue_text_chunked(input: &InputWriter, bytes: Vec<u8>) {\n+4867|fn enqueue_text_chunked(input: &InputWriter, attempt: &Arc<DeliveryAttempt>, bytes: Vec<u8>) {\n+4868|    let mut remaining = bytes.len();\n 4844|    chunk_text(&bytes, inject_text_chunk(), |part| {\n-4845|        input.enqueue(part.to_vec());\n+4870|        remaining -= part.len();\n+4871|        input.enqueue_record(InputRecord::delivery(\n+4872|            part.to_vec(),\n+4873|            attempt,\n+4874|            DeliveryPart::Text { end: remaining == 0 },\n+4875|        ));\n 4846|    });\n 4847|}\n 4898|    let mut disconnected = false;\n 4899|    let mut sent_text: Vec<u8> = Vec::new();\n+4930|    let delivery = Arc::new(DeliveryAttempt::default());\n 4900|    loop {\n 4901|        let now = Instant::now();\n\n 4906|        match cmd_rx.recv_timeout(remaining) {\n 4907|            Ok(KeyCmd::Key { key }) => {\n 4908|                if let Some(bytes) = key_to_bytes(&key) {\n-4909|                    input.enqueue(bytes);\n+4940|                    input.enqueue_record(InputRecord::delivery(\n+4941|                        bytes,\n+4942|                        &delivery,\n+4943|                        DeliveryPart::Key,\n+4944|                    ));\n 4910|                }\n 4911|            }\n 4912|            Ok(KeyCmd::Text { text }) => {\n\n 4914|                let bytes = text.into_bytes();\n 4915|                sent_text.extend_from_slice(&bytes);\n-4916|                enqueue_text_chunked(input, bytes);\n+4951|                enqueue_text_chunked(input, &delivery, bytes);\n 4917|            }\n 4918|            Ok(KeyCmd::Delay { delay_ms }) => {\n\n 4922|            }\n\n 4932|        }\n 4933|    }\n+4969|    // Logical Commit (or timeout/death) does not certify queued bytes. Each\n+4970|    // record retains this attempt until the physical writer confirms it.\n 4934|    // Flush buffered controller input AFTER the injected bytes + release the floor —\n 4935|    // in EVERY exit path (the ANTI-STALL guarantee).\n 11020|        let w = InputWriter {\n 11021|            tx,\n+11059|            deliveries: Arc::new(DeliveryBytes::default()),\n 11022|            backpressure: AtomicBool::new(false),\n 11023|            endpoint: String::new(),\n\n 11025|        };\n\n 11031|    /// through a single consumer that applies each record to a stub `SessionSurface`\n 11032|    /// recording the bytes it receives — EXACTLY mirroring the production\n-11033|    /// `input_writer` loop (`while let Ok(b) = rx.recv() { surface.write_input(&b) }`).\n+11071|    /// `input_writer` loop via the same source-tagged record's `write_to` seam.\n 11034|    /// One FIFO + one writer ⇒ exact input order. Non-vacuous: a reorder/LIFO/dedup\n 11035|    /// mutation of the single-writer contract makes the recorded sequence diverge.\n 11075|        // writer exactly as `input_writer` does.\n 11076|        drop(w);\n-11077|        while let Ok(bytes) = rx.recv() {\n-11078|            surface.write_input(&bytes).unwrap();\n+11115|        let deliveries = DeliveryBytes::default();\n+11116|        while let Ok(record) = rx.recv() {\n+11117|            record.write_to(&surface, &deliveries);\n 11079|        }\n 11080|\n 12159|        // calls (a re-driven keystroke must not double-type into the paste).\n 12160|        drop(w);\n-12161|        let drained: Vec<Vec<u8>> = std::iter::from_fn(|| rx.recv().ok()).collect();\n+12200|        let drained: Vec<Vec<u8>> = std::iter::from_fn(|| rx.recv().ok())\n+12201|            .map(InputRecord::into_bytes)\n+12202|            .collect();\n 12162|        assert_eq!(\n 12163|            drained,\n\n 12168|        );","firstChangedLine":4165,"op":"update","path":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\broker.rs","snapshotsPruned":true},"isError":false,"timestamp":1789295666285}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_EZ1Vf37xE8yEkvftrhWy1KJO|fc_0b12df87254bb4e6016aa67c3dfef087d1ac60a1148b9be06d","toolName":"read","startedAt":"2026-09-13T10:34:38.391Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/translation.rs:169-220"},"intent":"Reading controller floor interface"},"id":"272bf4d3","parentId":"27f628ff","timestamp":"2026-09-13T10:34:38.391Z"}
{"type":"message","id":"58031bde","parentId":"272bf4d3","timestamp":"2026-09-13T10:34:38.393Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Testing partial sink failures**\n\n**Adding partial-write tests**"},{"type":"toolCall","id":"call_EZ1Vf37xE8yEkvftrhWy1KJO|fc_0b12df87254bb4e6016aa67c3dfef087d1ac60a1148b9be06d","name":"read","arguments":{"i":"Reading controller floor interface","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/translation.rs:169-220"},"intent":"Reading controller floor interface"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":2778,"output":250,"cacheRead":50432,"cacheWrite":0,"totalTokens":53460,"reasoningTokens":202,"cost":{"input":0.027780000000000003,"output":0.0125,"cacheRead":0.050432,"cacheWrite":0,"total":0.090712}},"stopReason":"toolUse","timestamp":1789295666323,"responseId":"resp_0b12df87254bb4e6016aa67c32864487d1b13a9878c2768073","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c36dd0487d197a89fe5081ce613","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnw9l71NcjNB_nHSr_UaKPWpJhhOj76AIwkwUlODo0zKNF4tvvC_VeNuhCIoDrhT8b-M-OkzrCh24usfb9IR6H1lgZnu8l0Gw1OdTEYgN652IYy2WlVuh7AqGPzdZm2l8717uXZQKgMiqGEaSZzHHwnyycPWgiQsNbSq8LqrQdBjjZGKnMi1CMmZTCXLprOj7ITml6-kPwSWNMjU3r3hHgeke2BCFs3Hk8O_XifWQjfFe7UsKWxghcUbVKUSEI1sWpFCT6cPxqWFvstDLE_79J3q4Ja-Qp3cLHC0LqRfrkdKDQpQWGGas0dAcKaVj3niNtaa7KEaG3eBAaEEk14zeQAHikEe-nrwiP6MV2rFPdHhnDpwIg5V5OVej-zacaryTjGSgLd73IFCNzOB8ErTcXiO7qpLf-cMpQslfjJQD-K3lm94QLbbVcfdJ_aBT9mV-LhUxGAay2YL1e_PkfXgGvBAuhy8fCP-oSyFisEuIYixB_zON3Bxus6p2xjZH14mZ9Ig8TEgs1fj8BD0egEVuaBFVhpXHDoO2URIqj8G-AbowJNL7RJK_HyIjrFg3FhIDzExmAkYD3efbEeOJjW3tTosQlI0-owSI8x_yr8n2wqxQKmCgoEom7FNBwknK5vK4PhO6rSZhl98-Wpf7h9EguB5LFehl6KF-Roa6WkSvzd8KOcxJti-J9P6kzJEmsKkftj5FxwQ1T-hJNO35j0hvz7wFKGVL4cGytvC7ovo-V4NPTLmbGREsiowkqK1Jj2tn3HPCT5wMbVBdJafZNIutXA3yC0h1gtHGDdo3bNayehDCEx-O18sNQ9oJA-wSfnnydr1op70HlbYZRxGsEGOxxaWOAZTfddlsaErc2L8i3Q_yL82eFUNgwaV5iv3v2Qa0CfMDPGYiSndNMnu4DLJc7r13BDs8YvaeSC1CTsamuApTl2XTEyEPHm77IpznJW0JHg7io5YK34qz_FuH6mm8mj-oE2GjmltiUF3I13K1PTB3sF0CQCliR8bNTsHSG1qyXAYmyN8uN5ePGRwS8JI8bPCmqtEZ4n69r2BvvtdjBxsNXZiEqXnNXax0v-vYjHwafhN3IBqtU4a6cbT5NpJ78tG-6ql5VaqqU1VclvNObFf29XhLE8j5vjtykjdK-UtGHTOb-LXEKruD9O7A7Zh1jHvDrkDBCJyw57eNksUZfdoL5t5A72gjCKLta6va3waL2-PtqVgEltuhWiLwSQZV-xAcHFIXz7qiVqHkqfy32j-tRVs5VVvLq0URXww218QjOEXap79BDkaVvIZmk0ToyNQPTCtvET6Czz5WKxotW1wnOjOJLXbUIsstxNyASNCSgiV_qntZOcjSchYXUAuzCC3y5nVBTUVbbqjBsiCSQqpL0LahBh9U9TwZpKI2K8d42QqhcM61_es52FWUytB8_1AEKS5-3ivYziRXGCeVuzNc7ikAAPU6SWdY82HnHRzXRJ3hBnk3I8ZnZszDqIPG8k6enMKS4GbadIk876Uj7ElNGFM00ot7eEc03o8iXuKnp8fb0zZBS_OHu2YcwMfP6IJojUIT39vLlaR93j-FAPlRV9iOUUvRLllGi7BDbeVSICfStBFkfzM_RwtBeC7DS8UhLcz43Cpk2GLhmMgm5G5YpffcfsI1pBo6iZVBQ9NNYdRK2C3ohTcTRCjf8zuMh3u1a_s0NgUqd-bEEt4E1uBvWg2y6DBy5P_JIjjn1yUTCdynTniLz9wwpBjTr39XEP-GVDStl7h19OenY5Ri7WCmr2-3SXt6_uWCMoKOk93Ci00zGJrCCcw5I-pAD2X__UMhiWZrBxJ6YW-3bv2gpmt1038AzR7IsZIuoAt_TLYJqYESlWDPbWm00_T2cDJ8SHiIRXITe8jp8dUHDmjwaRxlKbSoz2BBEOn2irT4YZatCDmNg4Xmy5A7y-qJbwOsFnuelxKfzj1-Xj70cjL5U-eE7Azz9Hq_dinXHN2sKYb6hVbBXn1DPpZV1z-4mrk80tvOJzcqpzBKcn13e0c5ZQN-YAhwP2gAcyHidPOx12MrgfKlZNeTyhvts8_8nJsO9PLx-mYijL0Qw9BOCliZv3yd389OICYZz2Ic1YRIMItZhfInIZ1lbx2tpgkVosVFPgQRDPOIxvHho7KR-tz1GLziHYVVBHXCzLX5gAkoyFFvhZNyuWT4zUTWL8hv9RBA3NZn9vVcAAd90hF4N86gMs83MSNbMwwhMgcDyTez5xkJ0JeuUbHjsplOhc3FucPX4uoIX1XI7dCayY-upZ0wczT9pJwOKUmhHvlmVgxR1ZgkeipocwsSr985MZSQBbtHbPTb5zq0VPlePmMdP47F9lksjKL5u5Gjk-7w89aP5QZ2Uq1cTOdPvxzkoRasUYzxL5giZGuuSPj5pXsLjv-oYp8c12ZSb7CATSuMxj2xtzvi67dbyjNWnnT7MnciB2txUyVlFRNX7Skels-2zPNlo-_ENeKTnPHJnJMn0ufAbZ52BPfZ08lfKBWotLva6gYQVzpb-BTz66pDlbgpREnMLi_9qDD5J3gNXHmnQELlUOA9THNR7HyxXoLNxvB_yh7EOGLfZAUFZCxUdUwh7S0592B7ku5rfOP5VGJaw5PGQ9cfwXS3fmOxIQW1gWqOFyqzVKB8pSfbRV1UJa49UyLYI03YJjcwrJgPD2GRJDH--hko4cZuIgD6l76sYnAvaPlQ3LoKqPZWZywnCg_kiGgRhlsJOa7RXWLXcXcwJqJ_iZoMxrLVimjkAl0Uxj-84L95IWyUmqLd2RL0L93np8qtqX3uWIBPzeDkJzQgh84WhmXlk_Ml_1W_LZTFbYAH6BN7ExUzUhJ7U9MXK2hch-7OK_LAw4=","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Testing partial sink failures**"},{"type":"summary_text","text":"**Adding partial-write tests**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67c3dfef087d1ac60a1148b9be06d","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading controller floor interface\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/translation.rs:169-220\"}","call_id":"call_EZ1Vf37xE8yEkvftrhWy1KJO","internal_chat_message_metadata_passthrough":{"create_time":1789295666.680868,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":12065.565599999973,"ttft":4563.5792000000365,"completedAt":1789295678390,"contextSnapshot":{"promptTokens":53210,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"f804f06c","parentId":"58031bde","timestamp":"2026-09-13T10:34:38.428Z","message":{"role":"toolResult","toolCallId":"call_EZ1Vf37xE8yEkvftrhWy1KJO|fc_0b12df87254bb4e6016aa67c3dfef087d1ac60a1148b9be06d","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/translation.rs#CF0E]\n168:/// a PTY write under a lock the hot input path needs).\n169:#[derive(Debug, Default)]\n170:pub struct InjectFloor {\n171:    held: bool,\n172:    buffer: Vec<u8>,\n173:}\n174:\n175:impl InjectFloor {\n176:    /// Open the floor for a new injected sequence (clears any stale buffer — a\n177:    /// prior sequence always drains to empty before release, so this is belt-and-\n178:    /// braces). Subsequent operator input buffers until [`take_or_release`].\n179:    ///\n180:    /// [`take_or_release`]: InjectFloor::take_or_release\n181:    pub fn open(&mut self) {\n182:        self.held = true;\n183:        self.buffer.clear();\n184:    }\n185:\n186:    /// Whether the floor is currently held (a sequence is mid-flight).\n187:    pub fn is_held(&self) -> bool {\n188:        self.held\n189:    }\n190:\n191:    /// Route one operator-input chunk: if the floor is held, buffer it and return\n192:    /// `true` (the caller must NOT write to the PTY now — it is flushed after the\n193:    /// sequence); if free, return `false` (the caller writes through its normal\n194:    /// path).\n195:    pub fn buffer_if_held(&mut self, bytes: &[u8]) -> bool {\n196:        if self.held {\n197:            self.buffer.extend_from_slice(bytes);\n198:            true\n199:        } else {\n200:            false\n201:        }\n202:    }\n203:\n204:    /// One flush step — call in a loop after `{commit}` / the deadline. If the\n205:    /// buffer holds bytes, take them to write **off-lock** while the floor STAYS\n206:    /// held (so input arriving mid-flush keeps buffering → strict order); when the\n207:    /// buffer is empty, RELEASE the floor and return `None`. Looping until `None`\n208:    /// drains everything and leaves the floor free.\n209:    pub fn take_or_release(&mut self) -> Option<Vec<u8>> {\n210:        if self.buffer.is_empty() {\n211:            self.held = false;\n212:            None\n213:        } else {\n214:            Some(std::mem::take(&mut self.buffer))\n215:        }\n216:    }\n217:}\n218:\n219:/// A live translation-binary child process: its piped stdin (for [`ToBinary`]\n220:/// lines) plus a reader thread that parses [`KeyCmd`] lines off its stdout and\n221:/// forwards them on the caller-supplied channel. The broker owns the receiving\n222:/// end and the atomic PTY apply.\n223:pub struct TranslationChild {\n…\n233:}\n\n[Showing lines 168-223 of 507. Use :224 to continue]"}],"details":{"truncation":{"content":"/// a PTY write under a lock the hot input path needs).\r\n#[derive(Debug, Default)]\r\npub struct InjectFloor {\r\n    held: bool,\r\n    buffer: Vec<u8>,\r\n}\r\n\r\nimpl InjectFloor {\r\n    /// Open the floor for a new injected sequence (clears any stale buffer — a\r\n    /// prior sequence always drains to empty before release, so this is belt-and-\r\n    /// braces). Subsequent operator input buffers until [`take_or_release`].\r\n    ///\r\n    /// [`take_or_release`]: InjectFloor::take_or_release\r\n    pub fn open(&mut self) {\r\n        self.held = true;\r\n        self.buffer.clear();\r\n    }\r\n\r\n    /// Whether the floor is currently held (a sequence is mid-flight).\r\n    pub fn is_held(&self) -> bool {\r\n        self.held\r\n    }\r\n\r\n    /// Route one operator-input chunk: if the floor is held, buffer it and return\r\n    /// `true` (the caller must NOT write to the PTY now — it is flushed after the\r\n    /// sequence); if free, return `false` (the caller writes through its normal\r\n    /// path).\r\n    pub fn buffer_if_held(&mut self, bytes: &[u8]) -> bool {\r\n        if self.held {\r\n            self.buffer.extend_from_slice(bytes);\r\n            true\r\n        } else {\r\n            false\r\n        }\r\n    }\r\n\r\n    /// One flush step — call in a loop after `{commit}` / the deadline. If the\r\n    /// buffer holds bytes, take them to write **off-lock** while the floor STAYS\r\n    /// held (so input arriving mid-flush keeps buffering → strict order); when the\r\n    /// buffer is empty, RELEASE the floor and return `None`. Looping until `None`\r\n    /// drains everything and leaves the floor free.\r\n    pub fn take_or_release(&mut self) -> Option<Vec<u8>> {\r\n        if self.buffer.is_empty() {\r\n            self.held = false;\r\n            None\r\n        } else {\r\n            Some(std::mem::take(&mut self.buffer))\r\n        }\r\n    }\r\n}\r\n\r\n/// A live translation-binary child process: its piped stdin (for [`ToBinary`]\r\n/// lines) plus a reader thread that parses [`KeyCmd`] lines off its stdout and\r\n/// forwards them on the caller-supplied channel. The broker owns the receiving\r\n/// end and the atomic PTY apply.\r\npub struct TranslationChild {\r","truncated":true,"truncatedBy":"lines","totalLines":340,"totalBytes":2140,"outputLines":56,"outputBytes":2140,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":507,"displayContent":{"text":"/// a PTY write under a lock the hot input path needs).\r\n#[derive(Debug, Default)]\r\npub struct InjectFloor {\r\n    held: bool,\r\n    buffer: Vec<u8>,\r\n}\r\n\r\nimpl InjectFloor {\r\n    /// Open the floor for a new injected sequence (clears any stale buffer — a\r\n    /// prior sequence always drains to empty before release, so this is belt-and-\r\n    /// braces). Subsequent operator input buffers until [`take_or_release`].\r\n    ///\r\n    /// [`take_or_release`]: InjectFloor::take_or_release\r\n    pub fn open(&mut self) {\r\n        self.held = true;\r\n        self.buffer.clear();\r\n    }\r\n\r\n    /// Whether the floor is currently held (a sequence is mid-flight).\r\n    pub fn is_held(&self) -> bool {\r\n        self.held\r\n    }\r\n\r\n    /// Route one operator-input chunk: if the floor is held, buffer it and return\r\n    /// `true` (the caller must NOT write to the PTY now — it is flushed after the\r\n    /// sequence); if free, return `false` (the caller writes through its normal\r\n    /// path).\r\n    pub fn buffer_if_held(&mut self, bytes: &[u8]) -> bool {\r\n        if self.held {\r\n            self.buffer.extend_from_slice(bytes);\r\n            true\r\n        } else {\r\n            false\r\n        }\r\n    }\r\n\r\n    /// One flush step — call in a loop after `{commit}` / the deadline. If the\r\n    /// buffer holds bytes, take them to write **off-lock** while the floor STAYS\r\n    /// held (so input arriving mid-flush keeps buffering → strict order); when the\r\n    /// buffer is empty, RELEASE the floor and return `None`. Looping until `None`\r\n    /// drains everything and leaves the floor free.\r\n    pub fn take_or_release(&mut self) -> Option<Vec<u8>> {\r\n        if self.buffer.is_empty() {\r\n            self.held = false;\r\n            None\r\n        } else {\r\n            Some(std::mem::take(&mut self.buffer))\r\n        }\r\n    }\r\n}\r\n\r\n/// A live translation-binary child process: its piped stdin (for [`ToBinary`]\r\n/// lines) plus a reader thread that parses [`KeyCmd`] lines off its stdout and\r\n/// forwards them on the caller-supplied channel. The broker owns the receiving\r\n/// end and the atomic PTY apply.\r\npub struct TranslationChild {\r\n…\n}","startLine":168,"lineNumbers":[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,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,null,233]},"fileSize":22675,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\translation.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":507,"totalBytes":2140,"outputLines":56,"outputBytes":2140,"shownRange":{"start":168,"end":223},"nextOffset":224}}},"isError":false,"timestamp":1789295678426}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_KVwRJmZ80JBG6jPu2DSB6VWn|ctc_0b12df87254bb4e6016aa67c490e4087d1b3f85b9e605f830e","toolName":"edit","startedAt":"2026-09-13T10:34:58.821Z"},"id":"4df9f01b","parentId":"f804f06c","timestamp":"2026-09-13T10:34:58.821Z"}
{"type":"message","id":"4f7d3823","parentId":"4df9f01b","timestamp":"2026-09-13T10:34:58.822Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Adding shared test surface**\n\n**Adding chunk-splitting test**"},{"type":"toolCall","id":"call_KVwRJmZ80JBG6jPu2DSB6VWn|ctc_0b12df87254bb4e6016aa67c490e4087d1b3f85b9e605f830e","name":"edit","arguments":{"input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#4717]\nPUT >115:\n+    #[cfg(test)]\n+    pub(crate) fn into_bytes(self) -> Vec<u8> {\n+        self.bytes\n+    }\n+\nPUT >202:\n+    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    #[test]\n+    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n+        struct PartialFailure(Mutex<Vec<u8>>);\n+        impl SessionSurface for PartialFailure {\n+            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n+                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n+                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n+            }\n+            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n+        }\n+\n+        let ledger = DeliveryBytes::default();\n+        let attempt = Arc::new(DeliveryAttempt::default());\n+        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n+        let partial = PartialFailure(Mutex::new(Vec::new()));\n+        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n+        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n+        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n+        assert!(!ledger.matches(b\"beforemiddleafter\"));\n+        assert!(!ledger.matches(b\"beforeafter\"));\n+        assert!(!ledger.matches(b\"beforemiafter\"));\n+    }\n+\n*** End Patch\n"},"customWireName":"edit"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":1000,"output":628,"cacheRead":53120,"cacheWrite":0,"totalTokens":54748,"reasoningTokens":190,"cost":{"input":0.01,"output":0.031400000000000004,"cacheRead":0.05312,"cacheWrite":0,"total":0.09452}},"stopReason":"toolUse","timestamp":1789295678437,"responseId":"resp_0b12df87254bb4e6016aa67c3eb21087d1a11eb2128d1a2608","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c3ff0a887d1980b77f1ec380bb8","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnxJsD2ZMR9q_gb6MeFhE4SvWpbBZ0Unx0gWne2gkzf0zkqTFsGc1G2KvZpvlhyq9G4BkxdqfyYht7fqreX2Zd01-m6bztiMdx5QmljEyj-qLjNS6wfY_69nMW2ntaGgo073BCQt4IB_nyVoI0t_tmy7d4A3Tlbu31I6luJmirBGAKgTkhbtBq-gXbnBzd1Mlu5449Ivrdv5KHHeUEuuYXSfBMv6zuUGcubr-_9f_e8IBgxHtAgqGFexCKwim4kWtbhA3d0_YYtHgq5MUrVDNQNh7wtddMH8EqqgkGdnYxZcmfHAK_9gCOVzpCOs8ELGRGQqfztnyDFygFJgVd_SglIFYDemwwUUQ_T-W8qUNJJJnUc2P6gvBg-99yGYInbbb2MGscqNaVC5n75X1RyQdQCJzpiqOzVgSTf2815HzHsX-CpuRpdQ1lczsZNZaPQsqynsVxb4bpGRY0rKm2PnA_ptsnKZeEo0DU9tTX5YYw2S-ZiOf17bgtAieqPjBbFLmGxgUhNsSLugfCYJQDM9UEJxpa2OEFbJmY_nluDi8ziUJ4RpgyuGT80PwghoZMJBfn9owbEC1xNeVFC-vagF_BE4L7jLXQe_U-S3W6YR3t9kDgGEdHoamRehO8IcFgaG0Lh7-HUFj12gJ_rMA9e9UvS6HHNF3It4R0bkzpSYW2-sNkuIJYPCXSzVnBES4LWRKk6KinFmw4LfBX-1Zsu7tkmgwRIqBcigIClRZOvvAKQDg6ZSt_gB5j9u2XsbAuL-NyYDUL7i2KEs8F6oERySErSYrUj_T6432lMFArYRZuR8RcJMYAOIDrAquBFsjgps9js-WpnjQU_rkAVK-acT9DCzycKWYI7O40l2uZGaUb0HQ23J0ATtcRg7kARyajfiJ2nH-tD6xHmurn5wJ4nr1yC4Efnq1U9-mwBa2nhkciQ9N9D7DBmGOf17m6hhJxhSNDZ92mAwRruYrVhhHeYqYqqbaiU6CwEVbozWoLCJ1xBUz6OFD8u92OeiSoOrS--LHWC0P9yHdgNXnE54As7Y0yinN8EnoWZ_ZiYgWA8kcqy-RB2z_COWovhJNCRI7oeO4ONWTxeg1gO1tyzzeVH8l7cPzFy06YJo_3ko_OnRlA_KIHgcoc2wRXdWOgfVAKEbGIMlaY0KQs-ZO4yVWrrqodRVXKI8x33mb4ZxJIv3lZnd_KAQPKgEvpYqLh4Tuj3Rqf9iQJwIhJW54BbEqRyDsRPb_sXLkAEytNmxbADeG3qAMfem3nqWyVKOU1LDHcxCg8uLMUZhyQw5YrQQxLAzr9fJAgLB1rnq8GClvvaQkZBhWIiTJyDcc6drJZPCzA0gG19zNTWlLU0YZtF9abcf0hwpkt6Lz3gMmUZ8bwMWE4_5Gl8x1y9WzMXD_DbFVaDDmppXNPXk4nwYICHiv_At2wzWrmquS52rNt7yQRIu35ho2XziZVyEeViCQOZ4OJQXJzwUcaTcdsbW826uLeSp63p1exsVanD0aNsEm58YOYjvRmYUXj5BUj0ZnpyYIBTKNOPqbjmNqCiANETsWVSpid9AkW41xsVzQ3dNhKXEscnyE2I59Iru3hkiqr9kGD-caeTUfaYLXUrGEU6mJONyq-1CZ2d1iIrVccd-GNXy0-IlXGDKad1nnHGmPbhW8RwjkcK_mlvmCQhPk2WItv-Xp7jpHn_PM4lCFXy_I3BgYt-sOnwCF1fGxnulLIl1faKbwogFu0chJwnxfcnpi04Q-Y17i1ouHCJ_gLZ3xPq5rlVgW9X6jBMQkPOuSohh5SDfgW4xjkkjFlVoCzae6wK5DTi4GsegoIRvfVxwVOexDAmQEktHJNI7WqCBftFfYUSlHlLpjuuee_k4ZPabUzHR6CVj9Ps_x0NGDeT2Q99p_1x18Wh5ZcBuHKDXAwm1aNJ24u8IqSsoVXQvuPxfo-VP24nnD6H4WyVAw4U6dPzmnOp1yNxmQc2UaK1WoRyYyntf2umyeaNQRYQ-0IzsuOTRur27jyz-xw3HKCrL4dcsNMjQ1_LztSBpRsw1FFyGUaypkU_9fnsCAG875xza73T-zz8_Lb9u9m9MS8i2Cic3x7CfzEWMrOcsk-Va3TtzTDpgE2GIpclrg4c-TscKvazWeV4yHvfULl7LV_9c2E1pThAACInDmmTLyFJFItjXDPHvJo9WECKdLp2p7ywuGAzytRpkghCH43D5f_r8qL82rnQUEX4-ZqBV8jgSEY-f81SErHCiJo2m5Rkp4-eToEqk4n5TTZ94reyrj51UiZvsbvLHvjQTnZy7CHwXUdy4w0dBWnA3CIt5gLaQSJ85nguBegJBTqABxVF6e_JNSBQ8N9Z3i64exQ6yf1xeJMKxPAVGVdgv1RcHTIlrVTHTWB-bcgAWLgmzu_kyxmYNZSLc7a1QtORlc-Z35H3fsYYYtQ2t08VC0l084BAJhwiYZ3CdT96dLOpuTl1i1oMHWLi0fN3UBbF5Uo9PH654pg2G1zdXnwSIf8f_HbrE--sdBNbnzjevlKsECSOzsPH17wH8i32yPtOtLbip4vNBPhziSLU3RL6B4eaH7WWcoZcV-E4JB-IiZorG89DsW3wy7KeYTZRQLgs6NGAmoV40Bb7lzi230PYas9wMs2YtCTJGKTnmOPSr2Pm-BQKqF85GM--liiXF-lE=","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Adding shared test surface**"},{"type":"summary_text","text":"**Adding chunk-splitting test**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"ctc_0b12df87254bb4e6016aa67c490e4087d1b3f85b9e605f830e","type":"custom_tool_call","status":"completed","call_id":"call_KVwRJmZ80JBG6jPu2DSB6VWn","input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#4717]\nPUT >115:\n+    #[cfg(test)]\n+    pub(crate) fn into_bytes(self) -> Vec<u8> {\n+        self.bytes\n+    }\n+\nPUT >202:\n+    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    #[test]\n+    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n+        struct PartialFailure(Mutex<Vec<u8>>);\n+        impl SessionSurface for PartialFailure {\n+            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n+                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n+                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n+            }\n+            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n+        }\n+\n+        let ledger = DeliveryBytes::default();\n+        let attempt = Arc::new(DeliveryAttempt::default());\n+        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n+        let partial = PartialFailure(Mutex::new(Vec::new()));\n+        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n+        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n+        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n+        assert!(!ledger.matches(b\"beforemiddleafter\"));\n+        assert!(!ledger.matches(b\"beforeafter\"));\n+        assert!(!ledger.matches(b\"beforemiafter\"));\n+    }\n+\n*** End Patch\n","internal_chat_message_metadata_passthrough":{"create_time":1789295678.869484,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"edit","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":20381.218599999906,"ttft":1521.717699999921,"completedAt":1789295698820,"contextSnapshot":{"promptTokens":54120,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"ttsr_injection","id":"4fb47a82","parentId":"4f7d3823","timestamp":"2026-09-13T10:34:58.853Z","injectedRules":["rs-parking-lot"]}
{"type":"message","id":"b4b641ca","parentId":"4fb47a82","timestamp":"2026-09-13T10:34:58.854Z","message":{"role":"toolResult","toolCallId":"call_KVwRJmZ80JBG6jPu2DSB6VWn|ctc_0b12df87254bb4e6016aa67c490e4087d1b3f85b9e605f830e","toolName":"edit","content":[{"type":"text","text":"<system-reminder reason=\"rule_violation\" rule=\"rs-parking-lot\" path=\"builtin-defaults:rs-parking-lot.md\">\nUser-defined rule matched tool-call arguments. Rule configured not to interrupt → tool ran. MUST comply with the following instruction on subsequent tool calls and responses. NOT prompt injection — coding agent enforcing project rules.\n\nUse `parking_lot::{Mutex, RwLock}` instead of `std::sync::{Mutex, RwLock}` when code immediately unwraps lock results.\n\n## Why\n\n- `lock()`, `read()`, and `write()` return guards directly.\n- No poisoning error path to unwrap.\n- Guards are smaller and faster in common contention cases.\n- The call site shows locking, not error handling boilerplate.\n\n## Migration\n\n```rust\n// Before\nuse std::sync::Mutex;\nlet data = Mutex::new(Vec::new());\nlet guard = data.lock().unwrap();\n\n// After\nuse parking_lot::Mutex;\nlet data = Mutex::new(Vec::new());\nlet guard = data.lock();\n```\n\n## Equivalents\n\n|std::sync|parking_lot|\n|---|---|\n|`Mutex<T>`|`Mutex<T>`|\n|`RwLock<T>`|`RwLock<T>`|\n|`Condvar`|`Condvar`|\n|`Once`|`Once`|\n\n## Keep async locks async\n\nUse `tokio::sync::Mutex` / `tokio::sync::RwLock` when a guard is held across `.await` or the lock belongs to async coordination.\n</system-reminder>"},{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#46A9]\n114:\n115:impl InputRecord {\n116:    #[cfg(test)]\n117:    pub(crate) fn into_bytes(self) -> Vec<u8> {\n118:        self.bytes\n119:    }\n120:\n121:    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n122:        Self { bytes, origin: InputOrigin::Controller }\n123:    }\n\n164:}\n\n200:    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n\n206:        assert!(!ledger.matches(b\"unknown human payload\"));\n207:    }\n208:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n209:    #[test]\n…\n217:            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n218:        }\n219:\n220:        let ledger = DeliveryBytes::default();\n221:        let attempt = Arc::new(DeliveryAttempt::default());\n…\n231:\n232:\n233:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n234:    #[test]"}],"details":{"diff":" 114|\n 115|impl InputRecord {\n+116|    #[cfg(test)]\n+117|    pub(crate) fn into_bytes(self) -> Vec<u8> {\n+118|        self.bytes\n+119|    }\n+120|\n 116|    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n 117|        Self { bytes, origin: InputOrigin::Controller }\n 118|    }\n\n 159|}\n\n 195|    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n\n 201|        assert!(!ledger.matches(b\"unknown human payload\"));\n 202|    }\n+208|    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+209|    #[test]\n+210|    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n+211|        struct PartialFailure(Mutex<Vec<u8>>);\n+212|        impl SessionSurface for PartialFailure {\n+213|            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n+214|                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n+215|                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n+216|            }\n+217|            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n+218|        }\n 203|\n+220|        let ledger = DeliveryBytes::default();\n+221|        let attempt = Arc::new(DeliveryAttempt::default());\n+222|        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n+223|        let partial = PartialFailure(Mutex::new(Vec::new()));\n+224|        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n+225|        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n+226|        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n+227|        assert!(!ledger.matches(b\"beforemiddleafter\"));\n+228|        assert!(!ledger.matches(b\"beforeafter\"));\n+229|        assert!(!ledger.matches(b\"beforemiafter\"));\n+230|    }\n+231|\n+232|\n 204|    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n 205|    #[test]","firstChangedLine":115,"op":"update","path":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\deliverybytes.rs","oldText":"//! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\n\nuse sha2::{Digest, Sha256};\nuse spt_term::surface::SessionSurface;\nuse std::collections::HashSet;\nuse std::sync::{Arc, Mutex};\n\n// Digests, not retained payloads. Never evict evidence from a live hosted session:\n// exhaustion disables origin grants with a named reason instead.\nconst MAX_DELIVERY_DIGESTS: usize = 65_536;\n\n#[derive(Default)]\npub(crate) struct DeliveryBytes {\n    completed: Mutex<Completed>,\n}\n\n#[derive(Default)]\nstruct Completed {\n    digests: HashSet<[u8; 32]>,\n    exhausted: bool,\n}\n\nimpl DeliveryBytes {\n    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\n        let digest: [u8; 32] = Sha256::digest(payload).into();\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .digests\n            .contains(&digest)\n    }\n\n    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .exhausted\n            .then_some(\"delivery-evidence-capacity\")\n    }\n\n    fn remember(&self, digest: [u8; 32]) {\n        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n    }\n\n    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        if completed.digests.contains(&digest) {\n            return;\n        }\n        if completed.digests.len() >= limit {\n            completed.exhausted = true;\n        } else {\n            completed.digests.insert(digest);\n        }\n    }\n}\n\n/// One translation attempt; queued records keep its constant-size streaming state\n/// alive until the lone writer has processed them, independently of logical Commit.\n#[derive(Default)]\npub(crate) struct DeliveryAttempt {\n    text: Mutex<AttemptText>,\n}\n\n#[derive(Default)]\nstruct AttemptText {\n    hash: Sha256,\n    has_text: bool,\n    failed: bool,\n}\n\n#[derive(Clone, Copy)]\npub(crate) enum DeliveryPart {\n    Text { end: bool },\n    Key,\n}\n\nimpl DeliveryAttempt {\n    fn failed(&self) {\n        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\n    }\n\n    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\n        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\n        if text.failed {\n            return;\n        }\n        if let DeliveryPart::Text { end } = part {\n            text.hash.update(bytes);\n            text.has_text |= !bytes.is_empty();\n            if end && text.has_text {\n                // Publish each complete Text command's cumulative text, including\n                // exact embedded newlines. Keys are source-tagged controls, never\n                // guessed framing stripped from the reported payload.\n                ledger.remember(text.hash.clone().finalize().into());\n            }\n        }\n    }\n}\n\npub(crate) struct InputRecord {\n    bytes: Vec<u8>,\n    origin: InputOrigin,\n}\n\nenum InputOrigin {\n    Controller,\n    Probe,\n    Delivery {\n        attempt: Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    },\n}\n\nimpl InputRecord {\n    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Controller }\n    }\n\n    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Probe }\n    }\n\n    pub(crate) fn delivery(\n        bytes: Vec<u8>,\n        attempt: &Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    ) -> Self {\n        Self {\n            bytes,\n            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\n        }\n    }\n\n    pub(crate) fn dropped(&self) {\n        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\n            attempt.failed();\n        }\n    }\n\n    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n        // Never hold a custody lock across a potentially wedged physical write.\n        // Ok proves write_all + flush, not harness interpretation. Err may follow\n        // a partial write, whose byte count this API does not expose: do not guess.\n        let success = surface.write_input(&self.bytes).is_ok();\n        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n            if success {\n                attempt.written(&self.bytes, *part, ledger);\n            } else {\n                attempt.failed();\n            }\n        }\n        // A report caused by a separate Enter sees the preceding Text's published\n        // evidence before Enter is written (one FIFO, one writer). A report caused\n        // by Text itself can race between physical completion and this publication;\n        // enqueued bytes cannot honestly close that narrower window.\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use spt_term::surface::{SurfaceError, SurfaceSize};\n\n    struct Sink;\n    impl SessionSurface for Sink {\n        fn write_input(&self, _: &[u8]) -> Result<(), SurfaceError> { Ok(()) }\n        fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn split_multiline_delivery_matches_before_commit_without_normalizing() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        let first = InputRecord::delivery(b\"<EVENT>\\n C:/a\".to_vec(), &attempt, DeliveryPart::Text { end: false });\n        let last = InputRecord::delivery(b\"\\n</EVENT> \".to_vec(), &attempt, DeliveryPart::Text { end: true });\n        let payload = b\"<EVENT>\\n C:/a\\n</EVENT> \";\n        assert!(!ledger.matches(payload));\n        first.write_to(&Sink, &ledger);\n        assert!(!ledger.matches(payload));\n        last.write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        InputRecord::delivery(b\"\\r\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/b\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/a\\n</EVENT>\"));\n        assert!(!ledger.matches(b\"<EVENT>\\r\\n C:/a\\r\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"\\r\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n        let ledger = DeliveryBytes::default();\n        InputRecord::controller(b\"human C:/private\".to_vec()).write_to(&Sink, &ledger);\n        InputRecord::probe(b\"\\x1b[6n\".to_vec()).write_to(&Sink, &ledger);\n        assert!(!ledger.matches(b\"human C:/private\"));\n        assert!(!ledger.matches(b\"\\x1b[6n\"));\n        assert!(!ledger.matches(b\"unknown human payload\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"one\\ntwo\"));\n        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n        let next_attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"three\"));\n        assert!(!ledger.matches(b\"one\\ntwothree\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\n        let ledger = DeliveryBytes::default();\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        assert_eq!(ledger.unavailable_reason(), None);\n        ledger.remember_with_limit(Sha256::digest(b\"second\").into(), 1);\n        assert!(ledger.matches(b\"first\"));\n        assert!(!ledger.matches(b\"second\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-evidence-capacity\"));\n    }\n}\n","newText":"//! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\n\nuse sha2::{Digest, Sha256};\nuse spt_term::surface::SessionSurface;\nuse std::collections::HashSet;\nuse std::sync::{Arc, Mutex};\n\n// Digests, not retained payloads. Never evict evidence from a live hosted session:\n// exhaustion disables origin grants with a named reason instead.\nconst MAX_DELIVERY_DIGESTS: usize = 65_536;\n\n#[derive(Default)]\npub(crate) struct DeliveryBytes {\n    completed: Mutex<Completed>,\n}\n\n#[derive(Default)]\nstruct Completed {\n    digests: HashSet<[u8; 32]>,\n    exhausted: bool,\n}\n\nimpl DeliveryBytes {\n    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\n        let digest: [u8; 32] = Sha256::digest(payload).into();\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .digests\n            .contains(&digest)\n    }\n\n    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .exhausted\n            .then_some(\"delivery-evidence-capacity\")\n    }\n\n    fn remember(&self, digest: [u8; 32]) {\n        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n    }\n\n    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        if completed.digests.contains(&digest) {\n            return;\n        }\n        if completed.digests.len() >= limit {\n            completed.exhausted = true;\n        } else {\n            completed.digests.insert(digest);\n        }\n    }\n}\n\n/// One translation attempt; queued records keep its constant-size streaming state\n/// alive until the lone writer has processed them, independently of logical Commit.\n#[derive(Default)]\npub(crate) struct DeliveryAttempt {\n    text: Mutex<AttemptText>,\n}\n\n#[derive(Default)]\nstruct AttemptText {\n    hash: Sha256,\n    has_text: bool,\n    failed: bool,\n}\n\n#[derive(Clone, Copy)]\npub(crate) enum DeliveryPart {\n    Text { end: bool },\n    Key,\n}\n\nimpl DeliveryAttempt {\n    fn failed(&self) {\n        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\n    }\n\n    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\n        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\n        if text.failed {\n            return;\n        }\n        if let DeliveryPart::Text { end } = part {\n            text.hash.update(bytes);\n            text.has_text |= !bytes.is_empty();\n            if end && text.has_text {\n                // Publish each complete Text command's cumulative text, including\n                // exact embedded newlines. Keys are source-tagged controls, never\n                // guessed framing stripped from the reported payload.\n                ledger.remember(text.hash.clone().finalize().into());\n            }\n        }\n    }\n}\n\npub(crate) struct InputRecord {\n    bytes: Vec<u8>,\n    origin: InputOrigin,\n}\n\nenum InputOrigin {\n    Controller,\n    Probe,\n    Delivery {\n        attempt: Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    },\n}\n\nimpl InputRecord {\n    #[cfg(test)]\n    pub(crate) fn into_bytes(self) -> Vec<u8> {\n        self.bytes\n    }\n\n    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Controller }\n    }\n\n    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Probe }\n    }\n\n    pub(crate) fn delivery(\n        bytes: Vec<u8>,\n        attempt: &Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    ) -> Self {\n        Self {\n            bytes,\n            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\n        }\n    }\n\n    pub(crate) fn dropped(&self) {\n        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\n            attempt.failed();\n        }\n    }\n\n    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n        // Never hold a custody lock across a potentially wedged physical write.\n        // Ok proves write_all + flush, not harness interpretation. Err may follow\n        // a partial write, whose byte count this API does not expose: do not guess.\n        let success = surface.write_input(&self.bytes).is_ok();\n        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n            if success {\n                attempt.written(&self.bytes, *part, ledger);\n            } else {\n                attempt.failed();\n            }\n        }\n        // A report caused by a separate Enter sees the preceding Text's published\n        // evidence before Enter is written (one FIFO, one writer). A report caused\n        // by Text itself can race between physical completion and this publication;\n        // enqueued bytes cannot honestly close that narrower window.\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use spt_term::surface::{SurfaceError, SurfaceSize};\n\n    struct Sink;\n    impl SessionSurface for Sink {\n        fn write_input(&self, _: &[u8]) -> Result<(), SurfaceError> { Ok(()) }\n        fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn split_multiline_delivery_matches_before_commit_without_normalizing() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        let first = InputRecord::delivery(b\"<EVENT>\\n C:/a\".to_vec(), &attempt, DeliveryPart::Text { end: false });\n        let last = InputRecord::delivery(b\"\\n</EVENT> \".to_vec(), &attempt, DeliveryPart::Text { end: true });\n        let payload = b\"<EVENT>\\n C:/a\\n</EVENT> \";\n        assert!(!ledger.matches(payload));\n        first.write_to(&Sink, &ledger);\n        assert!(!ledger.matches(payload));\n        last.write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        InputRecord::delivery(b\"\\r\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/b\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/a\\n</EVENT>\"));\n        assert!(!ledger.matches(b\"<EVENT>\\r\\n C:/a\\r\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"\\r\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n        let ledger = DeliveryBytes::default();\n        InputRecord::controller(b\"human C:/private\".to_vec()).write_to(&Sink, &ledger);\n        InputRecord::probe(b\"\\x1b[6n\".to_vec()).write_to(&Sink, &ledger);\n        assert!(!ledger.matches(b\"human C:/private\"));\n        assert!(!ledger.matches(b\"\\x1b[6n\"));\n        assert!(!ledger.matches(b\"unknown human payload\"));\n    }\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n        struct PartialFailure(Mutex<Vec<u8>>);\n        impl SessionSurface for PartialFailure {\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n            }\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n        }\n\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n        let partial = PartialFailure(Mutex::new(Vec::new()));\n        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n        assert!(!ledger.matches(b\"beforemiddleafter\"));\n        assert!(!ledger.matches(b\"beforeafter\"));\n        assert!(!ledger.matches(b\"beforemiafter\"));\n    }\n\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"one\\ntwo\"));\n        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n        let next_attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"three\"));\n        assert!(!ledger.matches(b\"one\\ntwothree\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\n        let ledger = DeliveryBytes::default();\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        assert_eq!(ledger.unavailable_reason(), None);\n        ledger.remember_with_limit(Sha256::digest(b\"second\").into(), 1);\n        assert!(ledger.matches(b\"first\"));\n        assert!(!ledger.matches(b\"second\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-evidence-capacity\"));\n    }\n}\n"},"isError":false,"timestamp":1789295698853}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_bUzRptfG90o4QMkuS3Y9I89e|fc_0b12df87254bb4e6016aa67c57245887d1bdd99d5538de2cd5","toolName":"grep","startedAt":"2026-09-13T10:35:03.462Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml;.worktrees/300-input-acceptance/crates/spt-daemon/src"},"intent":"Checking available lock dependency"},"id":"4078efeb","parentId":"b4b641ca","timestamp":"2026-09-13T10:35:03.462Z"}
{"type":"message","id":"011cba3d","parentId":"4078efeb","timestamp":"2026-09-13T10:35:03.463Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Checking parking-lot rule**"},{"type":"toolCall","id":"call_bUzRptfG90o4QMkuS3Y9I89e|fc_0b12df87254bb4e6016aa67c57245887d1bdd99d5538de2cd5","name":"grep","arguments":{"i":"Checking available lock dependency","pattern":"parking_lot","path":".worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml;.worktrees/300-input-acceptance/crates/spt-daemon/src","case":true,"gitignore":true,"skip":0},"intent":"Checking available lock dependency"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":1327,"output":90,"cacheRead":54016,"cacheWrite":0,"totalTokens":55433,"reasoningTokens":10,"cost":{"input":0.01327,"output":0.0045000000000000005,"cacheRead":0.054015999999999995,"cacheWrite":0,"total":0.07178599999999999}},"stopReason":"toolUse","timestamp":1789295698884,"responseId":"resp_0b12df87254bb4e6016aa67c531f6c87d1be79b879c7ad94bf","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c54b22887d1a269a653289575d9","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnxXyAz7R_N25E8VURcZgbmxqZuNRB8nwWxc7sv8a7CMWaqCXPtH8p-wfpkjmx0D0Vllkt9DldUKXDMdlifCsQrmdhAJRWbbk4CP2UUyNpa8v1KaY7PiqTYm-aPPlUsYnmghAsZzhDSZdizNj9BM4Gd6WzUc2guR-LeJyp6Ry6seQ6V8KiFIPD2yaM1izVJq5EHzi9xVUcNE-DUe8xq6ZrMepP_tMN43v0EeCutMgR89pawUf99undEaUGUfcn4-ADMYWGowjOc8yMqLCHtBFHDMeibEgPR1C8uBHcAQau4jgi-5pC8KhQs7p6vUPvOHdWj2pezDfDnCP96rQMoajeuSPV6PMQvSGomDx5TS2zNWQqBNfMkSjAx5kMPd8yenFk0mw-hvvR-Aj-QGKAF-9Ep_BOmxGt734kdnjARZNELf-4va2fRv2SvWYENhJjrRo6-5QqE5nQ9QLVvwp9k3LtvMVtibF8SXdJFbejrkuCInyUGqD21HDQddiu3FaZqpgPunGRzjn2AVi74PHXpthc7WpnO1O6GePFqJNinuuoqIP_wkPWXX-mcruUcNz_01ZXDRsSqCyvLqazIkI_3kiTf1-wXBE_37u-9sIikH_r_S_NX74QadiLxiwQ3Ch8DOPceWA_PDjqSjQm_nWQ61-CNfW7BzmYlnJpzCLz-pIAgMlhXuXEiGfEaqmHIFjFYVRlhmptzi1i1l14DD-Qd80OXoNn_xJ_eb2Drgli1_0PWzrECP47K516fSmeavOf3xKXW_yNKggZCVKOd4h8xu9gaBbOmY8QdOBveqk6E1oOr_4hxxUlfNGXUDHuBLqmFH-u5MM7eZt-3_y6r3egP-_QGZNC_eW8Azb9IiswQS__JoqOS0aArbKmK41JEMZrJcFC7Yh6SIgbMZTD5kFjqsB3LNg65gBg1TmxVYDYpoQZ1REs9be5SSCDNEr6mMXFdpE-scC6UQ_Hhnc7hRh6lWehOgIDLqe9_1D9OnnKxh8z5tVl-uPIabCLgLJUXiPb8LcA7sAkBnZGnIZYqj9qrDtju5JY3o97CEaLfDr-3E-Y5EDgKKwM9ksxpRleric6SJr2r2B_K-rpLtpahvLQR6f2czkYgPlYiNPF4CYN0g7RgFa1F7v-JCOwSovQVDJ4hlizgerSbu1LBeuIg-Wgq_nfUvF25ZgT1QKoAUyZ0jn76UZcvTIeMx3LXXMe_HlQXhs_ZclPG8otyOl9Ctf1ziQqlGHabAv6qvLfurLIcyK0J44NQrMkqRSzllqf5SCEKGK81FsJIT6KxQ2_jsW5zSaak46Al2KasKWuSU-fxPI6PaAUo=","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Checking parking-lot rule**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67c57245887d1bdd99d5538de2cd5","type":"function_call","status":"completed","arguments":"{\"i\":\"Checking available lock dependency\",\"pattern\":\"parking_lot\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml;.worktrees/300-input-acceptance/crates/spt-daemon/src\",\"case\":true,\"gitignore\":true,\"skip\":0}","call_id":"call_bUzRptfG90o4QMkuS3Y9I89e","internal_chat_message_metadata_passthrough":{"create_time":1789295699.28654,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"grep","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":4575.677100000088,"ttft":1836.5095999999903,"completedAt":1789295703461,"contextSnapshot":{"promptTokens":55343,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"31c579e5","parentId":"011cba3d","timestamp":"2026-09-13T10:35:03.491Z","message":{"role":"toolResult","toolCallId":"call_bUzRptfG90o4QMkuS3Y9I89e|fc_0b12df87254bb4e6016aa67c57245887d1bdd99d5538de2cd5","toolName":"grep","content":[{"type":"text","text":"No matches found"}],"details":{"scopePath":".worktrees/300-input-acceptance/crates/spt-daemon/Cargo.toml, .worktrees/300-input-acceptance/crates/spt-daemon/src","searchPath":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon","cwd":"C:\\Users\\decid\\Documents\\projects\\spt-core","matchCount":0,"fileCount":0,"files":[],"truncated":false},"isError":false,"useless":true,"timestamp":1789295703490}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_B7BMLnv1RFXdFB472ntDYDtB|ctc_0b12df87254bb4e6016aa67c5dcba087d1b08f1c63043851ea","toolName":"edit","startedAt":"2026-09-13T10:35:33.588Z"},"id":"d1ffc691","parentId":"31c579e5","timestamp":"2026-09-13T10:35:33.588Z"}
{"type":"message","id":"9455b28f","parentId":"d1ffc691","timestamp":"2026-09-13T10:35:33.588Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Checking test recovery consistency**"},{"type":"toolCall","id":"call_B7BMLnv1RFXdFB472ntDYDtB|ctc_0b12df87254bb4e6016aa67c5dcba087d1b08f1c63043851ea","name":"edit","arguments":{"input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#8B20]\nPUT >11065:\n+    struct InputCustodySurface;\n+\n+    impl SessionSurface for InputCustodySurface {\n+        fn write_input(&self, _: &[u8]) -> Result<(), spt_term::surface::SurfaceError> {\n+            Ok(())\n+        }\n+\n+        fn resize(&self, _: spt_term::surface::SurfaceSize) -> Result<(), spt_term::surface::SurfaceError> {\n+            Ok(())\n+        }\n+    }\n+\n+    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    #[test]\n+    fn input_delivery_queue_drop_never_certifies_missing_text() {\n+        let (input, rx) = test_input_writer(1);\n+        let attempt = Arc::new(DeliveryAttempt::default());\n+        assert!(input.enqueue_record(InputRecord::delivery(\n+            b\"first\".to_vec(), &attempt, DeliveryPart::Text { end: false },\n+        )));\n+        assert!(!input.enqueue_record(InputRecord::delivery(\n+            b\"missing\".to_vec(), &attempt, DeliveryPart::Text { end: false },\n+        )));\n+        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n+        assert!(input.enqueue_record(InputRecord::delivery(\n+            b\"last\".to_vec(), &attempt, DeliveryPart::Text { end: true },\n+        )));\n+        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n+        assert!(!input.delivery_matches(b\"firstmissinglast\"));\n+        assert!(!input.delivery_matches(b\"firstlast\"));\n+\n+        let next_attempt = Arc::new(DeliveryAttempt::default());\n+        assert!(input.enqueue_record(InputRecord::delivery(\n+            b\"next\".to_vec(), &next_attempt, DeliveryPart::Text { end: true },\n+        )));\n+        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n+        assert!(input.delivery_matches(b\"next\"));\n+    }\n+\n+    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    #[test]\n+    fn chunked_delivery_is_visible_before_enter_and_floor_flush_stays_human() {\n+        let (input, rx) = test_input_writer(16);\n+        let attempt = Arc::new(DeliveryAttempt::default());\n+        let text = format!(\"{}\\\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n+        enqueue_text_chunked(&input, &attempt, text.as_bytes().to_vec());\n+        assert!(!input.delivery_matches(text.as_bytes()));\n+        while let Ok(record) = rx.try_recv() {\n+            record.write_to(&InputCustodySurface, &input.deliveries);\n+        }\n+        assert!(input.delivery_matches(text.as_bytes()));\n+        assert!(input.enqueue_record(InputRecord::delivery(\n+            b\"\\r\".to_vec(), &attempt, DeliveryPart::Key,\n+        )));\n+\n+        let floor = Mutex::new(InjectFloor::default());\n+        lock_floor(&floor).open();\n+        assert!(lock_floor(&floor).buffer_if_held(b\"human typeahead C:/private\"));\n+        flush_inject_floor(&floor, &input);\n+        assert!(input.enqueue(b\"direct controller C:/other\".to_vec()));\n+        while let Ok(record) = rx.try_recv() {\n+            record.write_to(&InputCustodySurface, &input.deliveries);\n+        }\n+        assert!(input.delivery_matches(text.as_bytes()));\n+        assert!(!input.delivery_matches(b\"human typeahead C:/private\"));\n+        assert!(!input.delivery_matches(b\"direct controller C:/other\"));\n+        assert!(!input.delivery_matches(b\"\\r\"));\n+    }\n+\n*** End Patch\n"},"customWireName":"edit"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":279,"output":962,"cacheRead":55168,"cacheWrite":0,"totalTokens":56409,"reasoningTokens":101,"cost":{"input":0.0027900000000000004,"output":0.048100000000000004,"cacheRead":0.055167999999999995,"cacheWrite":0,"total":0.106058}},"stopReason":"toolUse","timestamp":1789295703534,"responseId":"resp_0b12df87254bb4e6016aa67c57b71487d19102e065fd8f929d","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c58b4e087d19d36af9cfd8ad41a","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnxdXdvo7-pVBbRbAkxJSzOer5FFR2Xyi6YB0Ys2ZhUXOs9M57effCBxS5Zn-ORY8pDihJa4PLXRVE3obcniJxKuW-od0aTDykEGCwRC4bWuAw2YZfnCUeOVQqO7viP2QlQ-q7-Su4MsGu4pKlWceydIzrjMQ6EpV9gG06zkgIOPw5HwKrDo3Nr3YQkT0OYjhwLE902w49cHs0tLHXlZywrwg0mJvwipAuk7rXm8PQ_sQP9R0Zj9DJAoP8tk8YHe5gMw47ACErpwVQS0RISkZlx_oHoaL2NtOzxRTBctbCG0Za4sL_Nh-BBVNl_fDg9TtkvAhHglxbXfY0wE2Cy8SQg4yiNtYsr5pvUE_7uHbj8Yv7D07CwAmPhdqF7JUW7JIzAxZAbQWjrUjYzwJnf0MEOPU_oMqHMDNkkIDZP7gElLjxUz51GwiPHQ7Xs5QK554h94HOPvO64aTlKVm09xY63Zi06HY5VpPZvn0jff2rZIKX1dGWRv71enXY3Ul3uiV64ALlfmCGmVUQ1cOhp5W6ESlvO0H3Gsl9L8H31PAYuyZsAtOlexNkIizYimXVks9Mh526WL_PyNXzPBGV1BG_OS7yckUo5EauwpGEFa2hrieQDOKhjGvAoE47H1VJgy4FpVC4tGuRdyEIl7vmJ6i95PILNtJdW-_bGgY0Rj8wE0dkekqcRDCXp5mY12yPUG5HcnmdRV4e08AOFeb2aP8awdwNTgiYROrFZRynH9omrBNgT0M4CtPDEF5ZcIgmJrf8tXS3jgvp4z5XC6qLWD2RcH3EyDq1si5WHbLJly9lZSdeSmAC77hE1PY2MGNRqD2KAt2kzcMWD3vpvPFx8A1yjV5kGbuFsWc_gQU2zZsvL82Zy2PlRCz62g1q9Zch1lBuW_rLmhbScYUjnyxacN7lDcJOb_46UeW1RwV7r6z8CfBXTABd9Ww8J8_AitcAGaaW6_Qo7-t44XtLj6eF6fmAg1ALEpH1UfEInsmyGu40UOa4yqIIkAQiL8bFPzhVtID3D0Gho2bc73tf7rXhXxtRcy1ksD1fCAqM-vQSnESIMoBTB2h_F-W2SQukHYoKaYC9oAWyBCEl8T-XDua15n-_JBfZfDm7Eb6L8HP8CeQ3ySl1ZJB8oZkH9fi0YtA8uRjTWnMCrzXBa6rymLml-PSDpMVLOzcRCrcWbnV7TcxHorSzbmpiALN7wBCyfMM-p1EeMpeybg-zyMjoLEMU8j8ixRX6e3IPeqGC_EoaliLWw2Xc2RtFAyQKHnbhuBe7gKlVGM1lYt2VpkRXcjYtZAt5rdBCvlIn9fZU8mBJLqmcDS4V0fDMqTqxi5rnMi0hyBH2ZeNRsEkWvxEOZf68Z3_kSS5-DfYrw3V1SqyHGdErQWbnot3mSzv2QflAL9VH7ZXv-9hvMd053DsS0xpQnzSZFkDjAUmwLdRRaX-ZcZ2Ibn2Rs91O502TbExQBygZeXHnVGZTXzzlnr5tyjyOMTMLfOYrsOKRDW7iygSGbw_NS7b5KO_1j6Ulmv685d64JO2ZgiH-DxJutNXzmIdKpFN_rJZo-VCQgYDu3EATwHyynB8nWDgBcl22iyb2OXB3CL1LgZunlfyDmGefCc1FyB_jULtJUvgY_94GY2QeeFcuzFkjb6qHnuOCPUwRfQA2f-yv2KOtmDjjFcy25PSZDc7epgpJmYQxLv8LbFM2Nbz_A3tcBJC2UXi3YeZgw0fCXaVyGHFLElNmMnIrIdPBV2CN_gkz98u5AaNDbt6xP9nDGkxrBWbzeOKGYHRX0IWlQsfCEFrBQbt2bshOMT-Ep21ID_Jfqfl-BOHKhdInFGKHBppHHmNASEgabmNCoUE2nNPti-oa6cpRdT2XjQwik7EunjG8bv8vyL3YddtamzM7e3_9VziyYcTN_iYEcnewWo2UhknGJoJDf-IeEQ2Z4Ofxju68URqfeq3jPublO_a1jD62ELfLKAT90B8I2HcoZmuQp4wMwHRV-vTFf6YcIQ1YlTZAKcFKwNd7V5VBsCX8G9U9msfRs8ON15z6VMNDBJ6NGa","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Checking test recovery consistency**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"ctc_0b12df87254bb4e6016aa67c5dcba087d1b08f1c63043851ea","type":"custom_tool_call","status":"completed","call_id":"call_B7BMLnv1RFXdFB472ntDYDtB","input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#8B20]\nPUT >11065:\n+    struct InputCustodySurface;\n+\n+    impl SessionSurface for InputCustodySurface {\n+        fn write_input(&self, _: &[u8]) -> Result<(), spt_term::surface::SurfaceError> {\n+            Ok(())\n+        }\n+\n+        fn resize(&self, _: spt_term::surface::SurfaceSize) -> Result<(), spt_term::surface::SurfaceError> {\n+            Ok(())\n+        }\n+    }\n+\n+    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    #[test]\n+    fn input_delivery_queue_drop_never_certifies_missing_text() {\n+        let (input, rx) = test_input_writer(1);\n+        let attempt = Arc::new(DeliveryAttempt::default());\n+        assert!(input.enqueue_record(InputRecord::delivery(\n+            b\"first\".to_vec(), &attempt, DeliveryPart::Text { end: false },\n+        )));\n+        assert!(!input.enqueue_record(InputRecord::delivery(\n+            b\"missing\".to_vec(), &attempt, DeliveryPart::Text { end: false },\n+        )));\n+        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n+        assert!(input.enqueue_record(InputRecord::delivery(\n+            b\"last\".to_vec(), &attempt, DeliveryPart::Text { end: true },\n+        )));\n+        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n+        assert!(!input.delivery_matches(b\"firstmissinglast\"));\n+        assert!(!input.delivery_matches(b\"firstlast\"));\n+\n+        let next_attempt = Arc::new(DeliveryAttempt::default());\n+        assert!(input.enqueue_record(InputRecord::delivery(\n+            b\"next\".to_vec(), &next_attempt, DeliveryPart::Text { end: true },\n+        )));\n+        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n+        assert!(input.delivery_matches(b\"next\"));\n+    }\n+\n+    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    #[test]\n+    fn chunked_delivery_is_visible_before_enter_and_floor_flush_stays_human() {\n+        let (input, rx) = test_input_writer(16);\n+        let attempt = Arc::new(DeliveryAttempt::default());\n+        let text = format!(\"{}\\\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n+        enqueue_text_chunked(&input, &attempt, text.as_bytes().to_vec());\n+        assert!(!input.delivery_matches(text.as_bytes()));\n+        while let Ok(record) = rx.try_recv() {\n+            record.write_to(&InputCustodySurface, &input.deliveries);\n+        }\n+        assert!(input.delivery_matches(text.as_bytes()));\n+        assert!(input.enqueue_record(InputRecord::delivery(\n+            b\"\\r\".to_vec(), &attempt, DeliveryPart::Key,\n+        )));\n+\n+        let floor = Mutex::new(InjectFloor::default());\n+        lock_floor(&floor).open();\n+        assert!(lock_floor(&floor).buffer_if_held(b\"human typeahead C:/private\"));\n+        flush_inject_floor(&floor, &input);\n+        assert!(input.enqueue(b\"direct controller C:/other\".to_vec()));\n+        while let Ok(record) = rx.try_recv() {\n+            record.write_to(&InputCustodySurface, &input.deliveries);\n+        }\n+        assert!(input.delivery_matches(text.as_bytes()));\n+        assert!(!input.delivery_matches(b\"human typeahead C:/private\"));\n+        assert!(!input.delivery_matches(b\"direct controller C:/other\"));\n+        assert!(!input.delivery_matches(b\"\\r\"));\n+    }\n+\n*** End Patch\n","internal_chat_message_metadata_passthrough":{"create_time":1789295703.871258,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"edit","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":30051.606600000057,"ttft":1191.1659000000218,"completedAt":1789295733586,"contextSnapshot":{"promptTokens":55447,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"86f72c4f","parentId":"9455b28f","timestamp":"2026-09-13T10:35:33.843Z","message":{"role":"toolResult","toolCallId":"call_B7BMLnv1RFXdFB472ntDYDtB|ctc_0b12df87254bb4e6016aa67c5dcba087d1b08f1c63043851ea","toolName":"edit","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#CAD3]\n11055:    fn test_input_writer(depth: usize) -> (InputWriter, Receiver<InputRecord>) {\n\n11064:        (w, rx)\n11065:    }\n11066:    struct InputCustodySurface;\n11067:\n11068:    impl SessionSurface for InputCustodySurface {\n11069:        fn write_input(&self, _: &[u8]) -> Result<(), spt_term::surface::SurfaceError> {\n…\n11134:\n11135:\n11136:    /// Drain ORDER: records enqueued in sequence reach the sole writer in strict\n11137:    /// FIFO order. We drive the REAL `enqueue` into the REAL channel, then drain it"}],"details":{"diff":" 11055|    fn test_input_writer(depth: usize) -> (InputWriter, Receiver<InputRecord>) {\n\n 11064|        (w, rx)\n 11065|    }\n+11066|    struct InputCustodySurface;\n 11066|\n+11068|    impl SessionSurface for InputCustodySurface {\n+11069|        fn write_input(&self, _: &[u8]) -> Result<(), spt_term::surface::SurfaceError> {\n+11070|            Ok(())\n+11071|        }\n+11072|\n+11073|        fn resize(&self, _: spt_term::surface::SurfaceSize) -> Result<(), spt_term::surface::SurfaceError> {\n+11074|            Ok(())\n+11075|        }\n+11076|    }\n+11077|\n+11078|    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+11079|    #[test]\n+11080|    fn input_delivery_queue_drop_never_certifies_missing_text() {\n+11081|        let (input, rx) = test_input_writer(1);\n+11082|        let attempt = Arc::new(DeliveryAttempt::default());\n+11083|        assert!(input.enqueue_record(InputRecord::delivery(\n+11084|            b\"first\".to_vec(), &attempt, DeliveryPart::Text { end: false },\n+11085|        )));\n+11086|        assert!(!input.enqueue_record(InputRecord::delivery(\n+11087|            b\"missing\".to_vec(), &attempt, DeliveryPart::Text { end: false },\n+11088|        )));\n+11089|        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n+11090|        assert!(input.enqueue_record(InputRecord::delivery(\n+11091|            b\"last\".to_vec(), &attempt, DeliveryPart::Text { end: true },\n+11092|        )));\n+11093|        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n+11094|        assert!(!input.delivery_matches(b\"firstmissinglast\"));\n+11095|        assert!(!input.delivery_matches(b\"firstlast\"));\n+11096|\n+11097|        let next_attempt = Arc::new(DeliveryAttempt::default());\n+11098|        assert!(input.enqueue_record(InputRecord::delivery(\n+11099|            b\"next\".to_vec(), &next_attempt, DeliveryPart::Text { end: true },\n+11100|        )));\n+11101|        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n+11102|        assert!(input.delivery_matches(b\"next\"));\n+11103|    }\n+11104|\n+11105|    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+11106|    #[test]\n+11107|    fn chunked_delivery_is_visible_before_enter_and_floor_flush_stays_human() {\n+11108|        let (input, rx) = test_input_writer(16);\n+11109|        let attempt = Arc::new(DeliveryAttempt::default());\n+11110|        let text = format!(\"{}\\\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n+11111|        enqueue_text_chunked(&input, &attempt, text.as_bytes().to_vec());\n+11112|        assert!(!input.delivery_matches(text.as_bytes()));\n+11113|        while let Ok(record) = rx.try_recv() {\n+11114|            record.write_to(&InputCustodySurface, &input.deliveries);\n+11115|        }\n+11116|        assert!(input.delivery_matches(text.as_bytes()));\n+11117|        assert!(input.enqueue_record(InputRecord::delivery(\n+11118|            b\"\\r\".to_vec(), &attempt, DeliveryPart::Key,\n+11119|        )));\n+11120|\n+11121|        let floor = Mutex::new(InjectFloor::default());\n+11122|        lock_floor(&floor).open();\n+11123|        assert!(lock_floor(&floor).buffer_if_held(b\"human typeahead C:/private\"));\n+11124|        flush_inject_floor(&floor, &input);\n+11125|        assert!(input.enqueue(b\"direct controller C:/other\".to_vec()));\n+11126|        while let Ok(record) = rx.try_recv() {\n+11127|            record.write_to(&InputCustodySurface, &input.deliveries);\n+11128|        }\n+11129|        assert!(input.delivery_matches(text.as_bytes()));\n+11130|        assert!(!input.delivery_matches(b\"human typeahead C:/private\"));\n+11131|        assert!(!input.delivery_matches(b\"direct controller C:/other\"));\n+11132|        assert!(!input.delivery_matches(b\"\\r\"));\n+11133|    }\n+11134|\n+11135|\n 11067|    /// Drain ORDER: records enqueued in sequence reach the sole writer in strict\n 11068|    /// FIFO order. We drive the REAL `enqueue` into the REAL channel, then drain it","firstChangedLine":11065,"op":"update","path":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\broker.rs","snapshotsPruned":true},"isError":false,"timestamp":1789295733842}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_qPPn07aY2YIkuOogzWFRKEBC|fc_0b12df87254bb4e6016aa67c7c63c887d192b2da2af9e4e2c4","toolName":"read","startedAt":"2026-09-13T10:35:40.503Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:11100-11115"},"intent":"Locating multiline test literal"},"id":"a8a55db3","parentId":"86f72c4f","timestamp":"2026-09-13T10:35:40.503Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_9cg2xV7Oe8Nn2FBsTZACR4nI|fc_0b12df87254bb4e6016aa67c7c63dc87d199d232414d0f755e","toolName":"read","startedAt":"2026-09-13T10:35:40.504Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs:208-233"},"intent":"Locating new partial failure locks"},"id":"b9764aac","parentId":"a8a55db3","timestamp":"2026-09-13T10:35:40.504Z"}
{"type":"message","id":"38c31f89","parentId":"b9764aac","timestamp":"2026-09-13T10:35:40.504Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Inspecting test lines**"},{"type":"toolCall","id":"call_qPPn07aY2YIkuOogzWFRKEBC|fc_0b12df87254bb4e6016aa67c7c63c887d192b2da2af9e4e2c4","name":"read","arguments":{"i":"Locating multiline test literal","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:11100-11115"},"intent":"Locating multiline test literal"},{"type":"toolCall","id":"call_9cg2xV7Oe8Nn2FBsTZACR4nI|fc_0b12df87254bb4e6016aa67c7c63dc87d199d232414d0f755e","name":"read","arguments":{"i":"Locating new partial failure locks","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs:208-233"},"intent":"Locating new partial failure locks"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":1287,"output":178,"cacheRead":55296,"cacheWrite":0,"totalTokens":56761,"reasoningTokens":66,"cost":{"input":0.012870000000000001,"output":0.0089,"cacheRead":0.055296,"cacheWrite":0,"total":0.077066}},"stopReason":"toolUse","timestamp":1789295733876,"responseId":"resp_0b12df87254bb4e6016aa67c761cac87d1929b7031a502b0a3","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c77138c87d1b9aff6b6b0ecf601","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnx8anSOTdbF7Ds8496NjdQz9wz02cHAsztdxuZUUO6sDwmAp9JgufIo8LjgJLBQLZTWPwWIzM5tVmUz8tPxCiganUJxqFRb1R1ZFdJ47XSHTDerza2aT-pfvCb0TOlw93DOaodqllTuhyb3vylfGW6dywuBdzXVYQGnisyiru0iSpZEwcTJ0ZKMAMq-ilA7qhbrqrOR0aANadbwHsdQgPj7p0lkKQ591z00p1m-cXNVMqjoCnOT9kZGJDOAbJUpjVqFjayH5afDQwZziv-RhfygO6BXlLuyueBrNQvpz5uUbCpZeuz5UQELhRAFLXc34hrADfKn1Onjf_t8Evq2SkdBGjYfMahi8XGR3r7pEmJkcwAs_hra8XGOTC-Lrc8nx2Fb-9RZJmtd8f48mEKUTkAa0wnXuKdotii1xn9mdNvtgJYIJjKErbheJ9b3FsLYIT11li5fGc1llJ2Zjp78NR0uNl38L_f-DHwjL_zt6-qOb2bFjlWevrjQAiEqwPsIKdCk-6BOSTTY3Oh3xv8S-yennjuLa8egy73OJDZ67zNty2xkA1EoJPcIEc9BSeLHoWxJE7_zxPOBEvJdKeK7EL3dTLE1X6tEgLoBZAA-Jp-s7Ku9LdJ3nDT3S-KDQ7Hml6bfrwMHRSDXuvt49wPvjp8oGwPXrqGWZUo0Gr6axTZ92S6mV9vQ3943ZVvtvGj_UTsIeI2bVfP4e7mi_4a8aTTCjHpgDqdKKduIKUsWd4UxKpmByuErvqMmCTQXxGeSu73SSebANEue-aHilD-UWV1pJgZ5kAkSKTayH2LMVyDPugnFUkOLcXbsVd8kZW0T5OypstqdOp7rP3v-Wmwho4WRamTRi7JKQIUF2Hya8hLWrDmD1q5-Gkh-QU1-gxsycH0PU8ayZR1qNg3gF4e73MgRsjbw-8PnrgQEEaQBSJS21S1nM4e-2TqNCG0HNS5YKdj2wiM70BLyBfcz0-r2mrjcoRaZS5ZmxEgOlV9Ln9yLzZjl-kyKjgMZTLD1E9wiW5y_LEhxewwyoIaUvUtAPBkoo9CGavf52cxh3tGNWtHERTdPmCXkZRAQQt3FtTJ8AqXjCQeD53e3RQE4jY1QqdB1FAV6PVBBko07-iqHEsjqtBGZ7iKJJAmc-OG5z71Uf06uwjwcGTysofMLa4UsJ8PG6h3nlkwFsx_-eg9Gya-I96UN-LgiQqx84eEZpykFc-weZWX_8AHF-sZbyUX81-XceqBBsvJHbkAY6MC_nWmCvQWtSxQbjKIXMcmAItMifuYuxIh_bqI27IhdM7-x90nNsAVAMoSRav9w4w-A5Tx4UVCmoGj4wPx9rM1EgUkUYT6CDZhvankEeCFSlL59UH5BbC5pw88G6UI-Um8EFKGt6Ub-zXzjSrjqL7OPUV0_z2M3BGsTEE1EHJSBf8_QGezs51fhJtcVp3cXb635G0jmu75cJyC5wsfDSe8S2WKhvgoa7LG8VZ0LWK1PA8zAvjWmWKsD5jl56xlhN8cikBlMoe6jfVv3EFGtz8wbVCUKBMkZUH7vNqS8aW83BIHPcmS2jNi7gDdnfsbSw9-k2_62mDifmU71GuQm7MC_Pfx4C-drFyzoZ4yPLAmEGQWQlp75japSsO5JasZqSty5zAdMs8uDWSuZSDvBvH_vOI_BDNvkz2ImDHBfiL0l4xAx3Rgz8A==","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Inspecting test lines**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67c7c63c887d192b2da2af9e4e2c4","type":"function_call","status":"completed","arguments":"{\"i\":\"Locating multiline test literal\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs:11100-11115\"}","call_id":"call_qPPn07aY2YIkuOogzWFRKEBC","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67c7c63dc87d199d232414d0f755e","type":"function_call","status":"completed","arguments":"{\"i\":\"Locating new partial failure locks\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs:208-233\"}","call_id":"call_9cg2xV7Oe8Nn2FBsTZACR4nI","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"read","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":6625.471599999932,"ttft":1218.8064000000013,"completedAt":1789295740502,"contextSnapshot":{"promptTokens":56583,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"d5ba6630","parentId":"38c31f89","timestamp":"2026-09-13T10:35:40.517Z","message":{"role":"toolResult","toolCallId":"call_9cg2xV7Oe8Nn2FBsTZACR4nI|fc_0b12df87254bb4e6016aa67c7c63dc87d199d232414d0f755e","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#46A9]\n200:    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n…\n207:    }\n208:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n209:    #[test]\n210:    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n211:        struct PartialFailure(Mutex<Vec<u8>>);\n212:        impl SessionSurface for PartialFailure {\n213:            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n214:                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n215:                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n216:            }\n217:            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n218:        }\n219:\n220:        let ledger = DeliveryBytes::default();\n221:        let attempt = Arc::new(DeliveryAttempt::default());\n222:        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n223:        let partial = PartialFailure(Mutex::new(Vec::new()));\n224:        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n225:        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n226:        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n227:        assert!(!ledger.matches(b\"beforemiddleafter\"));\n228:        assert!(!ledger.matches(b\"beforeafter\"));\n229:        assert!(!ledger.matches(b\"beforemiafter\"));\n230:    }\n231:\n232:\n233:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n234:    #[test]\n235:    fn successful_text_commands_aggregate_without_key_bytes() {\n236:        let ledger = DeliveryBytes::default();\n…\n247:    }\n\n[Showing lines 207-236 of 261. Use :237 to continue]"}],"details":{"truncation":{"content":"    }\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n        struct PartialFailure(Mutex<Vec<u8>>);\n        impl SessionSurface for PartialFailure {\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n            }\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n        }\n\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n        let partial = PartialFailure(Mutex::new(Vec::new()));\n        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n        assert!(!ledger.matches(b\"beforemiddleafter\"));\n        assert!(!ledger.matches(b\"beforeafter\"));\n        assert!(!ledger.matches(b\"beforemiafter\"));\n    }\n\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();","truncated":true,"truncatedBy":"lines","totalLines":55,"totalBytes":1521,"outputLines":30,"outputBytes":1521,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":261,"displayContent":{"text":"    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n…\n    }\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n        struct PartialFailure(Mutex<Vec<u8>>);\n        impl SessionSurface for PartialFailure {\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n            }\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n        }\n\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n        let partial = PartialFailure(Mutex::new(Vec::new()));\n        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n        assert!(!ledger.matches(b\"beforemiddleafter\"));\n        assert!(!ledger.matches(b\"beforeafter\"));\n        assert!(!ledger.matches(b\"beforemiafter\"));\n    }\n\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();\n…\n    }","startLine":200,"lineNumbers":[200,null,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,null,247]},"fileSize":9859,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\deliverybytes.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":261,"totalBytes":1521,"outputLines":30,"outputBytes":1521,"shownRange":{"start":207,"end":236},"nextOffset":237}}},"isError":false,"timestamp":1789295740516}}
{"type":"message","id":"ac45ba6e","parentId":"d5ba6630","timestamp":"2026-09-13T10:35:40.525Z","message":{"role":"toolResult","toolCallId":"call_qPPn07aY2YIkuOogzWFRKEBC|fc_0b12df87254bb4e6016aa67c7c63c887d192b2da2af9e4e2c4","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#CAD3]\n11080:    fn input_delivery_queue_drop_never_certifies_missing_text() {\n…\n11098:        assert!(input.enqueue_record(InputRecord::delivery(\n11099:            b\"next\".to_vec(), &next_attempt, DeliveryPart::Text { end: true },\n11100:        )));\n11101:        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\n11102:        assert!(input.delivery_matches(b\"next\"));\n11103:    }\n11104:\n11105:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n11106:    #[test]\n11107:    fn chunked_delivery_is_visible_before_enter_and_floor_flush_stays_human() {\n11108:        let (input, rx) = test_input_writer(16);\n11109:        let attempt = Arc::new(DeliveryAttempt::default());\n11110:        let text = format!(\"{}\\\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n11111:        enqueue_text_chunked(&input, &attempt, text.as_bytes().to_vec());\n11112:        assert!(!input.delivery_matches(text.as_bytes()));\n11113:        while let Ok(record) = rx.try_recv() {\n11114:            record.write_to(&InputCustodySurface, &input.deliveries);\n11115:        }\n11116:        assert!(input.delivery_matches(text.as_bytes()));\n11117:        assert!(input.enqueue_record(InputRecord::delivery(\n11118:            b\"\\r\".to_vec(), &attempt, DeliveryPart::Key,\n11119:        )));\n…\n11133:    }\n\n[Showing lines 11099-11118 of 16589. Use :11119 to continue]"}],"details":{"truncation":{"content":"            b\"next\".to_vec(), &next_attempt, DeliveryPart::Text { end: true },\r\n        )));\r\n        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\r\n        assert!(input.delivery_matches(b\"next\"));\r\n    }\r\n\r\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\r\n    #[test]\r\n    fn chunked_delivery_is_visible_before_enter_and_floor_flush_stays_human() {\r\n        let (input, rx) = test_input_writer(16);\r\n        let attempt = Arc::new(DeliveryAttempt::default());\r\n        let text = format!(\"{}\\\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\r\n        enqueue_text_chunked(&input, &attempt, text.as_bytes().to_vec());\r\n        assert!(!input.delivery_matches(text.as_bytes()));\r\n        while let Ok(record) = rx.try_recv() {\r\n            record.write_to(&InputCustodySurface, &input.deliveries);\r\n        }\r\n        assert!(input.delivery_matches(text.as_bytes()));\r\n        assert!(input.enqueue_record(InputRecord::delivery(\r\n            b\"\\r\".to_vec(), &attempt, DeliveryPart::Key,\r","truncated":true,"truncatedBy":"lines","totalLines":5491,"totalBytes":1018,"outputLines":20,"outputBytes":1018,"lastLinePartial":false,"firstLineExceedsLimit":false},"totalLines":16589,"displayContent":{"text":"    fn input_delivery_queue_drop_never_certifies_missing_text() {\n…\n        assert!(input.enqueue_record(InputRecord::delivery(\n            b\"next\".to_vec(), &next_attempt, DeliveryPart::Text { end: true },\r\n        )));\r\n        rx.recv().unwrap().write_to(&InputCustodySurface, &input.deliveries);\r\n        assert!(input.delivery_matches(b\"next\"));\r\n    }\r\n\r\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\r\n    #[test]\r\n    fn chunked_delivery_is_visible_before_enter_and_floor_flush_stays_human() {\r\n        let (input, rx) = test_input_writer(16);\r\n        let attempt = Arc::new(DeliveryAttempt::default());\r\n        let text = format!(\"{}\\\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\r\n        enqueue_text_chunked(&input, &attempt, text.as_bytes().to_vec());\r\n        assert!(!input.delivery_matches(text.as_bytes()));\r\n        while let Ok(record) = rx.try_recv() {\r\n            record.write_to(&InputCustodySurface, &input.deliveries);\r\n        }\r\n        assert!(input.delivery_matches(text.as_bytes()));\r\n        assert!(input.enqueue_record(InputRecord::delivery(\r\n            b\"\\r\".to_vec(), &attempt, DeliveryPart::Key,\r\n        )));\n…\n    }","startLine":11080,"lineNumbers":[11080,null,11098,11099,11100,11101,11102,11103,11104,11105,11106,11107,11108,11109,11110,11111,11112,11113,11114,11115,11116,11117,11118,11119,null,11133]},"fileSize":862335,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\broker.rs"},"truncation":{"direction":"head","truncatedBy":"lines","totalLines":16589,"totalBytes":1018,"outputLines":20,"outputBytes":1018,"shownRange":{"start":11099,"end":11118},"nextOffset":11119}}},"isError":false,"timestamp":1789295740525}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_n4QUVkAQOdEC107l29iODtAG|ctc_0b12df87254bb4e6016aa67c81c7c087d194d5265a3bbc00ff","toolName":"edit","startedAt":"2026-09-13T10:35:48.321Z"},"id":"f67e0455","parentId":"ac45ba6e","timestamp":"2026-09-13T10:35:48.321Z"}
{"type":"message","id":"ba0d56cd","parentId":"f67e0455","timestamp":"2026-09-13T10:35:48.321Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Testing quota capacity**"},{"type":"toolCall","id":"call_n4QUVkAQOdEC107l29iODtAG|ctc_0b12df87254bb4e6016aa67c81c7c087d194d5265a3bbc00ff","name":"edit","arguments":{"input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#CAD3]\nPUT 11110.=11110:\n+        let text = format!(\"{}\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#46A9]\nPUT 214.=214:\n+                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\nPUT 226.=226:\n+        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\nCUT 232.=232\n*** End Patch\n"},"customWireName":"edit"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":1228,"output":212,"cacheRead":56448,"cacheWrite":0,"totalTokens":57888,"reasoningTokens":40,"cost":{"input":0.012280000000000001,"output":0.0106,"cacheRead":0.056448,"cacheWrite":0,"total":0.079328}},"stopReason":"toolUse","timestamp":1789295740566,"responseId":"resp_0b12df87254bb4e6016aa67c7cc32c87d1a310f17e55fe1d0f","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c7de49087d1886c7ae8b209ee98","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnyBufoFkXf45--QOrSJriZF9wQsIKG00kg2ynraTEiIV9GgFNqA3BpQPurD6sn35QPF_26-UC3xUeun-cBb4s9NfkuuRcWDCFSC3SAOAE0oB0piz3mfxL3jRFrB1fCMmSpwEabdYxv2r-EN8Mr7r93oVbWpmq_ZBL3zZehCsiVOOsMyQoIT6Fo58FPcFGUi0OPwQJX7OVcxZB2vLeN9AZng1BzQh_hCXHNXMOKN_ziofvJRhswZnlCwcaGO3664tp3xLkgsXdlAAGyIfKdAT97Rc4qmSR6DQOhyqhpOTz2b8UkVIhUvSfn3j_D_Q5t7ItimF4obMKiIDuEn7lvaUovfQP0Xuh4MJ-Idy-Kjp7ITfAAroyeisaArnzmPudhkeJAoXO1AlkPOhmIFIjvD1B9OLxL5oW0j3EeIKLcJJA4maSbSXNzfKYYBxnF4pWHLHG8JujIKg6GpZ9DC5SLEbzMH7KeSu2n9VUZNCnk_ZZtLRsRjz69kkUwfzE-3pUVl9-XfWkqKbm0SaHpQt71JuyrwaxI4itctpwTXfu3vueGIe3vDjJ3IiQ0Q7ckLViVqp6XP-q7HHtAgsZfUiEtfL8ocdeEqKkgCyAbYPfcN-fqNzksc--yebjHDXk0xKD299eWFSkmFbwGdB6-LC9WkJ9b06zQmgkStBlENdIQ2dpLXVEdxFrudp0V1h1uyRUsVoa9cyAbLqYnDOHjSWw1Y72zVgOfthbj-KI_D_ESFwnm4uWT9Gvy1GOf8G5GWWQ5PqFOnsNhYu3f6V6axsw4rr_lKPaSWWMYAEwPdXiCVfkZYgSl9DwDCigyYrcMsFDxK5bCkE1AYC3aiFdoGlmbEMl5TqphTAuiFo_X0e7yLf0s5Lf5CSFMNFR1e-b_zQQ8_QVss3546Xe_F3THmy5p0BpcFePQHXWH0JEVyUDG63AGZLJYzPVkJ9xSHZ_ZQTenwAr2HdkavmhqBKYF0l_3gmzrroEyZAViWwPjcc_AQw5JFHa9kKntBFQPlNeo7wVh-ksFgUYNVYhr3eHzyn57ZXeXKTmKlJR3IDkWzMK6kfUKQrlZasOM3x6lHD4WLe8BEcT8Nw0TKcCKxMz1iIaLJTd2k7_HfvsFbnkUsTRuDel7pGad9iD-PaUdEAa8Vnd7BohFsi1JayKzTOWsmzOLJgpkZCuV6DJG7z02BunpPH9b-IDmFhCfauUBtXLbSF8ubIcXyyr8pCDMR7ejOmNKxi9zapS12Wyxh1ePYbJw6PN54pgutHBgx_z2EbysUbvawAICN7JJHQj04_V-j-xDf1zZP1XWuS3zaxtKWtjE_2F6kXNTfdNiBzhOGr8j9ZoUiOaeGbqfirKVHpEtQ8INay5DKM3aVg9xuKbyZCmqMtTrdev_WqyBMylJV5i9rR80qo36vHSGCR-QmT37as8J50ia_f8m3n-u2UAmcqJsQP_H0craDxkFYy8x2_yG7lHqkU9dn071d9mKMqK3mOp6rrnWaBP6ZRdKLggYhcD-hkaWhLVyW-W9nFM5qmN_7rSyOKnjOW2xyCCI6eIhhS13D1fm2BKheejE_JW0VzduIEG9fkc7C4_lzoFU_d8vULoIVTUF2","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Testing quota capacity**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"ctc_0b12df87254bb4e6016aa67c81c7c087d194d5265a3bbc00ff","type":"custom_tool_call","status":"completed","call_id":"call_n4QUVkAQOdEC107l29iODtAG","input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#CAD3]\nPUT 11110.=11110:\n+        let text = format!(\"{}\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#46A9]\nPUT 214.=214:\n+                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\nPUT 226.=226:\n+        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\nCUT 232.=232\n*** End Patch\n","internal_chat_message_metadata_passthrough":{"create_time":1789295740.921507,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"edit","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":7753.200799999991,"ttft":1348.1170000000857,"completedAt":1789295748320,"contextSnapshot":{"promptTokens":57676,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"e9ad645b","parentId":"ba0d56cd","timestamp":"2026-09-13T10:35:48.602Z","message":{"role":"toolResult","toolCallId":"call_n4QUVkAQOdEC107l29iODtAG|ctc_0b12df87254bb4e6016aa67c81c7c087d194d5265a3bbc00ff","toolName":"edit","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/broker.rs#C86D]\n11108:        let (input, rx) = test_input_writer(16);\n11109:        let attempt = Arc::new(DeliveryAttempt::default());\n11110:        let text = format!(\"{}\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n11111:        enqueue_text_chunked(&input, &attempt, text.as_bytes().to_vec());\n11112:        assert!(!input.delivery_matches(text.as_bytes()));\n\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#722F]\n210:    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n\n212:        impl SessionSurface for PartialFailure {\n213:            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n214:                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\n215:                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n216:            }\n\n218:        }\n\n224:        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n225:        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n226:        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\n227:        assert!(!ledger.matches(b\"beforemiddleafter\"));\n228:        assert!(!ledger.matches(b\"beforeafter\"));\n230:    }\n231:\n232:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n233:    #[test]"}],"details":{"diff":" 11108|        let (input, rx) = test_input_writer(16);\n 11109|        let attempt = Arc::new(DeliveryAttempt::default());\n-11110|        let text = format!(\"{}\\\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n+11110|        let text = format!(\"{}\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n 11111|        enqueue_text_chunked(&input, &attempt, text.as_bytes().to_vec());\n 11112|        assert!(!input.delivery_matches(text.as_bytes()));\n 210|    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n\n 212|        impl SessionSurface for PartialFailure {\n 213|            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n-214|                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n+214|                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\n 215|                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n 216|            }\n\n 218|        }\n\n 224|        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n 225|        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n-226|        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n+226|        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\n 227|        assert!(!ledger.matches(b\"beforemiddleafter\"));\n 228|        assert!(!ledger.matches(b\"beforeafter\"));\n 230|    }\n 231|\n-232|\n 233|    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n 234|    #[test]","firstChangedLine":11110,"perFileResults":[{"path":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\broker.rs","diff":" 11108|        let (input, rx) = test_input_writer(16);\n 11109|        let attempt = Arc::new(DeliveryAttempt::default());\n-11110|        let text = format!(\"{}\\\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n+11110|        let text = format!(\"{}\\nC:/exact\", \"a\".repeat(inject_text_chunk() + 1));\n 11111|        enqueue_text_chunked(&input, &attempt, text.as_bytes().to_vec());\n 11112|        assert!(!input.delivery_matches(text.as_bytes()));","firstChangedLine":11110,"op":"update","snapshotsPruned":true},{"path":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\deliverybytes.rs","diff":" 210|    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n\n 212|        impl SessionSurface for PartialFailure {\n 213|            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n-214|                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n+214|                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\n 215|                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n 216|            }\n\n 218|        }\n\n 224|        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n 225|        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n-226|        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n+226|        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\n 227|        assert!(!ledger.matches(b\"beforemiddleafter\"));\n 228|        assert!(!ledger.matches(b\"beforeafter\"));\n 230|    }\n 231|\n-232|\n 233|    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n 234|    #[test]","firstChangedLine":214,"op":"update","oldText":"//! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\n\nuse sha2::{Digest, Sha256};\nuse spt_term::surface::SessionSurface;\nuse std::collections::HashSet;\nuse std::sync::{Arc, Mutex};\n\n// Digests, not retained payloads. Never evict evidence from a live hosted session:\n// exhaustion disables origin grants with a named reason instead.\nconst MAX_DELIVERY_DIGESTS: usize = 65_536;\n\n#[derive(Default)]\npub(crate) struct DeliveryBytes {\n    completed: Mutex<Completed>,\n}\n\n#[derive(Default)]\nstruct Completed {\n    digests: HashSet<[u8; 32]>,\n    exhausted: bool,\n}\n\nimpl DeliveryBytes {\n    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\n        let digest: [u8; 32] = Sha256::digest(payload).into();\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .digests\n            .contains(&digest)\n    }\n\n    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .exhausted\n            .then_some(\"delivery-evidence-capacity\")\n    }\n\n    fn remember(&self, digest: [u8; 32]) {\n        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n    }\n\n    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        if completed.digests.contains(&digest) {\n            return;\n        }\n        if completed.digests.len() >= limit {\n            completed.exhausted = true;\n        } else {\n            completed.digests.insert(digest);\n        }\n    }\n}\n\n/// One translation attempt; queued records keep its constant-size streaming state\n/// alive until the lone writer has processed them, independently of logical Commit.\n#[derive(Default)]\npub(crate) struct DeliveryAttempt {\n    text: Mutex<AttemptText>,\n}\n\n#[derive(Default)]\nstruct AttemptText {\n    hash: Sha256,\n    has_text: bool,\n    failed: bool,\n}\n\n#[derive(Clone, Copy)]\npub(crate) enum DeliveryPart {\n    Text { end: bool },\n    Key,\n}\n\nimpl DeliveryAttempt {\n    fn failed(&self) {\n        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\n    }\n\n    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\n        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\n        if text.failed {\n            return;\n        }\n        if let DeliveryPart::Text { end } = part {\n            text.hash.update(bytes);\n            text.has_text |= !bytes.is_empty();\n            if end && text.has_text {\n                // Publish each complete Text command's cumulative text, including\n                // exact embedded newlines. Keys are source-tagged controls, never\n                // guessed framing stripped from the reported payload.\n                ledger.remember(text.hash.clone().finalize().into());\n            }\n        }\n    }\n}\n\npub(crate) struct InputRecord {\n    bytes: Vec<u8>,\n    origin: InputOrigin,\n}\n\nenum InputOrigin {\n    Controller,\n    Probe,\n    Delivery {\n        attempt: Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    },\n}\n\nimpl InputRecord {\n    #[cfg(test)]\n    pub(crate) fn into_bytes(self) -> Vec<u8> {\n        self.bytes\n    }\n\n    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Controller }\n    }\n\n    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Probe }\n    }\n\n    pub(crate) fn delivery(\n        bytes: Vec<u8>,\n        attempt: &Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    ) -> Self {\n        Self {\n            bytes,\n            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\n        }\n    }\n\n    pub(crate) fn dropped(&self) {\n        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\n            attempt.failed();\n        }\n    }\n\n    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n        // Never hold a custody lock across a potentially wedged physical write.\n        // Ok proves write_all + flush, not harness interpretation. Err may follow\n        // a partial write, whose byte count this API does not expose: do not guess.\n        let success = surface.write_input(&self.bytes).is_ok();\n        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n            if success {\n                attempt.written(&self.bytes, *part, ledger);\n            } else {\n                attempt.failed();\n            }\n        }\n        // A report caused by a separate Enter sees the preceding Text's published\n        // evidence before Enter is written (one FIFO, one writer). A report caused\n        // by Text itself can race between physical completion and this publication;\n        // enqueued bytes cannot honestly close that narrower window.\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use spt_term::surface::{SurfaceError, SurfaceSize};\n\n    struct Sink;\n    impl SessionSurface for Sink {\n        fn write_input(&self, _: &[u8]) -> Result<(), SurfaceError> { Ok(()) }\n        fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn split_multiline_delivery_matches_before_commit_without_normalizing() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        let first = InputRecord::delivery(b\"<EVENT>\\n C:/a\".to_vec(), &attempt, DeliveryPart::Text { end: false });\n        let last = InputRecord::delivery(b\"\\n</EVENT> \".to_vec(), &attempt, DeliveryPart::Text { end: true });\n        let payload = b\"<EVENT>\\n C:/a\\n</EVENT> \";\n        assert!(!ledger.matches(payload));\n        first.write_to(&Sink, &ledger);\n        assert!(!ledger.matches(payload));\n        last.write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        InputRecord::delivery(b\"\\r\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/b\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/a\\n</EVENT>\"));\n        assert!(!ledger.matches(b\"<EVENT>\\r\\n C:/a\\r\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"\\r\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n        let ledger = DeliveryBytes::default();\n        InputRecord::controller(b\"human C:/private\".to_vec()).write_to(&Sink, &ledger);\n        InputRecord::probe(b\"\\x1b[6n\".to_vec()).write_to(&Sink, &ledger);\n        assert!(!ledger.matches(b\"human C:/private\"));\n        assert!(!ledger.matches(b\"\\x1b[6n\"));\n        assert!(!ledger.matches(b\"unknown human payload\"));\n    }\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n        struct PartialFailure(Mutex<Vec<u8>>);\n        impl SessionSurface for PartialFailure {\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n                self.0.lock().unwrap().extend_from_slice(&bytes[..2]);\n                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n            }\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n        }\n\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n        let partial = PartialFailure(Mutex::new(Vec::new()));\n        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert_eq!(*partial.0.lock().unwrap(), b\"mi\");\n        assert!(!ledger.matches(b\"beforemiddleafter\"));\n        assert!(!ledger.matches(b\"beforeafter\"));\n        assert!(!ledger.matches(b\"beforemiafter\"));\n    }\n\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"one\\ntwo\"));\n        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n        let next_attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"three\"));\n        assert!(!ledger.matches(b\"one\\ntwothree\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\n        let ledger = DeliveryBytes::default();\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        assert_eq!(ledger.unavailable_reason(), None);\n        ledger.remember_with_limit(Sha256::digest(b\"second\").into(), 1);\n        assert!(ledger.matches(b\"first\"));\n        assert!(!ledger.matches(b\"second\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-evidence-capacity\"));\n    }\n}\n","newText":"//! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\n\nuse sha2::{Digest, Sha256};\nuse spt_term::surface::SessionSurface;\nuse std::collections::HashSet;\nuse std::sync::{Arc, Mutex};\n\n// Digests, not retained payloads. Never evict evidence from a live hosted session:\n// exhaustion disables origin grants with a named reason instead.\nconst MAX_DELIVERY_DIGESTS: usize = 65_536;\n\n#[derive(Default)]\npub(crate) struct DeliveryBytes {\n    completed: Mutex<Completed>,\n}\n\n#[derive(Default)]\nstruct Completed {\n    digests: HashSet<[u8; 32]>,\n    exhausted: bool,\n}\n\nimpl DeliveryBytes {\n    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\n        let digest: [u8; 32] = Sha256::digest(payload).into();\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .digests\n            .contains(&digest)\n    }\n\n    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .exhausted\n            .then_some(\"delivery-evidence-capacity\")\n    }\n\n    fn remember(&self, digest: [u8; 32]) {\n        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n    }\n\n    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        if completed.digests.contains(&digest) {\n            return;\n        }\n        if completed.digests.len() >= limit {\n            completed.exhausted = true;\n        } else {\n            completed.digests.insert(digest);\n        }\n    }\n}\n\n/// One translation attempt; queued records keep its constant-size streaming state\n/// alive until the lone writer has processed them, independently of logical Commit.\n#[derive(Default)]\npub(crate) struct DeliveryAttempt {\n    text: Mutex<AttemptText>,\n}\n\n#[derive(Default)]\nstruct AttemptText {\n    hash: Sha256,\n    has_text: bool,\n    failed: bool,\n}\n\n#[derive(Clone, Copy)]\npub(crate) enum DeliveryPart {\n    Text { end: bool },\n    Key,\n}\n\nimpl DeliveryAttempt {\n    fn failed(&self) {\n        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\n    }\n\n    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\n        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\n        if text.failed {\n            return;\n        }\n        if let DeliveryPart::Text { end } = part {\n            text.hash.update(bytes);\n            text.has_text |= !bytes.is_empty();\n            if end && text.has_text {\n                // Publish each complete Text command's cumulative text, including\n                // exact embedded newlines. Keys are source-tagged controls, never\n                // guessed framing stripped from the reported payload.\n                ledger.remember(text.hash.clone().finalize().into());\n            }\n        }\n    }\n}\n\npub(crate) struct InputRecord {\n    bytes: Vec<u8>,\n    origin: InputOrigin,\n}\n\nenum InputOrigin {\n    Controller,\n    Probe,\n    Delivery {\n        attempt: Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    },\n}\n\nimpl InputRecord {\n    #[cfg(test)]\n    pub(crate) fn into_bytes(self) -> Vec<u8> {\n        self.bytes\n    }\n\n    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Controller }\n    }\n\n    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Probe }\n    }\n\n    pub(crate) fn delivery(\n        bytes: Vec<u8>,\n        attempt: &Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    ) -> Self {\n        Self {\n            bytes,\n            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\n        }\n    }\n\n    pub(crate) fn dropped(&self) {\n        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\n            attempt.failed();\n        }\n    }\n\n    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n        // Never hold a custody lock across a potentially wedged physical write.\n        // Ok proves write_all + flush, not harness interpretation. Err may follow\n        // a partial write, whose byte count this API does not expose: do not guess.\n        let success = surface.write_input(&self.bytes).is_ok();\n        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n            if success {\n                attempt.written(&self.bytes, *part, ledger);\n            } else {\n                attempt.failed();\n            }\n        }\n        // A report caused by a separate Enter sees the preceding Text's published\n        // evidence before Enter is written (one FIFO, one writer). A report caused\n        // by Text itself can race between physical completion and this publication;\n        // enqueued bytes cannot honestly close that narrower window.\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use spt_term::surface::{SurfaceError, SurfaceSize};\n\n    struct Sink;\n    impl SessionSurface for Sink {\n        fn write_input(&self, _: &[u8]) -> Result<(), SurfaceError> { Ok(()) }\n        fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn split_multiline_delivery_matches_before_commit_without_normalizing() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        let first = InputRecord::delivery(b\"<EVENT>\\n C:/a\".to_vec(), &attempt, DeliveryPart::Text { end: false });\n        let last = InputRecord::delivery(b\"\\n</EVENT> \".to_vec(), &attempt, DeliveryPart::Text { end: true });\n        let payload = b\"<EVENT>\\n C:/a\\n</EVENT> \";\n        assert!(!ledger.matches(payload));\n        first.write_to(&Sink, &ledger);\n        assert!(!ledger.matches(payload));\n        last.write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        InputRecord::delivery(b\"\\r\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/b\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/a\\n</EVENT>\"));\n        assert!(!ledger.matches(b\"<EVENT>\\r\\n C:/a\\r\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"\\r\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n        let ledger = DeliveryBytes::default();\n        InputRecord::controller(b\"human C:/private\".to_vec()).write_to(&Sink, &ledger);\n        InputRecord::probe(b\"\\x1b[6n\".to_vec()).write_to(&Sink, &ledger);\n        assert!(!ledger.matches(b\"human C:/private\"));\n        assert!(!ledger.matches(b\"\\x1b[6n\"));\n        assert!(!ledger.matches(b\"unknown human payload\"));\n    }\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n        struct PartialFailure(Mutex<Vec<u8>>);\n        impl SessionSurface for PartialFailure {\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\n                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n            }\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n        }\n\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n        let partial = PartialFailure(Mutex::new(Vec::new()));\n        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\n        assert!(!ledger.matches(b\"beforemiddleafter\"));\n        assert!(!ledger.matches(b\"beforeafter\"));\n        assert!(!ledger.matches(b\"beforemiafter\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"one\\ntwo\"));\n        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n        let next_attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"three\"));\n        assert!(!ledger.matches(b\"one\\ntwothree\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\n        let ledger = DeliveryBytes::default();\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        assert_eq!(ledger.unavailable_reason(), None);\n        ledger.remember_with_limit(Sha256::digest(b\"second\").into(), 1);\n        assert!(ledger.matches(b\"first\"));\n        assert!(!ledger.matches(b\"second\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-evidence-capacity\"));\n    }\n}\n"}]},"isError":false,"timestamp":1789295748601}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_QGcscBoIfpjoVWyWrgQfdBRq|fc_0b12df87254bb4e6016aa67c8efd5887d19bffbaf512467ccf","toolName":"hub","startedAt":"2026-09-13T10:36:01.894Z","intent":"Handing broker ownership back"},"id":"f0448cde","parentId":"e9ad645b","timestamp":"2026-09-13T10:36:01.894Z"}
{"type":"message","id":"78f6babc","parentId":"f0448cde","timestamp":"2026-09-13T10:36:01.897Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Distinguishing text from controls**\n\n**Reporting completed changes**"},{"type":"toolCall","id":"call_QGcscBoIfpjoVWyWrgQfdBRq|fc_0b12df87254bb4e6016aa67c8efd5887d19bffbaf512467ccf","name":"hub","arguments":{"i":"Handing broker ownership back","op":"send","to":"Main","message":"DeliveryRecording complete; broker.rs now yours. Added private deliverybytes.rs (you add lib.rs `mod deliverybytes;`). InputWriter delivery_matches + delivery_unavailable_reason exposed internally; latter returns `delivery-evidence-capacity` after 65,536 unique hashes, MUST decline before grant. Successful Text command aggregates recorded at physical completion; chunks aggregate and Key/Controller/Probe distinguished; queue drops/write Err poison attempt, no omitted full payload certified. No tests/build/format run per assignment. Added 7 focused tests (details in final). Narrow Text-caused receipt before post-write publication remains; separate Enter follows published text FIFO. No LSP tool available; grep references used."},"intent":"Handing broker ownership back"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":838,"output":382,"cacheRead":57472,"cacheWrite":0,"totalTokens":58692,"reasoningTokens":209,"cost":{"input":0.00838,"output":0.019100000000000002,"cacheRead":0.057471999999999995,"cacheWrite":0,"total":0.084952}},"stopReason":"toolUse","timestamp":1789295748636,"responseId":"resp_0b12df87254bb4e6016aa67c84dd1487d1a4a53851635de697","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c865df487d1872a04b313389518","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnyOM3FLtd6wJG0JQ9GV8ukjMrS4CJzCCjr0fLc0OMobF3KuLJKNBnazDzcLOvQ6UTRTHkEkhbbHb_Odkp-c2mFwQyshlwmzvEUCQazJzsTUebfhxcIAJnV0n0RMwjEhq8nzXSUczk0EWH7iQwGyxC4Zyt3qRqfiQfRBOTPvtxMxFJEVQLR5YmIOaQNPOLPI6-l3H8vk8Qpc5g0IuLIvNgFjVOEBcSABPpvzbGRP-YrqlwviujIZ6LGY1MYSws_-A7K8u2yHhInce8KO4xDe_zbPOfMqJeZz6mtIp2HzQPzubhNnlVzcjRP8dTsT0T-sA6-uKde-2P-B-M_-E923Ci-th1B6CfAWA39zrosY8XYggwN-yIKf6NvVP3X9cB6xhqXTnqZ3mnRb7sduTHLrQ4nX5miNYSoxpvrVDl7Mwk24Nn3wXDIRULKbKoq0l6VYtn9QFTz6lLIGpuNBfoCcHpFcV-9MWtg5faj-G0sai-dX3ujtCadE5v5HJRyxENn_CMNnTE40WJRzCV7Jh7gLXix4DheBm0VhKmgtwwiHWRANK75yrScmJvjoAs_fjW70cUtmn-rVrubLYBxUtijWJq8Lj7vQ6u783rjFwQ3BkT_H8gqQmmwZTDzEjz_2EdnlgnVtc88GqXBTbc_gPCrLLrwIIXE1QOB5UmuEp4wKBV1nDIe-b5DINL-cRxbFZVpWzPAfTPOjPS6DTzOicVkYF_pa0TQBTSJ6eFa0CjeBx4xJMWRZ1z9sz90fjus_xf54HGgXHwc0FOXjJelGpuM9L9cLNMze7vSGbntSELTenKhCcHbnEgs2wAaOyrcL927bwmtuvNLPVfv8gtvnaBlaYQfJ5SSP5klrba4aDAtkW9MS-D3PBUAER50wzPcNlRgFhuItx2cINd6ib0bGEeN3Y88KO7bMNPOVmDaBmPbnZnMe-P93R6sYDiY6nmGSllbAwmYu0MoJ-pTfODJwEZQgLimlDlyZqO7O3emQRH3PElsgq0Mzz7oubNI1ghXGN38BNR4AyV5UL5F10W4WlPIAqFPy0Q1xGyqsMmBH0v8jw3MLfe4SZXcnxZmEKMhqHs0nehuN-c_5_8yFRWpOEeicVt_DafIBvZMDHPeFsGRCMzY9g1nZukhoo3Lo07pE9wvIqw_JGfjU2ufxNtaKb9vgEguJIgXBLjvhMZLLPzyYWRsZDl5B_HfUBKyossF7QQ0Xoqzq4ZcOko1GFg7EeQlyVbwwEan2AzEXZ9KVOAIruJclCyZ5B6hkkvXm4JqG52Hl8CtryfrwhQTwPBorxPeHlahmucFcHWunUgugGtcMmDy1U7y6Erx1LGChsmm-1iVBSyvOqEyAHjDYvlEPastiYnIan67w-Xjy0eo1zWKHtGFRS-xyIv4lYp8qCsZ7MD8cAXfnfsRsTLMAxKmMfSm4p2_5vcsw2D3f7vwFFcQA3oprilvqaaMh-w42CSBKvs7tIUNaG5500eLSnLxIyR1fepClfuAiGNbUD6bg_jsWvSRfoMtMM4qxtEdZyC-VVjNz8gQ63i4bzNheNVNE49rYe7SBf8jP3JOVPFZR8WE78CJnIk7Tcz2UjZAdC9G6iq0nsidca2-aw17FfNvlQk_JsSgRc-6gGcpoovS4LC0cnxs16y0I2DRGHpl3JZ4f3e0I2HL8WRsk6Or_qpZPqUtE1ygSC9cEMotRk2k-Hx6DSFL8UttnLpV0--aLHKtIL2ZCc-Hn29WKOKQoG3EQkQxntcZBUOGHgqUiu-Hw-ZE2u3s2RNVWJXLj1QBH0ySQCdXOmIAegDiyQBHxvOCgn-88eZeDOJly1xoKet_cWAELK2xstBM0nDnk8_d6rUHszAlZNh9gBqXvOTgzG_ZOYVPTxd6iHMpoBy9TvpMALKeODyFFGky45zlkX-yfgRjDoKesJE5nZYqaY-8-0kPIOtl3Z9GYrVyAWPjgmzboProtL70HffblsjLGg3OWb96xuIoBEWYITda2bS7lEFjH4bnTyAAO7tPRhWml07HXWUj4TBaH7O3JZ4zjphh4o3_nY23QUHkubQjRZhhmEPIcuGF3qlJpNyx7a_gLBjoMU3a-dpySi-yVwHh99qw1SFIkCgVW4bc5KRgeJK1qQziWQflaV5Vdb0XYtxblIzVw6mkvW9LEcu6vs0EuWZ--vH3EXlVJMabc3kA3arjT1Q4Uk5gN5Ri4xebkyYAsHVYPGxBf3iAfVvTFLvqRw_-MNzQSue7GyaC6Sx2aeXxRhHXtXabTug_FRDGWZNrlaK8ok6RWJ9MbA4TyqKgcFaNVsu-ZmC_cWhqUBCsSJj-5WNGnuzrsFGjRuh9bxKnFtPRXUXFfX_-XsiT_odwAohf_CN51sAEeTwMXr06ScN6zu25Yy8-JLd_8KjdWMMwzN-KSp1pyfJ2Ti07XwPtz8YTRJUrA6u2N2PIbne5SbkdPGR6l_0dPeTGirSnPsTBhfHhphntq0XxMoRUc5Hkg2yns3-VbQmnQHX7JgIHxVSeTIWvehjVErpIMNynZp6hn4rVY-CQzmHC2A1GvsC5ArNdQjp8dSWENi0Ogizpx9axkgX8aSG5vcIar7o7e0JbGTpmb6pVVP1KViW1LaUXdL7pVjrZrReOpNkyiGF4oZGldHpkSBFhoIGb5HZxPKckvXXlW6-cuR2AZ7Qyrk05rvUspf1ppSg4py2tMlbo8npcRLeQR3sfL-_L3pMD2ynASi0J6s1FegAQkOnNjUKDjVYHw7M0NTnlh2Jvo4tg3vlMhWIuTsi6IFOAdBH-isiti2TuNJLGuAONXKvhtzCREtGknJW_2YiFlswqYcLXLMbQSms3bflZNFRe-3v8dGqtZeFp0M4ow51shSVXXz19RntSfqAvOeSBRXFeCCKARoDHmxcCTwCGhsupiQZmjpNb2t9UK40sXB1Bu5iAKWyvvS5MSY2Ff6NHm0JRwRKvGVJ-qomqQHN362jU8cg==","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Distinguishing text from controls**"},{"type":"summary_text","text":"**Reporting completed changes**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67c8efd5887d19bffbaf512467ccf","type":"function_call","status":"completed","arguments":"{\"i\":\"Handing broker ownership back\",\"op\":\"send\",\"to\":\"Main\",\"message\":\"DeliveryRecording complete; broker.rs now yours. Added private deliverybytes.rs (you add lib.rs `mod deliverybytes;`). InputWriter delivery_matches + delivery_unavailable_reason exposed internally; latter returns `delivery-evidence-capacity` after 65,536 unique hashes, MUST decline before grant. Successful Text command aggregates recorded at physical completion; chunks aggregate and Key/Controller/Probe distinguished; queue drops/write Err poison attempt, no omitted full payload certified. No tests/build/format run per assignment. Added 7 focused tests (details in final). Narrow Text-caused receipt before post-write publication remains; separate Enter follows published text FIFO. No LSP tool available; grep references used.\"}","call_id":"call_QGcscBoIfpjoVWyWrgQfdBRq","internal_chat_message_metadata_passthrough":{"create_time":1789295749.01923,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"hub","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":13255.02509999997,"ttft":1752.6456000000471,"completedAt":1789295761892,"contextSnapshot":{"promptTokens":58310,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"9e306dea","parentId":"78f6babc","timestamp":"2026-09-13T10:36:01.902Z","message":{"role":"toolResult","toolCallId":"call_QGcscBoIfpjoVWyWrgQfdBRq|fc_0b12df87254bb4e6016aa67c8efd5887d19bffbaf512467ccf","toolName":"hub","content":[{"type":"text","text":"Delivered to 1 peer(s):\n- Main: injected"}],"details":{"op":"send","from":"DeliveryRecording","to":"Main","receipts":[{"to":"Main","outcome":"injected"}]},"isError":false,"timestamp":1789295761901}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_4ltF9fKU5hcyJfnNcwwu04WV|fc_0b12df87254bb4e6016aa67c9754e487d1b8e5930f1902a346","toolName":"yield","startedAt":"2026-09-13T10:36:20.022Z"},"id":"58f567f2","parentId":"9e306dea","timestamp":"2026-09-13T10:36:20.022Z"}
{"type":"message","id":"5b21007a","parentId":"58f567f2","timestamp":"2026-09-13T10:36:20.023Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Preparing proof parent tests**"},{"type":"toolCall","id":"call_4ltF9fKU5hcyJfnNcwwu04WV|fc_0b12df87254bb4e6016aa67c9754e487d1b8e5930f1902a346","name":"yield","arguments":{"data":{"changes":[{"path":"crates/spt-daemon/src/broker.rs","edits":"Replaced raw InputRecord alias with source-tagged records; attached session-lifetime DeliveryBytes to InputWriter; added delivery_matches and delivery_unavailable_reason; classified controller enqueue and settle probes separately; marked translated Text/Key with per-attempt custody; aggregated chunked Text at command boundaries; published only after successful physical writes through unchanged bounded FIFO/single writer; poisoned attempt on dropped enqueue or physical error; preserved controller floor flush classification; updated two existing writer tests only for record contract changes."},{"path":"crates/spt-daemon/src/deliverybytes.rs","edits":"New private delivery ledger and physical-write custody seam. SHA-256 cumulative Text candidates preserve exact multiline bytes without payload normalization. Source-tagged Key controls excluded. Constant-size pending attempt hashes plus maximum 65,536 session-lifetime completed digests, never evicted; quota returns named delivery-evidence-capacity non-grant."}],"integration_required":["Parent adds `mod deliverybytes;` to lib.rs.","Report dispatch must check InputWriter::delivery_unavailable_reason() before granting origin and decline with returned reason. Parent owns broker.rs again."],"tests_added":["deliverybytes::tests::split_multiline_delivery_matches_before_commit_without_normalizing","deliverybytes::tests::controller_and_probe_bytes_never_become_delivery_evidence","deliverybytes::tests::failed_physical_write_cannot_certify_omitted_or_partial_bytes","deliverybytes::tests::successful_text_commands_aggregate_without_key_bytes","deliverybytes::tests::exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants","broker::tests::input_delivery_queue_drop_never_certifies_missing_text","broker::tests::chunked_delivery_is_visible_before_enter_and_floor_flush_stays_human"],"verification":"No build, test, lint, formatter, or other validation run, as explicitly assigned. Every new test carries [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]. No LSP tool available; scoped grep reference lookup used.","limits":["Separate Enter follows completed Text evidence publication on the single FIFO. A report caused by Text itself can still race the narrow interval between physical write completion and ledger publication; queued bytes are never falsely marked successful to hide this.","write_input Err exposes no partial byte count, so that attempt cannot certify later cumulative text; earlier successfully completed candidates remain valid evidence.","Text equality cannot distinguish a later human submission identical to historical core delivery. Key tagging is not terminal-editor emulation."]}}}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":602,"output":556,"cacheRead":58112,"cacheWrite":0,"totalTokens":59270,"reasoningTokens":17,"cost":{"input":0.00602,"output":0.027800000000000002,"cacheRead":0.058112,"cacheWrite":0,"total":0.091932}},"stopReason":"toolUse","timestamp":1789295761958,"responseId":"resp_0b12df87254bb4e6016aa67c9229ac87d1b5d22602594bcd35","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67c93444887d1a87d68b524e4a8ee","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpnyXiSSJgIY-8eOoqzX5N3Zf-u4Rqp1E6at12rLz6LHXQg21ALsuArWJn--GxHQ3eb2BCkJp5Q6uy9VFvE5Tvbi6PRbETNZ5d56DyGn-CMwM2_aGUSKly4yZhuWzxMbHMiTvkxqqU3yJLI31rwhKNAfn59tFcZU44TsBkffbOUXY7wZD5v_vgmyAt9dxG4-sEG1Drrb1SEAD03lSN7Wis8rWqHo548LeUmzOsDhs0c_PE_LgWng4EGx_WHZ0lnLIKTQy1pqOQqPLFb-x7uoWeURHkCTByvfsuALkgfIQpWmlZTd7XfAS_gOfNQwTVwrSVmdkrc6p5qrGHN_n3hPPNEmIEYlAfziU_wKihicKepT6E_IDRSrbeAD2uCDSxIjJWRO754WOrtRRMtVe9okibQisGfMNHeLcxd8NAjDPcOqiKzS9xqf6W1hUFoeDlR3mLIdFUnnynZQoVKjsK_13oAmMJXNIcVOz2HOahsZbHmQMBMEZ3E7o8ndCptiVZcvRdTo81dCWFS4DKyEK9-SQNwVq_EWQJozJyxkTHtKz7tKu5rFgngZIEZ3OQg3CJbUjy0W3IyOoVtpcllw_YHsF5WWSiNa1mW_d20Tkrdq80qQf-rIsPoUoSrwDVeI0REFl5MwxBcm0f3FHZohw6iPT297GeEExTYQxk5ONZSQzLKhikLHet-fawSpwCFEnRt11Kqm2qt_cQawsBxq-fpG03bILZ3q_F88aT_mkdz5GfJhmamXyJaIUU19C5gui8W9ZkJyYHtXyBMoJ3IPvdVO8WLGyfB-KW9jOuzwZ8O6keDOU3021zDCAcLnVU6wj4yEaOwlXIbt3yf2gVIXXqLyM2m_2CzSowEY58WiVdBhCyB8SneBHmHa7yvhKMe1LSyh3ts05ASEGwli9P-JP-ylW5bcOC6e7Hp4J3jUqYMl4W_e6NZln-bOgDTZ3KrT7v5PV4Py3gr4dSheyiY5Q3NsLR-1ci7LkK4N0OnPeN2hfa-5kLFsAJEnpBdMEq8_Gvv7VNc4svwCtSEbJvoQ1u5dgLh8gywnfHJlzhy1LnodCnJVV-DuTYV5Di0OXXNNy8xeYJyiTr-gmjuuVLlOOYcJyMHVse7gOBUc2qP9bbpP2teXWgVVIaMt1W7PZCRZ5-xyW4Bz_sbCRg2u-uRiuCvGVnEi9i8UCGzD0xn3dm02FjIbA6UPGxvh90MXVJwvsCN8LhyK1j-MzoSqgl0EudL-cigaOtPat0JyMxfolH6CxhP1i1ET-IONd0AxmUALXfH91dB1hhyy1-ElyeEkBhlL8tHiWy6AK-pGFTrIWou0J7i0lv0LSlUXkUm4RvROzPL0B-rgTq2UgXeeslJye_01FpKraHsOMCXBzC3j86Hkykr58Sis=","internal_chat_message_metadata_passthrough":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"summary":[{"type":"summary_text","text":"**Preparing proof parent tests**"}],"metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}},{"id":"fc_0b12df87254bb4e6016aa67c9754e487d1b8e5930f1902a346","type":"function_call","status":"completed","arguments":"{\"data\":{\"changes\":[{\"path\":\"crates/spt-daemon/src/broker.rs\",\"edits\":\"Replaced raw InputRecord alias with source-tagged records; attached session-lifetime DeliveryBytes to InputWriter; added delivery_matches and delivery_unavailable_reason; classified controller enqueue and settle probes separately; marked translated Text/Key with per-attempt custody; aggregated chunked Text at command boundaries; published only after successful physical writes through unchanged bounded FIFO/single writer; poisoned attempt on dropped enqueue or physical error; preserved controller floor flush classification; updated two existing writer tests only for record contract changes.\"},{\"path\":\"crates/spt-daemon/src/deliverybytes.rs\",\"edits\":\"New private delivery ledger and physical-write custody seam. SHA-256 cumulative Text candidates preserve exact multiline bytes without payload normalization. Source-tagged Key controls excluded. Constant-size pending attempt hashes plus maximum 65,536 session-lifetime completed digests, never evicted; quota returns named delivery-evidence-capacity non-grant.\"}],\"integration_required\":[\"Parent adds `mod deliverybytes;` to lib.rs.\",\"Report dispatch must check InputWriter::delivery_unavailable_reason() before granting origin and decline with returned reason. Parent owns broker.rs again.\"],\"tests_added\":[\"deliverybytes::tests::split_multiline_delivery_matches_before_commit_without_normalizing\",\"deliverybytes::tests::controller_and_probe_bytes_never_become_delivery_evidence\",\"deliverybytes::tests::failed_physical_write_cannot_certify_omitted_or_partial_bytes\",\"deliverybytes::tests::successful_text_commands_aggregate_without_key_bytes\",\"deliverybytes::tests::exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants\",\"broker::tests::input_delivery_queue_drop_never_certifies_missing_text\",\"broker::tests::chunked_delivery_is_visible_before_enter_and_floor_flush_stays_human\"],\"verification\":\"No build, test, lint, formatter, or other validation run, as explicitly assigned. Every new test carries [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]. No LSP tool available; scoped grep reference lookup used.\",\"limits\":[\"Separate Enter follows completed Text evidence publication on the single FIFO. A report caused by Text itself can still race the narrow interval between physical write completion and ledger publication; queued bytes are never falsely marked successful to hide this.\",\"write_input Err exposes no partial byte count, so that attempt cannot certify later cumulative text; earlier successfully completed candidates remain valid evidence.\",\"Text equality cannot distinguish a later human submission identical to historical core delivery. Key tagging is not terminal-editor emulation.\"]}}","call_id":"call_4ltF9fKU5hcyJfnNcwwu04WV","internal_chat_message_metadata_passthrough":{"create_time":1789295762.333591,"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"},"name":"yield","metadata":{"turn_id":"87cd48c1-8735-473f-8cd5-49036251bcf4"}}]},"duration":18062.887699999963,"ttft":1347.761899999925,"completedAt":1789295780022,"contextSnapshot":{"promptTokens":58714,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"43e24cf8","parentId":"5b21007a","timestamp":"2026-09-13T10:36:20.027Z","message":{"role":"toolResult","toolCallId":"call_4ltF9fKU5hcyJfnNcwwu04WV|fc_0b12df87254bb4e6016aa67c9754e487d1b8e5930f1902a346","toolName":"yield","content":[{"type":"text","text":"Result submitted."}],"details":{"data":{"changes":[{"path":"crates/spt-daemon/src/broker.rs","edits":"Replaced raw InputRecord alias with source-tagged records; attached session-lifetime DeliveryBytes to InputWriter; added delivery_matches and delivery_unavailable_reason; classified controller enqueue and settle probes separately; marked translated Text/Key with per-attempt custody; aggregated chunked Text at command boundaries; published only after successful physical writes through unchanged bounded FIFO/single writer; poisoned attempt on dropped enqueue or physical error; preserved controller floor flush classification; updated two existing writer tests only for record contract changes."},{"path":"crates/spt-daemon/src/deliverybytes.rs","edits":"New private delivery ledger and physical-write custody seam. SHA-256 cumulative Text candidates preserve exact multiline bytes without payload normalization. Source-tagged Key controls excluded. Constant-size pending attempt hashes plus maximum 65,536 session-lifetime completed digests, never evicted; quota returns named delivery-evidence-capacity non-grant."}],"integration_required":["Parent adds `mod deliverybytes;` to lib.rs.","Report dispatch must check InputWriter::delivery_unavailable_reason() before granting origin and decline with returned reason. Parent owns broker.rs again."],"tests_added":["deliverybytes::tests::split_multiline_delivery_matches_before_commit_without_normalizing","deliverybytes::tests::controller_and_probe_bytes_never_become_delivery_evidence","deliverybytes::tests::failed_physical_write_cannot_certify_omitted_or_partial_bytes","deliverybytes::tests::successful_text_commands_aggregate_without_key_bytes","deliverybytes::tests::exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants","broker::tests::input_delivery_queue_drop_never_certifies_missing_text","broker::tests::chunked_delivery_is_visible_before_enter_and_floor_flush_stays_human"],"verification":"No build, test, lint, formatter, or other validation run, as explicitly assigned. Every new test carries [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]. No LSP tool available; scoped grep reference lookup used.","limits":["Separate Enter follows completed Text evidence publication on the single FIFO. A report caused by Text itself can still race the narrow interval between physical write completion and ledger publication; queued bytes are never falsely marked successful to hide this.","write_input Err exposes no partial byte count, so that attempt cannot certify later cumulative text; earlier successfully completed candidates remain valid evidence.","Text equality cannot distinguish a later human submission identical to historical core delivery. Key tagging is not terminal-editor emulation."]},"status":"success"},"isError":false,"timestamp":1789295780024}}
{"type":"custom_message","customType":"irc:incoming","content":"<irc>\nIncoming IRC message from agent `Main`:\n\nPlease modify ONLY deliverybytes.rs now (broker parent active). Close physical-write/report race with active-delivery-write evidence: set before physical write, publish digest then clear; unavailable_reason returns named delivery-write-in-progress during interval. On physical Err partial count unproven, mark session exclusion evidence unavailable (named delivery-write-unproven), not pretend absent match grants. Keep nonblocking receipt; no lock over PTY. Add deterministic callback surface test asking ledger unavailable during write, false after successful published text; partial failure non-grant. Skip validation. Report module done.\nIf response expected, reply via `hub` (`op: \"send\"`, `to: \"Main\"`) when available; otherwise what you `yield` or say last this turn is delivered to `Main` when you stop.\n</irc>","display":true,"details":{"id":"157de3d679c48177","from":"Main","message":"Please modify ONLY deliverybytes.rs now (broker parent active). Close physical-write/report race with active-delivery-write evidence: set before physical write, publish digest then clear; unavailable_reason returns named delivery-write-in-progress during interval. On physical Err partial count unproven, mark session exclusion evidence unavailable (named delivery-write-unproven), not pretend absent match grants. Keep nonblocking receipt; no lock over PTY. Add deterministic callback surface test asking ledger unavailable during write, false after successful published text; partial failure non-grant. Skip validation. Report module done."},"attribution":"agent","id":"57160b92","parentId":"43e24cf8","timestamp":"2026-09-13T10:39:47.175Z"}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_CnLJcRenaS6lJ8V0tN0EYqAA|fc_0b12df87254bb4e6016aa67d77d53087d1b93bb8e72eaf686b","toolName":"read","startedAt":"2026-09-13T10:39:53.184Z","args":{"path":".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs:1-170,205-270"},"intent":"Reading current delivery ledger"},"id":"4dba4214","parentId":"57160b92","timestamp":"2026-09-13T10:39:53.184Z"}
{"type":"message","id":"695b26df","parentId":"4dba4214","timestamp":"2026-09-13T10:39:53.185Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_CnLJcRenaS6lJ8V0tN0EYqAA|fc_0b12df87254bb4e6016aa67d77d53087d1b93bb8e72eaf686b","name":"read","arguments":{"i":"Reading current delivery ledger","path":".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs:1-170,205-270"},"intent":"Reading current delivery ledger"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":840,"output":51,"cacheRead":58624,"cacheWrite":0,"totalTokens":59515,"cost":{"input":0.008400000000000001,"output":0.00255,"cacheRead":0.058623999999999996,"cacheWrite":0,"total":0.069574}},"stopReason":"toolUse","timestamp":1789295987216,"responseId":"resp_0b12df87254bb4e6016aa67d736a0c87d1b8fde7c9c3c0943b","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0b12df87254bb4e6016aa67d77d53087d1b93bb8e72eaf686b","type":"function_call","status":"completed","arguments":"{\"i\":\"Reading current delivery ledger\",\"path\":\".worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs:1-170,205-270\"}","call_id":"call_CnLJcRenaS6lJ8V0tN0EYqAA","internal_chat_message_metadata_passthrough":{"create_time":1789295987.695398,"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"},"name":"read","metadata":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"}}]},"duration":5966.880899999989,"ttft":5177.8582999999635,"completedAt":1789295993183,"contextSnapshot":{"promptTokens":59464,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"194cc6b8","parentId":"695b26df","timestamp":"2026-09-13T10:39:53.191Z","message":{"role":"toolResult","toolCallId":"call_CnLJcRenaS6lJ8V0tN0EYqAA|fc_0b12df87254bb4e6016aa67d77d53087d1b93bb8e72eaf686b","toolName":"read","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#722F]\n1://! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\n2:\n3:use sha2::{Digest, Sha256};\n4:use spt_term::surface::SessionSurface;\n5:use std::collections::HashSet;\n6:use std::sync::{Arc, Mutex};\n7:\n8:// Digests, not retained payloads. Never evict evidence from a live hosted session:\n9:// exhaustion disables origin grants with a named reason instead.\n10:const MAX_DELIVERY_DIGESTS: usize = 65_536;\n11:\n12:#[derive(Default)]\n13:pub(crate) struct DeliveryBytes {\n14:    completed: Mutex<Completed>,\n15:}\n16:\n17:#[derive(Default)]\n18:struct Completed {\n19:    digests: HashSet<[u8; 32]>,\n20:    exhausted: bool,\n21:}\n22:\n23:impl DeliveryBytes {\n24:    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\n25:        let digest: [u8; 32] = Sha256::digest(payload).into();\n26:        self.completed\n27:            .lock()\n28:            .unwrap_or_else(|p| p.into_inner())\n29:            .digests\n30:            .contains(&digest)\n31:    }\n32:\n33:    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n34:        self.completed\n35:            .lock()\n36:            .unwrap_or_else(|p| p.into_inner())\n37:            .exhausted\n38:            .then_some(\"delivery-evidence-capacity\")\n39:    }\n40:\n41:    fn remember(&self, digest: [u8; 32]) {\n42:        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n43:    }\n44:\n45:    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\n46:        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n47:        if completed.digests.contains(&digest) {\n48:            return;\n49:        }\n50:        if completed.digests.len() >= limit {\n51:            completed.exhausted = true;\n52:        } else {\n53:            completed.digests.insert(digest);\n54:        }\n55:    }\n56:}\n57:\n58:/// One translation attempt; queued records keep its constant-size streaming state\n59:/// alive until the lone writer has processed them, independently of logical Commit.\n60:#[derive(Default)]\n61:pub(crate) struct DeliveryAttempt {\n62:    text: Mutex<AttemptText>,\n63:}\n64:\n65:#[derive(Default)]\n66:struct AttemptText {\n67:    hash: Sha256,\n68:    has_text: bool,\n69:    failed: bool,\n70:}\n71:\n72:#[derive(Clone, Copy)]\n73:pub(crate) enum DeliveryPart {\n74:    Text { end: bool },\n75:    Key,\n76:}\n77:\n78:impl DeliveryAttempt {\n79:    fn failed(&self) {\n80:        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\n81:    }\n82:\n83:    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\n84:        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\n85:        if text.failed {\n86:            return;\n87:        }\n88:        if let DeliveryPart::Text { end } = part {\n89:            text.hash.update(bytes);\n90:            text.has_text |= !bytes.is_empty();\n91:            if end && text.has_text {\n92:                // Publish each complete Text command's cumulative text, including\n93:                // exact embedded newlines. Keys are source-tagged controls, never\n94:                // guessed framing stripped from the reported payload.\n95:                ledger.remember(text.hash.clone().finalize().into());\n96:            }\n97:        }\n98:    }\n99:}\n100:\n101:pub(crate) struct InputRecord {\n102:    bytes: Vec<u8>,\n103:    origin: InputOrigin,\n104:}\n105:\n106:enum InputOrigin {\n107:    Controller,\n108:    Probe,\n109:    Delivery {\n110:        attempt: Arc<DeliveryAttempt>,\n111:        part: DeliveryPart,\n112:    },\n113:}\n114:\n115:impl InputRecord {\n116:    #[cfg(test)]\n117:    pub(crate) fn into_bytes(self) -> Vec<u8> {\n118:        self.bytes\n119:    }\n120:\n121:    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n122:        Self { bytes, origin: InputOrigin::Controller }\n123:    }\n124:\n125:    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\n126:        Self { bytes, origin: InputOrigin::Probe }\n127:    }\n128:\n129:    pub(crate) fn delivery(\n130:        bytes: Vec<u8>,\n131:        attempt: &Arc<DeliveryAttempt>,\n132:        part: DeliveryPart,\n133:    ) -> Self {\n134:        Self {\n135:            bytes,\n136:            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\n137:        }\n138:    }\n139:\n140:    pub(crate) fn dropped(&self) {\n141:        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\n142:            attempt.failed();\n143:        }\n144:    }\n145:\n146:    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n147:    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n148:        // Never hold a custody lock across a potentially wedged physical write.\n149:        // Ok proves write_all + flush, not harness interpretation. Err may follow\n150:        // a partial write, whose byte count this API does not expose: do not guess.\n151:        let success = surface.write_input(&self.bytes).is_ok();\n152:        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n153:            if success {\n154:                attempt.written(&self.bytes, *part, ledger);\n155:            } else {\n156:                attempt.failed();\n157:            }\n158:        }\n159:        // A report caused by a separate Enter sees the preceding Text's published\n160:        // evidence before Enter is written (one FIFO, one writer). A report caused\n161:        // by Text itself can race between physical completion and this publication;\n162:        // enqueued bytes cannot honestly close that narrower window.\n163:    }\n164:}\n165:\n166:#[cfg(test)]\n167:mod tests {\n168:    use super::*;\n169:    use spt_term::surface::{SurfaceError, SurfaceSize};\n170:\n…\n200:    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n…\n205:        assert!(!ledger.matches(b\"\\x1b[6n\"));\n206:        assert!(!ledger.matches(b\"unknown human payload\"));\n207:    }\n208:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n209:    #[test]\n210:    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n211:        struct PartialFailure(Mutex<Vec<u8>>);\n212:        impl SessionSurface for PartialFailure {\n213:            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n214:                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\n215:                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n216:            }\n217:            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n218:        }\n219:\n220:        let ledger = DeliveryBytes::default();\n221:        let attempt = Arc::new(DeliveryAttempt::default());\n222:        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n223:        let partial = PartialFailure(Mutex::new(Vec::new()));\n224:        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n225:        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n226:        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\n227:        assert!(!ledger.matches(b\"beforemiddleafter\"));\n228:        assert!(!ledger.matches(b\"beforeafter\"));\n229:        assert!(!ledger.matches(b\"beforemiafter\"));\n230:    }\n231:\n232:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n233:    #[test]\n234:    fn successful_text_commands_aggregate_without_key_bytes() {\n235:        let ledger = DeliveryBytes::default();\n236:        let attempt = Arc::new(DeliveryAttempt::default());\n237:        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n238:        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n239:        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n240:        assert!(ledger.matches(b\"one\\ntwo\"));\n241:        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n242:        let next_attempt = Arc::new(DeliveryAttempt::default());\n243:        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n244:        assert!(ledger.matches(b\"three\"));\n245:        assert!(!ledger.matches(b\"one\\ntwothree\"));\n246:    }\n247:\n248:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n249:    #[test]\n250:    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\n251:        let ledger = DeliveryBytes::default();\n252:        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n253:        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n254:        assert_eq!(ledger.unavailable_reason(), None);\n255:        ledger.remember_with_limit(Sha256::digest(b\"second\").into(), 1);\n256:        assert!(ledger.matches(b\"first\"));\n257:        assert!(!ledger.matches(b\"second\"));\n258:        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-evidence-capacity\"));\n259:    }\n260:}"}],"details":{"displayContent":{"text":"//! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\n\nuse sha2::{Digest, Sha256};\nuse spt_term::surface::SessionSurface;\nuse std::collections::HashSet;\nuse std::sync::{Arc, Mutex};\n\n// Digests, not retained payloads. Never evict evidence from a live hosted session:\n// exhaustion disables origin grants with a named reason instead.\nconst MAX_DELIVERY_DIGESTS: usize = 65_536;\n\n#[derive(Default)]\npub(crate) struct DeliveryBytes {\n    completed: Mutex<Completed>,\n}\n\n#[derive(Default)]\nstruct Completed {\n    digests: HashSet<[u8; 32]>,\n    exhausted: bool,\n}\n\nimpl DeliveryBytes {\n    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\n        let digest: [u8; 32] = Sha256::digest(payload).into();\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .digests\n            .contains(&digest)\n    }\n\n    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .exhausted\n            .then_some(\"delivery-evidence-capacity\")\n    }\n\n    fn remember(&self, digest: [u8; 32]) {\n        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n    }\n\n    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        if completed.digests.contains(&digest) {\n            return;\n        }\n        if completed.digests.len() >= limit {\n            completed.exhausted = true;\n        } else {\n            completed.digests.insert(digest);\n        }\n    }\n}\n\n/// One translation attempt; queued records keep its constant-size streaming state\n/// alive until the lone writer has processed them, independently of logical Commit.\n#[derive(Default)]\npub(crate) struct DeliveryAttempt {\n    text: Mutex<AttemptText>,\n}\n\n#[derive(Default)]\nstruct AttemptText {\n    hash: Sha256,\n    has_text: bool,\n    failed: bool,\n}\n\n#[derive(Clone, Copy)]\npub(crate) enum DeliveryPart {\n    Text { end: bool },\n    Key,\n}\n\nimpl DeliveryAttempt {\n    fn failed(&self) {\n        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\n    }\n\n    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\n        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\n        if text.failed {\n            return;\n        }\n        if let DeliveryPart::Text { end } = part {\n            text.hash.update(bytes);\n            text.has_text |= !bytes.is_empty();\n            if end && text.has_text {\n                // Publish each complete Text command's cumulative text, including\n                // exact embedded newlines. Keys are source-tagged controls, never\n                // guessed framing stripped from the reported payload.\n                ledger.remember(text.hash.clone().finalize().into());\n            }\n        }\n    }\n}\n\npub(crate) struct InputRecord {\n    bytes: Vec<u8>,\n    origin: InputOrigin,\n}\n\nenum InputOrigin {\n    Controller,\n    Probe,\n    Delivery {\n        attempt: Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    },\n}\n\nimpl InputRecord {\n    #[cfg(test)]\n    pub(crate) fn into_bytes(self) -> Vec<u8> {\n        self.bytes\n    }\n\n    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Controller }\n    }\n\n    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Probe }\n    }\n\n    pub(crate) fn delivery(\n        bytes: Vec<u8>,\n        attempt: &Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    ) -> Self {\n        Self {\n            bytes,\n            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\n        }\n    }\n\n    pub(crate) fn dropped(&self) {\n        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\n            attempt.failed();\n        }\n    }\n\n    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n        // Never hold a custody lock across a potentially wedged physical write.\n        // Ok proves write_all + flush, not harness interpretation. Err may follow\n        // a partial write, whose byte count this API does not expose: do not guess.\n        let success = surface.write_input(&self.bytes).is_ok();\n        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n            if success {\n                attempt.written(&self.bytes, *part, ledger);\n            } else {\n                attempt.failed();\n            }\n        }\n        // A report caused by a separate Enter sees the preceding Text's published\n        // evidence before Enter is written (one FIFO, one writer). A report caused\n        // by Text itself can race between physical completion and this publication;\n        // enqueued bytes cannot honestly close that narrower window.\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use spt_term::surface::{SurfaceError, SurfaceSize};\n\n…\n    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n…\n        assert!(!ledger.matches(b\"\\x1b[6n\"));\n        assert!(!ledger.matches(b\"unknown human payload\"));\n    }\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n        struct PartialFailure(Mutex<Vec<u8>>);\n        impl SessionSurface for PartialFailure {\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\n                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n            }\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n        }\n\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n        let partial = PartialFailure(Mutex::new(Vec::new()));\n        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\n        assert!(!ledger.matches(b\"beforemiddleafter\"));\n        assert!(!ledger.matches(b\"beforeafter\"));\n        assert!(!ledger.matches(b\"beforemiafter\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"one\\ntwo\"));\n        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n        let next_attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"three\"));\n        assert!(!ledger.matches(b\"one\\ntwothree\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\n        let ledger = DeliveryBytes::default();\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        assert_eq!(ledger.unavailable_reason(), None);\n        ledger.remember_with_limit(Sha256::digest(b\"second\").into(), 1);\n        assert!(ledger.matches(b\"first\"));\n        assert!(!ledger.matches(b\"second\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-evidence-capacity\"));\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,84,85,86,87,88,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,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,null,200,null,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260]},"fileSize":9910,"meta":{"source":{"type":"path","value":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\deliverybytes.rs"}}},"isError":false,"timestamp":1789295993191}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_XXq2FsScRW1fyA0q28nkm0HL|fc_0b12df87254bb4e6016aa67d84568487d1ac449e7cdc995a2e","toolName":"hub","startedAt":"2026-09-13T10:40:04.597Z","intent":"Coordinating race-safe lookup order"},"id":"4296770b","parentId":"194cc6b8","timestamp":"2026-09-13T10:40:04.597Z"}
{"type":"message","id":"70e3c6d0","parentId":"4296770b","timestamp":"2026-09-13T10:40:04.598Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Advising unavailable-first checks**"},{"type":"toolCall","id":"call_XXq2FsScRW1fyA0q28nkm0HL|fc_0b12df87254bb4e6016aa67d84568487d1ac449e7cdc995a2e","name":"hub","arguments":{"i":"Coordinating race-safe lookup order","op":"send","to":"Main","message":"Adding active/unproven status inside deliverybytes.rs. Receipt should check delivery_unavailable_reason BEFORE delivery_matches: matches-first can miss unpublished digest, then see cleared status after writer publishes, allowing grant. Status-first sees either active non-grant or published digest (for report caused by that write). No broker edits from me."},"intent":"Coordinating race-safe lookup order"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":2703,"output":204,"cacheRead":59264,"cacheWrite":0,"totalTokens":62171,"reasoningTokens":102,"cost":{"input":0.027030000000000002,"output":0.0102,"cacheRead":0.059264,"cacheWrite":0,"total":0.096494}},"stopReason":"toolUse","timestamp":1789295993229,"responseId":"resp_0b12df87254bb4e6016aa67d796a7c87d1be85acd22182e8cf","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67d7d9dcc87d181344a5bb1005a14","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpn2EUmhMjl1dq0zuaKDevYvoNrrdhVLiOcMiG3W7jyRB7tgNMZI2iZpeECKrZKCSCGO13KPwvC-f7tw6LSUQB3zR6PYjLnbMxNYBnoPCrj-11sch03yOslc7dbNW4rCl98zY1i13uzV4bWHzaGz8lOfdQJN2PBRFwPI4QScbL9x7LAAxT1UqChZEXAWxWiI7IVp7s4TEplnTVfeY2SntGFvMOcR_8H3Ds77w3seeghpbpScVc9cGtaGyKMNDiNI4ziBbr1JFdAQO9HFMJ75ORXF3L6IWUxTA0zgGMK5x9lVMY58PDMTLz3ucOdJX6X2so52ADiObQFuzovRvCOeOTNEVxs7bTVV4oUH_sdKV_JgmoLPZMFvpYVKR8ul8QTn7IB3hIbg3IRQUfmPgS13nY74Vcu1_2qvxEd3FltYJHOGec2wJk0tP88h8UtvOfveY2aRna9QhBC_zjH5j6kxysdEx1g4kOpf67axXqp6lIgDQIrvkGwciXIpBAPavIvj9jy93UJTuFkWMZgpGNsZ44SzOrCIOi6ceTU-C12AdLYSiWHPolR4WSu5oGa-TkxjEkW9hwEGHJlK2FkdtgYRZChIF879VM1Mjt_47-LG-mmbahBRitjP7RlL9Y7yt6UNCpoBsRYi5FMOJSK5NM3R9jlIFUrCXSFOUEnZYT0pMnLgbCWTpJzhtKOZcvfxGs66gJrwdaKZPmXjmU0NPOlYMP-zweE7J89qxVA-miaR_iGgnSBTr6fKVkXaF6bWTVCW2Asqb8Q5-opCtpsXQYMHuqo1Iu8NrpqShwsaS5mQoj98fWIRc9X9d6kmTIs94VpcH3VO3CSKjqtLXKoYTu3y7KcavNbywdI-vjmmTQos0Mu-JUSCRmdQkRuA0YwdHk3BfYg_vzbOIHiMm5ojFvoEZrDzFL_LuIWj_m-rxWr8whUWnArX2mdTKClDvdPFq3jxouh4kG-XjoEt2-BZH6BmzqZN6wl1irHSBBymAVZSXJYfT1qyMqQRG_4ytNzKJRllTAbiWyIbfKowZzvIQPd6hrwdVCzvtXhakeaU2hwc5A0PRop68JEqTeGwsTHiF6mvylPylww0MT_VXGA3RuFTopJFIn0MFnhk6T4t_VF-C_iejZcErf8m15oE96_UKzGdzfs6dncDnNeV4CXpyGFMd2ZtKd2ledeuTojuxZF7FXNEWNnugPvGGDmQC_QDFheXmIDJJ8eB8dgr4ugFFeDm8ceHJ2PiV9T4fitjL0izyF6l9F3j1xAx92-kTJMvOgOxDN3x5fbIyehqtJleg4otJLwjGi5ZI9uIz67DoGKqlkM6Ccqcfex8LvFWy4ce3cghh6zrvmJ8TSkmXgFRmlgehlL-vzmEicvR9xXVPliZNhdd0OntmH4oQdC7HBQFW9mzuuq1tB-fff8BQUkOyzDKeCbBiwJD-uQO3ydfjwXi_ouT23VHgVpe9816yWh_LquyWm6YueM4bFg_TBJ32Y95iMiN2xwH4ihhB0W2zLvYsgEcx_U8anfp8kYx_N7TXj1zTRChFJtsX4PsIcW2q8V9thFbmDbbgWijqYKYYEsF9NOPBJQjqJ_PdzJm1oQeGhgqA5cHi43qkUSnp8r0bzdcNJbs9VysJrlWqvIl8oIZAoR8i0bSO5k3ngNKy2dt0k5Wy5WhvfbdwcPeJSVDne25tJd0OIFqUJbC8xXnXLDD31fkXQpS0FLijcASxOpXR5D99cRR_fRJsbq3y_Ap0wWN55X5ZmNCDk7nWeo73jd5_dn-izEL01yC2uLu9KfFZw0beeJdJZ_k1uinZgZScKUHl0-RXgW6vWxo6-ZtdjT39Fqu0DJwkcJlPSrvSFSDFgTdD3nuKL8QpR1Rxj4RN35YW2i-HdZz116wU0wR-7CekcBikdgZwjAr2CD6B0EkafW6Gl_HbLlc_4uE23wwBV2esocUnc0IqJrTm6b0oUK4O9Y2yFa1uE-awqe1fZN6DK7rDEyEPPmuygGKYVFFm1FNp1vzCQgYWhnJYnrLa4HGQeXGMjnonE4Tps4oLjK-arxuAdnQAsdfIQh-qEtFp5K2zASJoqFFILIp7ADohvqYUk7ZFnCDbK6yQ6lIzg6IhF1kLNci6z84TsAc_vIhVD19W4_nmJw==","internal_chat_message_metadata_passthrough":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"},"summary":[{"type":"summary_text","text":"**Advising unavailable-first checks**"}],"metadata":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"}},{"id":"fc_0b12df87254bb4e6016aa67d84568487d1ac449e7cdc995a2e","type":"function_call","status":"completed","arguments":"{\"i\":\"Coordinating race-safe lookup order\",\"op\":\"send\",\"to\":\"Main\",\"message\":\"Adding active/unproven status inside deliverybytes.rs. Receipt should check delivery_unavailable_reason BEFORE delivery_matches: matches-first can miss unpublished digest, then see cleared status after writer publishes, allowing grant. Status-first sees either active non-grant or published digest (for report caused by that write). No broker edits from me.\"}","call_id":"call_XXq2FsScRW1fyA0q28nkm0HL","internal_chat_message_metadata_passthrough":{"create_time":1789295993.593059,"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"},"name":"hub","metadata":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"}}]},"duration":11366.33030000003,"ttft":4406.757699999958,"completedAt":1789296004596,"contextSnapshot":{"promptTokens":61967,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"8557ac11","parentId":"70e3c6d0","timestamp":"2026-09-13T10:40:04.599Z","message":{"role":"toolResult","toolCallId":"call_XXq2FsScRW1fyA0q28nkm0HL|fc_0b12df87254bb4e6016aa67d84568487d1ac449e7cdc995a2e","toolName":"hub","content":[{"type":"text","text":"Delivered to 1 peer(s):\n- Main: injected"}],"details":{"op":"send","from":"DeliveryRecording","to":"Main","receipts":[{"to":"Main","outcome":"injected"}]},"isError":false,"timestamp":1789296004599}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_YVbKMEOmNJf5u9Lg0jXS8s1D|ctc_0b12df87254bb4e6016aa67d8e5c3087d183ae249d4ca50775","toolName":"edit","startedAt":"2026-09-13T10:40:39.062Z"},"id":"60043871","parentId":"8557ac11","timestamp":"2026-09-13T10:40:39.062Z"}
{"type":"message","id":"b1deca2b","parentId":"60043871","timestamp":"2026-09-13T10:40:39.062Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Implementing Completed flags**\n\n**Implementing write-state locks**"},{"type":"toolCall","id":"call_YVbKMEOmNJf5u9Lg0jXS8s1D|ctc_0b12df87254bb4e6016aa67d8e5c3087d183ae249d4ca50775","name":"edit","arguments":{"input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#722F]\nPUT >20:\n+    writing: bool,\n+    unproven: bool,\nPUT 33.=39:\n+    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n+        let completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n+        if completed.unproven {\n+            Some(\"delivery-write-unproven\")\n+        } else if completed.writing {\n+            Some(\"delivery-write-in-progress\")\n+        } else if completed.exhausted {\n+            Some(\"delivery-evidence-capacity\")\n+        } else {\n+            None\n+        }\n+    }\n+\n+    fn begin_write(&self) {\n+        self.completed.lock().unwrap_or_else(|p| p.into_inner()).writing = true;\n+    }\n+\n+    fn finish_write(&self, success: bool) {\n+        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n+        completed.unproven |= !success;\n+        completed.writing = false;\n+    }\nPUT 147.=163:\n+    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n+        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n+            // Mark uncertainty BEFORE input can cause a report. No custody lock\n+            // spans the blocking PTY call; receipt declines immediately instead.\n+            ledger.begin_write();\n+            let success = surface.write_input(&self.bytes).is_ok();\n+            if success {\n+                attempt.written(&self.bytes, *part, ledger);\n+            } else {\n+                // Err can follow a partial write; this API exposes no byte count.\n+                // Keep session evidence unavailable, rather than grant an origin\n+                // merely because the partly delivered payload lacks a digest.\n+                attempt.failed();\n+            }\n+            // Successful candidate publication precedes clearing the active flag.\n+            // Receipt checks unavailable_reason BEFORE matches so it cannot miss\n+            // an unpublished digest and then observe an already-cleared flag.\n+            ledger.finish_write(success);\n+        } else {\n+            let _ = surface.write_input(&self.bytes);\n+        }\n+    }\nPUT >207:\n+\n+    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    #[test]\n+    fn report_during_physical_write_declines_until_success_is_published() {\n+        struct ReportingSurface<'a>(&'a DeliveryBytes);\n+        impl SessionSurface for ReportingSurface<'_> {\n+            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n+                assert_eq!(self.0.unavailable_reason(), Some(\"delivery-write-in-progress\"));\n+                assert!(!self.0.matches(bytes));\n+                Ok(())\n+            }\n+            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n+        }\n+\n+        let ledger = DeliveryBytes::default();\n+        let attempt = Arc::new(DeliveryAttempt::default());\n+        InputRecord::delivery(\n+            b\"submission C:/exact\".to_vec(), &attempt, DeliveryPart::Text { end: true },\n+        ).write_to(&ReportingSurface(&ledger), &ledger);\n+        assert_eq!(ledger.unavailable_reason(), None);\n+        assert!(ledger.matches(b\"submission C:/exact\"));\n+    }\n+\nPUT >229:\n+        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n+\n+        let recovered_attempt = Arc::new(DeliveryAttempt::default());\n+        InputRecord::delivery(\n+            b\"later success\".to_vec(), &recovered_attempt, DeliveryPart::Text { end: true },\n+        ).write_to(&Sink, &ledger);\n+        assert!(ledger.matches(b\"later success\"));\n+        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n*** End Patch\n"},"customWireName":"edit"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":369,"output":1094,"cacheRead":61824,"cacheWrite":0,"totalTokens":63287,"reasoningTokens":215,"cost":{"input":0.00369,"output":0.054700000000000006,"cacheRead":0.061824,"cacheWrite":0,"total":0.120214}},"stopReason":"toolUse","timestamp":1789296004606,"responseId":"resp_0b12df87254bb4e6016aa67d84e14887d193eda63f38b81c74","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67d86317487d1b8e63ca03bbbc405","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpn2OyI6COC6U9STH8OEgXkK3VTkE7-6M1ioi25anV_YWNt3JS5NeKlrUD8CaeuhwfZZ9zhcVf7eSrKYtx7XL_NvPK8P7uwHhpwcc0dheFTnkqui5j5Ing7BemRdXdlJpco09m_7g_xGq_FJm_TMHPP0Nldlt5YuhKDfEvb3lV9iV1dgKAUNHrENHp398su7sMVrFluirjIoNg9PPpP77VTZhwJAz_nqrgiMCLkDtPg_qi8uli-Os5mi1F-jKi3cT58Fiv7pmkLnuM-nOLSeyFIVCx0qoAHFd70PbcBAzfXvQO-msPmtW9nG5f2TtFXjM6flRgBhnU_Q3t_gb6BpARhtl0MCjy1vtf1XczASyIpqFcwutGyTibX7zh9omn6YsaHLbKuj3tdYxb1eoPxO6E1B9_kzIrbIyPh91-Fq3-x_78-EcIBXdfoFsNOsZI4mu1xV1R21q1rCXP_dOtN30zcMM_0HFWAdyUwo33642FVxp6zm1HaZZpqV_iEZqt8S7nRMer05z9H0sDfgka9QIOHo30vL3h6h73SUnkRhX4I1XJXLyy9fQXSe6Kxbf9YFQOIlaxAcwU1fGAtDRxHLrbCpwZbBSlB4_gZCo-T4pZWSChX5pTdBozd3nFCk0TW53ZwSblo_Uin_XNyBbzXSf2WPqAothK1BJYbYCXRMpg_gwZIL5wajlUoBgDyD1iaWlEoaGIL98bktpU-xy6hiL-Mow969dW_GUniQpjvfv33ZOFUlYPcz_qwjfSBuSRSkEzdzG_v89H8h-038m50xnkFh6ebuk3_DsQCOtlQgf9avuqd1suGWmPh2muNSLjuB-aMp8T6dVaeWgweFUXKxY9SbRBhRpF3yH9y_2gjc2nz1HuqMjpZIeibeGqQkpOP3Sh7n2Gj6cXQyOV2IN8LuLvxX2BG44DOy0o5FeFZTB5uzmh3abN2jATBPiOLnp4GmDs9zDM5Ct9apWkUIJzlZJ0o90-ry8v_86Wb0-B0iRBnE_5UCFPf1iEElsQwHQDrEMpExwaIwM9In0VzpKTraydUSIuYCXBmmglQvMY-DUn2njS42qDvWf26obWZKfiQ1p2tKCh7UtFF44C9-YfjzUAvZl_-L_Woq-BdnsOgEETMb9TY-ViKdvB65bSQvc6nKEagKxiyKDT0BnaxcBqnBieoGhIxbloL7qOMdH0UCSQu3KsmQc-PHN4dIrfufY9iS7AJhhmjsqoL1kRewWT4u2hldeBm8cdaqCC3z5YYLh1t2lEB0jaLoQ_no0IHLrYU5w4kda1VOBiineGGE1EKz418AfSE_jrX3vN8EJRiepcArhvITG7gAYA2tdq3eZd67Z3yZmLf3kFgDJHs4t3P9typIddwqIi9uYJaL0wRVD1MYmqNRhHFhGbttQZN3BRU810_m2_ooYifdh9At9PoKAeaQVvBMlPsZ_VpW9Bu-rRecHKFagzMfTfk6xsObKUzs6OIw2BGgogu_YCGjTEY7qwYE4KfE_9Zc6F0qJVrJZZLVHo3r0DRWKh8qWuf3eo0SEOAVaW-BaxunUsh6wVLZYmLZBrWcWWY9XFBDbZI4AjdEgmI_WbR53KTi1mjcq1ELcI4D6F6e7e2U6oytyFaY4-fDihEO97WmOZyQU3BAnE3gNhRxpbg0VrRkX0_uUd3OuAD-iZhtE424T0t9OomtRmJazhnaxLFQ2kDWYdL5zU5fYMGCT776cqCvLcnsleoohIlII98teQIHR6K8CcLiZ4tmznQbG92zq0v2tAFunMkmpzcR4QiPnJXMztkKVcVCu2W_oGnxepdexveUMtZ94jRRKs-W6etlvL-u50YMDNWsMVZYaNhfSBZlmZz51_Az_2l9laSInnCAItnsrm6Glrnv4VERM1xoXutkAfg2EGowoRjCpTVeA2Hf6-qYawBi4CBmO3-UZtxL0zs9k4OY51L0a3yuLfDIlSUGAjBSrWTpc3nkN1AF0B5295L9p2hiv7J8jFT6EZ658Tf29kvB52DdUIJt0SYnlskuaHbswkTQkmGppyVD81RA60B08ngKAgqNd9-T2FSDUfnJAIoKS45_tMVzNyAYFgggo11M-LXpW1wBHCl75MpOURCBfznWW9nISdI6zlLxtCaPrSG94vPE16cY8LQtYXBX38cBgyE2lnySzov1ePVC1KMW247TrHP7NlcU4MPvCN9dkqqxnewwZHQjU-oJLIRZmamoQxplq4vK73wdX0NjJ4brOk4eqNp6NgkM-37NXo-jPmOFJ2rxzmDufnDzhuGh9FkzdFLV5jCSmZt2LsPpdyslUpI5Uj_ypk9EzMKAVMFtggiPGp1oLLTKjr8oD7_1ex8zKnfNgYrrvllAdxuYUJ4yvdOAgzvvBZPTeT12bBVS0VWOLfGTo8YFtehQqW0Lr8oN3-tzKUeuyTyFuNv7J9CoWVHTYecfxrW1I2wQRJkzsxXLHn_esZKP-faZHmvztCXLI4f7xUNYXpRc-MZKLDMkrc65C8j89iGBA111DG7q7qnayhG33SDrI0AsoOKIqauckSx-Qi2kZwnsSaoxAzIdgCHFt7ImC0tud7JTjGFoyPSw4lMCqsIUAuqt0qwB_qd3mum_kN-_dLSDnyhzYoVYJGK7Dt44FdV3tzfgjQTbAwxQpudToZWNO3FSMbRJMf6hi4ec_LyYb3GVjduv2HnDAJJtSvaLdpmImjyVNFsYM-j6UzWL-AfKEXzB-gslTHOHTE-LXj652sskh-B4Fuq7WADuQnBXUHocBqe-In-zY1H5_9pQNQJv59HABYBHyUT93GzmcZf6oC_9hEXi-BnCz8Ljf2rS2pjMTC6u5gF-MBpsfupfUXioV1p3PsCU0MtlZ950FK4u_HpyziT5mHDM9q6WEMNaEMC82IVUlUQ4Mifkj4ZKBdQ==","internal_chat_message_metadata_passthrough":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"},"summary":[{"type":"summary_text","text":"**Implementing Completed flags**"},{"type":"summary_text","text":"**Implementing write-state locks**"}],"metadata":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"}},{"id":"ctc_0b12df87254bb4e6016aa67d8e5c3087d183ae249d4ca50775","type":"custom_tool_call","status":"completed","call_id":"call_YVbKMEOmNJf5u9Lg0jXS8s1D","input":"*** Begin Patch\n[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#722F]\nPUT >20:\n+    writing: bool,\n+    unproven: bool,\nPUT 33.=39:\n+    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n+        let completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n+        if completed.unproven {\n+            Some(\"delivery-write-unproven\")\n+        } else if completed.writing {\n+            Some(\"delivery-write-in-progress\")\n+        } else if completed.exhausted {\n+            Some(\"delivery-evidence-capacity\")\n+        } else {\n+            None\n+        }\n+    }\n+\n+    fn begin_write(&self) {\n+        self.completed.lock().unwrap_or_else(|p| p.into_inner()).writing = true;\n+    }\n+\n+    fn finish_write(&self, success: bool) {\n+        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n+        completed.unproven |= !success;\n+        completed.writing = false;\n+    }\nPUT 147.=163:\n+    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n+        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n+            // Mark uncertainty BEFORE input can cause a report. No custody lock\n+            // spans the blocking PTY call; receipt declines immediately instead.\n+            ledger.begin_write();\n+            let success = surface.write_input(&self.bytes).is_ok();\n+            if success {\n+                attempt.written(&self.bytes, *part, ledger);\n+            } else {\n+                // Err can follow a partial write; this API exposes no byte count.\n+                // Keep session evidence unavailable, rather than grant an origin\n+                // merely because the partly delivered payload lacks a digest.\n+                attempt.failed();\n+            }\n+            // Successful candidate publication precedes clearing the active flag.\n+            // Receipt checks unavailable_reason BEFORE matches so it cannot miss\n+            // an unpublished digest and then observe an already-cleared flag.\n+            ledger.finish_write(success);\n+        } else {\n+            let _ = surface.write_input(&self.bytes);\n+        }\n+    }\nPUT >207:\n+\n+    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+    #[test]\n+    fn report_during_physical_write_declines_until_success_is_published() {\n+        struct ReportingSurface<'a>(&'a DeliveryBytes);\n+        impl SessionSurface for ReportingSurface<'_> {\n+            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n+                assert_eq!(self.0.unavailable_reason(), Some(\"delivery-write-in-progress\"));\n+                assert!(!self.0.matches(bytes));\n+                Ok(())\n+            }\n+            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n+        }\n+\n+        let ledger = DeliveryBytes::default();\n+        let attempt = Arc::new(DeliveryAttempt::default());\n+        InputRecord::delivery(\n+            b\"submission C:/exact\".to_vec(), &attempt, DeliveryPart::Text { end: true },\n+        ).write_to(&ReportingSurface(&ledger), &ledger);\n+        assert_eq!(ledger.unavailable_reason(), None);\n+        assert!(ledger.matches(b\"submission C:/exact\"));\n+    }\n+\nPUT >229:\n+        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n+\n+        let recovered_attempt = Arc::new(DeliveryAttempt::default());\n+        InputRecord::delivery(\n+            b\"later success\".to_vec(), &recovered_attempt, DeliveryPart::Text { end: true },\n+        ).write_to(&Sink, &ledger);\n+        assert!(ledger.matches(b\"later success\"));\n+        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n*** End Patch\n","internal_chat_message_metadata_passthrough":{"create_time":1789296005.039723,"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"},"name":"edit","metadata":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"}}]},"duration":34455.1372,"ttft":1607.563099999912,"completedAt":1789296039061,"contextSnapshot":{"promptTokens":62193,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"90dc3b86","parentId":"b1deca2b","timestamp":"2026-09-13T10:40:39.085Z","message":{"role":"toolResult","toolCallId":"call_YVbKMEOmNJf5u9Lg0jXS8s1D|ctc_0b12df87254bb4e6016aa67d8e5c3087d183ae249d4ca50775","toolName":"edit","content":[{"type":"text","text":"[.worktrees/300-input-acceptance/crates/spt-daemon/src/deliverybytes.rs#93C3]\n18:struct Completed {\n19:    digests: HashSet<[u8; 32]>,\n20:    exhausted: bool,\n21:    writing: bool,\n22:    unproven: bool,\n23:}\n24:\n34:\n35:    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n36:        let completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n37:        if completed.unproven {\n…\n44:            None\n45:        }\n46:    }\n47:\n48:    fn begin_write(&self) {\n49:        self.completed.lock().unwrap_or_else(|p| p.into_inner()).writing = true;\n…\n56:    }\n57:\n58:    fn remember(&self, digest: [u8; 32]) {\n59:        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n60:    }\n\n132:impl InputRecord {\n\n163:    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n164:    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n165:        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n166:            // Mark uncertainty BEFORE input can cause a report. No custody lock\n167:            // spans the blocking PTY call; receipt declines immediately instead.\n168:            ledger.begin_write();\n169:            let success = surface.write_input(&self.bytes).is_ok();\n170:            if success {\n171:                attempt.written(&self.bytes, *part, ledger);\n172:            } else {\n173:                // Err can follow a partial write; this API exposes no byte count.\n174:                // Keep session evidence unavailable, rather than grant an origin\n175:                // merely because the partly delivered payload lacks a digest.\n176:                attempt.failed();\n177:            }\n178:            // Successful candidate publication precedes clearing the active flag.\n179:            // Receipt checks unavailable_reason BEFORE matches so it cannot miss\n…\n182:        } else {\n183:            let _ = surface.write_input(&self.bytes);\n184:        }\n185:    }\n186:}\n\n222:    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n\n228:        assert!(!ledger.matches(b\"unknown human payload\"));\n229:    }\n230:\n231:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n232:    #[test]\n233:    fn report_during_physical_write_declines_until_success_is_published() {\n234:        struct ReportingSurface<'a>(&'a DeliveryBytes);\n…\n253:    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n254:    #[test]\n255:    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n256:        struct PartialFailure(Mutex<Vec<u8>>);\n273:        assert!(!ledger.matches(b\"beforeafter\"));\n274:        assert!(!ledger.matches(b\"beforemiafter\"));\n275:        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n276:\n…\n281:        assert!(ledger.matches(b\"later success\"));\n282:        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n283:    }\n284:"}],"details":{"diff":" 18|struct Completed {\n 19|    digests: HashSet<[u8; 32]>,\n 20|    exhausted: bool,\n+21|    writing: bool,\n+22|    unproven: bool,\n 21|}\n 22|\n 32|\n 33|    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n-34|        self.completed\n-35|            .lock()\n-36|            .unwrap_or_else(|p| p.into_inner())\n-37|            .exhausted\n-38|            .then_some(\"delivery-evidence-capacity\")\n+36|        let completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n+37|        if completed.unproven {\n+38|            Some(\"delivery-write-unproven\")\n+39|        } else if completed.writing {\n+40|            Some(\"delivery-write-in-progress\")\n+41|        } else if completed.exhausted {\n+42|            Some(\"delivery-evidence-capacity\")\n+43|        } else {\n+44|            None\n+45|        }\n 39|    }\n 40|\n+48|    fn begin_write(&self) {\n+49|        self.completed.lock().unwrap_or_else(|p| p.into_inner()).writing = true;\n+50|    }\n+51|\n+52|    fn finish_write(&self, success: bool) {\n+53|        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n+54|        completed.unproven |= !success;\n+55|        completed.writing = false;\n+56|    }\n+57|\n 41|    fn remember(&self, digest: [u8; 32]) {\n 42|        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n 43|    }\n\n 115|impl InputRecord {\n\n 146|    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n 147|    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n-148|        // Never hold a custody lock across a potentially wedged physical write.\n-149|        // Ok proves write_all + flush, not harness interpretation. Err may follow\n-150|        // a partial write, whose byte count this API does not expose: do not guess.\n-151|        let success = surface.write_input(&self.bytes).is_ok();\n 152|        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n+166|            // Mark uncertainty BEFORE input can cause a report. No custody lock\n+167|            // spans the blocking PTY call; receipt declines immediately instead.\n+168|            ledger.begin_write();\n+169|            let success = surface.write_input(&self.bytes).is_ok();\n 153|            if success {\n 154|                attempt.written(&self.bytes, *part, ledger);\n 155|            } else {\n+173|                // Err can follow a partial write; this API exposes no byte count.\n+174|                // Keep session evidence unavailable, rather than grant an origin\n+175|                // merely because the partly delivered payload lacks a digest.\n 156|                attempt.failed();\n 157|            }\n+178|            // Successful candidate publication precedes clearing the active flag.\n+179|            // Receipt checks unavailable_reason BEFORE matches so it cannot miss\n+180|            // an unpublished digest and then observe an already-cleared flag.\n+181|            ledger.finish_write(success);\n+182|        } else {\n+183|            let _ = surface.write_input(&self.bytes);\n 158|        }\n-159|        // A report caused by a separate Enter sees the preceding Text's published\n-160|        // evidence before Enter is written (one FIFO, one writer). A report caused\n-161|        // by Text itself can race between physical completion and this publication;\n-162|        // enqueued bytes cannot honestly close that narrower window.\n 163|    }\n 164|}\n\n 200|    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n\n 206|        assert!(!ledger.matches(b\"unknown human payload\"));\n 207|    }\n+230|\n 208|    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n 209|    #[test]\n+233|    fn report_during_physical_write_declines_until_success_is_published() {\n+234|        struct ReportingSurface<'a>(&'a DeliveryBytes);\n+235|        impl SessionSurface for ReportingSurface<'_> {\n+236|            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n+237|                assert_eq!(self.0.unavailable_reason(), Some(\"delivery-write-in-progress\"));\n+238|                assert!(!self.0.matches(bytes));\n+239|                Ok(())\n+240|            }\n+241|            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n+242|        }\n+243|\n+244|        let ledger = DeliveryBytes::default();\n+245|        let attempt = Arc::new(DeliveryAttempt::default());\n+246|        InputRecord::delivery(\n+247|            b\"submission C:/exact\".to_vec(), &attempt, DeliveryPart::Text { end: true },\n+248|        ).write_to(&ReportingSurface(&ledger), &ledger);\n+249|        assert_eq!(ledger.unavailable_reason(), None);\n+250|        assert!(ledger.matches(b\"submission C:/exact\"));\n+251|    }\n+252|\n+253|    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n+254|    #[test]\n 210|    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n 211|        struct PartialFailure(Mutex<Vec<u8>>);\n 228|        assert!(!ledger.matches(b\"beforeafter\"));\n 229|        assert!(!ledger.matches(b\"beforemiafter\"));\n+275|        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n+276|\n+277|        let recovered_attempt = Arc::new(DeliveryAttempt::default());\n+278|        InputRecord::delivery(\n+279|            b\"later success\".to_vec(), &recovered_attempt, DeliveryPart::Text { end: true },\n+280|        ).write_to(&Sink, &ledger);\n+281|        assert!(ledger.matches(b\"later success\"));\n+282|        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n 230|    }\n 231|","firstChangedLine":20,"op":"update","path":"C:\\Users\\decid\\Documents\\projects\\spt-core\\.worktrees\\300-input-acceptance\\crates\\spt-daemon\\src\\deliverybytes.rs","oldText":"//! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\n\nuse sha2::{Digest, Sha256};\nuse spt_term::surface::SessionSurface;\nuse std::collections::HashSet;\nuse std::sync::{Arc, Mutex};\n\n// Digests, not retained payloads. Never evict evidence from a live hosted session:\n// exhaustion disables origin grants with a named reason instead.\nconst MAX_DELIVERY_DIGESTS: usize = 65_536;\n\n#[derive(Default)]\npub(crate) struct DeliveryBytes {\n    completed: Mutex<Completed>,\n}\n\n#[derive(Default)]\nstruct Completed {\n    digests: HashSet<[u8; 32]>,\n    exhausted: bool,\n}\n\nimpl DeliveryBytes {\n    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\n        let digest: [u8; 32] = Sha256::digest(payload).into();\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .digests\n            .contains(&digest)\n    }\n\n    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .exhausted\n            .then_some(\"delivery-evidence-capacity\")\n    }\n\n    fn remember(&self, digest: [u8; 32]) {\n        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n    }\n\n    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        if completed.digests.contains(&digest) {\n            return;\n        }\n        if completed.digests.len() >= limit {\n            completed.exhausted = true;\n        } else {\n            completed.digests.insert(digest);\n        }\n    }\n}\n\n/// One translation attempt; queued records keep its constant-size streaming state\n/// alive until the lone writer has processed them, independently of logical Commit.\n#[derive(Default)]\npub(crate) struct DeliveryAttempt {\n    text: Mutex<AttemptText>,\n}\n\n#[derive(Default)]\nstruct AttemptText {\n    hash: Sha256,\n    has_text: bool,\n    failed: bool,\n}\n\n#[derive(Clone, Copy)]\npub(crate) enum DeliveryPart {\n    Text { end: bool },\n    Key,\n}\n\nimpl DeliveryAttempt {\n    fn failed(&self) {\n        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\n    }\n\n    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\n        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\n        if text.failed {\n            return;\n        }\n        if let DeliveryPart::Text { end } = part {\n            text.hash.update(bytes);\n            text.has_text |= !bytes.is_empty();\n            if end && text.has_text {\n                // Publish each complete Text command's cumulative text, including\n                // exact embedded newlines. Keys are source-tagged controls, never\n                // guessed framing stripped from the reported payload.\n                ledger.remember(text.hash.clone().finalize().into());\n            }\n        }\n    }\n}\n\npub(crate) struct InputRecord {\n    bytes: Vec<u8>,\n    origin: InputOrigin,\n}\n\nenum InputOrigin {\n    Controller,\n    Probe,\n    Delivery {\n        attempt: Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    },\n}\n\nimpl InputRecord {\n    #[cfg(test)]\n    pub(crate) fn into_bytes(self) -> Vec<u8> {\n        self.bytes\n    }\n\n    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Controller }\n    }\n\n    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Probe }\n    }\n\n    pub(crate) fn delivery(\n        bytes: Vec<u8>,\n        attempt: &Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    ) -> Self {\n        Self {\n            bytes,\n            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\n        }\n    }\n\n    pub(crate) fn dropped(&self) {\n        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\n            attempt.failed();\n        }\n    }\n\n    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n        // Never hold a custody lock across a potentially wedged physical write.\n        // Ok proves write_all + flush, not harness interpretation. Err may follow\n        // a partial write, whose byte count this API does not expose: do not guess.\n        let success = surface.write_input(&self.bytes).is_ok();\n        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n            if success {\n                attempt.written(&self.bytes, *part, ledger);\n            } else {\n                attempt.failed();\n            }\n        }\n        // A report caused by a separate Enter sees the preceding Text's published\n        // evidence before Enter is written (one FIFO, one writer). A report caused\n        // by Text itself can race between physical completion and this publication;\n        // enqueued bytes cannot honestly close that narrower window.\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use spt_term::surface::{SurfaceError, SurfaceSize};\n\n    struct Sink;\n    impl SessionSurface for Sink {\n        fn write_input(&self, _: &[u8]) -> Result<(), SurfaceError> { Ok(()) }\n        fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn split_multiline_delivery_matches_before_commit_without_normalizing() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        let first = InputRecord::delivery(b\"<EVENT>\\n C:/a\".to_vec(), &attempt, DeliveryPart::Text { end: false });\n        let last = InputRecord::delivery(b\"\\n</EVENT> \".to_vec(), &attempt, DeliveryPart::Text { end: true });\n        let payload = b\"<EVENT>\\n C:/a\\n</EVENT> \";\n        assert!(!ledger.matches(payload));\n        first.write_to(&Sink, &ledger);\n        assert!(!ledger.matches(payload));\n        last.write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        InputRecord::delivery(b\"\\r\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/b\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/a\\n</EVENT>\"));\n        assert!(!ledger.matches(b\"<EVENT>\\r\\n C:/a\\r\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"\\r\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n        let ledger = DeliveryBytes::default();\n        InputRecord::controller(b\"human C:/private\".to_vec()).write_to(&Sink, &ledger);\n        InputRecord::probe(b\"\\x1b[6n\".to_vec()).write_to(&Sink, &ledger);\n        assert!(!ledger.matches(b\"human C:/private\"));\n        assert!(!ledger.matches(b\"\\x1b[6n\"));\n        assert!(!ledger.matches(b\"unknown human payload\"));\n    }\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n        struct PartialFailure(Mutex<Vec<u8>>);\n        impl SessionSurface for PartialFailure {\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\n                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n            }\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n        }\n\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n        let partial = PartialFailure(Mutex::new(Vec::new()));\n        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\n        assert!(!ledger.matches(b\"beforemiddleafter\"));\n        assert!(!ledger.matches(b\"beforeafter\"));\n        assert!(!ledger.matches(b\"beforemiafter\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"one\\ntwo\"));\n        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n        let next_attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"three\"));\n        assert!(!ledger.matches(b\"one\\ntwothree\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\n        let ledger = DeliveryBytes::default();\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        assert_eq!(ledger.unavailable_reason(), None);\n        ledger.remember_with_limit(Sha256::digest(b\"second\").into(), 1);\n        assert!(ledger.matches(b\"first\"));\n        assert!(!ledger.matches(b\"second\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-evidence-capacity\"));\n    }\n}\n","newText":"//! Session-lifetime evidence from successful physical delivery writes, not enqueue intent.\n\nuse sha2::{Digest, Sha256};\nuse spt_term::surface::SessionSurface;\nuse std::collections::HashSet;\nuse std::sync::{Arc, Mutex};\n\n// Digests, not retained payloads. Never evict evidence from a live hosted session:\n// exhaustion disables origin grants with a named reason instead.\nconst MAX_DELIVERY_DIGESTS: usize = 65_536;\n\n#[derive(Default)]\npub(crate) struct DeliveryBytes {\n    completed: Mutex<Completed>,\n}\n\n#[derive(Default)]\nstruct Completed {\n    digests: HashSet<[u8; 32]>,\n    exhausted: bool,\n    writing: bool,\n    unproven: bool,\n}\n\nimpl DeliveryBytes {\n    pub(crate) fn matches(&self, payload: &[u8]) -> bool {\n        let digest: [u8; 32] = Sha256::digest(payload).into();\n        self.completed\n            .lock()\n            .unwrap_or_else(|p| p.into_inner())\n            .digests\n            .contains(&digest)\n    }\n\n    pub(crate) fn unavailable_reason(&self) -> Option<&'static str> {\n        let completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        if completed.unproven {\n            Some(\"delivery-write-unproven\")\n        } else if completed.writing {\n            Some(\"delivery-write-in-progress\")\n        } else if completed.exhausted {\n            Some(\"delivery-evidence-capacity\")\n        } else {\n            None\n        }\n    }\n\n    fn begin_write(&self) {\n        self.completed.lock().unwrap_or_else(|p| p.into_inner()).writing = true;\n    }\n\n    fn finish_write(&self, success: bool) {\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        completed.unproven |= !success;\n        completed.writing = false;\n    }\n\n    fn remember(&self, digest: [u8; 32]) {\n        self.remember_with_limit(digest, MAX_DELIVERY_DIGESTS);\n    }\n\n    fn remember_with_limit(&self, digest: [u8; 32], limit: usize) {\n        let mut completed = self.completed.lock().unwrap_or_else(|p| p.into_inner());\n        if completed.digests.contains(&digest) {\n            return;\n        }\n        if completed.digests.len() >= limit {\n            completed.exhausted = true;\n        } else {\n            completed.digests.insert(digest);\n        }\n    }\n}\n\n/// One translation attempt; queued records keep its constant-size streaming state\n/// alive until the lone writer has processed them, independently of logical Commit.\n#[derive(Default)]\npub(crate) struct DeliveryAttempt {\n    text: Mutex<AttemptText>,\n}\n\n#[derive(Default)]\nstruct AttemptText {\n    hash: Sha256,\n    has_text: bool,\n    failed: bool,\n}\n\n#[derive(Clone, Copy)]\npub(crate) enum DeliveryPart {\n    Text { end: bool },\n    Key,\n}\n\nimpl DeliveryAttempt {\n    fn failed(&self) {\n        self.text.lock().unwrap_or_else(|p| p.into_inner()).failed = true;\n    }\n\n    fn written(&self, bytes: &[u8], part: DeliveryPart, ledger: &DeliveryBytes) {\n        let mut text = self.text.lock().unwrap_or_else(|p| p.into_inner());\n        if text.failed {\n            return;\n        }\n        if let DeliveryPart::Text { end } = part {\n            text.hash.update(bytes);\n            text.has_text |= !bytes.is_empty();\n            if end && text.has_text {\n                // Publish each complete Text command's cumulative text, including\n                // exact embedded newlines. Keys are source-tagged controls, never\n                // guessed framing stripped from the reported payload.\n                ledger.remember(text.hash.clone().finalize().into());\n            }\n        }\n    }\n}\n\npub(crate) struct InputRecord {\n    bytes: Vec<u8>,\n    origin: InputOrigin,\n}\n\nenum InputOrigin {\n    Controller,\n    Probe,\n    Delivery {\n        attempt: Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    },\n}\n\nimpl InputRecord {\n    #[cfg(test)]\n    pub(crate) fn into_bytes(self) -> Vec<u8> {\n        self.bytes\n    }\n\n    pub(crate) fn controller(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Controller }\n    }\n\n    pub(crate) fn probe(bytes: Vec<u8>) -> Self {\n        Self { bytes, origin: InputOrigin::Probe }\n    }\n\n    pub(crate) fn delivery(\n        bytes: Vec<u8>,\n        attempt: &Arc<DeliveryAttempt>,\n        part: DeliveryPart,\n    ) -> Self {\n        Self {\n            bytes,\n            origin: InputOrigin::Delivery { attempt: Arc::clone(attempt), part },\n        }\n    }\n\n    pub(crate) fn dropped(&self) {\n        if let InputOrigin::Delivery { attempt, .. } = &self.origin {\n            attempt.failed();\n        }\n    }\n\n    // [impl->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    pub(crate) fn write_to(&self, surface: &impl SessionSurface, ledger: &DeliveryBytes) {\n        if let InputOrigin::Delivery { attempt, part } = &self.origin {\n            // Mark uncertainty BEFORE input can cause a report. No custody lock\n            // spans the blocking PTY call; receipt declines immediately instead.\n            ledger.begin_write();\n            let success = surface.write_input(&self.bytes).is_ok();\n            if success {\n                attempt.written(&self.bytes, *part, ledger);\n            } else {\n                // Err can follow a partial write; this API exposes no byte count.\n                // Keep session evidence unavailable, rather than grant an origin\n                // merely because the partly delivered payload lacks a digest.\n                attempt.failed();\n            }\n            // Successful candidate publication precedes clearing the active flag.\n            // Receipt checks unavailable_reason BEFORE matches so it cannot miss\n            // an unpublished digest and then observe an already-cleared flag.\n            ledger.finish_write(success);\n        } else {\n            let _ = surface.write_input(&self.bytes);\n        }\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use spt_term::surface::{SurfaceError, SurfaceSize};\n\n    struct Sink;\n    impl SessionSurface for Sink {\n        fn write_input(&self, _: &[u8]) -> Result<(), SurfaceError> { Ok(()) }\n        fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn split_multiline_delivery_matches_before_commit_without_normalizing() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        let first = InputRecord::delivery(b\"<EVENT>\\n C:/a\".to_vec(), &attempt, DeliveryPart::Text { end: false });\n        let last = InputRecord::delivery(b\"\\n</EVENT> \".to_vec(), &attempt, DeliveryPart::Text { end: true });\n        let payload = b\"<EVENT>\\n C:/a\\n</EVENT> \";\n        assert!(!ledger.matches(payload));\n        first.write_to(&Sink, &ledger);\n        assert!(!ledger.matches(payload));\n        last.write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        InputRecord::delivery(b\"\\r\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        assert!(ledger.matches(payload));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/b\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"<EVENT>\\n C:/a\\n</EVENT>\"));\n        assert!(!ledger.matches(b\"<EVENT>\\r\\n C:/a\\r\\n</EVENT> \"));\n        assert!(!ledger.matches(b\"\\r\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn controller_and_probe_bytes_never_become_delivery_evidence() {\n        let ledger = DeliveryBytes::default();\n        InputRecord::controller(b\"human C:/private\".to_vec()).write_to(&Sink, &ledger);\n        InputRecord::probe(b\"\\x1b[6n\".to_vec()).write_to(&Sink, &ledger);\n        assert!(!ledger.matches(b\"human C:/private\"));\n        assert!(!ledger.matches(b\"\\x1b[6n\"));\n        assert!(!ledger.matches(b\"unknown human payload\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn report_during_physical_write_declines_until_success_is_published() {\n        struct ReportingSurface<'a>(&'a DeliveryBytes);\n        impl SessionSurface for ReportingSurface<'_> {\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n                assert_eq!(self.0.unavailable_reason(), Some(\"delivery-write-in-progress\"));\n                assert!(!self.0.matches(bytes));\n                Ok(())\n            }\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n        }\n\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(\n            b\"submission C:/exact\".to_vec(), &attempt, DeliveryPart::Text { end: true },\n        ).write_to(&ReportingSurface(&ledger), &ledger);\n        assert_eq!(ledger.unavailable_reason(), None);\n        assert!(ledger.matches(b\"submission C:/exact\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn failed_physical_write_cannot_certify_omitted_or_partial_bytes() {\n        struct PartialFailure(Mutex<Vec<u8>>);\n        impl SessionSurface for PartialFailure {\n            fn write_input(&self, bytes: &[u8]) -> Result<(), SurfaceError> {\n                self.0.lock().unwrap_or_else(|p| p.into_inner()).extend_from_slice(&bytes[..2]);\n                Err(SurfaceError::Io(std::io::Error::from(std::io::ErrorKind::BrokenPipe)))\n            }\n            fn resize(&self, _: SurfaceSize) -> Result<(), SurfaceError> { Ok(()) }\n        }\n\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"before\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&Sink, &ledger);\n        let partial = PartialFailure(Mutex::new(Vec::new()));\n        InputRecord::delivery(b\"middle\".to_vec(), &attempt, DeliveryPart::Text { end: false }).write_to(&partial, &ledger);\n        InputRecord::delivery(b\"after\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert_eq!(*partial.0.lock().unwrap_or_else(|p| p.into_inner()), b\"mi\");\n        assert!(!ledger.matches(b\"beforemiddleafter\"));\n        assert!(!ledger.matches(b\"beforeafter\"));\n        assert!(!ledger.matches(b\"beforemiafter\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n\n        let recovered_attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(\n            b\"later success\".to_vec(), &recovered_attempt, DeliveryPart::Text { end: true },\n        ).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"later success\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-write-unproven\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn successful_text_commands_aggregate_without_key_bytes() {\n        let ledger = DeliveryBytes::default();\n        let attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"one\\n\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"\\x1b[A\".to_vec(), &attempt, DeliveryPart::Key).write_to(&Sink, &ledger);\n        InputRecord::delivery(b\"two\".to_vec(), &attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"one\\ntwo\"));\n        assert!(!ledger.matches(b\"one\\n\\x1b[Atwo\"));\n        let next_attempt = Arc::new(DeliveryAttempt::default());\n        InputRecord::delivery(b\"three\".to_vec(), &next_attempt, DeliveryPart::Text { end: true }).write_to(&Sink, &ledger);\n        assert!(ledger.matches(b\"three\"));\n        assert!(!ledger.matches(b\"one\\ntwothree\"));\n    }\n\n    // [unit->REQ-INPUT-PROVENANCE-ACCEPTANCE-REPORT]\n    #[test]\n    fn exhausted_evidence_keeps_old_matches_and_declines_future_origin_grants() {\n        let ledger = DeliveryBytes::default();\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        ledger.remember_with_limit(Sha256::digest(b\"first\").into(), 1);\n        assert_eq!(ledger.unavailable_reason(), None);\n        ledger.remember_with_limit(Sha256::digest(b\"second\").into(), 1);\n        assert!(ledger.matches(b\"first\"));\n        assert!(!ledger.matches(b\"second\"));\n        assert_eq!(ledger.unavailable_reason(), Some(\"delivery-evidence-capacity\"));\n    }\n}\n"},"isError":false,"timestamp":1789296039084}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_Z0F2VjkINP0kVBQQSg4jguHb|fc_0b12df87254bb4e6016aa67dab72ec87d1b5c6fbcede7ac4fc","toolName":"hub","startedAt":"2026-09-13T10:40:45.381Z","intent":"Reporting race guard completion"},"id":"25023b2d","parentId":"90dc3b86","timestamp":"2026-09-13T10:40:45.381Z"}
{"type":"message","id":"f4c34f26","parentId":"25023b2d","timestamp":"2026-09-13T10:40:45.382Z","message":{"role":"assistant","content":[{"type":"thinking","thinking":"**Following brief report**"},{"type":"toolCall","id":"call_Z0F2VjkINP0kVBQQSg4jguHb|fc_0b12df87254bb4e6016aa67dab72ec87d1b5c6fbcede7ac4fc","name":"hub","arguments":{"i":"Reporting race guard completion","op":"send","to":"Main","message":"deliverybytes.rs done; broker untouched. Delivery writes set active before physical call, publish candidate then clear; unavailable_reason names delivery-write-in-progress. Any physical delivery Err permanently latches delivery-write-unproven even if later deliveries succeed. Added deterministic callback test report_during_physical_write_declines_until_success_is_published; partial failure test now verifies permanent named non-grant. Receipt must check unavailable_reason BEFORE matches (ordering documented). No validation run."},"intent":"Reporting race guard completion"}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":1953,"output":136,"cacheRead":62080,"cacheWrite":0,"totalTokens":64169,"reasoningTokens":11,"cost":{"input":0.019530000000000002,"output":0.0068000000000000005,"cacheRead":0.062079999999999996,"cacheWrite":0,"total":0.08841}},"stopReason":"toolUse","timestamp":1789296039090,"responseId":"resp_0b12df87254bb4e6016aa67da74b0487d1a46e785c375e9035","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"rs_0b12df87254bb4e6016aa67da9416887d1890000bfda030257","type":"reasoning","content":[],"encrypted_content":"gAAAAABqpn2rmosHcGPC0ha9yN0FGIVGynVG9H7RcKvidvIgwY19eTicd4cLN85_Nd89LO1Z9j952qf-FRENZJwi7Bvzy5yNXnjgOjaJQcRdKs2oY_JIITwju27V5Eter6d9e9oqyXRlZjTs8mQ8jVQKzrckYMjV46Lxz7yl801XDhvjI58chdPiIcVMyP6dadyFVe2INzVSR-JKeA2b2iilhrmd9_ptvaQj2kcjrxzXgEoRbt3E2yyj2RCpEceRnXUpry66EFpJKGbAWXsc-iSy7ezUZhGbfNLoYsYHqhPgbWNlwSN1ZSl6AmlT_cRXpyZDDEajtRs5sNTlSau-SsQYwwh3ry-JUG7hnyuuyO_rTEhuICFDdq-Vxkit-ke2H4PEN8c7gKgTomrJbdoCOvJprsHGvZaNpEesvbXwkgFpmA5u8rqsb_IWeHL_jbz-F3OYzteT8wch6T0jHqDrt02DcJFrEnnysim8Qm-1pjD3dzPmuTmH8BVEv7IKxjuvV5pF3kk3MKCoMvLiyNAK1XiH3HwVosnMF_TfRcbbYZ00GDI48H_QaTXv8ScwjXTXks5HRG1-vNXfBK_VHaV52DUp5Qz3eWJVvVXViihXdGu1FBCW_QXGoB7fFy3vBBdS6SPyOrMThHL8MuJTVYPTU2AoTZ5UsVEq-jlUanS7SWHTkDSgqm7WKsc-awe5tPf5Dk3kb2emZ8dK5iNFRfWsuKqOG_2oeeLli1Phm6s8jYrCZ6PLs3kB89XRcbwmk-LXoL4bdpXzIyVWzHDbtV8g5cyubvtaeFhwYIhUdR_H7iT9D8UPfeeNnOtdAtJ0hVOWwmBdE4BmM16rfAyQ6b-UiN8cH1GeBpnp0WvUVrOAhFGkBwG0HQuH4hvwa1_tY-5sPayBdt_DD3VQMSeB6Ig5_IYYnhEH5z2NcdkaCioesnjUCj6z1b9hYa04mmBIHLy5GUHslY4VVSDpGKbpEjxORewlMX-AV-CJLG1gatPpC1sCS-nzod1ZYYXeptecwn4aYb_xzhD9cUBDNOAtLFf34-cvs3XHYyp1O4a2GOsK6y1kc2p05JFwcqEwT1ds9NaMQmJIXZbvloIaQl6lMPzxSPmIgc9TnYwZbB3xcAJ-WvjbQcIHxDeTBNRSEnGHiwSJGuds45D_MKKhUcrLBAV9jix69purEWBS1Lno0mgU_hx5hX3l5G2KJOAQVKzb5Gi--S5x9Ph0uY81-FZaFlszs3NBadLEEZItXfAKQCcnu-3flmUUbCe-0PvJbYw41XTlohliIxuxBYeu34FRHipD5Am-Plfrlox9cW-vLo7t-hlH08lfK5IfByic8BlHUbjjs0t1ErwYtSBR","internal_chat_message_metadata_passthrough":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"},"summary":[{"type":"summary_text","text":"**Following brief report**"}],"metadata":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"}},{"id":"fc_0b12df87254bb4e6016aa67dab72ec87d1b5c6fbcede7ac4fc","type":"function_call","status":"completed","arguments":"{\"i\":\"Reporting race guard completion\",\"op\":\"send\",\"to\":\"Main\",\"message\":\"deliverybytes.rs done; broker untouched. Delivery writes set active before physical call, publish candidate then clear; unavailable_reason names delivery-write-in-progress. Any physical delivery Err permanently latches delivery-write-unproven even if later deliveries succeed. Added deterministic callback test report_during_physical_write_declines_until_success_is_published; partial failure test now verifies permanent named non-grant. Receipt must check unavailable_reason BEFORE matches (ordering documented). No validation run.\"}","call_id":"call_Z0F2VjkINP0kVBQQSg4jguHb","internal_chat_message_metadata_passthrough":{"create_time":1789296039.46759,"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"},"name":"hub","metadata":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"}}]},"duration":6288.85289999994,"ttft":2203.7761000000173,"completedAt":1789296045380,"contextSnapshot":{"promptTokens":64033,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"3bba5bfe","parentId":"f4c34f26","timestamp":"2026-09-13T10:40:45.384Z","message":{"role":"toolResult","toolCallId":"call_Z0F2VjkINP0kVBQQSg4jguHb|fc_0b12df87254bb4e6016aa67dab72ec87d1b5c6fbcede7ac4fc","toolName":"hub","content":[{"type":"text","text":"Delivered to 1 peer(s):\n- Main: injected"}],"details":{"op":"send","from":"DeliveryRecording","to":"Main","receipts":[{"to":"Main","outcome":"injected"}]},"isError":false,"timestamp":1789296045383}}
{"type":"custom","customType":"tool_execution_start","data":{"toolCallId":"call_w6jF5ekKQVusjj5qC7QrqcFI|fc_0b12df87254bb4e6016aa67db09d3487d185af368f1e6e8d08","toolName":"yield","startedAt":"2026-09-13T10:40:54.033Z"},"id":"c65e1114","parentId":"3bba5bfe","timestamp":"2026-09-13T10:40:54.033Z"}
{"type":"message","id":"98584b1e","parentId":"c65e1114","timestamp":"2026-09-13T10:40:54.034Z","message":{"role":"assistant","content":[{"type":"toolCall","id":"call_w6jF5ekKQVusjj5qC7QrqcFI|fc_0b12df87254bb4e6016aa67db09d3487d185af368f1e6e8d08","name":"yield","arguments":{"data":{"changed":"crates/spt-daemon/src/deliverybytes.rs only","behavior":["Delivery writes mark active before physical I/O; successful digest publication precedes clearing active status.","Reports during physical delivery return delivery-write-in-progress without holding a lock across PTY I/O.","Physical delivery errors permanently latch delivery-write-unproven; later successful delivery cannot erase partial-write uncertainty."],"integration":"Check delivery_unavailable_reason BEFORE delivery_matches; inverse order can miss an unpublished digest and then observe cleared status.","tests":["Added report_during_physical_write_declines_until_success_is_published with deterministic report callback inside write_input.","Extended failed_physical_write_cannot_certify_omitted_or_partial_bytes to assert permanent delivery-write-unproven after a subsequent successful delivery."],"validation":"Skipped as assigned; broker.rs untouched."}}}],"api":"openai-codex-responses","provider":"openai-codex","model":"gpt-6-astra","usage":{"input":319,"output":180,"cacheRead":63872,"cacheWrite":0,"totalTokens":64371,"cost":{"input":0.00319,"output":0.009000000000000001,"cacheRead":0.063872,"cacheWrite":0,"total":0.076062}},"stopReason":"toolUse","timestamp":1789296045401,"responseId":"resp_0b12df87254bb4e6016aa67dadb71887d1b640402494c94cb8","providerPayload":{"type":"openaiResponsesHistory","provider":"openai-codex","dt":true,"items":[{"id":"fc_0b12df87254bb4e6016aa67db09d3487d185af368f1e6e8d08","type":"function_call","status":"completed","arguments":"{\"data\":{\"changed\":\"crates/spt-daemon/src/deliverybytes.rs only\",\"behavior\":[\"Delivery writes mark active before physical I/O; successful digest publication precedes clearing active status.\",\"Reports during physical delivery return delivery-write-in-progress without holding a lock across PTY I/O.\",\"Physical delivery errors permanently latch delivery-write-unproven; later successful delivery cannot erase partial-write uncertainty.\"],\"integration\":\"Check delivery_unavailable_reason BEFORE delivery_matches; inverse order can miss an unpublished digest and then observe cleared status.\",\"tests\":[\"Added report_during_physical_write_declines_until_success_is_published with deterministic report callback inside write_input.\",\"Extended failed_physical_write_cannot_certify_omitted_or_partial_bytes to assert permanent delivery-write-unproven after a subsequent successful delivery.\"],\"validation\":\"Skipped as assigned; broker.rs untouched.\"}}","call_id":"call_w6jF5ekKQVusjj5qC7QrqcFI","internal_chat_message_metadata_passthrough":{"create_time":1789296045.91219,"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"},"name":"yield","metadata":{"turn_id":"406604e3-da20-434b-a8b0-5b75e30e791f"}}]},"duration":8631.296299999929,"ttft":3231.6436999998987,"completedAt":1789296054033,"contextSnapshot":{"promptTokens":64191,"nonMessageTokens":17205,"compactionEpoch":0}}}
{"type":"message","id":"db03e5db","parentId":"98584b1e","timestamp":"2026-09-13T10:40:54.036Z","message":{"role":"toolResult","toolCallId":"call_w6jF5ekKQVusjj5qC7QrqcFI|fc_0b12df87254bb4e6016aa67db09d3487d185af368f1e6e8d08","toolName":"yield","content":[{"type":"text","text":"Result submitted."}],"details":{"data":{"changed":"crates/spt-daemon/src/deliverybytes.rs only","behavior":["Delivery writes mark active before physical I/O; successful digest publication precedes clearing active status.","Reports during physical delivery return delivery-write-in-progress without holding a lock across PTY I/O.","Physical delivery errors permanently latch delivery-write-unproven; later successful delivery cannot erase partial-write uncertainty."],"integration":"Check delivery_unavailable_reason BEFORE delivery_matches; inverse order can miss an unpublished digest and then observe cleared status.","tests":["Added report_during_physical_write_declines_until_success_is_published with deterministic report callback inside write_input.","Extended failed_physical_write_cannot_certify_omitted_or_partial_bytes to assert permanent delivery-write-unproven after a subsequent successful delivery."],"validation":"Skipped as assigned; broker.rs untouched."},"status":"success"},"isError":false,"timestamp":1789296054034}}
{"type":"custom","customType":"session_exit","data":{"reason":"dispose","kind":"normal","recordedAt":"2026-09-13T10:47:54.037Z"},"id":"e850818b","parentId":"db03e5db","timestamp":"2026-09-13T10:47:54.037Z"}
