crates\spt-daemon\tests\access.rs:5
crates\spt\tests\attach_wedge_e2e.rs:2
crates\spt\tests\bind_cwd_project_e2e.rs:1
crates\spt-daemon\tests\attach.rs:33
crates\spt\tests\brain_respawn_rename.rs:1
crates\spt-daemon\tests\brain_swap.rs:3
crates\spt-term\tests\surface.rs:1
crates\spt\tests\brain_restart_psyche_dup_e2e.rs:2
crates\spt-daemon\tests\broker.rs:10
crates\spt\tests\brain_split.rs:4
crates\spt-daemon\tests\budget.rs:3
crates\spt\tests\brain_survive.rs:9
crates\spt-daemon\tests\daemon_e2e.rs:5
crates\spt-daemon\tests\daemon_lifecycle_real_brain.rs:13
crates\spt\tests\dummy_harness_e2e.rs:3
crates\spt-daemon\tests\dispatch.rs:25
crates\spt\tests\job_escape_e2e.rs:8
crates\spt-daemon\tests\driven_by_selfheal.rs:4
crates\spt\tests\gateway_owner_shell_e2e.rs:1
crates\spt\tests\livehost_bootgate_e2e.rs:3
crates\spt-daemon\tests\handoff.rs:3
crates\spt-daemon\tests\idempotent.rs:3
crates\spt\tests\livehost_bootrace_e2e.rs:5
crates\spt\tests\livehost_nonresident_e2e.rs:2
crates\spt-daemon\tests\inject_control_wedge.rs:46
crates\spt\tests\livehost_psyche_fail_e2e.rs:2
crates\spt-daemon\tests\input_ack_deadlock.rs:12
crates\spt-daemon\tests\mesh.rs:4
crates\spt-daemon\tests\netbroker.rs:12
crates\spt-daemon\tests\netstream.rs:7
crates\spt\tests\n1_pairing.rs:3
crates\spt-daemon\tests\notifsync.rs:5
crates\spt-daemon\tests\presence.rs:5
crates\spt\tests\oneliner_e2e.rs:3
crates\spt-daemon\tests\propagate.rs:4
crates\spt-daemon\tests\pump.rs:7
crates\spt-daemon\tests\pumpdeadline.rs:1
crates\spt-daemon\tests\replicate.rs:5
crates\spt\tests\resume_template_e2e.rs:2
crates\spt-daemon\tests\resume.rs:11
crates\spt-daemon\tests\shellchan.rs:4
crates\spt\tests\tunnel_e2e.rs:1
crates\spt\tests\unhost_psyche_reap_e2e.rs:2
crates\spt-daemon\tests\sync.rs:9
crates\spt-daemon\tests\twohost.rs:3
crates\spt-daemon\tests\wanmsg.rs:7
crates\spt-daemon\tests\xfer.rs:7

Found 311 total occurrences across 47 files.


311 matches across 47 files — but `net_broker`/`cold_start` are too broad (nearly all spt-daemon tests use an in-process loopback broker). The TRUE heavy class = spawns a **real PTY child (forkpty)** or a **real OS process / daemon-tree**, not in-process QUIC-loopback wire tests. doyle's 5 chosen spt-daemon binaries spawn PTY children; netbroker/netstream/dispatch/etc. are pure loopback-wire (lighter). Need per-binary classification — delegating the sweep with precise criteria.


Agent

Classify heavy vs light test binaries

Prompt:
Repo: C:\Users\decid\Documents\projects\spt-core. I'm building a two-phase CI test split. I need EVERY integration-test binary (files under crates/*/tests/*.rs) classified as HEAVY or LIGHT by a precise resource criterion. This feeds a load-bearing nextest filter, so be exhaustive and evidence-based.

HEAVY = the test (any test fn in that binary) does ANY of:
  (a) spawns a REAL PTY CHILD via forkpty/ConPTY — look for `SpawnReq`, `spawn_req`, a spawn carrying a `program`/`args` (e.g. "cat", "yes", "findstr", "sh", "cmd", flood/echo children), `flood_spawn`, `host_pty`, `spawn_session`/`spawn` that hosts a PTY, `session_pid`, real PTY output streaming; OR
  (b) spawns a REAL OS PROCESS / daemon-tree — `CARGO_BIN_EXE_spt`, `Command::new(... spt ...)`, `"daemon","run"`, a detached `spt daemon`, a real brain PROCESS restart (process-level, not in-process), kill_pid/taskkill of a spawned tree; OR
  (c) is a real brain-restart / brain-respawn / brain-survive process lifecycle test.

LIGHT = in-process only: uses `net_broker(...)` / `Brain::cold_start` over LOOPBACK QUIC or in-memory transport but spawns NO real PTY child and NO real OS process (pure wire/protocol/mesh/replication/sync tests). `net_broker` or `cold_start` ALONE does NOT make it heavy — only an actual PTY child or real process does.

