# PUMP-FIX JIT — releases#188 + #189 (todlando build lane)

Dispatched by doyle via alchemy 2026-08-17/18 as the NAMEPLATE **fix-first product lane**
(operator ruling = releases#181 comment 5324415705). Both issues are WIP sub-issues of #181.
Base for everything below: **main @`27d40b9` (frozen)**. Worktree `.worktrees/pump-188`, branch
`fix/pump-cold-start-dial`. No pool claimed yet.

## Scope and constraints (binding, from doyle's brief)
- **Product changes ONLY.** The twohost int cells (#163/#169) are the acceptance probe and stay
  BYTE-UNTOUCHED. Test-side rework routes to hertz through doyle.
- Thin lanes off `27d40b9`. **TWO LANES approved** (#188 loop-liveness; #189 reply-read starve).
  Collapse only on measurement, announced before building.
- Worktrees under `.worktrees/` only. **doyle owns `nameplate-asm` + its warm pool — do not claim.**
- REQs first, then tag impl/unit in the same commit; `traceable-reqs check` before gate.
- Acceptance: doyle re-gates the lanes → reassembles the NAMEPLATE head → deployah intake → golden.
  `a8c3227` is dead.

## Grounded facts (measured, not inferred)
- **doyle's exoneration holds, audited:** `27d40b9..a8c3227` touches `pump/registry.rs` only inside
  `mod tests`; `nethost.rs`, `pump/`, `brain.rs`, `broker.rs` are zero-delta. The defects predate
  NAMEPLATE.
- **twohost-a job log (run 32097943571, job 95597031932) read first-hand.** 04:40:23.878 two
  `PUMP_IPC_READER: spawned`, never an `exited`. 04:40:23.893 `SELF_ADDR_REBIND` (registry
  pre_round ran). 04:40:23.914 ONE `PUMP_DIAL_SUBMIT … leg=cache … mono_ms=0`. Then NOTHING pump-side
  until the rig panic at 04:55:39. No `PUMP_PEER_FAIL`, no restart, no reader exit.
- **Therefore the pump LOOP is blocked, not merely starved of an outcome** — the drain loop is
  deadline-bounded (`round_start + PEER_REPLY_READ_BUDGET + ROUND_DRAIN_MARGIN`, pump/mod.rs:809),
  so a lost dial outcome would close the round at ~12s and the next round would print a SECOND
  submit line. One line in 900s says no round ever closed.
- **Three silent-block candidates, two eliminated by the log:** `submit_dial`'s ack read is bounded
  (30s) and its expiry would have printed `PEER_PUMP_FAIL` + a reader exit — absent, so not there;
  `read_frame_until`'s Whole-carrier arm ignores the deadline (brain.rs:2209) but both pump brains
  are `cold_start_pump`/Split — exonerated here, **filed separately as releases#190 (BACKLOG)** at
  doyle's ruling, NOT folded into this lane.
- **Surviving candidate = the drain loop's exit condition** (pump/mod.rs:810-825): it exits ONLY on
  `Err(TimedOut)`. Each iteration re-arms against the SAME absolute deadline, so once the deadline
  is past `remaining` is zero and `recv_timeout(ZERO)` still returns any ALREADY-QUEUED frame
  (brain.rs:2215-2217, deliberate). Non-presence frames `Skip` and continue; presence frames for a
  NON-target peer apply silently. So while frames keep arriving at all, the round never ends.
- **NOT yet proven: what feeds the carrier.** The obvious candidate is the failing rung's `rig_wait`
  probe (~10,611 brain conns / 900s ≈ 12/s on THIS side; B, unhammered, drained fine and fired its
  bound 172×). But brain IPC conns are LOCAL socket conns and the presence stream is NET presence
  (the only three producers are `append_connected` / `append_dial_failed` / the disconnect append in
  nethost.rs) — so the feed is NOT obviously those conns. **Measure it; do not assert it.**
- The pump writes a **per-tick heartbeat file** (`write_heartbeat`, pump/mod.rs ~658) — that file,
  not the log, is the field discriminator between "loop blocked" and "loop alive but never
  re-dialing". It produces no log line, which is why the job log cannot settle it.

## Rulings in force (doyle, 2026-08-18)
1. **Two lanes.** Collapse only on measurement, announced first.
2. **#189's re-dial arm is HELD.** Build #188 + #189's reply-read-starve arm now; when #188 lands,
   re-measure B against a healthy A **in the twohost rig inside my own lane gate** — that is the
   arbitration, not the golden run ("golden never arbitrates a hypothesis; a golden leg is a verdict
   on a head"). Both outcomes get **commented on #189 before further build**: heal ⇒ #189 shrinks to
   the reply-read arm (scope re-derivation is board-visible, never silent); still fail ⇒ build the
   arm on the measured mechanism.
3. **#188's title clause is to be re-derived, with probe numbers, in a comment on #188 BEFORE the
   fix is built.** If confirmed, "cold-start/cache leg" becomes *first observable instance* in the
   record and doyle's evidence comment stands as-is.
4. **Hermetic probe approved, negative control FIRST:** the same probe UNHAMMERED must go quiet and
   close rounds, so the instrument is proven able to show the healthy shape before the loaded arm is
   read.
5. brain.rs:2209 → releases#190, filed. Not this lane.

## PROBE RUN 2026-08-17 — DONE. Verdict commented on #188 (comment 5324576285)

Pool claimed: `target` for lane `pump-188` from `.worktrees/pump-188` (branch
`fix/pump-cold-start-dial`, base `27d40b9`). Probe:
`.worktrees/pump-188/crates/spt-daemon/tests/pump188_probe.rs` — UNTRACKED, every cell
`#[ignore]`d (instrument, not an acceptance cell). Run with
`cargo test -p spt-daemon --test pump188_probe -- --ignored --nocapture --test-threads=1`.
Real broker + real `cold_start_pump` carrier + real presence producers (peer `NetHost`s dialing
and closing); only the four-line loop at `pump/mod.rs:810-826` is replicated.

| arm | feed ev/s | per-event cost | closed | elapsed | max carrier gap |
|---|---|---|---|---|---|
| A control | 0 | 0 | yes | 12.0073s | 12.0073s |
| A control sweep-only | 0 | 0 | yes | 2.2µs | 2.1µs |
| B rig order | 9.3 | 0 | yes | 12.0128s | 648ms |
| C saturated | 77.3 | 0 | yes | 12.0076s | 133ms |
| D amplified | 10.0 in / 5.0 served | 200ms | **NO** | 60.10s (cap) | 201ms |

- **CONFIRMED:** the `pump/mod.rs:810-825` unboundedness is real and reproduces (arm D, 5× past
  its own deadline; the product loop has no cap).
- **REFUTED:** rate alone. The exit needs the queue empty at ONE poll after the deadline, not 12s
  of quiet. Wedge condition = **arrival rate > service rate**.
- **Title clause NOT carried.** The `~12 conns/s` is `role=brain` BROKER-IPC conns (`conn.rs:270`;
  10,790 over 923s = 11.7/s) and IPC conns are not presence producers (`PresenceLog` is appended
  only by `register_conn` / `append_dial_failed` / the disconnect watcher, `nethost.rs`). A
  blackholed cached address yields ONE `dial-failed`, and even 77/s cannot wedge a free consumer.
  Ruling 3's "if confirmed" branch does not fire; the split was reported instead.
- **NOT measured, named only:** what paid the service cost in round 1. Candidate = a leg entered
  from the CONNECTED arm (`handle_presence_event` → `run_peer_subnets`, `pump/mod.rs:984-998`,
  legs run INLINE inside the drain loop) where `read_peer_reply_until`'s deadline is deliberately
  re-armed on every arriving chunk (`sync.rs:415`, `propagate.rs:413`, `digestlink.rs:271`).

## HEARTBEAT RE-RUN 2026-08-18 — WEDGE DOES NOT REPRODUCE. #188 premise falsified.

Run 32108557362, branch `diag/pump-188-heartbeat`, workflow `pump188-diag` (two ladder jobs only;
golden NOT fired). Base a8c3227 — the failing rung does not exist at 27d40b9 (`git grep -c
"ER conjunction"`: none at 27d40b9, 4 at a8c3227) and the pump is byte-identical across the two.
doyle approved both shape decisions, no veto. Logs saved as `diag-a.log` / `diag-b.log`;
readout script `analyze.sh` (all readings pre-registered before the log existed).

**Role A — every pre-registered reading negative:** drain ENTER/EXIT 709/709 unmatched 0 · legs
registry/notif/sync/update ENTER−EXIT all 0 · heartbeat 170 ticks / 921s, zero gaps >10s ·
presence events applied across all 709 rounds = **3** · PUMP_PEER_FAIL 0 · PUMP_DIAL_SUBMIT 1
(mono_ms=19) · _CONNECTED 3, is_target=true · rounds close in 190–300ms · slowest leg sync 5162ms.

**The founding inference is falsified.** The RCA read "one PUMP_DIAL_SUBMIT in 900s ⇒ no round ever
closed". This run emits exactly ONE submit with 709 closed rounds underneath it: the dial connected
at mono 27ms, the conn cached in `conns`, and a peer with a live conn is never re-dialed. Silence
after the first submit is the HEALTHY path. The visible token set otherwise matches job 95597031932
exactly, so that set never distinguished wedged from healthy. (NOT a claim that the original run was
healthy — only that the cited evidence cannot carry the wedge claim.)

**Load reproduced, wedge did not:** 28,924 CONN_LIFECYCLE lines, 11,174 conns/921s = 12.13 conns/s
vs 11.7/s historical. But that is still the wrong wire — the TRUE carrier feed measures 3 presence
events / 709 rounds ≈ 0.003/s against the probe's ≥~5/s threshold. Three orders of magnitude off.

**Role B:** 955/956 rounds closed (the one unmatched ENTER is teardown truncation — opened at mono
962220 with pending=1, test panicked ~7s later). B is loud, not stalled: 164 submits, 170
PUMP_PEER_FAIL, 172 CONNECTED. Dial→address pairing:
`159 fbebd8fc cache 100.98.197.12:53860` · `1 bcead52b roster 192.168.1.81:7460` ·
`1 bcead52b cache 192.168.1.81:7460` · `1 bcead52b cache 100.68.35.65:7462`
(bcead52b = A, 9bbcee97 = B). 159 of 164 dials are cache-leg retries against a THIRD node that never
heal to the roster leg — #189-shaped, mechanism NOT measured, asserted nowhere.
⚠ My first read of B's SEPARATED histograms said "B dials its own IP for A" — WRONG. Pair target to
address; never read two histograms side by side.

**Consequence:** the rig reds at the same rung (twohost.rs:384, ER conjunction) in 921s — red
faithfully reproduced, but it is NOT a pump wedge on either side.

## READOUTS 2026-08-18 (doyle's 2a–2d + population guard) — commented on #188 (5324922765)

Logs in hand: `diag-a.log`/`diag-b.log` (run 32108557362), `twohost-a.log`/`golden-b.log`
(golden 32097943571 jobs 95597031932/95597031941). No new run.

- **(a) reply-read drop RECURS** — diag-B 2 (both peer A), diag-A 0, golden-B 1. With both pumps
  healthy ⇒ independent of any pump wedge. **#189's core event survives falsification.**
- **(b) first missing artifact NAMED.** B PASSED both ER arms (`A measured the withheld
  advertisement`, `engine-room whitelist now names A`). A is stuck on the sibling rung, predicate
  `registry.rows(subnet, ENGINE_ROOM_ID).any(|i| i.node == b_hex)`. ⇒ **B's engine-room row never
  reaches A's registry despite B's own whitelist arm going green.** B's later panic
  (`courtesy: A's plain knock reached B's inbox`) is DOWNSTREAM — A never gets to the knock step.
- **(c) B→A dials = 5, not 3** (my regex `leg=([a-z]+)` dropped `leg=failed-addr-skip-then-discovery`
  twice; 159+5=164 reconciles). Outcomes: 5 CONNECTED for A + 2 quic-connect 10s-bound + 2
  reply-read drops. ⚠ **Hypothesis KILLED mid-readout:** "B→A transport is down" — refuted by
  B running **3730 LEG_ENTER against A** (A: 2841 against B). Transport up BOTH ways.
- **(d) third node identified.** diag `fbebd8fc`@`100.98.197.12:53860` (159 dials); golden
  `fc60d519`@`100.98.197.12:60284` (155). Same IP = kitsubito's OWN tailscale addr, different hex +
  different ephemeral port per run. Rig uses the CANONICAL home (`canonical_pump_paths` →
  `perch::spt_home()`), so B's roster is kitsubito's LIVE fleet roster — a short-lived local
  endpoint re-minting identity between runs. Environmental, in both runs, not rig state.
- **(guard) golden B paired: 2 dials to A, not 164.** The 164 is golden-B's PUMP_PEER_FAIL count —
  a different population from submits, mostly the third node. doyle corrects #189's evidence.

**HUNT NOW LOCALISES TO:** what the advertise/disclosure path puts ON THE WIRE for an ER-scoped row
(DISCOVER-gate / NAMEPLATE access code) — NOT the pump, NOT reachability. Region named only; no
mechanism measured or asserted there.

## CODE-READ 2026-08-18 (doyle's suspects a+b) — NEITHER READ ALONE EXPLAINS withheld-for-A

Read at a8c3227 (the sha that ran). What it RULES OUT:
- **Fixture is correct and knew the trap.** `seed_nameplate_fixtures` (twohost.rs ~713) seeds B's
  EngineRoom with `advertise_to` EMPTY, writes the ER perch, then `info::set_controlled(&er_perch,
  true)` — comment: *"Posture ONLINE: without a controller at the controls the row is withheld by
  the POSTURE, and the whitelist arm below would prove nothing — posture beats whitelist"*. The
  earned-positive arm (twohost.rs ~1308) does `load() → advertise_to.push(a_hex) → save()`. Both
  halves persist. "Rig forgot the controller" and "rig never saved the whitelist" are both DEAD.
- **⚠ HYPOTHESIS KILLED:** `DiscoverGate` snapshots BOTH the ER record and the posture at
  construction (`access.rs` ~585), and `RegistryWorker` holds `discover: Option<DiscoverGate>`
  across rounds — a lazy once-only init would pin the pre-flip EMPTY whitelist and explain the gap
  exactly. **Refuted at `pump/registry.rs:271`** — `self.discover = Some(DiscoverGate::load())` is
  assigned UNCONDITIONALLY in `pre_round`. Fresh every round.
- Suspect (a) `disclosable_lines` filters only on `gate.discloses(endpoint_id, viewer)`; suspect (b)
  the legacy allow-row shape is made MORE permissive by default-on. Neither narrows to withholding.

**WHAT SURVIVES (a decision INPUT, not a mechanism):** posture is DERIVED, not stored, and
fail-closed. `posture_now()` = `classify_posture(EngineRoom::load().is_some(), info.controlled` on
the ER perch`)`, unreadable perch ⇒ Offline. The gate re-reads it EVERY round, so anything that
rewrites/clears `controlled` on B's engine-room perch after seed flips disclosure off permanently
with **no log line anywhere** — same class as the terminal_normalize stamp. NOT measured, NOT
asserted; three other hops are live.

**PRE-REGISTERED CHAIN** (B: T1–T3, A: T4–T5), each logging the decision's INPUTS:
`T1 ER_MINT` registryhost.rs:509 (advertisable + posture + advertises_to_anyone + survived :526/:531)
· `T2 ER_GATE` access.rs `engine_room_discloses_to` (viewer, whitelisted, posture, verdict)
· `T3 ER_PUSH` `disclosable_lines` (subnet, viewer, ER line present?) · `T4 ER_RECV` A's feed-apply
seam (ER line for b_hex arrived?) · `T5 ER_APPLY` A post-reconcile (row exists?).
Readings fixed: T1 false ⇒ never minted · T1∧¬T2 ⇒ composed-not-disclosed (inputs say which) ·
T2∧¬T3 ⇒ disclosed-not-pushed · T3∧¬T4 ⇒ pushed-not-received · T4∧¬T5 ⇒ received-not-applied.
**Prediction to falsify: T1/T2 report posture=Offline on B.**

Also live (doyle ruling 3): the rung's predicate is a claim too — it waits on a ROW in A's registry.
If the contract only promised DISCLOSURE, the mechanism is test-side and his operator caveat fires.
Read REQ-ACL-DISCOVER-GATE's amended wording against T4/T5 before calling that.

## CHAIN FIRED 2026-08-18 — run 32111921251, `diag/pump-188-heartbeat` @ `f3d40f1`

doyle's go arrived on the perch ("Fire."), with the T2 triple agreed as the primary reading and
one thing he carries himself: **if the external writer convicts, the DISPOSITION forks** (rig-design
defect: synthetic controlled-without-session perch on a canonical home · product defect: reconciler
clears a field it cannot know is synthetic · contract question) — **that classification is his with
the board, not mine.** I bring the **flip window** and, only if the box yields it, the **writer's
identity** (kitsubito's own fleet-daemon log post-run may bound WHICH process wrote; SECONDARY —
never block the run on it).

Built on `a8c3227`+`fe5febd`, `cargo check -p spt-daemon --tests` clean with zero warnings before
push. Tokens (all `PUMP188_DIAG_*`, product code, diag branch only, no REQ minted, twohost cells
byte-untouched):

| token | site | inputs printed |
|---|---|---|
| `T1_ER_MINT` | `registryhost.rs` :509 | advertisable · posture · provisioned · anyone · whitelist · **info_read** · **raw controlled** · **ER-perch info.json mtime** · perch |
| `T1B_ER_SCAN` | after :526 | on_disk · survived · live_ids (separates never-minted from minted-then-filtered) |
| `T2_ER_GATE` | `access.rs` `engine_room_discloses_to` | viewer · **posture (the load()-SNAPSHOT, i.e. what the round held)** · whitelisted · verdict · whitelist |
| `T3_ER_PUSH` | `pump/registry.rs` `disclosable_lines` | subnet · viewer · in_adverts (T1 one hop on) · pushed (T2 applied) · adverts |
| `T4_ER_RECV` | `dispatch.rs` `commit_feed_batch` | origin · subnet · node · status · epoch |
| `T5_ER_APPLY` | same, post-`apply_feed_batch` | `registry.rows(subnet, ENGINE_ROOM_ID)` count + nodes · merged (fires only when T4 saw a line) |

`info_read` is split from `controlled` deliberately: posture is fail-closed, so an unreadable perch
reads exactly like an uncontrolled one and the derived verdict alone cannot tell them apart.

### PREDICATE CALL — settled while the chain built: **PRODUCT-SIDE**
Full write-up: `<scratchpad>/predicate-call.md`. Sent to doyle.
- doyle's own int-activation comment on `REQ-ACL-ER-DISCOVER-CONJUNCTION-NOTICE` scopes int to the
  **enforcement half**: *"empty whitelist discloses nothing cross-node + whitelist add starts
  disclosing on the same rule."* The A-side rung (twohost.rs ~2234 and ~2263) is **exactly those two
  clauses in that order**, earned-negative arm included. Not an over-read.
- Both clauses are about what a VIEWER holds, and the only cross-node artifact of an advertisement
  is a registry row at the viewer — the same structure clause 1 reads for its negative. A test-side
  escape needs clause 2 satisfiable without a row, which makes clause 1 unfalsifiable too.
- **The #180/#181 amendment cannot rescue the withheld side:** DISCOVER default-on widens the access
  CHAIN; the ER filter runs BEFORE the chain (`discloses()` returns false first) and only ever
  WITHHOLDS. Nothing upstream of it changes.
- **Surviving caveat, NOT a test-side escape:** `REQ-ER-NOT-ADVERTISED` is filter-local at every
  stage it activates (doc/impl/unit, no int). T1∧T2∧T3 all TRUE with A still not receiving ⇒ the
  defect is downstream of the ER contract (replication, not disclosure) — that moves which REQ owns
  it, not whether the rung is legitimate. The ONLY test-side reading is one where B is CORRECT to
  withhold, which is exactly what T1's separated inputs decide.

## CHAIN READOUT 2026-08-18 — CONVICTS AT T1. Commented on #188 (5325298796), sent to doyle.

Run 32111921251 @ `f3d40f1`. Logs `chain-a.log` / `chain-b.log`, script `analyze-chain.sh`, both in
the scratchpad. **Pre-registered fork that fired: `T1 false ⇒ never minted`. doyle's prediction
(posture=Offline on B) CONFIRMED.**

| token | side | reading |
|---|---|---|
| T1 | B | `advertisable=false` in **949/949** rounds. Never once true. |
| T1b | B | 949/949 `on_disk=true survived=false` — row never enters the scan. |
| T2 | both | **0 emissions.** No ER row in adverts ⇒ the gate is never asked. T1 explains the hole; it is not a missing measurement. |
| T3 | B | 1102, **all** `in_adverts=false pushed=false` (viewers A `bcead52b…` 933, `1b5ff7b0…` 169). |
| T4 / T5 | A | **0 / 0.** Nothing ever reaches A's feed-apply seam. |
| T1 (A) | A | 845/845 `provisioned=false info_read=false controlled=None` — free negative control: a false at T1 has a *different* input signature when there is simply no ER. |

### THE FINDING: the two preconditions were NEVER SIMULTANEOUSLY TRUE

| n | posture | whitelist | controlled | window (wall_ms) |
|---|---|---|---|---|
| 11 | **Online** | **empty** | `Some(true)` | 1787038598064 – 1787038604798 |
| 30 | Offline | empty | `Some(false)` | 1787038615137 – 1787038665185 |
| 908 | Offline | **names A** | `Some(false)` | 1787038665894 – 1787039557710 |

Posture beats whitelist ⇒ `engine_room_advertisable()` false in every round. **The disclosure never
had a window to happen in;** the rung's red is the honest consequence, not a downstream fault.

**Flip window pinned:** info.json mtime `1787038598059` (fixture seed) → **`1787038610067`**,
`controlled` true→false, bracketed by last-true `1787038604798` / first-false `1787038615137`,
`info_read=true` on BOTH sides (a real rewrite, not the fail-closed unreadable path). **No log line
names the writer.** The whitelist add lands **55.2s AFTER** the flip (07:37:45.298).

### Hypotheses KILLED (both would have misdirected the disposition)
1. **B-2 severed-controller reap is NOT the writer** — refuted by 55s (its rung 07:37:45.297, flip
   07:36:50.067).
2. **No external fleet daemon** — the ER perch resolves under a RUN-SCOPED TEMP ROOT
   (`…/_temp/spt-test-tmp-32111921251-1-JscEST/.tmprcPTXH/owlery/engine-room`), not the canonical
   home, so nothing on the canonical home can see it. doyle's secondary errand is CLOSED, not open.

**NAMED, NOT MEASURED:** broker's no-session stamp convergence — `converge_perch_stamps`
(broker.rs ~1034) and `stamp_reaped` (broker.rs ~3069): both clear `controlled` for an endpoint with
no live session, both best-effort, both SILENT. The fixture stamps `controlled=true` with no session
behind it, deliberately and with a comment. Code read only — asserted nowhere.

### Open question filed against an existing record (doyle's to keep or correct)
#189's third-node reading rested on "the rig uses the CANONICAL home". The ER perch measured here is
under a per-run temp root, which puts that premise in tension. Perch path measured; nothing else
claimed.

## WRITER HUNT 2026-08-18 — doyle FIRED it; one candidate already dead from the log in hand

Run **32114194310** @ `c476f5b` in flight. `PUMP188_DIAG_ER_STAMP_WRITE` rides
`spt_store::info::set_controlled` ITSELF — the one site every writer passes through — with
`#[track_caller]` so the CALL SITE is printed, not this frame. No candidate privileged; a writer
nobody considered is caught the same as one that was.

**doyle's disposition pre-frame (his ruling, not mine to carry):** if the writer is broker stamp
convergence IMPLEMENTING decision 4's ruled no-session rule ⇒ product behaves as ruled, mechanism is
**FIXTURE-side** (a `controlled=true` faked without a session the product actively reconciles away),
his operator-return caveat fires, and any test fix routes to **hertz** per the dispatch split. If the
writer clears OUTSIDE its ruled scope ⇒ product defect, stays in my lane.

### ⚠ RETRACTED — `livehost.rs:821` **IS** the writer (named by run 32122237934; see the close-out below)
**The claim that stood here was wrong and is removed rather than annotated.** It read: that site is
LOUD (its `CONTROL_REAP_NO_SESSION:{id}: cleared stale controlled/driven_by/viewer_count (no broker
session)` print sits in the same divergence-gated `if` as the three `set_` calls), `chain-b.log`
contains ZERO of them, therefore a write from that site would have printed and did not.

**Why it failed, and it is the bound the claim itself carried:** the zero was over the TEST PROCESS's
stderr. The site fired from a SECOND `spt` process whose stderr is `Stdio::null()`, so its print could
never reach that log. Measured directly on the naming run — the site provably wrote, and
`CONTROL_REAP_NO_SESSION` count in that job log is still **0**. A refutation is only as wide as the
channel it was measured on.

Retracted on #188 (comment 5326579394), where the kill was published.

⚠ **SECOND correction to this same note.** It also said the silent per-session stampers named here
(`converge_perch_stamps` ~1034, `stamp_driven_by` ~3027, `stamp_reaped` ~3069) "stay unimplicated".
**Two of them do not.** hertz's red run implicates `converge_perch_stamps` and `stamp_driven_by` —
NOT as the clobberer, but as the **OPPOSING writer** (see the split-brain section below).
`stamp_reaped` ~3069 remains unimplicated.

## WRITER RUN 32114194310 LANDED — **THE HUNT INVERTS. No setter ever cleared the field.**

`ER_STAMP_WRITE` on the engine-room perch, whole run, both sides = **ONE line**:
`value=true caller=crates/spt-daemon/tests/twohost.rs:752:5 wall_ms=1787040148783` — the fixture's
own seed. **There is no `value=false` write anywhere.**

**Flip REPRODUCED independently (2nd run):** 8 rounds Online/whitelist-empty
(1787040279185–1787040284104), mtime `1787040279179` → **`1787040290522`**, `controlled`
`Some(true)` → `Some(false)`, then 932 Offline rounds (903 with the whitelist naming A).

⇒ **The field is not CLEARED by a setter — it is CLOBBERED by a whole-record write.** Corroborated
inside the same log: the Online-window record's mtime `1787040279179` is **130.4s after** the
fixture's `set_controlled` at `1787040148783`, so info.json was being rewritten repeatedly by
non-setter paths that PRESERVED `controlled=true` — and then one rewrite did not.

**PROBE BOUND (what makes the negative worth anything):** `ER_STAMP_WRITE`'s population is *calls to
`set_controlled`*, NOT *writes to the field*. Right instrument for the question as framed; blind to a
whole-record write, which is what the evidence now points at. Filter is `file_name()=="engine-room"`
on the perch dir — a writer reaching it under a different last component is invisible too.

**doyle's fork may need a THIRD branch (his call, flagged not ruled):** both branches he framed
describe a STAMP SITE clearing a field — one inside its ruled no-session scope (fixture-side), one
outside it (product-side). Neither describes *a whole-record write that fails to preserve the field*.
If that is the shape, "product behaving as ruled" has nothing to attach to, because no ruled clear
ran.

### NEXT TOKEN BUILT, HELD UNPUSHED (cargo check clean, 0 warnings)
`PUMP188_DIAG_ER_INFO_WRITE` on **`write_info_unlocked`** — the single funnel `write_info`,
`mutate_info` and `establish_locked` all end in, so no writer routes around it — with
`#[track_caller]` propagated through those three so the printed site is the real origin, not an
info.rs frame. Prints the `controlled` value being written beside the caller: **a preserving RMW
shows `true`, the clobberer shows `false`.** Bound: sees writes through spt-store only; a raw
filesystem write to info.json from elsewhere stays invisible, and that is the remaining explanation
if the funnel comes back clean.

## FUNNEL RUN IN FLIGHT — 32116338355 @ `4047240` (doyle FIRED it; writer readout on #188 5325594491)

Tokens shipped: `ER_INFO_WRITE` on `write_info_unlocked` **+ `ER_INFO_READ` on `read_info`** (both
engine-room-perch-only). The read half is an ADDITION I declared to doyle, not slipped in — his own
discriminator turns on it.

**doyle's two readings, and how the readout slots (his framing, named before the log exists):**
- **(a) COMPOSE defect** — the clobbering write's caller shows a read of the SAME record moments
  before, or **no read at all**: it BUILT the record instead of carrying one forward.
- **(b) LOST-UPDATE race** — that caller's last read PREDATES the last preserving write, so it writes
  back a stale snapshot. The mtime series brackets it; the read line dates it exactly.
- **(neither)** — funnel returns no `controlled=false` write ⇒ remaining mass goes to a **raw
  filesystem write outside spt-store**. Already named as the bound; it stays named, not a surprise.

**Rig-vs-product falls out of the CALLER** (doyle): product code ⇒ product-shaped; the test's own
frame ⇒ rig-shaped. I bring the name and the read/write pairing, **never the classification**.

## FUNNEL RUN 32116338355 LANDED — **doyle's split returns (neither).** #188 comment 5325861353

`ER_INFO_WRITE` (on `write_info_unlocked`) + `ER_INFO_READ` (on `read_info`), engine-room-perch-only.
Population guard: WRITE B=4 / A=0, READ B=4702 / A=0. **A is a free negative control** — 883 rounds of
`provisioned=false info_read=false controlled=None`, zero token lines: the perch filter does not fire
where there is no ER perch.

**The COMPLETE write census on B's ER perch, whole run — four lines** (all `pid=Numeric(916377)
state=ready_agent`):

| # | wall_ms | controlled | caller |
|---|---|---|---|
| 1 | 1787041664690 | false | `twohost.rs:736` fixture `write_info(InfoJson::new)` |
| 2 | 1787041664691 | false | `info.rs:601` `set_resources` RMW (pre-seed) |
| 3 | 1787041664692 | **true** | `twohost.rs:752` fixture `set_controlled` |
| 4 | 1787041799336 | **true** | `home.rs:270` `adopt_for_unset` home CAS — **PRESERVED** |

Write 4 is the one-shot home-subnet adoption: `home.rs:258`'s cheap pre-filter reads the record every
advertise cadence (939 reads) and `continue`s forever once `home_subnet` is set — which is why exactly
ONE write follows the seed.

**THE FLIP HAS NO FUNNEL LINE.** T1 saw exactly two mtimes all run: `Some(1787041799334)`
controlled=true, 10 rounds (1787041799341–1787041805185) → `Some(`**`1787041811073`**`)`
controlled=false, 929 rounds (1787041815480–1787042757496). The first IS funnel write 4 (the print
precedes the write; ext4's coarse timestamp clock sits a few ms behind it). The second matches **no
funnel write** — 11.737s after the last one.

Read-stream bracket (denser than T1's cadence): last true read **1787041805192** (`engineroom.rs:265`),
first false read **1787041815479** (`home.rs:258`). **Zero ER reads in 1787041810000–1787041812500** —
the write landed in a read-quiet window.

⇒ **(a) COMPOSE and (b) LOST-UPDATE die together.** Both describe a clobbering write's CALLER; the
funnel contains no clobbering write to anchor either on. Remaining mass = a write that does not route
through spt-store. Named as this probe's bound BEFORE the run — the pre-registered third branch, not a
surprise.

**PROBE BOUND (say it with the reading):** population = writes reaching `write_info_unlocked` **from a
process whose stderr reaches the job log**. The daemon runs IN the test process (`registryhost.rs:519`,
`engineroom.rs:265`, `home.rs:258/270`, `notif.rs:146` all print here) and the rig's ONLY subprocess
(`twohost.rs:2134`, the B-2 attacher child) inherits stdio — both covered. NOT covered: a raw
filesystem write bypassing spt-store, and any process whose stderr is piped away. Perch filter is
`file_name()=="engine-room"` — a writer reaching the record under a different last component is
invisible to both halves.

**Carried forward** (⚠ the first two were WRONG — both were zeros over the test process's stderr, and
run 32122237934's cross-process sink overturned both; kept only so the error is legible, do not reuse):
~~`livehost.rs:821` stays dead (0 `CONTROL_REAP_NO_SESSION` both sides)~~ — it is the writer ·
~~`set_controlled` census still ONE line all run~~ — the real census is TWO, the second being
`value=false caller=livehost.rs:821 exe=spt` · the flip reproduces across FIVE independent runs
(32111921251, 32114194310, 32116338355, 32119561081, 32122237934).

**FLAGGED, NOT ASSERTED:** the flip's mtime falls inside a stalled sync leg (`LEG_EXIT leg=sync
took_ms=10086 ok=false` ending 1787041815477 + `PUMP_PEER_FAIL` reply-read no progress) — the same
read-quiet window. One sample, no mechanism, and the stall explains the read gap on its own, so it
carries nothing against #189 either way. Logged only because doyle carries that issue.

**NEXT INSTRUMENT (proposed to doyle, NOT built, NOT pushed):** move the token DOWN to
`atomic_write_string_durable` — the last common point before the rename. A raw writer bypasses that
too, so a clean run there convicts a raw write POSITIVELY rather than by elimination. Alternative: a
filesystem watch on the perch dir for the run — sees every writer including raw ones, but names a pid
rather than a source line. A push to `diag/pump-188-**` FIRES the workflow, so it waits on doyle's word.

Logs `funnel-a.log` / `funnel-b.log` + pre-registered `analyze-funnel.sh` in
`<scratchpad-4f0ff324>`. Source read for the caller pre-placement was done at `4047240` (the sha that
ran), before the log existed.

## RAW-WRITER CODE READ 2026-08-18 (doyle's STEP 1) — **raw population EMPTY.** #188 comment 5325928946

doyle ruled: enumerate the raw-writer population by code read BEFORE any push; unique live candidate ⇒
one targeted token, inconclusive ⇒ build both step-2 shapes in ONE run. Read done at `4047240`.

1. **Product-side raw `info.json` rewriters: ZERO.** Every `fs::write` touching info.json is inside
   `#[cfg(test)]` (activity:358, shellhost:1306/1520, shellwake:1091/1214, registryhost:2311,
   perch:1022/1029/1052/1149/1151, perchgc:744, liveness:316/338, livehost:2320). The ONE product raw
   op is `livehost.rs:1138` `remove_file(psyche_perch/info.json)` — scoped to `<id>-psyche`, DELETES
   rather than rewrites, and a delete yields `info_read=false`. Measurement says `info_read=true
   controlled=Some(false)`. **Refuted, not merely improbable.**
2. **The rig holds no raw perch-record path.** twohost.rs's raw writes: digest.log, idle sentinel,
   release-keys.json, adapter manifest.toml, mind files, sid/sid2.txt, done marker. `seed_perch` (:543),
   gateway seed (:659) and the ER seed (:746) ALL go through `info::write_info` — which is why all
   three printed in the census. twohost.rs declares no `mod`; there is no support module.
3. **No wholesale perch-dir rewriter reaches a live perch.** `copy_dir_all` = adapter registry only
   (spt-runtime/registry.rs:277); the `remove_dir_all` family are reaps (perchgc:329, worker_reap:121,
   ring:317, shellinfo:409, reporting:367, cli:5084); `rename.rs:140` re-writes THROUGH `write_info`.
4. ⇒ **WHAT SURVIVES IS STRUCTURAL:** the daemon spawns children with **stderr `Stdio::null()`** at
   every product site — shellhost:494-496/641-642/649-650, shellwake:283-285, daemon:869-871 + the
   default arm of `detached_no_inherit_env` at daemon:1864, service:213-214 (cfg(test) starts at
   shellhost 980, shellwake 925, daemon 2287, service 338, so all product). **A FUNNEL write from a
   daemon-spawned child is invisible to the job log BY CONSTRUCTION** — no bypass of spt-store needed.

⚠ **SELF-CORRECTION, already on the board:** the `atomic_write_string_durable` token I proposed (and
doyle adopted) **cannot see this population** — it prints to the SAME stderr, which is null for exactly
the surviving writers. Offered before reading the spawn sites. Retracted in #188 5325928946.

**Instruments that CAN see it** (my ordering, doyle's call):
(a) **take the token OFF stderr** — append to a run-scoped FILE instead of `eprintln`; keeps the
`#[track_caller]` source line, survives `Stdio::null()`, and returns a NAME. First.
(b) **inotify perch-dir watch** — separates `CREATE`+`MOVED_TO` (store-shaped atomic rename) from bare
`MODIFY` (raw in-place), adds a pid; corroborating arm, names a pid not a source line.

**CANDIDATE NAMED, NOT CONFIRMED** (⇒ read is INCONCLUSIVE on uniqueness ⇒ instrument is owed):
`establish_locked` at `spt/src/api/startup.rs:769` — the ONLY `establish_locked` caller in the
workspace, and it lives in the **`spt` BINARY crate**, not spt-daemon, so it is unreachable from the
in-process daemon and its writes could never have appeared in this log. Its `build` closure composes
`InfoJson::new` (hardcodes `controlled: false`) and carries an EXPLICIT allowlist — `controllable`,
`cwd`, `read_env`, `rest_state`, `dormant_since_ms`, `state`, home/adapter — **`controlled` is not in
it**. The rig puts that binary in play: `seed_notify_shell` (twohost.rs:570-604) passes the spt binary
as `--spt <path>` to the notify shell. AGAINST: no invocation found targeting the engine-room id, and
`spt/src/api/engineroom.rs:152` `reserved_bind_refusal` refuses a bind of the reserved id unless
`engine_room_hosted()`.

**⚠ REFUTATION SCOPE WITHDRAWN:** my 55s kill of the B-2 severed-controller reap was computed on run
32111921251's ordering and does NOT transfer. In 32116338355 the rung sits on the OTHER side of the
flip: `B-2 ticker session 2 ready` 08:30:04.346 → `B-2: the attacher child's control stamps landed`
08:30:04.847 → SIGKILL sever → flip mtime 08:30:11.073, **6.2s LATER**. Not reviving the hypothesis;
narrowing the refutation to the run it was measured on. (General shape: a refutation computed from one
run's rung ordering is a claim about THAT run, and a rig whose rungs move between runs voids it.)

## BOTH ARMS BUILT + FIRED 2026-08-18 — run **32119561081 @ `ba97a66`** (doyle ruled BOTH, my order)

doyle: "(a) is the answering arm, (b) corroborates" — inversion of his step-2 ordering accepted with the
reasoning, and he added that the stderr-null read **retroactively scopes every earlier "loud site
printed zero" refutation to the TEST PROCESS's population**, which the sink now closes wholesale.
`cargo check -p spt-daemon --tests` clean, ZERO warnings; twohost int cells byte-untouched (diff = 3
spt-store files + the workflow); no REQ minted.

**(a) ANSWERING ARM — new `crates/spt-store/src/pump188.rs`** (temporary, dies with the branch).
Sink path from `perch::spt_home()` — the root the child already resolves, no env plumbing. `O_APPEND`,
ONE `write_all` per line so cross-process lines interleave whole. Every line carries `proc_pid` + `exe`
BESIDE the existing `#[track_caller]` site. **All THREE tokens ride it** (`ER_STAMP_WRITE`,
`ER_INFO_WRITE`, `ER_INFO_READ`) per doyle's point that a child-process reap at a "loud" site is exactly
what the old zeros cannot exclude. stderr copy KEPT so the job log stays comparable with the 3 prior runs.

**(b) CORROBORATING ARM — mechanism CHANGED, flagged not substituted.** `inotifywait` is **not installed
on kitsubito**, no `fatrace` either (checked before building; a runner box is not mine to mutate for a
diagnostic). Built an in-process poller on the record's **INODE identity** instead — sharper than the
event name: `crate::atomic`'s durable write is tmp+rename ⇒ **replaces the inode**; a raw in-place write
**keeps** it. Emits only on change (one line per real write). ⚠ **Correction sent to doyle: inotify
reports NO pid** (needs fanotify + `FAN_REPORT_PID`/CAP_SYS_ADMIN, or fatrace) — so (b) was never going
to name a writer under any implementation. It reports SHAPE only; (a) is the sole naming arm.

**BOUND FOUND WHILE BUILDING, AND CLOSED:** `spt_home()` reads `SPT_HOME` with a platform-default
fallback, and the spawn layer documents children that LOSE it — `daemon.rs:2093-2094` ("SPT_HOME …
LOST — verified empirically") and `brainproc.rs:1119-1120` (`spawn_detached` rebuilds the Windows env
block and drops it). Such a child resolves the **canonical home**, writes a DIFFERENT engine-room perch,
and drops its sink OUTSIDE the sandbox — a sandbox-scoped dump would return a clean zero for exactly the
population the arm exists to catch. Workflow now dumps the canonical home too, **READ ONLY**, both boxes.
Second-order consequence for doyle to weigh: if that is the shape, the child was never writing the RIG's
perch at all.

**FREE NEGATIVE CONTROL:** role A holds no ER perch (883 rounds `provisioned=false`), so **A's sink dump
must come back EMPTY**. If it is not, the sink writes where the perch is untouched and the instrument is
wrong before any verdict is read off it.

**CANDIDATE 7 ERRAND (doyle's) — DONE, and it goes AGAINST the candidate.** `engine_room_hosted()` does
not key on provisioning: it cold-starts the brain and asks whether the broker hosts a live SESSION whose
endpoint is the engine room, failing closed if unreachable. B provisions an ER RECORD but never spawns an
ER session (only the drive session + B-2 ticker appear in B's log) ⇒ **gate CLOSED on B, bind refused**.
Independently `spt-msg/src/ready.rs:73` refuses the reserved id outright with no hosted-session escape,
killing the `ready.rs` composer too. Argued against on two seams; no bespoke instrumentation added — the
file-funnel line names `startup.rs:769` if it fires, as ruled.

## SINK RUN 32119561081 LANDED — **(neither) is CLOSED. The flip is ANOTHER PROCESS's `write_info_unlocked`.** #188 comment 5326279408

**GATE 1 PASSES.** Role A: `SINK_DUMP: 0 sink file(s)`, zero `ER_*` lines, searching sandbox AND
canonical `LOCALAPPDATA\spt-core`. The verdict below is not read off a mis-firing instrument.

### ⚠ ARM (a) RETURNED NO NAME — my instrument's fault, NOT an absence
B: ONE sink file, ONE line. Sink path is `spt_home()/pump188-diag.log` — **inside the rig's TempDir**.
The test process exited **09:23:37.873** (`error: test failed`, exit 101) and the TempDir drop removed
the tree — `info.json` AND the sink — **29 ms before the dump step ran** (dump printed 09:23:37.902).
The surviving line is the recreate: `ER_FSWATCH shape=removed prev_ino=1311215 wall_ms=1787045017873
proc_pid=1016677 exe=spt` — and `1787045017873` **IS** that exit instant. The emptiness reads "reaped
0.03 s before it was read". The property that let a child find the sink with no env plumbing (derive
it from the home the child already resolves) is exactly what put it in the reap path.

### ARM (b) CONVICTS POSITIVELY
**Flip reproduces a FOURTH time** (T1 on B, 939 rounds): 9 `Online`/`[]`/`Some(true)` @mtime
`1787044049387` → 30 `Offline`/`[]`/`Some(false)` + 900 `Offline`/names-A/`Some(false)`, both @mtime
**`1787044062853`**.

| # | shape | ino | len | record mtime | pairs with |
|---|---|---|---|---|---|
| 1 | `first-sight` | 1311135 | 170 | 1787043909990 | fixture seed |
| 2 | `rename-new-inode` | 1311128 | 194 | 1787044049387 | **funnel write 4**, `home.rs:270` CAS @…389 ✓ |
| 3 | `rename-new-inode` | **1311215** | 195 | **1787044062853** | **THE FLIP — no funnel line, 13.46 s after the CAS** |
| 4 | `removed` | – | – | – | teardown, `exe=spt` |

Write census in the test process again exactly four lines (`twohost.rs:736` · `info.rs:601`
`set_resources` RMW · `twohost.rs:752` `set_controlled(true)` · `home.rs:270` CAS **preserving**
true); `ER_STAMP_WRITE` again ONE line.

**The flip is `rename-new-inode` = tmp+rename = STORE-SHAPED**, and the ONLY
`atomic_write_string_durable` against a perch `info.json` in the workspace is **inside
`write_info_unlocked` itself** (diag branch: fn `info.rs:794`, token `:808`, durable write `:820` —
token INSIDE the fn, before the write; the only other atomic info.json write is `liveness.rs:316`,
`cfg(test)`). ⇒ **doyle's (neither) branch is CLOSED — not a raw write outside spt-store.** It is a
`write_info_unlocked` call with no token line in the test process ⇒ **another PROCESS's**. Conviction
THROUGH the rename, not by elimination — what the `atomic_write_string_durable` token was meant to
buy, obtained without the push.

### THE OTHER PROCESSES ARE NAMED (reap census, B, alive at job end)
`pid 1016658 target/debug/spt` · `pid 1016677 target/debug/spt` ·
`pid 1016942 .adapter-notify/target/debug/notify-shell` (test process `1016212`). The predicted
population is real: the notify shell spawned, and **two `spt` BINARY processes** ran with it.
**pid 1016677 provably touched the RIG's ER perch** — `watch_er_perch()` is called at exactly the
three ER-filtered token sites (`set_controlled` :639, `write_info_unlocked` :808, `read_info` :893),
so its watcher cannot exist unless it hit one, and it resolved the rig's home (it saw inode 1311215).

**NOT PROVEN:** which of 1016658/1016677 wrote the flip, from which caller, or whether 1016677 wrote
at all vs read. That line died with the tree. No classification offered — disposition is doyle's with
the board; a rig verdict routes to hertz.

**⚠ SELF-CORRECTION:** my earlier "zero `SHELL_*`/`WAKER_*` in funnel-b ⇒ B never spawned a shell" is
**WRONG** — the census proves notify-shell ran with two spt processes. Those sites emit nothing on the
success path. Third instance of the healthy-path-is-silent class in this hunt.

**REPAIR PROPOSED, NOT BUILT, NOT PUSHED:** move the sink off `spt_home()` onto
`std::env::temp_dir()`. The CI sandbox root reaches every process as `TMPDIR`/`TEMP`/`TMP`
(= `SPT_CI_TEST_TMP`), so a child resolves it with no plumbing — the exact property `spt_home()` was
picked for — while sitting one level ABOVE the rig's `TempDir`, outside the teardown that ate this
one. Arm (b) unchanged.

### Caller-placement machinery (built this lane, still in force)
`crates/spt` has **no lib target** and `spt-daemon` does not depend on it ⇒ a sink `caller=` under
`crates/spt/...` is a separate `spt` BINARY process **by construction**. `crates/spt-daemon/...` is
ambiguous (in-process daemon vs spawned `spt daemon run`) — place by `proc_pid`. Product funnel sites
in the binary crate: **`api/startup.rs:769`** (`establish_locked`, allowlist lacks `controlled`) and
**`cli.rs:4755`** (`resolve_home_and_write_skeleton`, `InfoJson::new` @:4734 — NEW, second
signature-compatible composer); `cli.rs:3734`, `auth.rs:200`, `reporting.rs:81` are preserving RMWs;
`worker.rs:91` composes onto a worker perch. `InfoJson::new` hardcodes `controlled: false`
(`info.rs:367`). `cli.rs` has INTERLEAVED `cfg(test)` blocks (2824/2998/3299/3528/4768/4812/4844/
22522) — a first-block line test misclassifies both composers. Full read:
`<scratchpad f0a4566c>/sink-coverage.md`; readout script `analyze-sink.sh`; logs `sink-a.log` /
`sink-b.log`.

## NAMING RUN FIRED 2026-08-18 — **32122237934 @ `b20e770`** (doyle: "REPAIR APPROVED — FIRE")

`sink_path()` = `std::env::temp_dir()` instead of `perch::spt_home()`. `cargo check -p spt-daemon
--tests` clean, ZERO warnings; two files (`pump188.rs` + the workflow's two dump steps); twohost int
cells byte-untouched; no REQ minted; no product behaviour changed. The env-loss population bound
MOVED with the path rather than being dropped — B also searches `/tmp` (`temp_dir()`'s fallback when
TMPDIR is unset), A the profile + Windows temp dirs **non-recursively**. The canonical-home arm is
RETIRED *and the retirement is written down*: the sink no longer resolves through `spt_home()`, so a
hit there could only be a stale file from an earlier run — which would read as evidence. Arm (b)
untouched.

### doyle's pre-registered fork for this readout (his framing, slot off `caller` + `pid`)
- caller lands in a **composer** (`startup.rs:769` / `cli.rs:4755`) ⇒ the skeleton shape already argued.
- caller lands in a **loop the in-process daemon ALSO runs** (`home.rs` adoption, any RMW) ⇒ a
  **cross-PROCESS lost update through the funnel** — a mechanism neither of us had framed, made
  live by the census fact that TWO `spt` binary processes ran beside the in-process daemon over the
  same temp-root home. Naming only; no new instrumentation.

### ⚠ NARROWING SENT TO DOYLE (a question, not a verdict) — the funnel already holds a CROSS-PROCESS lock
`lock_perch_sentinel` (`info.rs:778`) takes an **fs2 `lock_exclusive()` on a STABLE per-perch
`.info.lock` sentinel** — an advisory OS lock, so cross-process effective — and its comment names the
hazard: *"serialize ALL info.json writers so a whole-record write and a locked RMW can never lose each
other's update (`REQ-HAZARD-INFO-RMW-LOST-UPDATE`)"*. Constant inode deliberately, because info.json
is renamed every write. `mutate_info` (`:424-433`) orders it correctly — **lock FIRST**, then read,
mutate, `write_info_unlocked` still holding it. Both spt processes share that sentinel (same temp-root
perch; `ER_STAMP_WRITE` printed the path). So what survives his lost-update branch:
- **(a) COMPOSER — untouched by the lock.** A lock serializes writers; it cannot preserve a field the
  writer never read. Both composers clobber whether or not they hold it.
- **(b) LOCK-ORDERING DEFECT at a specific caller** (read outside the lock, then lock, then write the
  stale snapshot) — a real lost update, but it must be shown AT a caller, not assumed from the shape.
- **(c) different perch path ⇒ different sentinel** — NOT this case.
⇒ a caller landing in a shared RMW loop does **not** by itself establish a cross-process lost update;
it owes the lock ordering at that caller as a second step.

**doyle CONFIRMED the lock read** and added a fourth branch — a **LOCK-BYPASS caller** reaching
`write_info_unlocked` without the sentinel (the token sits inside, so it sees locked and unlocked
callers alike, and one bypasser voids serialization while every other caller's discipline reads
correct).

### ⚠ BYPASS BRANCH REFUTED BY CONSTRUCTION (code read at `b20e770`, the running sha)
`write_info_unlocked` is declared **`fn` at `info.rs:794` — not `pub`, not `pub(crate)`** ⇒ reachable
only from inside `info.rs`. Complete caller set is three sites, **all taking the sentinel first**:
`:426` `mutate_info` (lock→read→mutate→write :432) · `:842` `write_info` (lock→write :843) · `:860`
`establish_locked` (lock→read→build→write :865). Workspace grep for `info::write_info_unlocked` /
`super::write_info_unlocked`: **zero**. The `_unlocked` suffix is enforced by VISIBILITY, not trust.

### AND THAT COLLAPSES (b) INTO (a) — the useful form
Read-outside-lock cannot occur *inside* the funnel: both read-carrying entries read under the hold.
So a stale-snapshot write requires a caller that read the record itself, outside, then called the
**public `write_info`** — which takes the lock at `:842`, i.e. **after** the caller composed `info`.
The lock makes that write atomic; it cannot make it **preserving**.

> **EVERY caller of the public `write_info` is structurally unable to preserve a field it did not
> carry.** Only `mutate_info` / `establish_locked` can preserve, because only they read inside the
> hold.

Step 2 at the named caller therefore becomes:
- **caller used `write_info`** ⇒ mechanism settled by that fact alone (composer and stale-snapshot
  are the same defect wearing two names). Census write #1 (`twohost.rs:736`, `controlled=false`) is
  the existing example.
- **caller used `mutate_info` / `establish_locked`** ⇒ preserving by construction, so a clobber means
  the **BUILD** dropped the field (`establish_locked`'s allowlist) — the narrower composer read.

**Carried for the mint (doyle's, with the board):** the sentinel's comment claims it serializes "ALL
info.json writers so a whole-record write and a locked RMW can never lose each other's update" —
TRUE for interleaving, FALSE for preservation. Flagged as a candidate correction target; no mechanism
asserted, no wording proposed.

## NAMING RUN 32122237934 LANDED — **WRITER NAMED: `livehost.rs:821`, from a SECOND `spt` PROCESS.** #188 comment 5326579394

The relocated sink survived teardown and returned the census the previous run lost.

- **GATE 1 PASSES.** A: 0 sink files, 0 `ER_*` lines, sandbox + new TMP/TEMP fallbacks.
- **GATE 2.** B: **1 sink file, 5349 lines**, sandbox root depth 1; `/tmp` contributed nothing.
  Process split inside it: **4785 lines `proc_pid=1114464 exe=twohost-…`** (test process) and
  **564 lines `proc_pid=1114877 exe=spt`**. The invisible population was real and substantial.

### THE NAMING LINE
```
PUMP188_DIAG_ER_INFO_WRITE: controlled=false state=ready_agent pid=Numeric(1114464)
  caller=crates/spt-daemon/src/livehost.rs:821:21 wall_ms=1787045885015 proc_pid=1114877 exe=spt
```
`pid=Numeric(1114464)` = the RECORD's pid field; `proc_pid=1114877` = the WRITING process, a separate
`target/debug/spt`, `SCOPED`+`REAP`ed by the job-end census. Two more writes 7 ms later from the same
process (`info.rs:610`, `info.rs:668`) = the block's other two `set_` calls.

**`ER_STAMP_WRITE` is TWO lines now**, both on the rig's ER perch: `value=true twohost.rs:752`
(fixture, pid 1114464) and **`value=false livehost.rs:821` (pid 1114877, `exe=spt`)**.
`set_controlled(false)` WAS called — three runs of "ONE `set_controlled` all run" were a zero scoped
to the test process's stderr.

**Flip, fifth reproduction.** T1: 9 rounds `Online`/`[]`/`Some(true)` @mtime `1787045873358` →
39+906 `Offline`/`Some(false)` @mtime **`1787045885022`**. Inode `1311128`→`1311214`,
`rename-new-inode`, reported by **both** watchers (test process wall …025, `spt` child wall …033);
the child's `first-sight ino=1311128` at wall …008 is its watcher starting 7 ms before its own write.

### STEP 2 — the caller's funnel entry (the pre-registered reading)
`livehost.rs:819-826` is the control-stamp reconcile —
`if !has_session && (info.controlled || driven_by.is_some() || viewer_count.is_some())` → three
`set_` calls → the `CONTROL_REAP_NO_SESSION` print. Tagged `[impl->REQ-ENDPOINT-ONLINE-TRUTH]`,
`[impl->REQ-CONTROL-STAMP-CONVERGENCE]`, `[impl->REQ-PRESENCE-CONTROL-REAP-ON-EXIT]` (ADR-0041
decisions 2 + 4). `set_controlled` → `mutate_info` → **lock→read→mutate→write**, a read-under-hold
entry ⇒ **NOT a composer · NOT a lost update · allowlist question does not arise.** It **cleared the
field on purpose.** Mechanism = the ruled no-session control reap, in a second process, erasing a
`controlled=true` the fixture stamps with no broker session behind it.

### THE SITE'S OWN PRINT IS STILL INVISIBLE — measured, not argued
`CONTROL_REAP_NO_SESSION` count in the job log where the site provably fired: **0**. The write is
loud; its stderr is null. The structural claim from the raw-writer code read, measured directly.

### What this closes
doyle's (a) COMPOSE · (b) LOST-UPDATE · (neither)/raw-write · his cross-process lost-update branch ·
the lock-bypass branch (refuted by construction) — **all dead.** What survives is a named product
site behaving as ruled, in a process the job log could never see.

**Disposition is doyle's with the board** (his pre-frame: a writer inside decision 4's ruled scope ⇒
fixture-side mechanism, operator-return caveat fires, test fix routes to **hertz**). I brought the
name, the entry, and the retraction — no classification, no fix.

**Inference, flagged as inference:** the caller is `spt-daemon` code running inside the `spt` BINARY
and the reconcile is documented as running "from boot tick 1" ⇒ consistent with a real spawned daemon
(`daemon.rs:861/871`, stderr null, `SPT_HOME` inherited by documented design). No spawn line observed;
read off the crate+exe pairing.

**Repair grounding (verified, worth keeping):** `TestHome` (`spt-test-support/src/lib.rs:44`) sets
**only `SPT_HOME`**; its doc states the workflow sandbox "exclusively controls `TEMP`/`TMP`/`TMPDIR`
so subprocess scratch paths cannot escape its kill-safe cleanup boundary", and the unit at :98-111
asserts those three vars unchanged. So `env::temp_dir()` = the sandbox root, and the rig's `TempDir`
is a **sibling** of the sink, not its parent.

## DISPOSITION RULED 2026-08-18 — RCA CLOSED. **STAND DOWN; the lane holds.**

doyle countersigned the naming readout (#188 comment **5326598499**), forked to the operator on #181
(**5326601528**), and the **operator RULED test-fix-first in session** (record **5332715107**).
Board already executed:

| issue | outcome |
|---|---|
| **#188** | **CUT — not a product defect.** The fixture-side split fired exactly as pre-framed: the writer sits inside decision 4's ruled scope, clears under the lock, product behaved as ruled. Mechanism = the fixture faking `controlled`-without-session. |
| **#189** | detached → **EVAL** |
| **#191** | minted (BUGFIX, EVAL) — daemon autostart binds a home already hosted by a live daemon; split-brain control reap |
| **#192** | minted (CHANGE, EVAL) — daemon-spawned children unobservable; every ruled loud print dies in `Stdio::null()` |

**hertz is cleared BY doyle's DISPATCH** (sent to him directly, confirmed to me first-hand — not a
relay): fixture fix giving the ER perch a **real session**, cells byte-identical as spec, **validate
on the diag instrument FIRST**, then a test-only thin lane off `main @27d40b9`. Runner spend for his
validation runs is authorized under that dispatch. He branched `diag/pump-188-honest-er-session` off
`b20e770` (+23 lines spawning a real `ENGINE_ROOM_ID` session in B's existing rig broker) and fired;
I confirmed both boxes clear.

**MY STANDING ORDER: hold `.worktrees/pump-188` + the diag branch + its workflow until hertz's fix
validates. Then both die with the RCA.** Nothing pushed since `b20e770`; nothing to push.

### ⚠ CORRECTION SENT AGAINST #191's EVIDENCE LINE (mine to file — it restates my measurements)
1. **"5/5 reproductions" is WRONG for the WRITER.** The *flip* reproduces 5/5. The *writer* was named
   in **1** run — the only one whose cross-process sink survived (runs 1–3 had no sink; run 4's was
   reaped 29 ms before the dump). Four of the five never CONTAINED the measurement credited to them.
   Honest form is stronger: "flip 5/5; writer observable in exactly one run, named there, 1/1."
2. **The autostart route (`daemon.rs:861/871`) is my flagged INFERENCE**, not measured — no spawn line
   observed; it is read off the crate+exe pairing. Measured is narrower: a second process with
   `exe=spt` executed spt-daemon code at `livehost.rs:821` against the rig's home.
3. **"each daemon reaps stamps belonging to sessions live on the OTHER daemon" is NOT measured** and
   is in tension with the ruled disposition — in this rig the cleared stamp had **no session behind it
   on either side**, which is exactly the fixture-side finding. Split-brain is the production question
   the shape RAISES, not something the rig showed. Worth EVAL as a hypothesis; fatal to the issue if
   an evaluator checks it as measured.

**#192 audited and STANDS** — spawn-site list matches, brain `stderrlog`-before-anything is right, and
the headline (`CONTROL_REAP_NO_SESSION` = **0** in the job log on the run the site provably fired) is
exactly what I measured.

### Knowledge boundary, flagged
I do not hold doyle's *original* stand-down message in this context (session cleared 2026-08-18; only
two of his messages spilled to files I read). The instruction is unambiguous as restated and I am
honouring it — recorded so no one assumes I received the first one.

### Pass condition handed to hertz (T1 shows it directly)
"The flip stops" is NOT sufficient. The A-side rung waits on a ROW at A, and B advertises only when
`engine_room_advertisable()` sees **posture=Online AND the whitelist naming A in the SAME round**.
Measured: 9 rounds Online with an EMPTY whitelist, then Offline for ~940 rounds — and the whitelist
add lands **after** the flip (55.2 s in one run, 13.5 s in another). Posture must still be Online when
the whitelist add lands. Green signal: `T1_ER_MINT` with `posture=Online` **and** a non-empty whitelist
on the same line, then **`T2_ER_GATE` emitting at all** — T2 was **0 emissions in every run so far**,
because with no ER row in adverts the gate is never asked.

## HERTZ'S FIX VALIDATED — and his RED arm MEASURES #191's split-brain

**Green:** run **32177198934** GREEN both roles, after changing B's rig broker to `broker_socket_name`
so the CLI rungs share session truth. Ruled chain lane **`build/nameplate-w6-honest-er` @ `8c41f1d`**
on `f967208`, handed to doyle. My pass criteria (T1 conjunction + T2 emitting at all) were what he
read it against.

### His RED arm is the discriminator my five runs lacked
Run **32174970789 @ `fc9be81`, job 95834656729** (branch off my `b20e770`, so the instrument rode it).
ER session on a CUSTOM broker ⇒ the canonical second daemon reaped `controlled` anyway. Read
first-hand from the sink, not taken on report:

| writer | value | process | count |
|---|---|---|---|
| `livehost.rs:821` | **false** | `proc_pid=1239267 exe=spt` | **16** |
| `broker.rs:1034` `converge_perch_stamps` | **true** | `proc_pid=1238808` (test proc) | **15** |

Window `1787080412018 → 1787080487316` = **75.3 s, ~5 s cadence, one perch, two session tables.**
`converge_perch_stamps` (fn at `broker.rs:1002`) writes `set_controlled(&perch, want_controlled)`
**only on `stamp_divergence`** ⇒ its true-writes are that broker re-asserting its OWN session truth,
i.e. evidence a session genuinely exists there. Each burst is exactly THREE writes (`:821`
`set_controlled`, then `info.rs:610` / `:668` — the block's other two `set_` calls), 16 apiece.

**Why this is the second reading and my runs could not reach it:** in all five of mine the stamp was
SYNTHETIC — no session on either side — so a clear was the ruled, correct behaviour. Here a session
demonstrably exists and is reaped 16 times anyway.

**Scope, stated with it:** the broker divergence is **RIG-CONSTRUCTED** (hertz's custom broker socket,
which is precisely what he then fixed). This measures the MECHANISM, not a naturally-arising
production split — #191's real question (boot race, discovery miss) stays open. Amendment handed to
doyle; **the board edit is his**, since he wrote that line and rewrote it on my correction.

### ⚠ THE NULL-STDERR TRAP CAUGHT A PEER, MEASURED
hertz first reported he could find no sink line whose write caller resolved to `:821`. Attribution is
in fact DIRECT in both tokens, **16/16**. Occurrences of `livehost.rs:821` in that job log OUTSIDE the
sink-dump region: **0 of 47,958 lines** — the writer is a `Stdio::null()` child, so grepping the job
log returns a confident zero on the run where the site fired 16 times. Exactly the reading that made
me publish a wrong refutation of `:821`, and exactly what **#192** is minted about. hertz recorded the
fix: **anchor at `--- PUMP188_DIAG sink:` and search DOWNWARD**, never the whole log. (His zero also
had a second cause he named: his tool's first-4MB search window never reached the end-of-job dump.)

## Immediate next steps
0. **DONE — RCA closed; disposition ruled; lane HELD; hertz's fix GREEN and his red arm filed to
   doyle as #191 evidence.** Await doyle's board edit + the retirement word, then retire the diag
   branch, its workflow, `.worktrees/pump-188` and `.worktrees/pump-188-diag` with the RCA.
   Previous step, for the record: await hertz's validation result, then retire
   the diag branch + workflow + `.worktrees/pump-188` and `.worktrees/pump-188-diag` with the RCA.
   Previous step, for the record: run 32122237934 read; writer NAMED, reported to doyle + #188
   (5326579394). Hold for
   doyle's disposition; the diag branch and workflow stay (they die when the RCA closes, not before).
   Previous step, for the record: (i) A's sink dump EMPTY —
   instrument gate, else stop; (ii) sink file count, sandbox vs `/tmp`; (iii) the sink's
   `ER_INFO_WRITE … controlled=false` → `caller=` + `proc_pid=` + `exe=` — **this is the naming
   line**, and `crates/spt/...` places it as a child by construction; (iv) `ER_FSWATCH shape=` at the
   flip mtime. Then slot into doyle's fork above, honouring the lock narrowing. Report either
   polarity to doyle + #188. Still no classification, still no fix.
   Previous step, for the record:
   **DONE — run 32119561081 read; (neither) CLOSED, reported to doyle + #188 (5326279408).** Order was:
   (i) A's sink dump EMPTY — else the
   instrument is wrong, stop and say so; (ii) `PUMP188_DIAG_SINK_DUMP: N sink file(s)` — how many roots
   answered, sandbox vs canonical home; (iii) grep the sink for `ER_INFO_WRITE … controlled=false` and
   take its `caller=` + `proc_pid=` + `exe=`; (iv) `ER_FSWATCH` `shape=` at the flip mtime —
   `rename-new-inode` = store-shaped, `in-place-same-inode` = raw. Report either polarity to doyle + #188.
   **Still no classification and no fix — disposition is doyle's with the board; a rig verdict routes to
   hertz.**
1. **DONE — run 32116338355 read, (neither) reported to doyle + #188 (5325861353).** Held for doyle's
   word on the next instrument; do not push to the diag branch without it (a push fires the workflow).
   Previous step, for the record:
   **Read run 32116338355 when it lands.** `gh run view --job <id> --log` both jobs into the
   scratchpad, then: `grep ER_INFO_WRITE` for the `controlled=false` line nearest the flip, take its
   `caller=`, then `grep ER_INFO_READ` for that caller's last read BEFORE that write. Report to doyle
   AND #188, either polarity. Do **not** propose a fix — classification is doyle's, and a rig verdict
   routes to hertz.
   Previous step, for the record:
   read `PUMP188_DIAG_ER_STAMP_WRITE` for the `value=false` write nearest the flip window, name the
   `caller=` site, report to doyle + #188 either polarity. Do **not** propose a fix — the
   fixture-vs-product classification is doyle's, and a fixture verdict routes to hertz, not to me.
   Original token build note (kept for the record): `PUMP188_DIAG_ER_STAMP_WRITE` on
   `spt_store::info::set_controlled` itself — the ONE site every writer passes through — with
   `#[track_caller]` so the CALL SITE is named rather than guessed, filtered to the engine-room perch
   so the one write is not buried under every hosted endpoint's stamps. **Do not push without
   doyle's word: a push to `diag/pump-188-**` FIRES the workflow, which is a runner decision.**
   It names which of doyle's three fork branches this is.
2. Disposition is **doyle's with the board** — rig-design defect (synthetic
   controlled-without-session perch) vs product defect (a reconciler clearing a field it cannot know
   is synthetic) vs contract question. I bring the window and the refutations, not the ruling.
3. Predicate call stands (PRODUCT-SIDE, above); doyle countersigns against the REQ text now that the
   readout has landed.
2. Disposition of #188 + title edit stay doyle's with the board.
3. **KEEP `diag/pump-188-heartbeat` + its workflow** (doyle ruling 1 — it is the proven instrument;
   dies when the RCA closes, not before). Confinement verified.
4. REQs stay unminted until a mechanism survives measurement. — shape sketched and doyle-accepted as *a round deadline
   the drain loop cannot outlast (exit on deadline-passed, not on queue-empty)* plus *arming the
   bound around the permit wait* (`sem.acquire_owned()` sits OUTSIDE the `tokio::time::timeout` in
   `NetHost::submit_dial`, nethost.rs:1616-1628 — a dial that never gets a permit yields no result
   and no bound-exceeded line).
4. #189's reply-read-starve arm builds on its own evidence (B-side, fired during the advert barrier).
5. Report to doyle at the probe verdict, or anything that breaks the two-lane shape.

## Peer/report protocol
doyle gates; report at measurement, not at intention. Progress comments on #188/#189 as work lands.
Evidence log saved at `<scratchpad>/twohost-a.log` (30,360 lines, run 32097943571 job 95597031932).
