p = 'docs/INFRA-REGISTER.md'
raw = open(p, 'rb').read()
crlf = b'\r\n' in raw
s = raw.decode('utf-8').replace('\r\n', '\n')

ir156 = """### IR-156 — spt tests that autostart a real daemon tree through a CLI verb are invisible to the HEAVY detector, and three leak that tree past the test
- **Status:** OPEN; census and measured leak arm DONE; remedy lane owned by hertz (propose per binary, then build). Filed by hertz, 2026-09-25, at doyle's request (`HDDEXZNE`, `YITQXO5A`, `D3GY32HJ`, rulings `FISCITF2`). Origin: todlando's W10 rig: `busy_window_axis_e2e` (`89fd4412`) leaked a detached daemon+brain pair per run and held `target\\debug\\spt.exe` (next build: os error 5). Records: `.spt/preserved/331/hertz/autostart-census/` (census, verb map, population) and `.spt/preserved/331/hertz/leak-arm/`.
- **Which verbs autostart (main `abaa1696`).** From a reverse call graph out of `ensure_running`, with every deciding edge read by hand.
  - **Unconditional,** after input checks: every `spt api <sub>`, because `api::run`'s first statement is `ensure_daemon()`. Also `serve` (all but `lan-firewall`), `fetch`, `seal mint`, `seal enroll-authenticator`, `endpoint digest`, `subnet create`, `subnet join`, `shell drive` and `shell tunnel`.
  - **Explicit:** `daemon start` / `node start`.
  - **Conditional:**
    - `send`, with `--attachment`, with `--seal`, or on the WAN leg (NoPerch without `--active-only`).
    - The remote arms of `knock`, `adapter add -vs`, `adapter update` and `update`.
    - `endpoint list` and `subnet status` when they probe a node.
    - `endpoint start`, `resume`, `fork`, `wake` and `suspend` on their remote or stdin-receipt arms.
    - `shell spawn`, `cmd`, `send`, `relink` and `teardown` on stdin receipt.
  - **`spt ready` does NOT autostart:** it goes `run_listen` → `spt_msg::ReadyAgent`, and spt-msg has no spt-daemon dependency. This corrects the rig finding's premise; the driver in `busy_window_axis_e2e` is `api … poll`.
- **The MECHANISM that makes most of them light (measured).** `ensure_running` is a no-op when `is_running()` answers, and `is_running()` answers when SEED CONTROL answers (daemon.rs:3519). A test that hosts `spt_daemon::seedmap::serve_seed_control(` in-process therefore never spawns a tree, however many `spt api` calls it makes. That server dies with the test.
  - Measured by `strace -f -e trace=execve`: `io_state_payload_e2e` makes 14 `spt api` execs and **0** `daemon run` execs. `poll_envelope_e2e`, which hosts no seed control, makes 1 `api` exec that is followed by `daemon run` and then `daemon brain`.
  - Control: the same `api` argv in a FRESH home, run by hand, prints `DAEMON_AUTOSTART: no daemon and no standing operator stop — starting one` and execs one `daemon run`.
- **Population** (the 118 top-level `crates/spt/tests/*.rs` binaries, the xtask detector's own scope):
  - 51 are HEAVY. 39 pass an unconditional autostart verb, and 25 of those are NOT HEAVY. The current detector (`spawns_daemon_tree`: the literals `"daemon", "run"`, `"daemon", "brain"`, `supervise_brain(`) misses all 25.
  - Of the 25, **16 host seed control in-process** and never spawn a tree. **9 do spawn one:**
    - 7 via an explicit `daemon start` WITH a `daemon stop`: HEAVY-at-birth misses, with no leak. They are `boundary_events_e2e`, `broker_stop_endpoint_deny_e2e`, `daemon_stop_convoy_e2e`, `io_events_poll_e2e`, `io_events_undriven_kinds_e2e`, `midturn_span_e2e` and `now_signal_delta_e2e`.
    - `poll_envelope_e2e` (leaks).
    - `worker_lifecycle_e2e` (clean).
  - 47 more binaries pass only CONDITIONAL verbs, and 23 of them are non-HEAVY without seed control. All 23 were measured below.
- **MEASURED leak arm** (kitsubito, main `abaa1696`, one pool; each binary run SOLO; new `daemon|node run|brain` processes counted against a per-binary baseline at +5 s and +30 s; kills restricted to `SPT_HOME=/tmp/…`):
  - **LEAK: 3 binaries.** Each left a daemon+brain pair alive at +30 s, and each test PASSED:
    - `poll_envelope_e2e`: 4/4 runs. It uses `api --adapter spt poll` under a tempdir home, with no teardown.
    - `active_only_never_relay_e2e`: 2/2. Its `send remotegw` without `--active-only` takes the WAN leg by design ("it takes the WAN leg", its own comment).
    - `er_inbound_local`: 1/1, through `send`.
  - **Negative control** `io_events_poll_e2e` (a literal `daemon stop`): 1 process at +5 s, **0** at +30 s. The control holds; its stop just takes more than 5 s.
  - **CLEAN** (0 at +30 s): `worker_lifecycle_e2e`, the 5 seed-control binaries, and 21 of the 23 conditional binaries.
  - **`gateway_e2e`** was a HOLE in the first run (its `mock-session` fixture was not built by the rig) and PASSES clean once the fixture is built.
  - Limits: Linux only. todlando's original leak was on Windows. A Windows arm is doyle-scheduled if it is needed.
- **Rig lessons, each paid for in this arm:**
  - **Key a KILL on the SPT_HOME / exe path, never on sampled pids** (doyle `FISCITF2`). Run 2 sampled the process table every 200 ms during each test to tell never-started from exited-early. It is VOID:
    - the tests finish in under a second, so the sampler missed even its own positive control (`poll_envelope_e2e`, which leaks 4/4 under a plain census);
    - its after-checks and kill were keyed on the pids it had sampled, so a pid it missed was also never killed. It LEFT a leaked pair on kitsubito, found later and killed by pid.
    - A sampler that misses a process also misses its kill.
  - **The discriminator that cannot miss** is `strace -f -e trace=execve`: it records a `daemon run` exec however briefly the process lives. Two traps:
    - **`strace -f` HANGS on a leaking binary.** It follows the orphaned daemon and waits for it to exit. The hang itself confirms the leak, but the run needs an outside kill.
    - **strace truncates strings at 32 characters.** The long exe path prints as `"…"...`, so a matcher must accept `..., "api"`. A first count read `api_execs=0` on the binary that plainly calls `api`.
  - **`pgrep -f PATTERN` over ssh matches the ssh command line that carries PATTERN.** A synthetic-control kill took down the ssh session itself (exit 255), the known `pkill -f` trap. Write the pattern self-excluding (`[s]pt`) and kill by explicit pid.
- **Remedy shape (doyle `D3GY32HJ` §3 and `FISCITF2`), proposed per binary before any flip; NOT 25 blind HEAVY flips:**
  - **Does the test NEED a daemon?**
    - If not, pre-write `daemon-stop.inhibit` in its home. That kills the leak and keeps it light.
    - If it does, it goes HEAVY, with a teardown guard.
  - The 3 leakers and the 7 explicit-`daemon start` binaries are the decision set.
  - Measure the Phase-B duration delta for every binary that goes HEAVY before landing.
- **Detector widening (lands in the SAME lane, so it reds on anything left unclassified).** `spawns_daemon_tree` becomes today's literals, OR `"daemon", "start"`, OR (`CARGO_BIN_EXE_spt` AND a string-array verb head in {`api`, `serve`, `fetch`, `seal mint`, `seal enroll-authenticator`, `endpoint digest`, `subnet create`, `subnet join`, `shell drive`, `shell tunnel`}).
  - It EXEMPTS a binary that calls `serve_seed_control(` or pre-writes the inhibit, and each exemption gets its own negative-control unit test.
  - Negative control for the widening, kept as a unit in `heavy_integration_tests`: `busy_window_axis_e2e` at `89fd4412` reads False under the current rule and TRUE under the widened one (static port), and golden.yml at `89fd4412` lists it 0 times.
  - Conditional verbs are NOT statically decidable (the condition is runtime data); the measured arm above is their answer today.
- **Ripe when:** now. Two of the leakers are in the default suite, and every leaked tree holds `target/debug/spt` on Windows. **Size:** medium. It needs a per-binary read and decision for about 10 binaries, the detector change plus 3 units, and a Phase-B timing measurement.

"""
anchor = "### IR-155 — the brainproc supervisor tests'"
assert s.count(anchor) == 1
s = s.replace(anchor, ir156 + anchor)
out = s.replace('\n', '\r\n') if crlf else s
open(p, 'wb').write(out.encode('utf-8'))
print('ok crlf', crlf)