Known HEAVY (confirm + find evidence, don't just trust me): spt-daemon::{broker, attach, inject_control_wedge, daemon_e2e, daemon_lifecycle_real_brain}; spt::{job_escape_e2e, brain_survive, brain_respawn_rename}.

These 47 files matched a broad marker grep — classify EACH:
spt-daemon: access, attach, brain_swap, broker, budget, daemon_e2e, daemon_lifecycle_real_brain, dispatch, driven_by_selfheal, handoff, idempotent, inject_control_wedge, input_ack_deadlock, mesh, netbroker, netstream, notifsync, presence, propagate, pump, pumpdeadline, replicate, resume, shellchan, sync, twohost, wanmsg, xfer
spt: attach_wedge_e2e, bind_cwd_project_e2e, brain_respawn_rename, brain_restart_psyche_dup_e2e, brain_split, brain_survive, dummy_harness_e2e, gateway_owner_shell_e2e, job_escape_e2e, livehost_bootgate_e2e, livehost_bootrace_e2e, livehost_nonresident_e2e, livehost_psyche_fail_e2e, n1_pairing, oneliner_e2e, resume_template_e2e, tunnel_e2e, unhost_psyche_reap_e2e
spt-term: surface (and check the rest of spt-term/tests/: dsr, inject, stream, winspawn — all spawn real PTY children, likely HEAVY)

ALSO: list ALL test files in crates/*/tests/ you can find that are NOT in the list above (e.g. spt-msg, mock-adapter, spt-term others) and classify them too — don't miss any.

Return a single structured report:
1. HEAVY list: `package::binary` + one-line evidence (the specific marker + line) for each.
2. LIGHT list: `package::binary` + one-line reason.
3. Any UNCERTAIN binaries with the ambiguity, so I can decide.
4. Total count of test binaries found (so I can verify the partition later).
Read excerpts; do not edit anything. Precision of binary names matters — they go straight into a regex filter.


<owl_reachability_notice>
You have an active owl perch. Launch this Agent with run_in_background: true so you stay reachable for incoming messages while it works.
</owl_reachability_notice>


Async agent launched successfully.
agentId: a61f0f3267f7dd8fc (internal ID - do not mention to user. Use SendMessage with to: 'a61f0f3267f7dd8fc' to continue this agent.)
The agent is working in the background. You will be notified automatically when it completes.
Do not duplicate this agent's work — avoid working with the same files or topics it is using. Work on non-overlapping tasks, or briefly tell the user what you launched and end your response.
output_file: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\a61f0f3267f7dd8fc.output
Do NOT Read or tail this file via the shell tool — it is the full subagent JSONL transcript and reading it will overflow your context. If the user asks for progress, say the agent is still running; you'll get a completion notification.

Classify heavy vs light test binaries

Prompt:
Repo: C:\Users\decid\Documents\projects\spt-core. I'm building a two-phase CI test split. I need EVERY integration-test binary (files under crates/*/tests/*.rs) classified as HEAVY or LIGHT by a precise resource criterion. This feeds a load-bearing nextest filter, so be exhaustive and evidence-based.

HEAVY = the test (any test fn in that binary) does ANY of:
  (a) spawns a REAL PTY CHILD via forkpty/ConPTY — look for `SpawnReq`, `spawn_req`, a spawn carrying a `program`/`args` (e.g. "cat", "yes", "findstr", "sh", "cmd", flood/echo children), `flood_spawn`, `host_pty`, `spawn_session`/`spawn` that hosts a PTY, `session_pid`, real PTY output streaming; OR
  (b) spawns a REAL OS PROCESS / daemon-tree — `CARGO_BIN_EXE_spt`, `Command::new(... spt ...)`, `"daemon","run"`, a detached `spt daemon`, a real brain PROCESS restart (process-level, not in-process), kill_pid/taskkill of a spawned tree; OR
  (c) is a real brain-restart / brain-respawn / brain-survive process lifecycle test.

LIGHT = in-process only: uses `net_broker(...)` / `Brain::cold_start` over LOOPBACK QUIC or in-memory transport but spawns NO real PTY child and NO real OS process (pure wire/protocol/mesh/replication/sync tests). `net_broker` or `cold_start` ALONE does NOT make it heavy — only an actual PTY child or real process does.

Known HEAVY (confirm + find evidence, don't just trust me): spt-daemon::{broker, attach, inject_control_wedge, daemon_e2e, daemon_lifecycle_real_brain}; spt::{job_escape_e2e, brain_survive, brain_respawn_rename}.

These 47 files matched a broad marker grep — classify EACH:
spt-daemon: access, attach, brain_swap, broker, budget, daemon_e2e, daemon_lifecycle_real_brain, dispatch, driven_by_selfheal, handoff, idempotent, inject_control_wedge, input_ack_deadlock, mesh, netbroker, netstream, notifsync, presence, propagate, pump, pumpdeadline, replicate, resume, shellchan, sync, twohost, wanmsg, xfer
spt: attach_wedge_e2e, bind_cwd_project_e2e, brain_respawn_rename, brain_restart_psyche_dup_e2e, brain_split, brain_survive, dummy_harness_e2e, gateway_owner_shell_e2e, job_escape_e2e, livehost_bootgate_e2e, livehost_bootrace_e2e, livehost_nonresident_e2e, livehost_psyche_fail_e2e, n1_pairing, oneliner_e2e, resume_template_e2e, tunnel_e2e, unhost_psyche_reap_e2e
spt-term: surface (and check the rest of spt-term/tests/: dsr, inject, stream, winspawn — all spawn real PTY children, likely HEAVY)

ALSO: list ALL test files in crates/*/tests/ you can find that are NOT in the list above (e.g. spt-msg, mock-adapter, spt-term others) and classify them too — don't miss any.

Return a single structured report:
1. HEAVY list: `package::binary` + one-line evidence (the specific marker + line) for each.
2. LIGHT list: `package::binary` + one-line reason.
3. Any UNCERTAIN binaries with the ambiguity, so I can decide.
4. Total count of test binaries found (so I can verify the partition later).
Read excerpts; do not edit anything. Precision of binary names matters — they go straight into a regex filter.


Sweep delegated (background Explore classifying all ~47+ binaries HEAVY vs LIGHT with evidence). The job_escape reap-bump and driver-pacing edits touch files the agent is currently reading (inject_control_wedge.rs, job_escape_e2e.rs) — holding those edits to avoid concurrent-file conflict. The filter string + ci.yml + nextest.toml edits all depend on the sweep's HEAVY membership anyway.

Sweep is the critical path. Backstop set; agent completion will re-invoke me.


ScheduleWakeup

Heavy/light classification sweep running as a background Explore agent; its completion notification re-invokes me — this is just the backstop.

Prompt: <<autonomous-loop-dynamic>>


<owl_messages>
<owl_message from="todlando-w189" priority="info">[WORKING_PERCH_NOTICE] Subagent working perch created.
Perch: todlando-w189
Agent type: Explore
To message it: $OWL send todlando-w189 todlando</owl_message>
</owl_messages>

[OWL SYSTEM] Informational owl messages above — no acknowledgment needed. Continue your current task.


Next wakeup scheduled for 21:51:00 (in 1220s). Nothing more to do this turn — the harness re-invokes you when the wakeup fires or a task-notification arrives.


Building doyle's gated two-phase spec. Sweep agent classifying every test binary HEAVY vs LIGHT (load-bearing for the partition filter). Holding the reap-bump + driver-pacing edits until it's done (shared files). Will then: assemble HEAVY filter, update nextest.toml group + ci.yml Phase A/B, bump job_escape reap-poll 10s→25s, pace the drivers, pre-flight the partition (A+B==total, zero overlap), traceability, then commit/push for doyle to gate.


<task-notification>
<task-id>a61f0f3267f7dd8fc</task-id>
<tool-use-id>toolu_01BuTEyT1dkGPkbVRAytnS5e</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\a61f0f3267f7dd8fc.output</output-file>
<status>completed</status>
<summary>Agent "Classify heavy vs light test binaries" came to rest</summary>
<note>A task-notification fires each time this agent comes to rest with no live background children of its own. The user can send it another message and resume it, so the same task-id may notify more than once.</note>
<result>Perfect! I now have the complete picture. Let me compile my comprehensive classification report:

## Comprehensive Integration Test Binary Classification Report

Based on exhaustive analysis of all test files in `crates/*/tests/*.rs`, here is the definitive classification:

### **HEAVY Tests (47 total)**
Tests that spawn REAL PTY children, REAL OS processes, or test real brain process lifecycle:

**spt-daemon (23 HEAVY):**
1. `attach` — Real PTY child (`cat`/`findstr`) + real broker hosted under loopback QUIC with `Brain::cold_start`, plus real attach stream. Lines 27-30 define `SpawnReq` with echo child.
2. `broker` — Real PTY child (echo `cat`/`findstr`) hosted under real broker, spawned via `SpawnReq` (line 43-58), full B1 contract validation.
3. `daemon_e2e` — Real PTY child (`cat`/`findstr`), real `BrainLifecycle`, real broker + hosted session with psyche lifecycle (lines 63-77).
4. `daemon_lifecycle_real_brain` — Real process: `run_brain` (the actual brain main) spawns with `RESIDENT_PSYCHE` (`sleep 99999` / `ping`), real broker PTY child hosting (lines 22-39).
5. `inject_control_wedge` — Real broker hosting REAL PTY child (`cat`/`findstr`) over local IPC with real brain connections driving the wedge scenario (line 1-2 explicit).
6. `twohost` — Two real brokers, real QUIC endpoints, cross-host net streams. *Needs explicit check for PTY but marked known HEAVY.*
7-23. **Remaining spt-daemon HEAVY candidates**: `brain_swap`, `dispatch`, `driven_by_selfheal`, `handoff`, `idempotent`, `input_ack_deadlock`, `mesh`, `netbroker`, `netstream`, `notifsync`, `presence`, `propagate`, `pump`, `pumpdeadline`, `replicate`, `resume`, `shellchan`, `sync`, `wanmsg`, `xfer` — **ALL use `net_broker()` + `Brain::cold_start()` ONLY (in-process loopback), NO real PTY child spawning.**

**spt (15 HEAVY):**
1. `brain_respawn_rename` — Real `spt daemon run` PROCESS, real on-disk binary rename + respawn via `supervise_brain()` (lines 32-82), `CARGO_BIN_EXE_spt` explicit (line 89).
2. `brain_split` — Real `spt daemon run` broker PROCESS via `supervise_brain()`, real brain child kill + respawn (line 69), `CARGO_BIN_EXE_spt` (line 62), real PTY echo child spawned by brain.
3. `brain_survive` — Real in-process broker but with real PTY child (`cat`/`findstr`) hosted and validated (implicit from text "a real PTY child + a live QUIC connection" line 2).
4. `dummy_harness_e2e` — Real `spt daemon run` (line 70), real detached `spt endpoint run` spawns daemon + harness, PTY child heartbeat monitoring.
5. `gateway_owner_shell_e2e` — In-process daemon surfaces but real `spt shell` spawning via `Command::new`, real tunnel/drive control (lines 30-40 in daemon seed).
6. `job_escape_e2e` — Real `spt daemon start` under Windows job (lines 32-46, Windows-gated), validates real process escape from job via WMI (`WmiPrvSE`).
7. `livehost_bootgate_e2e` — Real `spt daemon run` broker PROCESS (line 73), supervised brain with net-less config, real psyche spawn testing.
8. `livehost_bootrace_e2e` — Real `spt daemon run` broker PROCESS, supervised brain CHILD (lines 73-85), real manifest + psyche binary resolution from install dir.
9. `livehost_nonresident_e2e` — Real `spt daemon run` PROCESS (lines 73-85), REAL brain CHILD, LONG-LIVED resident psyche (`spt ready` hardblock), residency confirmation waits.
10. `livehost_psyche_fail_e2e` — Real `spt daemon run` broker PROCESS, supervised brain CHILD (lines 73-85), real psyche binary spawn failure scenario.
11. `brain_restart_psyche_dup_e2e` — Real `spt daemon run` PROCESS (implicit in lines 32-40 pattern), supervised brain restart with orphan psyche reap validation.
12. `attach_wedge_e2e` — Real `spt` spawning (via `Command::new()` pattern in common), real attach wedge scenario validation.
13. `unhost_psyche_reap_e2e` — Real `spt daemon run` PROCESS, `spt endpoint stop` kills real process, real psyche reap validation (lines 68-80).
14. `resume_template_e2e` — Real `spt` invocations via `Command::new()` pattern (common pattern in spt tests).
15. `bind_cwd_project_e2e` — Real `spt` spawning via `Command::new()` pattern.

**spt-term (5 HEAVY):**
1. `surface` — Real PTY spawn: `PtySession::spawn_program("sleep", ...) / ("ping", ...)` (lines 16-21), real child under PTY, resize under load.
2. `dsr` — Real PTY spawn: `PtySession::spawn_program(...)` (lines 18-30), real ConPTY DSR auto-answer scenario.
3. `inject` — Real PTY spawn: `PtySession::spawn_program("cat"/"findstr", ...)` (lines 16-20), real injection round-trip.
4. `stream` — (Need explicit check, but spt-term pattern indicates real PTY) — Real PTY spawn implicit in spt-term.
5. `winspawn` — Real PTY spawn: `.cmd` wrapper via `PtySession::spawn_program(path, ...)` (lines 30-35, Windows-gated).

**spt-msg (0 HEAVY):**
1. `killer_quickstart` — In-process test only, likely unit-level mock.

### **LIGHT Tests (34 total)**
In-process only: `net_broker()` + `Brain::cold_start()` loopback over QUIC; NO real PTY child, NO real OS process:

**spt-daemon (19 LIGHT):**
`access`, `brain_swap`, `budget`, `digest`, `dispatch`, `driven_by_selfheal`, `handoff`, `idempotent`, `input_ack_deadlock`, `mesh`, `netbroker`, `netstream`, `notifsync`, `pairjoin`, `presence`, `propagate`, `pump`, `pumpdeadline`, `replicate`, `reseed`, `rosterprop`, `seedproofx`, `shellchan`, `sync`, `two_origin_spanning`, `wanmsg`, `xfer`.
— All use hermetic in-process `net_broker(name, &dir)` with `NetHost::start()` + `Broker::bind_in_with_net()`, loopback-only QUIC endpoints, `Brain::cold_start()` connecting to a local socket. No real PTY children, no real OS processes spawned.

**spt (15 LIGHT):**
`contract_e2e`, `drive_e2e`, `gateway_e2e`, `live_bind_firsthost_e2e`, `live_firsthost_e2e`, `live_resolve_e2e`, `n1_compat`, `n1_pairing`, `notify_shell_e2e`, `oneliner_e2e`, `poll_envelope_e2e`, `quickstart_e2e`, `ready_resume_ledger_e2e`, `release_verify_e2e`, `shell_actgate_e2e`, `shell_e2e`, `shell_sleepwake_e2e`, `tunnel_e2e`.
— These spawn in-process seed daemon (in-memory socket listener) only. The `spt` subcommand invocations (`Command::new(&spt_bin)`) are LIGHTWEIGHT subprocess spawns (API calls, not daemon lifecycle tests). Core logic is in-process mocking.

### **SUMMARY COUNTS**
- **Total test binaries found:** 79
- **HEAVY:** 47 (`spt-daemon`: 23, `spt`: 15, `spt-term`: 5, `spt-msg`: 0)
- **LIGHT:** 32 (`spt-daemon`: 19, `spt`: 13)
- **Unreported test binaries:** Common modules (`common/`), not counted as test binaries.

### **NEXTEST FILTER REGEX**

**HEAVY binary filter** (for slow/resource-intensive phase):
```
(^spt-daemon::(attach|broker|daemon_e2e|daemon_lifecycle_real_brain|inject_control_wedge|twohost|brain_swap|dispatch|driven_by_selfheal|handoff|idempotent|input_ack_deadlock|mesh|netbroker|netstream|notifsync|presence|propagate|pump|pumpdeadline|replicate|resume|shellchan|sync|wanmsg|xfer)$) | (^spt::(brain_respawn_rename|brain_split|brain_survive|dummy_harness_e2e|gateway_owner_shell_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|brain_restart_psyche_dup_e2e|attach_wedge_e2e|unhost_psyche_reap_e2e|resume_template_e2e|bind_cwd_project_e2e)$) | (^spt-term::(surface|dsr|inject|stream|winspawn)$)
```

**LIGHT binary filter** (for fast phase):
```
(^spt-daemon::(access|pairjoin|netbroker|netstream|notifsync|replicate|reseed|rosterprop|seedproofx|budget|digest|idempotent|pumpdeadline|two_origin_spanning|wanmsg|xfer|shellchan|sync)$) | (^spt::(contract_e2e|drive_e2e|gateway_e2e|live_bind_firsthost_e2e|live_firsthost_e2e|live_resolve_e2e|n1_compat|n1_pairing|notify_shell_e2e|oneliner_e2e|poll_envelope_e2e|quickstart_e2e|ready_resume_ledger_e2e|release_verify_e2e|shell_actgate_e2e|shell_e2e|shell_sleepwake_e2e|tunnel_e2e)$) | (^spt-msg::killer_quickstart$)
```</result>
<usage><subagent_tokens>80039</subagent_tokens><tool_uses>49</tool_uses><duration_ms>83225</duration_ms></usage>
</task-notification>


<owl_reachability_notice>
You have an active owl perch. When spawning subagents or doing work, use run_in_background: true so you stay reachable for incoming messages.
</owl_reachability_notice>


CAVEMAN MODE ACTIVE (full). Drop articles/filler/pleasantries/hedging. Fragments OK. Code/commits/security: write normal.


The sweep is **internally inconsistent** — it lists netbroker/netstream/dispatch/mesh/sync/wanmsg/xfer as both "HEAVY candidates" AND says they're "net_broker in-process loopback, NO real PTY" (=LIGHT), and its HEAVY regex wrongly includes those loopback-wire binaries. Too sloppy to drive a load-bearing filter. Verifying membership myself with deterministic markers.

Discriminators: (a) real PTY child = `SpawnReq`/`spawn_program`/`flood_spawn`; (b) real daemon-tree = `daemon run`/`supervise_brain`; LIGHT spt-e2e use `in_process_daemon` seed sockets, not real processes.


Found 19 files
crates\spt-daemon\tests\inject_control_wedge.rs
crates\spt-daemon\tests\broker.rs
crates\spt-daemon\tests\attach.rs
crates\spt-daemon\tests\input_ack_deadlock.rs
crates\spt\tests\brain_survive.rs
crates\spt-daemon\tests\driven_by_selfheal.rs
crates\spt-daemon\tests\daemon_e2e.rs
crates\spt-daemon\tests\dispatch.rs
crates\spt-daemon\tests\brain_swap.rs
crates\spt-daemon\tests\handoff.rs
crates\spt-daemon\tests\resume.rs
crates\spt-daemon\tests\idempotent.rs
crates\spt-daemon\tests\budget.rs
crates\spt-daemon\tests\twohost.rs
crates\spt-term\tests\winspawn.rs
crates\spt-term\tests\surface.rs
crates\spt-term\tests\stream.rs
crates\spt-term\tests\inject.rs
crates\spt-term\tests\dsr.rs


Found 16 files
crates\spt\tests\brain_survive.rs
crates\spt\tests\resume_template_e2e.rs
crates\spt\tests\dummy_harness_e2e.rs
crates\spt\tests\job_escape_e2e.rs
crates\spt\tests\attach_wedge_e2e.rs
crates\spt\tests\bind_cwd_project_e2e.rs
crates\spt\tests\brain_restart_psyche_dup_e2e.rs
crates\spt\tests\unhost_psyche_reap_e2e.rs
crates\spt\tests\livehost_bootgate_e2e.rs
crates\spt\tests\livehost_bootrace_e2e.rs
crates\spt\tests\livehost_nonresident_e2e.rs
crates\spt\tests\livehost_psyche_fail_e2e.rs
crates\spt\tests\oneliner_e2e.rs
crates\spt\tests\brain_respawn_rename.rs
crates\spt\tests\brain_split.rs
crates\spt\tests\n1_pairing.rs


No files found


`in_process_daemon` isn't a real marker (first agent invented it). Two deterministic sets returned. The SpawnReq grep correctly EXCLUDED the pure loopback-wire tests (netbroker/netstream/mesh/sync/wanmsg/etc. — confirmed LIGHT). But some matches may only reference the type, not host a real child. Pinpointing actual PTY children + real daemons by concrete literals.


Found 23 files
crates\spt-daemon\tests\inject_control_wedge.rs
crates\spt-daemon\tests\broker.rs
crates\spt-daemon\tests\attach.rs
crates\spt-daemon\tests\input_ack_deadlock.rs
crates\spt\tests\brain_survive.rs
crates\spt-daemon\tests\two_origin_spanning.rs
crates\spt\tests\job_escape_e2e.rs
crates\spt-daemon\tests\driven_by_selfheal.rs
crates\spt-daemon\tests\daemon_e2e.rs
crates\spt-daemon\tests\dispatch.rs
crates\spt-daemon\tests\brain_swap.rs
crates\spt-daemon\tests\handoff.rs
crates\spt-daemon\tests\resume.rs
crates\spt-daemon\tests\idempotent.rs
crates\spt-daemon\tests\budget.rs
crates\spt-daemon\tests\twohost.rs
crates\spt-term\tests\winspawn.rs
crates\spt-term\tests\surface.rs
crates\spt-daemon\tests\digest.rs
crates\spt-term\tests\stream.rs
crates\spt-term\tests\inject.rs
crates\spt-term\tests\dsr.rs
crates\spt-daemon\tests\shellchan.rs


Found 32 files
crates\spt\tests\brain_survive.rs
crates\spt\tests\resume_template_e2e.rs
crates\spt\tests\dummy_harness_e2e.rs
crates\spt\tests\job_escape_e2e.rs
crates\spt\tests\attach_wedge_e2e.rs
crates\spt\tests\bind_cwd_project_e2e.rs
crates\spt\tests\ready_resume_ledger_e2e.rs
crates\spt\tests\brain_restart_psyche_dup_e2e.rs
crates\spt\tests\unhost_psyche_reap_e2e.rs
crates\spt\tests\livehost_bootgate_e2e.rs
crates\spt\tests\live_resolve_e2e.rs
crates\spt\tests\livehost_bootrace_e2e.rs
crates\spt\tests\livehost_nonresident_e2e.rs
crates\spt\tests\livehost_psyche_fail_e2e.rs
crates\spt\tests\oneliner_e2e.rs
crates\spt\tests\tunnel_e2e.rs
crates\spt\tests\shell_actgate_e2e.rs
crates\spt\tests\live_bind_firsthost_e2e.rs
crates\spt\tests\live_firsthost_e2e.rs
crates\spt\tests\gateway_owner_shell_e2e.rs
crates\spt\tests\contract_e2e.rs
crates\spt\tests\drive_e2e.rs
crates\spt\tests\shell_e2e.rs
crates\spt\tests\poll_envelope_e2e.rs
crates\spt\tests\shell_sleepwake_e2e.rs
crates\spt\tests\gateway_e2e.rs
crates\spt\tests\brain_respawn_rename.rs
crates\spt\tests\quickstart_e2e.rs
crates\spt\tests\n1_compat.rs
crates\spt\tests\brain_split.rs
crates\spt\tests\n1_pairing.rs
crates\spt\tests\notify_shell_e2e.rs


`CARGO_BIN_EXE_spt` hits 32 spt files — every e2e uses the real binary, so it doesn't discriminate; the daemon-tree spawners (`supervise_brain`/`daemon run`, 16 files) do. The PTY-child-literal grep cleanly splits spt-daemon (~16 with a child program vs ~17 pure loopback-wire). Spot-checking the 3 odd spt-daemon hits (digest, two_origin_spanning, shellchan — literal but no SpawnReq) + the borderline spt CLI-vs-daemon ones.


38:const PASSTHROUGH: &str = "cat";

38:const PASSTHROUGH: &str = "cat";


36:const PASSTHROUGH: &str = "cat";

36:const PASSTHROUGH: &str = "cat";


33:const ECHO_SPAWN: &str = "cat";

33:const ECHO_SPAWN: &str = "cat";


All 3 odd spt-daemon hits (digest/two_origin_spanning/shellchan) define a real `cat`/echo child (`const PASSTHROUGH/ECHO_SPAWN = "cat"`) → real PTY → HEAVY. The PTY-child-literal grep is reliable.

**Key finding to flag:** the real-PTY/real-daemon heavy class is **~38 binaries**, not the ~7-8 doyle's spec assumed. The partition is auto-correct by construction (Phase A = `not(HEAVY)`), so the risk is just Phase-B serial duration under `max-threads=1`. I'll build per spec and surface the tradeoff.

Agent done — files free. Doing the independent edits first. job_escape reap-poll 10s→25s:


Edit

        let tree_reaped = {
            let deadline = Instant::now() + Duration::from_secs(10);

        let tree_reaped = {
            // 25s (was 10s): the kill is already issued (taskkill /F /T above); this
            // only WAITS for the tree to finish exiting. Under CPU starvation the
            // tree teardown blows past 10s and false-fails `tree_reaped` (the
            // kitsubito reliability victim). A real leak never reaps and still fails
            // at 25s, so the wider window adds load-tolerance without masking a leak.
            let deadline = Instant::now() + Duration::from_secs(25);


<tool_use_error>Found 2 matches of the string to replace, but replace_all is false. To replace all occurrences, set replace_all to true. To replace only one occurrence, please provide more context to uniquely identify the instance.
String:         let tree_reaped = {
            let deadline = Instant::now() + Duration::from_secs(10);</tool_use_error>

Error: Found 2 matches of the string to replace, but replace_all is false. To replace all occurrences, set replace_all to true. To replace only one occurrence, please provide more context to uniquely identify the instance.
String:         let tree_reaped = {
            let deadline = Instant::now() + Duration::from_secs(10);


Two reap-poll sites (wmi test + its sibling cold_start test) — same teardown-wait pattern, same load-tolerance need. Bumping both.


        let tree_reaped = {
            let deadline = Instant::now() + Duration::from_secs(10);

        let tree_reaped = {
            // 25s (was 10s): the kill is already issued (taskkill /F /T above); this
            // only WAITS for the tree to finish exiting. Under CPU starvation the
            // tree teardown blows past 10s and false-fails `tree_reaped` (the
            // kitsubito reliability victim). A real leak never reaps and still fails
            // at 25s, so the wider window adds load-tolerance without masking a leak.
            let deadline = Instant::now() + Duration::from_secs(25);


The file C:\Users\decid\Documents\projects\spt-core\crates\spt\tests\job_escape_e2e.rs has been updated. All occurrences were successfully replaced. (file state is current in your context — no need to Read it back)

        let tree_reaped = {
            let deadline = Instant::now() + Duration::from_secs(10);

        let tree_reaped = {
            // 25s (was 10s): the kill is already issued (taskkill /F /T above); this
            // only WAITS for the tree to finish exiting. Under CPU starvation the
            // tree teardown blows past 10s and false-fails `tree_reaped` (the
            // kitsubito reliability victim). A real leak never reaps and still fails
            // at 25s, so the wider window adds load-tolerance without masking a leak.
            let deadline = Instant::now() + Duration::from_secs(25);

-            let deadline = Instant::now() + Duration::from_secs(10);

+            // 25s (was 10s): the kill is already issued (taskkill /F /T above); this

+            // only WAITS for the tree to finish exiting. Under CPU starvation the

+            // tree teardown blows past 10s and false-fails `tree_reaped` (the

+            // kitsubito reliability victim). A real leak never reaps and still fails

+            // at 25s, so the wider window adds load-tolerance without masking a leak.

+            let deadline = Instant::now() + Duration::from_secs(25);

let broker_gone = !is_process_alive(broker_pid);

let brain_gone = !is_process_alive(brain_pid);

// Poll both recorded pids — broker (daemon.pid) and brain (brain.ready) —

// dead. `taskkill /T` is prompt, so a 10s window is generous.

let broker_gone = broker_pid.map(|p| !is_process_alive(p)).unwrap_or(true);


Now driver pacing. Locating both driver loops' exact text.


533-        // the journal lock) until teardown. Each send_effect writes a frame; the
534-        // pump reader drains replies concurrently so the write never deadlocks.
535-        while !driver_stop.load(std::sync::atomic::Ordering::Relaxed) {
536:            if w.send_effect(op, &chunk).is_err() {
537-                break;
538-            }
539:            driver_pumped.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
540-            op += 1;
541-            // Drain any queued replies (acks/output) so the carrier stays healthy,
542-            // then a brief pace so we don't spin a CPU.
543:            let _ = w.read_event_until(Some(std::time::Instant::now() + Duration::from_millis(20)));
544-        }
545-    });
546-
--
1774-        let chunk = vec![b'P'; 4 * 1024];
1775-        let mut op = 1u64;
1776-        while !driver_stop.load(Ordering::Relaxed) {
1777:            if w.send_effect(op, &chunk).is_err() {
1778-                break;
1779-            }
1780:            driver_pumped.fetch_add(1, Ordering::Relaxed);
1781-            op += 1;
1782-            let _ = w.read_event_until(Some(Instant::now() + Duration::from_millis(15)));
1783-        }


Pacing both drivers — explicit sleep floor keeps a journaled write in-flight (facet-B load) without pegging the core that starves the sibling attacher.


            driver_pumped.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
            op += 1;
            // Drain any queued replies (acks/output) so the carrier stays healthy,
            // then a brief pace so we don't spin a CPU.
            let _ = w.read_event_until(Some(std::time::Instant::now() + Duration::from_millis(20)));
        }

            driver_pumped.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
            op += 1;
            // Drain queued replies (acks/output) so the carrier stays healthy, then
            // PACE with an explicit floor sleep. The doc above says "sustain a write
            // in-flight", but the bare `while !stop` pumped ~6094 ops and pegged the
            // core, out-competing the SIBLING attacher thread for scheduling under
            // contention so its subscribe was never serviced in 30s (the kitsubito
            // reliability victim, subscribed=false). A small sleep keeps a journaled
            // write continuously in-flight (facet-B's load is intact) while yielding
            // the CPU the attacher needs — sustained, not storming.
            let _ = w.read_event_until(Some(std::time::Instant::now() + Duration::from_millis(20)));
            std::thread::sleep(Duration::from_millis(5));
        }


The file C:\Users\decid\Documents\projects\spt-core\crates\spt-daemon\tests\inject_control_wedge.rs has been updated successfully. (file state is current in your context — no need to Read it back)

            driver_pumped.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
            op += 1;
            // Drain any queued replies (acks/output) so the carrier stays healthy,
            // then a brief pace so we don't spin a CPU.
            let _ = w.read_event_until(Some(std::time::Instant::now() + Duration::from_millis(20)));
        }

            driver_pumped.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
            op += 1;
            // Drain queued replies (acks/output) so the carrier stays healthy, then
            // PACE with an explicit floor sleep. The doc above says "sustain a write
            // in-flight", but the bare `while !stop` pumped ~6094 ops and pegged the
            // core, out-competing the SIBLING attacher thread for scheduling under
            // contention so its subscribe was never serviced in 30s (the kitsubito
            // reliability victim, subscribed=false). A small sleep keeps a journaled
            // write continuously in-flight (facet-B's load is intact) while yielding
            // the CPU the attacher needs — sustained, not storming.
            let _ = w.read_event_until(Some(std::time::Instant::now() + Duration::from_millis(20)));
            std::thread::sleep(Duration::from_millis(5));
        }

-            // Drain any queued replies (acks/output) so the carrier stays healthy,

-            // then a brief pace so we don't spin a CPU.

+            // Drain queued replies (acks/output) so the carrier stays healthy, then

+            // PACE with an explicit floor sleep. The doc above says "sustain a write

+            // in-flight", but the bare `while !stop` pumped ~6094 ops and pegged the

+            // core, out-competing the SIBLING attacher thread for scheduling under

+            // contention so its subscribe was never serviced in 30s (the kitsubito

+            // reliability victim, subscribed=false). A small sleep keeps a journaled

+            // write continuously in-flight (facet-B's load is intact) while yielding

+            // the CPU the attacher needs — sustained, not storming.

+            std::thread::sleep(Duration::from_millis(5));


            driver_pumped.fetch_add(1, Ordering::Relaxed);
            op += 1;
            let _ = w.read_event_until(Some(Instant::now() + Duration::from_millis(15)));
        }

            driver_pumped.fetch_add(1, Ordering::Relaxed);
            op += 1;
            // Pace the pump (see the journaled-wedge driver): keep a paste write
            // in-flight without a CPU storm that starves the concurrent attacher.
            let _ = w.read_event_until(Some(Instant::now() + Duration::from_millis(15)));
            std::thread::sleep(Duration::from_millis(5));
        }


            driver_pumped.fetch_add(1, Ordering::Relaxed);
            op += 1;
            let _ = w.read_event_until(Some(Instant::now() + Duration::from_millis(15)));
        }

            driver_pumped.fetch_add(1, Ordering::Relaxed);
            op += 1;
            // Pace the pump (see the journaled-wedge driver): keep a paste write
            // in-flight without a CPU storm that starves the concurrent attacher.
            let _ = w.read_event_until(Some(Instant::now() + Duration::from_millis(15)));
            std::thread::sleep(Duration::from_millis(5));
        }

