{
  "summary": "Exact candidate source rules out a direct NetHost/runtime/journal dependency between waiter_armed and spawn reply. That interval synchronously creates the translation process, writes Init, and launches ordinary threads; there is no translation readiness handshake. The observed 2.04s failures fit exhaustion of the fixture's shared 2s client-read budget, but available logs do not identify which translation-startup operation consumed the remaining time or prove a persistent wedge. #302 equivalence is unproved and its proposed direct runtime seam is contradicted by this call path.",
  "files": [
    {
      "path": ".worktrees/297-enforcement-shape/crates/spt-daemon/src/broker.rs:4702-4774",
      "description": "build_translation: synchronous child spawn, hostname lookup, Init pipe write, ordinary inject-worker thread creation; no NetHost or journal access."
    },
    {
      "path": ".worktrees/297-enforcement-shape/crates/spt-daemon/src/broker.rs:8672-8739",
      "description": "Exact interval: waiter_armed \u2192 build_translation \u2192 translation_ready \u2192 session row insertion \u2192 row_inserted \u2192 KIND_SPAWNED send."
    },
    {
      "path": ".worktrees/297-enforcement-shape/crates/spt-daemon/src/translation.rs:245-320",
      "description": "Translation process creation, independent stdout reader, synchronous unbounded stdin write/flush."
    },
    {
      "path": ".worktrees/297-enforcement-shape/crates/spt-daemon/src/bin/xlate_choreo_fixture.rs:43-76",
      "description": "Child startup reads environment and stdin; Init is ignored after optional file logging, not acknowledged."
    },
    {
      "path": ".worktrees/297-enforcement-shape/crates/spt-store/src/hostlabel.rs:24-28,49-54",
      "description": "Windows hostname lookup reads COMPUTERNAME environment variable, not DNS or a subprocess."
    },
    {
      "path": ".worktrees/297-enforcement-shape/crates/spt-daemon/src/nethost.rs:1280-1305,1469-1483,1765-1853",
      "description": "Dedicated two-worker runtime; runtime-dependent timeout bridge; stream-open path separate from session spawn."
    },
    {
      "path": ".worktrees/297-enforcement-shape/crates/spt-daemon/src/nethost.rs:1100-1182,1890-1927",
      "description": "Stream registration/read tasks and synchronous mutex sites; send serialization and async write budget."
    },
    {
      "path": ".worktrees/297-enforcement-shape/crates/spt-daemon/src/broker.rs:5676,9753-9810",
      "description": "EffectJournal opened at broker construction; journaled stream-open invokes NetHost in a separate stream dispatch operation."
    },
    {
      "path": ".worktrees/297-enforcement-shape/crates/spt-daemon/tests/inject_control_wedge.rs:110-133,560-579,1003-1017,1289-1318",
      "description": "Hermetic in-process broker topology, translation-bearing request, reused default 2s attach IPC deadline on spawn."
    },
    {
      "path": ".worktrees/297-enforcement-shape/docs/adr/0018-broker-brain-process-isolation-restoration.md",
      "description": "Production broker/brain process boundary; differs intentionally from fixture's in-process broker and Brain objects."
    },
    {
      "path": ".worktrees/297-enforcement-shape/docs/adr/0022-spt-hosted-idle-delivery-translation-binary.md",
      "description": "Translation lifecycle and init/event protocol, failure-to-spool contract, separate injection commit watchdog."
    },
    {
      "path": ".worktrees/297-enforcement-shape/docs/adr/0038-broker-stream-lifecycle-truth.md:78-108",
      "description": "Historical stream stall mechanism: repeated 15s subscriber writes under stream-log lock; distinct from translation startup."
    },
    {
      "path": ".worktrees/297-enforcement-shape/docs/REMOTE-FRICTION-PLAN.md:38",
      "description": "Repository-backed #302 characterization: recurring local/remote hitches; diagnosis before conflation or timeout widening."
    }
  ],
  "architecture": "Production: broker process owns PTYs, translation child, NetHost runtime and journal; brain is a separate restartable process. Fixture: test process owns Broker plus Brain over real IPC, with ordinary broker/reader/input/drain/waiter/inject threads and a dedicated two-worker Tokio runtime; echo harness and translation fixture are real child processes. Spawn's post-waiter continuation runs synchronously on broker dispatch, not on NetHost workers. NetHost stream tasks and effect-journal stream operations are separate paths.",
  "report": "## Scope and evidence\nRead-only analysis of source under `.worktrees/297-enforcement-shape` identified in the assignment as candidate 7890ead39bb7f14ed44aaae44b0951f098ffe9ac. No execution, process launch, tests, build, lint, formatter, or edits. No claim of runtime reproduction or fix verification. Used direct exact-candidate reads rather than LSP references: parent reported worktree references empty and root references source-skewed. Read CONTEXT broker/brain definitions at35-42 plus ADR-0018, ADR-0022, and stream-lifecycle ADR-0038 before interpreting ownership.\n\n## Actual post-waiter dependency chain\n1. `broker.rs:8672` emits waiter_armed.\n2. `:8682-8694` calls `build_translation` because xlate_spawn_req supplies the real translation fixture binary (`tests/inject_control_wedge.rs:1003-1017`).\n3. `build_translation(:4702-4774)` creates channels, calls `TranslationChild::spawn`, wraps the child, obtains the hostname, sends Init, creates the inject worker thread, returns Translation.\n4. `translation.rs:245-298` configures piped stdin/stdout, inherited stderr and Windows CREATE_NO_WINDOW; `:266` synchronously calls `std::process::Command::spawn`. `:273` creates an ordinary stdout-reader thread. That thread blocks in BufRead::lines independently; constructor does not wait for its first read or a child response.\n5. `broker.rs:4715-4721` sends identity Init. Windows hostname is just COMPUTERNAME (`hostlabel.rs:49-54`). `TranslationChild::send(:311-320)` serializes, takes a std mutex, writes JSON and newline synchronously, flushes. No timeout surrounds this path; the result is discarded at the caller. The new stdin mutex has no previously published Translation sharing it at this point, so existing injection/controller contention is not supported as an explanation for this first Init lock.\n6. `broker.rs:4742-4754` launches an ordinary inject-worker thread and returns without waiting for it. `run_inject_worker(:5037-5085)` eventually waits on its event channel; no startup event has been queued by build_translation.\n7. Only after return does `:8696` emit translation_ready, insert the HostedSession, clear bringup state, emit row_inserted, and send KIND_SPAWNED at8738.\n\n**There is NO child-ready handshake.** Child source `xlate_choreo_fixture.rs:43-76` reads env/stdin and optionally appends stdin lines to its fixture log; Init is ignored and produces no output. translation_ready means broker constructor completion, not a verified ready binary. The child logging operation is in the child process, not a parent readiness barrier. Parent can ordinarily finish its small buffered Init write without the child having consumed it [INFERENCE about OS pipe behavior, not measured here].\n\n**There are zero NetHost block_on/bounded_block_on calls, zero stream opens, and zero EffectJournal operations in this post-waiter chain.** `build_translation` does not receive NetHost or journal handles. Broker NetHost start and EffectJournal open occur before cold_start_pump and before spawn_session begins (`fixture:570-578`, `broker:5676`). This is the decisive distinction from the suspected seam.\n\n## Runtime and journal bounds: real, but separate\n- `nethost.rs:1286-1290` creates two named `spt-broker-net` Tokio workers. `:1291-1305` synchronously block_on-binds the endpoint without an outer bound, but the fixture has completed that before any spawn request/read deadline.\n- `:1469-1483` implements bounded_block_on using Handle::block_on around tokio::time::timeout. Default is 10,000ms (`:59-74`, initialized at1409), designed against production pump's documented 30s budget, not this fixture's 2s.\n- Journaled stream-open runs `EffectJournal::apply_once` then `host.open_stream` (`broker.rs:9801-9806`); unjournaled open also calls host.open_stream (`:9787-9790`). Neither is invoked by build_translation or post-waiter spawn.\n- QUIC and loopback open both use bounded_block_on (`nethost.rs:1801,1825`). Loopback body creates a duplex pair and synchronously registers two rows; it does not await first read-pump progress. Handle::block_on polls this bridge future on its caller; do not assume every body statement executes on one of the two workers merely because it enters the runtime [runtime API semantics]. Its spawned read pumps do execute as runtime tasks.\n- register_stream `:1100-1168` inserts under a std::sync::Mutex and spawns a read pump. Read pumps acquire synchronous log locks after async reads; await_ring_room `:1173-1182` also takes a synchronous log lock then releases before await. Thus lock contention can physically block a runtime worker. Async socket read or Notify wait alone yields rather than blocking the OS worker.\n- send_stream `:1890-1927` takes synchronous table/log locks BEFORE entering its timed future, then awaits send mutex and write/finish inside it. Pre-timeout locks are not protected by that timeout. A synchronous non-yielding poll inside the future is not preempted by Tokio timeout; a starved timer/I/O driver is not an independent wall-clock watchdog [INFERENCE from timeout/Handle design]. Accordingly the comment claiming a sick runtime always gets a prompt loopback timeout is stronger than this implementation alone proves.\n- The deliberate test-only freeze helper `:2284-2290` blocks workers with non-yielding sleep loops and explicitly notes frozen runtimes cannot be dropped normally. It demonstrates the repository recognizes worker-starvation mechanics, not that this fixture invokes them.\n- Subscriber writes are already offloaded to dedicated writer threads (nethost:151-255; ADR-0038 amendment). The historical 15s replay-under-log-lock incident must not be silently substituted for these candidate reds.\n- Other NetHost bare bridges are pairing join/meet (`:1497,:1513`) and close (`:2260`), also not spawn dependencies.\n- Injection's 5s commit watchdog (`broker:622`) exceeds 2s but applies after an event, not child startup. Translation reap's 500ms grace (`translation:37,333-355`) is shutdown logic, not an initial ready budget; later kill/wait is synchronous. Neither explains this missing translation_ready phase as an awaited startup contract.\n\n## What the reported logs establish\nParent-supplied observations: g1 reaches waiter_armed at892ms; g7 at1328ms; both panic near2.04s at spawn_session TimedOut, with no translation_ready or later phase in the supplied log. The configured fixture deadline defaults to2s and Main reports allSPT scrubbing removed the CI's documented30s override. Brain's spawn read uses one deadline for the reply loop, per SpawnReplyTrace.\n\nTherefore approximately1.1s /0.67s of the nominal budget remained after waiter_armed (not a freshly reset2s translation budget). These logs prove the client deadline expired before a successful spawn reply was consumed. They localize the last observed broker progress to immediately before translation construction. They do NOT prove a permanently blocked thread, which particular syscall was slow, a runtime worker deadlock, eventual failure rather than delayed completion, or translation child readiness. Panic/log cutoff could conceal later broker progress; no negative conclusion about eventual completion follows from absence after cutoff.\n\n## #302 comparison and access limits\nRepository artifacts call #302 recurring local/remote hitches (`docs/REMOTE-FRICTION-PLAN.md:38`) and explicitly require distinct diagnoses; `docs/49-267-REFRESH-OBSERVATION-PLAN.md:246` leaves its relationship to #49/#267 untested. `REMOTE-FRICTION-GRILL.md:10` likewise rejects merging similar symptoms. These are the accessible documented facts, not proof of a NetHost root cause.\n\nAttempted issue://302, issue://sabermage/spt-releases/302 and the known https://github.com/sabermage/spt-releases/issues/302 URL: issue resolution failed and URL returned404. Searched candidate/root docs, CONTEXT, and accessible local reports for #302/NetHost2/unbounded-brain; no incident-specific worker-stack evidence found. Consequently cannot independently substantiate the alleged #302 worker/unbounded-read mechanism. The current failing caller is explicitly the bounded pump carrier, not an unbounded Brain read. A common host-scheduling pressure explanation remains possible [INFERENCE], but direct synchronous NetHost dependency is refuted by the inspected spawn route.\n\n## Ranked falsifiable discriminators\n1. **Finite translation creation/scheduling latency exhausts remaining client budget.** Strongest fit: two slow PTY creations already consume45%/66% of the same2s; remaining unbounded OS startup operations precede the missing phase. Discriminator: timestamp entry/exit of Command::spawn, reader-thread creation, Init send, inject-thread creation and broker reply; a late translation_ready/row_inserted/reply after client expiry supports this, without requiring any runtime stall. Stack/state evidence during the gap separates time inside CreateProcess from dispatch descheduling. Antivirus/image-load interference is only a possible cause, not established evidence.\n2. **Init synchronous pipe write stalls.** Supported structurally because write_all/flush is unbounded. Weaker for this specific startup: only a small first identity record on a new pipe and no readiness ack. Discriminator: process creation has returned, broker is inside Init write/flush, no Init-send completion stamp; direct stack/pipe state is decisive. Child's optional stdin log may prove consumption, but its absence alone cannot distinguish not yet scheduled from blocked logging/reading.\n3. **Ordinary thread creation or scheduling/logging delay, not translation protocol wait.** Reader creation and inject-worker creation are synchronous OS operations on dispatch, while worker execution is not joined. Discriminator: boundaries locate delay at one of these creations or around phase emission; healthy NetHost progress does not rule this out. A post-construction log-emission stall would also explain missing translation_ready without a constructor deadlock.\n4. **NetHost two-worker starvation as indirect co-tenant effect.** Low rank for this exact red; no direct dependency exists. Discriminator: worker stacks/timer-canary stagnation must coincide with the gap, AND a mechanism affecting dispatch/IPC/OS scheduling must be shown. Merely observing two workers or a2s timeout is insufficient. No request_attach/net_open_stream is reached through this helper before it returns the spawned session.\n5. **Reply delivery/read scheduling after constructor succeeds.** Lower rank given missing phases, but possible if capture is incomplete. Discriminator: broker translation_ready/row_inserted and successful reply write before expiry, with client receive delayed or absent. SpawnReplyTrace owns this terminal reply chain.\n\n## Evidence-backed fix seam, without proposing an unproved patch\nThe supported seam is **synchronous translation construction inside broker spawn's completion contract versus a fixture that reuses a2s attach-operation read budget for all PTY+translation startup**. First separate actual per-stage startup work from client/dispatch scheduling using the discriminators above; do not fix NetHost or widen timeouts merely because the error occurs at2s. If constructor stalls are established, fix/bound the actual process/pipe startup dependency and preserve lifecycle/failure-to-spool semantics. If bounded finite startup under the authorized load is established, the fixture's operation-specific deadline/admission contract is the relevant test-design seam\u2014not an injection choreography or network runtime change. Returning Spawned earlier is not automatically safe: currently session publication includes Translation and callers can immediately inject; moving work behind acknowledgement would change that observable contract and requires explicit lifecycle design. No specific product fix is justified by the current log granularity."
}