+            // Pace the pump (see the journaled-wedge driver): keep a paste write

+            // in-flight without a CPU storm that starves the concurrent attacher.


Independent edits done (reap-bump ×2, driver pacing ×2). Now the HEAVY filter + two-phase wiring. Rewriting nextest.toml with the full evidence-based membership.


1	# cargo-nextest configuration.
2	#
3	# CI runs the workspace test suite under `cargo nextest run` (one global parallel
4	# pool across all test binaries — far faster than `cargo test`'s serial-per-binary
5	# execution on a multi-core runner). See docs/RELEASE-RUNBOOK + ci-kitsubito.
6
7	[profile.default]
8	# A hung test (e.g. a blocking PTY/socket read that never completes under heavy
9	# parallelism) must FAIL FAST, never wedge the CI job up to its wall-clock
10	# timeout. Warn once a test exceeds 60s, then SIGKILL + fail it after 4 such
11	# periods (4 minutes). No legitimate test in this workspace runs that long; this
12	# is purely the no-infinite-wedge backstop.
13	slow-timeout = { period = "60s", terminate-after = 4 }
14
15	# Concurrency cap for the heavy real-broker + PTY integration tests.
16	#
17	# WHY: nextest fans the whole workspace into ONE global parallel pool sized to
18	# the runner's core count. The spt-daemon integration tests in `broker`,
19	# `attach`, and `inject_control_wedge` each spin a REAL broker, bind a real Unix
20	# domain socket / named pipe, and forkpty a real PTY child. When ~16 of those
21	# launch at once on a high-core CI box they contend for the scheduler, PTY
22	# allocation, and socket setup — producing wait-deadline / PTY-spawn / child-reap
23	# TIMING flakes whose victim changes run to run (observed: spawn_env_reaches_child
24	# on Linux forkpty, g4_translation_child_is_reaped on Windows, g2_*, w5_a2_*,
25	# controller_writer_*, attach_survives_*). This is load/timing contention, NOT a
26	# product bug — confirmed grounded (sockets use a per-process-unique name, so it
27	# is not a bind collision).
28	#
29	# FIX: serialize this heavy class via a test-group capped at one concurrent
30	# member. A cap > 1 would still let two real brokers race and stays "lucky, not
31	# reliable"; max-threads = 1 is contention-free and therefore deterministic. The
32	# wall-clock cost is bounded: the group only gates these binaries — the rest of
33	# the workspace (spt E2E, spt-term, net-transport tests) keeps running in
34	# parallel on the remaining threads. daemon_e2e + daemon_lifecycle_real_brain are
35	# included as the nearest heavy real-broker/PTY neighbours so they cannot become
36	# the next victim.
37	[test-groups]
38	heavy-broker-pty = { max-threads = 1 }
39
40	[[profile.default.overrides]]
41	filter = 'package(spt-daemon) & kind(test) & binary(/^(broker|attach|inject_control_wedge|daemon_e2e|daemon_lifecycle_real_brain)$/)'
42	test-group = 'heavy-broker-pty'
43

# cargo-nextest configuration.
#
# CI runs the workspace test suite under `cargo nextest run` (one global parallel
# pool across all test binaries — far faster than `cargo test`'s serial-per-binary
# execution on a multi-core runner). See docs/RELEASE-RUNBOOK + ci-kitsubito.

[profile.default]
# A hung test (e.g. a blocking PTY/socket read that never completes under heavy
# parallelism) must FAIL FAST, never wedge the CI job up to its wall-clock
# timeout. Warn once a test exceeds 60s, then SIGKILL + fail it after 4 such
# periods (4 minutes). No legitimate test in this workspace runs that long; this
# is purely the no-infinite-wedge backstop.
slow-timeout = { period = "60s", terminate-after = 4 }

# Concurrency cap for the heavy real-broker + PTY integration tests.
#
# WHY: nextest fans the whole workspace into ONE global parallel pool sized to
# the runner's core count. The spt-daemon integration tests in `broker`,
# `attach`, and `inject_control_wedge` each spin a REAL broker, bind a real Unix
# domain socket / named pipe, and forkpty a real PTY child. When ~16 of those
# launch at once on a high-core CI box they contend for the scheduler, PTY
# allocation, and socket setup — producing wait-deadline / PTY-spawn / child-reap
# TIMING flakes whose victim changes run to run (observed: spawn_env_reaches_child
# on Linux forkpty, g4_translation_child_is_reaped on Windows, g2_*, w5_a2_*,
# controller_writer_*, attach_survives_*). This is load/timing contention, NOT a
# product bug — confirmed grounded (sockets use a per-process-unique name, so it
# is not a bind collision).
#
# FIX: serialize this heavy class via a test-group capped at one concurrent
# member. A cap > 1 would still let two real brokers race and stays "lucky, not
# reliable"; max-threads = 1 is contention-free and therefore deterministic. The
# wall-clock cost is bounded: the group only gates these binaries — the rest of
# the workspace (spt E2E, spt-term, net-transport tests) keeps running in
# parallel on the remaining threads. daemon_e2e + daemon_lifecycle_real_brain are
# included as the nearest heavy real-broker/PTY neighbours so they cannot become
# the next victim.
[test-groups]
heavy-broker-pty = { max-threads = 1 }

[[profile.default.overrides]]
filter = 'package(spt-daemon) & kind(test) & binary(/^(broker|attach|inject_control_wedge|daemon_e2e|daemon_lifecycle_real_brain)$/)'
test-group = 'heavy-broker-pty'


Write

# cargo-nextest configuration.
#
# CI runs the workspace test suite under `cargo nextest run` in TWO PHASES (see the
# `test` job in .github/workflows/ci.yml):
#   Phase A  `-E 'not ( <HEAVY> )'`  — the light pool, full parallelism, fast.
#   Phase B  `-E '<HEAVY>'`          — the heavy real-broker/PTY/daemon-tree class,
#                                      run AFTER Phase A so the box is QUIET, and
#                                      serialized by the test-group below.
# <HEAVY> is the SAME filter string in both CI phases AND in the test-group override
# at the bottom of this file — keep all three in sync (a clean partition: A is the
# exact negation of B, so nothing is dropped or double-run).
# See docs/RELEASE-RUNBOOK + ci-kitsubito.

[profile.default]
# A hung test (e.g. a blocking PTY/socket read that never completes) must FAIL FAST,
# never wedge the CI job up to its wall-clock timeout. Warn once a test exceeds 60s,
# then SIGKILL + fail it after 4 such periods (4 minutes). No legitimate test in this
# workspace runs that long; this is purely the no-infinite-wedge backstop.
slow-timeout = { period = "60s", terminate-after = 4 }

# Concurrency cap for the heavy real-broker / PTY / daemon-tree integration tests.
#
# WHY: nextest fans a phase into ONE parallel pool sized to the runner's core count.
# The "heavy" tests each spin a REAL broker, forkpty a REAL PTY child, and/or spawn a
# REAL `spt daemon`/brain process tree. Two failure modes were observed on the shared
# self-hosted runners:
#   1. heavy-vs-heavy contention: ~16 real brokers launching at once contend for the
#      scheduler / PTY allocation / socket setup, producing wait-deadline / PTY-spawn
#      / child-reap TIMING flakes whose victim rotates run to run (spawn_env on Linux
#      forkpty, g4 on Windows, controller_writer, attach_survives, …).
#   2. heavy-starved-by-light: even with the heavy class serialized, the ~1200 LIGHT
#      tests still ran at full parallelism in the SAME pool and saturated the box, so
#      a heavy test's helper thread lost the CPU race (a_journaled_input_wedge
#      subscribed=false; job_escape_e2e tree-reap timeout). The two-phase split fixes
#      THIS: when Phase B runs, Phase A is done and the box is idle.
#
# The test-group then serializes the heavy class WITHIN Phase B so failure mode 1
# can't bite either, even on the idle box. max-threads = 1 is contention-free and
# deterministic (a cap > 1 still lets two real brokers race = lucky, not reliable).
# Group membership == the <HEAVY> phase filter. (Driver-pacing in inject_control_wedge
# additionally removes that gate's self-inflicted CPU storm — a correctness nicety on
# top of the structural split.)
[test-groups]
heavy-broker-pty = { max-threads = 1 }

# <HEAVY> — the heavy real-broker/PTY/daemon-tree class, by package+binary. Swept by
# concrete evidence: a binary is HEAVY iff some test in it spawns a real PTY child
# (a `SpawnReq`/`spawn_program` with a `cat`/`findstr`/`yes`/`sleep`/`ping`/FLOOD
# program) OR a real `spt daemon`/brain process tree (`supervise_brain`, CARGO_BIN_EXE
# daemon run). Pure in-process loopback-QUIC wire tests (net_broker with NO PTY child:
# netbroker, netstream, mesh, sync, replicate, presence, …) are LIGHT and stay in
# Phase A. All spt-term test binaries forkpty a real PTY child, so the whole package
# is heavy. Keep this string IDENTICAL to both -E filters in ci.yml.
[[profile.default.overrides]]
filter = '(package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test))'
test-group = 'heavy-broker-pty'


The file C:\Users\decid\Documents\projects\spt-core\.config\nextest.toml has been updated successfully. (file state is current in your context — no need to Read it back)

# cargo-nextest configuration.
#
# CI runs the workspace test suite under `cargo nextest run` in TWO PHASES (see the
# `test` job in .github/workflows/ci.yml):
#   Phase A  `-E 'not ( <HEAVY> )'`  — the light pool, full parallelism, fast.
#   Phase B  `-E '<HEAVY>'`          — the heavy real-broker/PTY/daemon-tree class,
#                                      run AFTER Phase A so the box is QUIET, and
#                                      serialized by the test-group below.
# <HEAVY> is the SAME filter string in both CI phases AND in the test-group override
# at the bottom of this file — keep all three in sync (a clean partition: A is the
# exact negation of B, so nothing is dropped or double-run).
# See docs/RELEASE-RUNBOOK + ci-kitsubito.

[profile.default]
# A hung test (e.g. a blocking PTY/socket read that never completes) must FAIL FAST,
# never wedge the CI job up to its wall-clock timeout. Warn once a test exceeds 60s,
# then SIGKILL + fail it after 4 such periods (4 minutes). No legitimate test in this
# workspace runs that long; this is purely the no-infinite-wedge backstop.
slow-timeout = { period = "60s", terminate-after = 4 }

# Concurrency cap for the heavy real-broker / PTY / daemon-tree integration tests.
#
# WHY: nextest fans a phase into ONE parallel pool sized to the runner's core count.
# The "heavy" tests each spin a REAL broker, forkpty a REAL PTY child, and/or spawn a
# REAL `spt daemon`/brain process tree. Two failure modes were observed on the shared
# self-hosted runners:
#   1. heavy-vs-heavy contention: ~16 real brokers launching at once contend for the
#      scheduler / PTY allocation / socket setup, producing wait-deadline / PTY-spawn
#      / child-reap TIMING flakes whose victim rotates run to run (spawn_env on Linux
#      forkpty, g4 on Windows, controller_writer, attach_survives, …).
#   2. heavy-starved-by-light: even with the heavy class serialized, the ~1200 LIGHT
#      tests still ran at full parallelism in the SAME pool and saturated the box, so
#      a heavy test's helper thread lost the CPU race (a_journaled_input_wedge
#      subscribed=false; job_escape_e2e tree-reap timeout). The two-phase split fixes
#      THIS: when Phase B runs, Phase A is done and the box is idle.
#
# The test-group then serializes the heavy class WITHIN Phase B so failure mode 1
# can't bite either, even on the idle box. max-threads = 1 is contention-free and
# deterministic (a cap > 1 still lets two real brokers race = lucky, not reliable).
# Group membership == the <HEAVY> phase filter. (Driver-pacing in inject_control_wedge
# additionally removes that gate's self-inflicted CPU storm — a correctness nicety on
# top of the structural split.)
[test-groups]
heavy-broker-pty = { max-threads = 1 }

# <HEAVY> — the heavy real-broker/PTY/daemon-tree class, by package+binary. Swept by
# concrete evidence: a binary is HEAVY iff some test in it spawns a real PTY child
# (a `SpawnReq`/`spawn_program` with a `cat`/`findstr`/`yes`/`sleep`/`ping`/FLOOD
# program) OR a real `spt daemon`/brain process tree (`supervise_brain`, CARGO_BIN_EXE
# daemon run). Pure in-process loopback-QUIC wire tests (net_broker with NO PTY child:
# netbroker, netstream, mesh, sync, replicate, presence, …) are LIGHT and stay in
# Phase A. All spt-term test binaries forkpty a real PTY child, so the whole package
# is heavy. Keep this string IDENTICAL to both -E filters in ci.yml.
[[profile.default.overrides]]
filter = '(package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test))'
test-group = 'heavy-broker-pty'

-# CI runs the workspace test suite under `cargo nextest run` (one global parallel

-# pool across all test binaries — far faster than `cargo test`'s serial-per-binary

-# execution on a multi-core runner). See docs/RELEASE-RUNBOOK + ci-kitsubito.

+# CI runs the workspace test suite under `cargo nextest run` in TWO PHASES (see the

+# `test` job in .github/workflows/ci.yml):

+#   Phase A  `-E 'not ( <HEAVY> )'`  — the light pool, full parallelism, fast.

+#   Phase B  `-E '<HEAVY>'`          — the heavy real-broker/PTY/daemon-tree class,

+#                                      run AFTER Phase A so the box is QUIET, and

+#                                      serialized by the test-group below.

+# <HEAVY> is the SAME filter string in both CI phases AND in the test-group override

+# at the bottom of this file — keep all three in sync (a clean partition: A is the

+# exact negation of B, so nothing is dropped or double-run).

+# See docs/RELEASE-RUNBOOK + ci-kitsubito.

-# A hung test (e.g. a blocking PTY/socket read that never completes under heavy

-# parallelism) must FAIL FAST, never wedge the CI job up to its wall-clock

-# timeout. Warn once a test exceeds 60s, then SIGKILL + fail it after 4 such

-# periods (4 minutes). No legitimate test in this workspace runs that long; this

-# is purely the no-infinite-wedge backstop.

+# A hung test (e.g. a blocking PTY/socket read that never completes) must FAIL FAST,

+# never wedge the CI job up to its wall-clock timeout. Warn once a test exceeds 60s,

+# then SIGKILL + fail it after 4 such periods (4 minutes). No legitimate test in this

+# workspace runs that long; this is purely the no-infinite-wedge backstop.

slow-timeout = { period = "60s", terminate-after = 4 }

-# Concurrency cap for the heavy real-broker + PTY integration tests.

+# Concurrency cap for the heavy real-broker / PTY / daemon-tree integration tests.

-# WHY: nextest fans the whole workspace into ONE global parallel pool sized to

-# the runner's core count. The spt-daemon integration tests in `broker`,

-# `attach`, and `inject_control_wedge` each spin a REAL broker, bind a real Unix

-# domain socket / named pipe, and forkpty a real PTY child. When ~16 of those

-# launch at once on a high-core CI box they contend for the scheduler, PTY

-# allocation, and socket setup — producing wait-deadline / PTY-spawn / child-reap

-# TIMING flakes whose victim changes run to run (observed: spawn_env_reaches_child

-# on Linux forkpty, g4_translation_child_is_reaped on Windows, g2_*, w5_a2_*,

-# controller_writer_*, attach_survives_*). This is load/timing contention, NOT a

-# product bug — confirmed grounded (sockets use a per-process-unique name, so it

+# WHY: nextest fans a phase into ONE parallel pool sized to the runner's core count.

+# The "heavy" tests each spin a REAL broker, forkpty a REAL PTY child, and/or spawn a

+# REAL `spt daemon`/brain process tree. Two failure modes were observed on the shared

+#   1. heavy-vs-heavy contention: ~16 real brokers launching at once contend for the

+#      scheduler / PTY allocation / socket setup, producing wait-deadline / PTY-spawn

+#      / child-reap TIMING flakes whose victim rotates run to run (spawn_env on Linux

+#      forkpty, g4 on Windows, controller_writer, attach_survives, …).

+#   2. heavy-starved-by-light: even with the heavy class serialized, the ~1200 LIGHT

+#      tests still ran at full parallelism in the SAME pool and saturated the box, so

+#      a heavy test's helper thread lost the CPU race (a_journaled_input_wedge

+#      subscribed=false; job_escape_e2e tree-reap timeout). The two-phase split fixes

+#      THIS: when Phase B runs, Phase A is done and the box is idle.

-# FIX: serialize this heavy class via a test-group capped at one concurrent

-# member. A cap > 1 would still let two real brokers race and stays "lucky, not

-# reliable"; max-threads = 1 is contention-free and therefore deterministic. The

-# wall-clock cost is bounded: the group only gates these binaries — the rest of

-# the workspace (spt E2E, spt-term, net-transport tests) keeps running in

-# parallel on the remaining threads. daemon_e2e + daemon_lifecycle_real_brain are

-# included as the nearest heavy real-broker/PTY neighbours so they cannot become

+# The test-group then serializes the heavy class WITHIN Phase B so failure mode 1

+# can't bite either, even on the idle box. max-threads = 1 is contention-free and

+# deterministic (a cap > 1 still lets two real brokers race = lucky, not reliable).

+# Group membership == the <HEAVY> phase filter. (Driver-pacing in inject_control_wedge

+# additionally removes that gate's self-inflicted CPU storm — a correctness nicety on

+# <HEAVY> — the heavy real-broker/PTY/daemon-tree class, by package+binary. Swept by

+# concrete evidence: a binary is HEAVY iff some test in it spawns a real PTY child

+# (a `SpawnReq`/`spawn_program` with a `cat`/`findstr`/`yes`/`sleep`/`ping`/FLOOD

+# program) OR a real `spt daemon`/brain process tree (`supervise_brain`, CARGO_BIN_EXE

+# daemon run). Pure in-process loopback-QUIC wire tests (net_broker with NO PTY child:

+# netbroker, netstream, mesh, sync, replicate, presence, …) are LIGHT and stay in

+# Phase A. All spt-term test binaries forkpty a real PTY child, so the whole package

+# is heavy. Keep this string IDENTICAL to both -E filters in ci.yml.

-filter = 'package(spt-daemon) & kind(test) & binary(/^(broker|attach|inject_control_wedge|daemon_e2e|daemon_lifecycle_real_brain)$/)'

# cargo-nextest configuration.
#
# CI runs the workspace test suite under `cargo nextest run` (one global parallel
# pool across all test binaries — far faster than `cargo test`'s serial-per-binary
# execution on a multi-core runner). See docs/RELEASE-RUNBOOK + ci-kitsubito.

[profile.default]
# A hung test (e.g. a blocking PTY/socket read that never completes under heavy
# parallelism) must FAIL FAST, never wedge the CI job up to its wall-clock
# timeout. Warn once a test exceeds 60s, then SIGKILL + fail it after 4 such
# periods (4 minutes). No legitimate test in this workspace runs that long; this
# is purely the no-infinite-wedge backstop.
slow-timeout = { period = "60s", terminate-after = 4 }

# Concurrency cap for the heavy real-broker + PTY integration tests.
#
# WHY: nextest fans the whole workspace into ONE global parallel pool sized to
# the runner's core count. The spt-daemon integration tests in `broker`,
# `attach`, and `inject_control_wedge` each spin a REAL broker, bind a real Unix
# domain socket / named pipe, and forkpty a real PTY child. When ~16 of those
# launch at once on a high-core CI box they contend for the scheduler, PTY
# allocation, and socket setup — producing wait-deadline / PTY-spawn / child-reap
# TIMING flakes whose victim changes run to run (observed: spawn_env_reaches_child
# on Linux forkpty, g4_translation_child_is_reaped on Windows, g2_*, w5_a2_*,
# controller_writer_*, attach_survives_*). This is load/timing contention, NOT a
# product bug — confirmed grounded (sockets use a per-process-unique name, so it
# is not a bind collision).
#
# FIX: serialize this heavy class via a test-group capped at one concurrent
# member. A cap > 1 would still let two real brokers race and stays "lucky, not
# reliable"; max-threads = 1 is contention-free and therefore deterministic. The
# wall-clock cost is bounded: the group only gates these binaries — the rest of
# the workspace (spt E2E, spt-term, net-transport tests) keeps running in
# parallel on the remaining threads. daemon_e2e + daemon_lifecycle_real_brain are
# included as the nearest heavy real-broker/PTY neighbours so they cannot become
# the next victim.
[test-groups]
heavy-broker-pty = { max-threads = 1 }

[[profile.default.overrides]]
filter = 'package(spt-daemon) & kind(test) & binary(/^(broker|attach|inject_control_wedge|daemon_e2e|daemon_lifecycle_real_brain)$/)'
test-group = 'heavy-broker-pty'


nextest.toml updated. Now ci.yml — replacing the single nextest step with Phase A/B. Finding the current line.


Grep

cargo nextest run --workspace|name: Test \(nextest\)|name: Doctests


94:      - name: Test (nextest)
95:        run: cargo nextest run --workspace
97:      - name: Doctests


80	      # build is serial linking of the many test/bin targets; mold parallelizes
81	      # it. Linux-only + CI-only (set into the job env, never committed to
82	      # .cargo/config), so Windows (MSVC linker) and Linux devs without mold are
83	      # untouched. See ci-kitsubito-speedup-plan.
84	      - name: Use mold linker (Linux)
85	        if: runner.os == 'Linux'
86	        run: echo 'RUSTFLAGS=-C link-arg=-fuse-ld=mold' >> "$GITHUB_ENV"
87	      # `cargo nextest` runs every test across ALL test binaries in ONE global
88	      # parallel pool — `cargo test` runs the binaries SERIALLY (only threads
89	      # WITHIN a binary), so on a 16-core box the many integration-test binaries
90	      # (with their fixed wall-clock sleeps) sat queued behind each other. nextest
91	      # also builds the test targets, so the old standalone `cargo build
92	      # --all-targets` is dropped (clippy --all-targets below still compiles every
93	      # target — examples/benches included — so non-test breakage is still caught).
94	      - name: Test (nextest)
95	        run: cargo nextest run --workspace
96	      # nextest does not run doctests — keep them on `cargo test --doc`.
97	      - name: Doctests

      # build is serial linking of the many test/bin targets; mold parallelizes
      # it. Linux-only + CI-only (set into the job env, never committed to
      # .cargo/config), so Windows (MSVC linker) and Linux devs without mold are
      # untouched. See ci-kitsubito-speedup-plan.
      - name: Use mold linker (Linux)
        if: runner.os == 'Linux'
        run: echo 'RUSTFLAGS=-C link-arg=-fuse-ld=mold' >> "$GITHUB_ENV"
      # `cargo nextest` runs every test across ALL test binaries in ONE global
      # parallel pool — `cargo test` runs the binaries SERIALLY (only threads
      # WITHIN a binary), so on a 16-core box the many integration-test binaries
      # (with their fixed wall-clock sleeps) sat queued behind each other. nextest
      # also builds the test targets, so the old standalone `cargo build
      # --all-targets` is dropped (clippy --all-targets below still compiles every
      # target — examples/benches included — so non-test breakage is still caught).
      - name: Test (nextest)
        run: cargo nextest run --workspace
      # nextest does not run doctests — keep them on `cargo test --doc`.
      - name: Doctests


Replacing the single nextest step with Phase A/B. Using the HEAVY string inline in each (identical) — single-quoted, cross-shell safe for both the Linux-bash and Windows-pwsh matrix legs.


Edit

      # `cargo nextest` runs every test across ALL test binaries in ONE global
      # parallel pool — `cargo test` runs the binaries SERIALLY (only threads
      # WITHIN a binary), so on a 16-core box the many integration-test binaries
      # (with their fixed wall-clock sleeps) sat queued behind each other. nextest
      # also builds the test targets, so the old standalone `cargo build
      # --all-targets` is dropped (clippy --all-targets below still compiles every
      # target — examples/benches included — so non-test breakage is still caught).
      - name: Test (nextest)
        run: cargo nextest run --workspace
      # nextest does not run doctests — keep them on `cargo test --doc`.
      - name: Doctests

      # `cargo nextest` runs every test across ALL test binaries in ONE parallel
      # pool — `cargo test` runs the binaries SERIALLY (only threads WITHIN a
      # binary). nextest also builds the test targets, so the old standalone `cargo
      # build --all-targets` is dropped (clippy --all-targets below still compiles
      # every target — examples/benches included — so non-test breakage is caught).
      #
      # TWO-PHASE split (correctness > raw speed for the release gate): the heavy
      # real-broker/PTY/daemon-tree class is timing-sensitive and STARVES when it
      # shares the global pool with the ~1200 light tests on a saturated self-hosted
      # box (kitsubito a_journaled_input_wedge subscribed=false; Windows
      # job_escape_e2e tree-reap timeout). So run the LIGHT pool first at full
      # parallelism, THEN the HEAVY class on the now-idle box (and serialized by the
      # heavy-broker-pty test-group). The <HEAVY> filter MUST stay identical in both
      # `-E` strings below AND in .config/nextest.toml's override — Phase A is the
      # exact negation of Phase B, so the two phases partition the suite with nothing
      # dropped or double-run.
      - name: Test — Phase A (light pool, full parallel)
        run: cargo nextest run --workspace -E 'not ( (package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test)) )'
      - name: Test — Phase B (heavy class, serialized, on a now-quiet box)
        run: cargo nextest run --workspace -E '(package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test))'
      # nextest does not run doctests — keep them on `cargo test --doc`.
      - name: Doctests


The file C:\Users\decid\Documents\projects\spt-core\.github\workflows\ci.yml has been updated successfully. (file state is current in your context — no need to Read it back)

      # `cargo nextest` runs every test across ALL test binaries in ONE global
      # parallel pool — `cargo test` runs the binaries SERIALLY (only threads
      # WITHIN a binary), so on a 16-core box the many integration-test binaries
      # (with their fixed wall-clock sleeps) sat queued behind each other. nextest
      # also builds the test targets, so the old standalone `cargo build
      # --all-targets` is dropped (clippy --all-targets below still compiles every
      # target — examples/benches included — so non-test breakage is still caught).
      - name: Test (nextest)
        run: cargo nextest run --workspace
      # nextest does not run doctests — keep them on `cargo test --doc`.
      - name: Doctests

      # `cargo nextest` runs every test across ALL test binaries in ONE parallel
      # pool — `cargo test` runs the binaries SERIALLY (only threads WITHIN a
      # binary). nextest also builds the test targets, so the old standalone `cargo
      # build --all-targets` is dropped (clippy --all-targets below still compiles
      # every target — examples/benches included — so non-test breakage is caught).
      #
      # TWO-PHASE split (correctness > raw speed for the release gate): the heavy
      # real-broker/PTY/daemon-tree class is timing-sensitive and STARVES when it
      # shares the global pool with the ~1200 light tests on a saturated self-hosted
      # box (kitsubito a_journaled_input_wedge subscribed=false; Windows
      # job_escape_e2e tree-reap timeout). So run the LIGHT pool first at full
      # parallelism, THEN the HEAVY class on the now-idle box (and serialized by the
      # heavy-broker-pty test-group). The <HEAVY> filter MUST stay identical in both
      # `-E` strings below AND in .config/nextest.toml's override — Phase A is the
      # exact negation of Phase B, so the two phases partition the suite with nothing
      # dropped or double-run.
      - name: Test — Phase A (light pool, full parallel)
        run: cargo nextest run --workspace -E 'not ( (package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test)) )'
      - name: Test — Phase B (heavy class, serialized, on a now-quiet box)
        run: cargo nextest run --workspace -E '(package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test))'
      # nextest does not run doctests — keep them on `cargo test --doc`.
      - name: Doctests

run: echo 'RUSTFLAGS=-C link-arg=-fuse-ld=mold' >> "$GITHUB_ENV"

-      # `cargo nextest` runs every test across ALL test binaries in ONE global

-      # parallel pool — `cargo test` runs the binaries SERIALLY (only threads

-      # WITHIN a binary), so on a 16-core box the many integration-test binaries

-      # (with their fixed wall-clock sleeps) sat queued behind each other. nextest

-      # also builds the test targets, so the old standalone `cargo build

-      # --all-targets` is dropped (clippy --all-targets below still compiles every

-      # target — examples/benches included — so non-test breakage is still caught).

-        run: cargo nextest run --workspace

+      # `cargo nextest` runs every test across ALL test binaries in ONE parallel

+      # pool — `cargo test` runs the binaries SERIALLY (only threads WITHIN a

+      # binary). nextest also builds the test targets, so the old standalone `cargo

+      # build --all-targets` is dropped (clippy --all-targets below still compiles

+      # every target — examples/benches included — so non-test breakage is caught).

+      # TWO-PHASE split (correctness > raw speed for the release gate): the heavy

+      # real-broker/PTY/daemon-tree class is timing-sensitive and STARVES when it

+      # shares the global pool with the ~1200 light tests on a saturated self-hosted

+      # box (kitsubito a_journaled_input_wedge subscribed=false; Windows

+      # job_escape_e2e tree-reap timeout). So run the LIGHT pool first at full

+      # parallelism, THEN the HEAVY class on the now-idle box (and serialized by the

+      # heavy-broker-pty test-group). The <HEAVY> filter MUST stay identical in both

+      # `-E` strings below AND in .config/nextest.toml's override — Phase A is the

+      # exact negation of Phase B, so the two phases partition the suite with nothing

+      - name: Test — Phase A (light pool, full parallel)

+        run: cargo nextest run --workspace -E 'not ( (package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test)) )'

+      - name: Test — Phase B (heavy class, serialized, on a now-quiet box)

+        run: cargo nextest run --workspace -E '(package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test))'


All edits in place (reap ×2, pacing ×2, nextest.toml, ci.yml Phase A/B). Now doyle's load-bearing PRE-FLIGHT: verify the two `-E` sets partition the suite exactly (heavy + light == total, zero overlap) and that nextest parses the filter.


Bash

cd "C:\Users\decid\Documents\projects\spt-core" && HEAVY='(package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test))'
echo "=== TOTAL ==="; cargo nextest list --workspace 2>&1 | grep -iE "tests across|error" | tail -3
echo "=== HEAVY (Phase B) ==="; cargo nextest list --workspace -E "$HEAVY" 2>&1 | grep -iE "tests across|error|parse" | tail -3
echo "=== LIGHT (Phase A = not HEAVY) ==="; cargo nextest list --workspace -E "not ( $HEAVY )" 2>&1 | grep -iE "tests across|error|parse" | tail -3

Pre-flight partition counts: total vs heavy vs light


Command running in background with ID: bk811p5on. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bk811p5on.output. You will be notified when it completes. To check interim output, use Read on that file path.


Pre-flight partition counting in background. Awaiting.


1	=== TOTAL ===
2

=== TOTAL ===


Compiling for the list. Awaiting completion.


<task-notification>
<task-id>bk811p5on</task-id>
<tool-use-id>toolu_01N7zSmg2j2DcjRz5ygA4Rtz</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bk811p5on.output</output-file>
<status>completed</status>
<summary>Background command "Pre-flight partition counts: total vs heavy vs light" completed (exit code 0)</summary>
</task-notification>


<owl_reachability_notice>
You have an active owl perch. When spawning subagents or doing work, use run_in_background: true so you stay reachable for incoming messages.
</owl_reachability_notice>


CAVEMAN MODE ACTIVE (full). Drop articles/filler/pleasantries/hedging. Fragments OK. Code/commits/security: write normal.


1	=== TOTAL ===
2	spt-store info::tests::psyche_host_error_round_trips_and_set_clear_increments
3	spt-store nodeid::tests::corrupt_key_errors_never_regenerates
4	spt-store registry::tests::resolve_on_empty_registry_is_none_not_error
5	=== HEAVY (Phase B) ===
6	spt::livehost_psyche_fail_e2e online_live_agent_with_missing_psyche_binary_stamps_a_harness_reachable_error
7	spt-daemon::resume resume_below_ring_floor_clamps_forward_without_gap_error
8	=== LIGHT (Phase A = not HEAVY) ===
9	spt-store nodeid::tests::corrupt_key_errors_never_regenerates
10	spt-store registry::tests::resolve_on_empty_registry_is_none_not_error
11	spt-term projection::tests::ts_ordering_key_parses_and_is_optional
12

=== TOTAL ===
spt-store info::tests::psyche_host_error_round_trips_and_set_clear_increments
spt-store nodeid::tests::corrupt_key_errors_never_regenerates
spt-store registry::tests::resolve_on_empty_registry_is_none_not_error
=== HEAVY (Phase B) ===
spt::livehost_psyche_fail_e2e online_live_agent_with_missing_psyche_binary_stamps_a_harness_reachable_error
spt-daemon::resume resume_below_ring_floor_clamps_forward_without_gap_error
=== LIGHT (Phase A = not HEAVY) ===
spt-store nodeid::tests::corrupt_key_errors_never_regenerates
spt-store registry::tests::resolve_on_empty_registry_is_none_not_error
spt-term projection::tests::ts_ordering_key_parses_and_is_optional


My grep was polluted (`error` matched test-name substrings like `_errors_`). The list itself works — nextest parsed the filter fine (no parse error, real test lines emitted for both phases). Re-counting cleanly via stdout line counts.


cd "C:\Users\decid\Documents\projects\spt-core" && HEAVY='(package(spt-daemon) & kind(test) & binary(/^(attach|brain_swap|broker|budget|daemon_e2e|daemon_lifecycle_real_brain|digest|dispatch|driven_by_selfheal|handoff|idempotent|inject_control_wedge|input_ack_deadlock|resume|shellchan|two_origin_spanning|twohost)$/)) | (package(spt) & kind(test) & binary(/^(attach_wedge_e2e|bind_cwd_project_e2e|brain_respawn_rename|brain_restart_psyche_dup_e2e|brain_split|brain_survive|dummy_harness_e2e|job_escape_e2e|livehost_bootgate_e2e|livehost_bootrace_e2e|livehost_nonresident_e2e|livehost_psyche_fail_e2e|n1_pairing|oneliner_e2e|resume_template_e2e|unhost_psyche_reap_e2e)$/)) | (package(spt-term) & kind(test))'
T=$(cargo nextest list --workspace 2>/dev/null | grep -c '::')
H=$(cargo nextest list --workspace -E "$HEAVY" 2>/dev/null | grep -c '::')
L=$(cargo nextest list --workspace -E "not ( $HEAVY )" 2>/dev/null | grep -c '::')
echo "TOTAL=$T  HEAVY=$H  LIGHT=$L  H+L=$((H+L))"
echo "PARTITION_OK=$([ $((H+L)) -eq $T ] && echo YES || echo NO)"
echo "--- heavy binaries ---"; cargo nextest list --workspace -E "$HEAVY" --list-type binaries 2>/dev/null

Clean partition counts + heavy binary list


Command running in background with ID: bot60kc8o. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bot60kc8o.output. You will be notified when it completes. To check interim output, use Read on that file path.


<system-reminder>Warning: the file exists but is shorter than the provided offset (1). The file has 1 lines.</system-reminder>


<task-notification>
<task-id>bot60kc8o</task-id>
<tool-use-id>toolu_012VBLYnvMbknPYbAx28nMY5</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bot60kc8o.output</output-file>
<status>failed</status>
<summary>Background command "Clean partition counts + heavy binary list" failed with exit code 2</summary>
</task-notification>


Awaiting partition verdict.


1	TOTAL=1258  HEAVY=90  LIGHT=1168  H+L=1258
2	PARTITION_OK=YES
3	--- heavy binaries ---
4

TOTAL=1258  HEAVY=90  LIGHT=1168  H+L=1258
PARTITION_OK=YES
--- heavy binaries ---


Prompt:
<task-notification>
<task-id>bot60kc8o</task-id>
<tool-use-id>toolu_012VBLYnvMbknPYbAx28nMY5</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bot60kc8o.output</output-file>
<status>failed</status>
<summary>Background command "Clean partition counts + heavy binary list" failed with exit code 2</summary>
</task-notification>


**PARTITION VERIFIED: TOTAL=1258 = HEAVY=90 + LIGHT=1168, zero overlap, nothing dropped.** (exit 2 was only the trailing `--list-type binaries` flag form — partition check already printed YES.) 90 heavy tests serial on a quiet box ≈ 3-6 min Phase B — bounded, correctness-first.

Now verify the edits behave: run inject_control_wedge (pacing) + job_escape_e2e (reap bump) via the new filter, plus clippy + traceability.


cd "C:\Users\decid\Documents\projects\spt-core" && cargo nextest run -E '(package(spt-daemon) & binary(inject_control_wedge)) | (package(spt) & binary(job_escape_e2e))' 2>&1 | tail -14

Run inject_control_wedge + job_escape_e2e via new filter


Command running in background with ID: bzmydvnf2. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bzmydvnf2.output. You will be notified when it completes. To check interim output, use Read on that file path.


cd "C:\Users\decid\Documents\projects\spt-core" && cargo clippy -p spt-daemon -p spt --tests 2>&1 | tail -6; echo "[clippy $?]"

Clippy on edited crates' tests


Command running in background with ID: bp1it4rd2. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bp1it4rd2.output. You will be notified when it completes. To check interim output, use Read on that file path.


cd "C:\Users\decid\Documents\projects\spt-core" && traceable-reqs check >/tmp/tr2.out 2>&1; echo "[trace $?]"; git diff --stat

Traceability + diff stat


Command running in background with ID: bveg9hfd3. Output is being written to: C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bveg9hfd3.output. You will be notified when it completes. To check interim output, use Read on that file path.


<task-notification>
<task-id>bveg9hfd3</task-id>
<tool-use-id>toolu_013oG82oc3GRe6EKGNXhoGAG</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bveg9hfd3.output</output-file>
<status>completed</status>
<summary>Background command "Traceability + diff stat" completed (exit code 0)</summary>
</task-notification>


Three checks running (wedge+job_escape tests, clippy, traceability+diff). Awaiting all.


1	[trace 0]
2	warning: in the working copy of '.config/nextest.toml', LF will be replaced by CRLF the next time Git touches it
3	warning: in the working copy of 'crates/spt-daemon/tests/inject_control_wedge.rs', LF will be replaced by CRLF the next time Git touches it
4	warning: in the working copy of 'crates/spt/tests/job_escape_e2e.rs', LF will be replaced by CRLF the next time Git touches it
5	 .config/nextest.toml                            | 72 +++++++++++++++----------
6	 .github/workflows/ci.yml                        | 29 ++++++----
7	 crates/spt-daemon/tests/inject_control_wedge.rs | 14 ++++-
8	 crates/spt/tests/job_escape_e2e.rs              | 14 ++++-
9	 4 files changed, 87 insertions(+), 42 deletions(-)
10

[trace 0]
warning: in the working copy of '.config/nextest.toml', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt-daemon/tests/inject_control_wedge.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/tests/job_escape_e2e.rs', LF will be replaced by CRLF the next time Git touches it
 .config/nextest.toml                            | 72 +++++++++++++++----------
 .github/workflows/ci.yml                        | 29 ++++++----
 crates/spt-daemon/tests/inject_control_wedge.rs | 14 ++++-
 crates/spt/tests/job_escape_e2e.rs              | 14 ++++-
 4 files changed, 87 insertions(+), 42 deletions(-)


Prompt:
<task-notification>
<task-id>bveg9hfd3</task-id>
<tool-use-id>toolu_013oG82oc3GRe6EKGNXhoGAG</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bveg9hfd3.output</output-file>
<status>completed</status>
<summary>Background command "Traceability + diff stat" completed (exit code 0)</summary>
</task-notification>


Traceability green. Diff = 4 files, +87/-42. Awaiting the test run + clippy.


Tests still running. Awaiting completion notifications for the wedge+job_escape run and clippy.


<task-notification>
<task-id>bp1it4rd2</task-id>
<tool-use-id>toolu_01PGM3mZ4UHkp8ajXXvXRoQY</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bp1it4rd2.output</output-file>
<status>completed</status>
<summary>Background command "Clippy on edited crates' tests" completed (exit code 0)</summary>
</task-notification>


Read clippy + test results


    Checking spt-daemon v0.12.1 (C:\Users\decid\Documents\projects\spt-core\crates\spt-daemon)
    Checking spt v0.12.1 (C:\Users\decid\Documents\projects\spt-core\crates\spt)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 17.50s
[clippy 0]
===TESTS===


Clippy clean. Test run (wedge + job_escape, includes real-daemon WMI tests) still going. Awaiting.


ScheduleWakeup

Awaiting the wedge+job_escape verification run before committing the two-phase split; its completion notification re-invokes me — backstop only.

Prompt: <<autonomous-loop-dynamic>>


Next wakeup scheduled for 22:02:00 (in 1258s). Nothing more to do this turn — the harness re-invokes you when the wakeup fires or a task-notification arrives.


<task-notification>
<task-id>bzmydvnf2</task-id>
<tool-use-id>toolu_01JdjugHvSju1HpE6AL8GE8m</tool-use-id>
<output-file>C:\Users\decid\AppData\Local\Temp\claude\C--Users-decid-Documents-projects-spt-core\97787e5e-64b2-4afd-b3fe-becaa2ea8030\tasks\bzmydvnf2.output</output-file>
<status>completed</status>
<summary>Background command "Run inject_control_wedge + job_escape_e2e via new filter" completed (exit code 0)</summary>
</task-notification>


Two-phase split fully wired. Status: partition verified (1258 = 90 heavy + 1168 light, exact), clippy clean, traceability green, reap-bump + driver-pacing in. Final verification run (wedge + job_escape) in flight; will commit + push for doyle once green.


CAVEMAN MODE ACTIVE (full). Drop articles/filler/pleasantries/hedging. Fragments OK. Code/commits/security: write normal.


<owl_reachability_notice>
You have an active owl perch. When spawning subagents or doing work, use run_in_background: true so you stay reachable for incoming messages.
</owl_reachability_notice>


Bash

Read wedge+job_escape result


        PASS [   4.845s] ( 1/12) spt::job_escape_e2e win::cold_start_daemon_escapes_kill_on_close_job_via_wmi
        PASS [   3.364s] ( 2/12) spt::job_escape_e2e win::wmi_daemon_run_has_no_conhost_window
        PASS [   3.299s] ( 3/12) spt-daemon::inject_control_wedge a_backed_up_controller_does_not_wedge_the_session
        PASS [   3.489s] ( 4/12) spt-daemon::inject_control_wedge a_journaled_input_wedge_does_not_starve_a_concurrent_rc_attach
        PASS [  12.436s] ( 5/12) spt-daemon::inject_control_wedge g1_choreography_happy_path_payload_reaches_pty_and_controller_keeps_control
        PASS [   0.663s] ( 6/12) spt-daemon::inject_control_wedge g2_no_commit_deadline_faults_binary_and_does_not_wedge_controller_input
        PASS [   0.816s] ( 7/12) spt-daemon::inject_control_wedge g3_content_free_ping_never_duplicates_operator_keystrokes_into_binary
        PASS [   0.686s] ( 8/12) spt-daemon::inject_control_wedge g4_translation_child_is_reaped_no_zombie_after_session_down
        PASS [   0.476s] ( 9/12) spt-daemon::inject_control_wedge injecting_a_large_payload_into_a_stdin_ignoring_child
        PASS [   3.119s] (10/12) spt-daemon::inject_control_wedge p0_paste_wedge_parked_write_does_not_starve_attach_or_wedge_broker
        PASS [   0.602s] (11/12) spt-daemon::inject_control_wedge w5_a1_locally_driven_session_reports_controller_by_none
        PASS [   4.381s] (12/12) spt-daemon::inject_control_wedge w5_a2_abandoned_remote_controller_idle_session_keeps_controller_by_some
────────────
     Summary [  38.178s] 12 tests run: 12 passed, 0 skipped


12/12 PASS. Confirms: a_journaled_input_wedge PASS 3.5s (pacing preserved facet-B, subscribed=true), p0 3.1s, both job_escape WMI tests PASS (reap bump good), g2/g4/w5_a2 green. All gates: partition 1258=90+1168 ✓, clippy ✓, traceability ✓. Committing.


cd "C:\Users\decid\Documents\projects\spt-core" && git add .config/nextest.toml .github/workflows/ci.yml crates/spt-daemon/tests/inject_control_wedge.rs crates/spt/tests/job_escape_e2e.rs && git commit -q -F - <<'EOF'
ci(nextest): two-phase split (light pool, then heavy on a quiet box) to end load-starvation flakes structurally

Operator pivot: stop the group->hardening->reap->pace whack-a-mole and fix the CI
TOPOLOGY. RUN#1 of bcf1373 proved the root with the hardened discriminator: on
kitsubito the heavy gate FAST-failed (a_journaled_input_wedge, subscribed=false@41s,
driver pumped 6094 ops freely so the W1b driver fix is good) — the concurrent
attacher was STARVED of CPU; and Windows job_escape_e2e's tree-reap timed out. Same
meta-cause: timing-sensitive real-broker/PTY/daemon-tree tests starve under nextest's
GLOBAL parallelism on a saturated self-hosted box. The single-pool test-group
serialized heavy-vs-heavy but NOT vs the ~1200 light tests sharing the pool.

LEAD FIX — split the `test` job's one `nextest run --workspace` into two phases:
  Phase A: -E 'not ( <HEAVY> )'  — the light pool, full parallelism, fast.
  Phase B: -E '<HEAVY>'          — the heavy class, AFTER A, on a now-idle box,
                                   serialized by the heavy-broker-pty test-group.
When Phase B runs, Phase A is done -> box idle -> no cross-pool starvation. Subsumes
a global-thread cap without slowing the light phase. The <HEAVY> string is identical
in both -E filters AND in .config/nextest.toml's group override (Phase A is the exact
negation of B). Pre-flight partition verified: TOTAL 1258 = HEAVY 90 + LIGHT 1168,
zero overlap, nothing dropped/double-run.

HEAVY membership — swept by concrete evidence (operator's "stop the whack-a-mole":
include the whole class, not just yesterday's victim). A binary is HEAVY iff a test
in it spawns a real PTY child (SpawnReq/spawn_program with cat/findstr/yes/sleep/ping/
FLOOD) OR a real `spt daemon`/brain process tree (supervise_brain / CARGO_BIN_EXE
daemon run). All spt-term binaries forkpty -> whole package heavy. Pure in-process
loopback-QUIC wire tests (netbroker/netstream/mesh/sync/replicate/... — net_broker
with NO PTY child) stay LIGHT in Phase A. Expanded the group from doyle's 5 to the
full 38-binary / 90-test class so there is no next victim.

Folded fixes:
- job_escape_e2e: bump the tree-reap WAIT 10s->25s (both wmi gates). The kill is
  already issued (taskkill /F /T); this only waits for exit, which blows past 10s
  under starvation. A real leak never reaps and still fails at 25s — load-tolerance,
  not masking.
- inject_control_wedge: pace both wedge drivers (a small floor sleep per op). The
  documented-"BOUNDED" pump was an unbounded while!stop that pegged a core and
  out-competed its sibling attacher thread for scheduling. Paced-but-sustained keeps
  a journaled write in-flight (facet-B's load intact) while yielding CPU.

Verified local: partition exact; clippy clean; traceable-reqs green; the modified
gates pass via the new filter (inject_control_wedge 10/10 incl. a_journaled_input_wedge
subscribed=true + p0; job_escape_e2e both wmi gates green). No assertion/test-logic
change beyond the documented reap-wait widening.

Co-authored by: todlando
EOF
git log --oneline -1

Commit two-phase split + folded fixes


warning: in the working copy of '.config/nextest.toml', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt-daemon/tests/inject_control_wedge.rs', LF will be replaced by CRLF the next time Git touches it
warning: in the working copy of 'crates/spt/tests/job_escape_e2e.rs', LF will be replaced by CRLF the next time Git touches it
fe7957f ci(nextest): two-phase split (light pool, then heavy on a quiet box) to end load-starvation flakes structurally


cd "C:\Users\decid\Documents\projects\spt-core" && git push origin v0.13.0-p1b-ack-deadlock 2>&1 | tail -4

Push two-phase split commit


To https://github.com/SaberMage/spt-core.git
   bcf1373..fe7957f  v0.13.0-p1b-ack-deadlock -> v0.13.0-p1b-ack-deadlock


Pushed fe7957f. Reporting to doyle with the membership, partition proof, and the open tradeoffs for his gate.


$OWL send doyle <<'EOF'
TWO-PHASE SPLIT BUILT + PUSHED -> fe7957f on v0.13.0-p1b-ack-deadlock. Per your gated spec. Ready for fold + multi-run CI.

WHAT SHIPPED (all 6 spec points):
1+3. ci.yml `test` job: single `nextest run --workspace` -> Phase A `-E 'not(<HEAVY>)'` (light, full parallel) THEN Phase B `-E '<HEAVY>'` (heavy, on now-idle box). Same <HEAVY> string in both -E AND in nextest.toml override.
2. Kept test-group heavy-broker-pty {max-threads=1}; membership == <HEAVY>.
4. Driver-pacing folded: both wedge drivers get a 5ms floor sleep/op (the "BOUNDED" pump was unbounded while!stop, 6094 ops, pegged a core, starved its sibling attacher). facet-B intact — a_journaled_input_wedge PASSES subscribed=true clean.
5. traceable-reqs check GREEN (CI-infra, no new REQ). Confirmed.
6. PRE-FLIGHT PARTITION VERIFIED: nextest list -> TOTAL=1258, HEAVY=90, LIGHT=1168, H+L=1258, zero overlap, nothing dropped/double-run.
+ job_escape_e2e reap-WAIT 10s->25s on BOTH wmi gates (kill already issued; just waits for exit; real leak still fails at 25s).

SWEEP CORRECTION — IMPORTANT: my first delegated sweep was internally INCONSISTENT (it tagged loopback-wire tests like netbroker/netstream/mesh/sync as HEAVY in its regex while its prose called them in-process LIGHT). I threw it out and re-derived membership by DETERMINISTIC markers: HEAVY iff a binary spawns a real PTY child (SpawnReq/spawn_program + cat/findstr/yes/sleep/ping/FLOOD literal) OR a real spt daemon/brain tree (supervise_brain / CARGO_BIN_EXE daemon run). Pure net_broker loopback-QUIC wire tests = LIGHT.

HEAVY = 38 binaries / 90 tests (expanded from your 8, per operator's stop-the-whack-a-mole):
- spt-daemon (17): attach, brain_swap, broker, budget, daemon_e2e, daemon_lifecycle_real_brain, digest, dispatch, driven_by_selfheal, handoff, idempotent, inject_control_wedge, input_ack_deadlock, resume, shellchan, two_origin_spanning, twohost  (all host a real cat/findstr PTY child)
- spt (16): attach_wedge_e2e, bind_cwd_project_e2e, brain_respawn_rename, brain_restart_psyche_dup_e2e, brain_split, brain_survive, dummy_harness_e2e, job_escape_e2e, livehost_boot{gate,race}_e2e, livehost_nonresident_e2e, livehost_psyche_fail_e2e, n1_pairing, oneliner_e2e, resume_template_e2e, unhost_psyche_reap_e2e  (real spt daemon/brain process tree)
- spt-term (5, whole pkg): dsr, inject, stream, surface, winspawn  (all forkpty)

TWO THINGS FOR YOUR GATE:
A. SPEED: Phase B = 90 tests fully SERIAL (max-threads=1) ~= 3-6 min on the quiet box (Phase A stays fast/parallel). Correct per your spec. BUT: the two-phase split already removes the LIGHT-pool load, so on the idle box a group cap of 2-4 (not 1) would likely stay clean AND cut Phase B time materially. Your call — I left it at 1 per spec; one-line change if you want it.
B. UNCERTAIN (left LIGHT): gateway_owner_shell_e2e spawns a real `spt shell` child but no daemon-tree/PTY-host evidence -> kept in Phase A. Promote it if you want max safety.

VERIFIED LOCAL: partition exact; clippy clean; traceable green; via the NEW filter inject_control_wedge 10/10 (incl a_journaled_input_wedge subscribed=true + p0) + job_escape_e2e both wmi gates green. Over to you: fold + x2-3 CI. Reachable. -todlando
EOF

Report two-phase build to doyle


➜ SENT:doyle


Two-phase split built, pushed (fe7957f), reported to doyle with full membership, verified partition (1258=90+1168), and the two gate-decisions (Phase B serial-duration vs cap, gateway_owner_shell uncertainty). All local gates green. Awaiting doyle's fold + multi-run CI verdict via the Monitor.


ScheduleWakeup

Two-phase split pushed; awaiting doyle's fold + multi-run CI verdict, which arrives via the armed Monitor — fallback heartbeat only.

Prompt: <<autonomous-loop-dynamic>>


Next wakeup scheduled for 22:08:00 (in 1530s). Nothing more to do this turn — the harness re-invokes you when the wakeup fires or a task-notification arrives.


Delivered. doyle has the full two-phase implementation (fe7957f) + the decision points for his gate. Idle until his CI verdict.


<task-notification>
<task-id>b4cwwiglf</task-id>
<summary>Monitor event: "« spt event »"</summary>
<event><EVENT type="msg" from="doyle">Got seq 1-8, TRUNCATED mid-seq-8 at &quot;A. SPEED: Phase B = 90 tests fully SERIAL ~3-6 min on the qu...&quot; — seq 8-tail + 9 + 10 LOST. Resend from &quot;TWO THINGS FOR YOUR GATE&quot; onward (concern A tail + concern B + close). Gating the diff + re-running partition myself in parallel. -doyle</EVENT></event>
</task-notification>


My message truncated mid-seq-8. doyle wants concern A tail + B + close resent. Sending shorter.


Bash

$OWL send doyle <<'EOF'
[RESEND tail — concerns A/B + close]

TWO THINGS FOR YOUR GATE:

A. SPEED — Phase B = 90 tests fully SERIAL (test-group max-threads=1) ~= 3-6 min on the quiet box; Phase A stays fast/parallel. Correct per your spec. BUT the two-phase split ALREADY removes the light-pool load, so on the now-idle box a group cap of 2-4 (instead of 1) would likely stay clean AND cut Phase B wall-time materially. I left it at 1 per your spec — one-line change in .config/nextest.toml if you want the cap raised. Your call at the gate.

B. UNCERTAIN binary (left LIGHT) — gateway_owner_shell_e2e spawns a real `spt shell` child but has NO daemon-tree / PTY-host evidence, so I kept it in Phase A. Promote it into <HEAVY> (both -E filters + the nextest.toml group string) if you want max safety. Everything else classified on hard evidence.

VERIFIED LOCAL: partition exact (1258 = 90 + 1168, zero overlap); clippy clean; traceable-reqs green; via the NEW filter inject_control_wedge 10/10 (incl a_journaled_input_wedge subscribed=true + p0_paste_wedge) + job_escape_e2e BOTH wmi gates green.

Over to you: fold + x2-3 CI per the flaky-cluster gate. If a Phase-B test still flakes it's now isolated on a quiet box (real signal, not load). Reachable. -todlando
EOF

Resend truncated tail to doyle


Tail resent (concerns A/B + verification + handoff). doyle is gating the diff + re-running the partition himself in parallel. Idle until his verdict; fallback already set.


<task-notification>
<task-id>b4cwwiglf</task-id>
Monitor event: "« spt event »"
<event><EVENT-PART seq="1/4" id="6e63f404" type="msg" from="doyle">ACK resend — got concerns A+B + partition (1258=90+1168). Two rulings:

A. SPEED / raise cap 1-&gt;2-4: DECLINE. Keep max-threads=1. We just fought a multi-round flake war to get deterministic; not trading that for ~3 min. cap=1 = contention-free is the whole point, and operator's stance is correctness &gt; raw </EVENT-PART>
<EVENT-PART seq="2/4" id="6e63f404">speed for the release gate. We can revisit a higher cap LATER once it's proven stable across many green runs — not now.

B. gateway_owner_shell_e2e (you left LIGHT): PROMOTE to HEAVY. It spawns a real `spt shell` child = real-process spawn that can contend/timing-flake; over-inclusion is the SAFE error and matches operator's stop-the-w</EVENT-PART>
<EVENT-PART seq="3/4" id="6e63f404">hack-a-mole + your own max-safety offer. ADD it to package(spt) binary group in ALL 3 sites (nextest.toml override + both ci.yml -E), keep the string BYTE-IDENTICAL across all three, re-run your partition list to confirm new totals (1258 = (90+N) + (1168-N)), push.

Then surface the new commit; I fold + re-run x2-3. One more thing for my</EVENT-PART>
<EVENT-PART seq="4/4" id="6e63f404"> gate: the 3-site string identity is load-bearing (drift = a test silently in neither phase). I'm verifying it textually here too. Push the gateway promotion and I'll gate the final. -doyle</EVENT-PART></event>
</task-notification>


doyle: (A) DECLINE cap raise — keep max-threads=1. (B) PROMOTE gateway_owner_shell_e2e to HEAVY in all 3 sites, byte-identical, re-verify partition, push.

Adding `gateway_owner_shell_e2e` (alphabetical, between dummy_harness_e2e and job_escape_e2e) to all 3 sites.