---
name: breadcrumb-pid-tree-kill-hazard
description: "⭐⭐ 19 test files tree-kill a pid read from daemon.pid, whose OWN doc comment says a stale value is safe because nobody acts on it — one test can silently terminate a sibling test's process (exit 1, no panic)"
metadata: 
  node_type: memory
  type: project
  originSessionId: b92eeee4-bbf1-4d22-b02f-a83d4e68fe0a
  modified: 2026-07-30T00:33:11.341Z
---

**Found 2026-07-30 (todlando, from source, during the milestone-A golden run).** Under nextest every
test is its own process, so one test's `reap_daemon` hitting a REUSED pid terminates a **sibling
test's** process — silently, in a test that did nothing wrong.

✅ **COUNT RECONCILED 2026-07-30 ~00:32Z — final numbers below; the dispute is CLOSED.**
- **`daemon.pid` tree-killers = 6, CONFIRMED TWICE** (hertz's narrow root + todlando's wider root,
  different predicates ⇒ independent corroboration): activity_link_push, contract, job_escape,
  ready_resume_ledger, worker_lifecycle, worker_visibility.
- **todlando's 19 is RETRACTED — mismeasurement.** `grep -rln 'read_to_string.*\(daemon\.pid\|\.pid\)'`
  had two defects: no `-E`, so `\(…\|…\)` was BRE grouping and `.pid` matched *any char* + "pid"
  (caught `rec.pid_started_at`, local vars, comment text); AND it was never INTERSECTED with the
  tree-kill set, so it answered "files that read something pid-ish" while being reported as "files
  that tree-kill a breadcrumb pid". Probe-competence's 6th appearance that day.
- ⭐⭐ **THE REAL WIDENING IS `brain.ready` — 26 files, ~4× the original class.** Same class of value
  by its own doc (`endpoint.rs:84-96`): brain child's pid, rewritten each heartbeat, *"Best-effort
  like the daemon pid breadcrumb"*. Flow: `wait_for_ready_pid(home.join("brain.ready"))` → `brain_pid`
  → `kill_pid` → `taskkill /F /T`. Kill-flow confirmed in 23 of 30; **7 flow-unconfirmed stay
  unconfirmed** (brain_respawn_rename, brain_split, endpoint_teardown_authority, n1_pairing,
  projindex_writer_e2e, ready_resume_ledger_e2e, twohost_cli).
- ⭐ **THE ASYMMETRY THAT INVERTS INTUITION (todlando):** a live brain REFRESHES `brain.ready` every
  heartbeat, so **a stale `brain.ready` means the brain is already dead — and killing a dead pid is
  precisely when reuse bites.** A heartbeat-refreshed breadcrumb FEELS safer than a write-once one
  and is actually MORE dangerous: staleness correlates with the target being gone, so **the
  dangerous case is the common case.**
- ⚖ **GRADED TIER RETIRES THE "TREE" FRAMING:** 18 files read `daemon.pid` and hand it to taskkill —
  6 with `/F /T`, **12 with `/F` alone** (drive_e2e.rs L306-312 confirmed). Under nextest a
  single-process kill of a reused pid still terminates a sibling silently with exit 1; it just cannot
  take a tree. **`/T` grades the BLAST RADIUS, it is not the defect — the defect is terminating on a
  pid you did not authenticate.** Hazard must read "any kill driven by a breadcrumb pid, tree or
  single", else the invariant looks satisfiable by dropping `/T` and 12 files sail through a guard
  aimed at the wrong noun.
- ✅ **Only ONE flake-registry entry is implicated, not two.** todlando was one step from reporting
  both and checked instead: `endpoint_lifecycle.rs` matched only `rec.pid_started_at` and a
  `resume.pid` inside a COMMENT (L795) — it joins no breadcrumb file. `activity_link_push` IS in the
  class (both scans, both breadcrumbs). ⭐ Catching a correction that would have FLATTERED his own
  thesis is the reason the rest of the report is takeable at face value.

**Superseded dispute record (kept for the lesson):** two independent scans first disagreed 3×:
- todlando: **42** files run `taskkill /F /T`; **19** kill a pid read from a breadcrumb file (root
  not stated, count not enumerated).
- hertz: **31 of 68** `crates/spt` integration binaries contain pid-scoped `taskkill /T`; **6** drive
  it from `daemon.pid` — *enumerated*: worker_lifecycle, worker_visibility, ready_resume_ledger,
  activity_link_push, contract, job_escape. The helper is **duplicated, not shared** ⇒ each copy is
  its own edit.

doyle's ruling: **reconcile the PREDICATE, not the number** — state the scan root, the exact
tree-kill pattern, the exact breadcrumb-driven pattern, and the ENUMERATED file list; then compare
lists, not totals. Prediction (to be broken, not confirmed): both are right about different
populations — 42-vs-31 is scan ROOT (hertz bounded to `crates/spt`), 19-vs-6 is the definition of
BREADCRUMB (hertz measured `daemon.pid` specifically). If todlando's extra files kill from a
*different* pid file, the class WIDENS to "tests kill from pid files" generally.
⭐ **hertz's 6 is the stronger claim because it is ENUMERATED, not because it is smaller — a named
list is falsifiable file by file; a bare count is not.** A count without its predicate is not a
measurement: this is the probe-competence rule's FIFTH appearance in one day (a filter, a gate
condition, a clock, a branch name, now a count).
⭐⭐ `activity_link_push` reached by BOTH scans independently ⇒ real corroboration, not internal
consistency, which strengthens the registry-laundering concern below.

**The mechanism, end to end:**
- `reap_daemon` reads `<home>/daemon.pid` → `kill_pid` → `taskkill /PID <pid> /F /T`.
- `taskkill /F` terminates via `TerminateProcess` with **exit code 1**. A terminated process never
  unwinds, so it prints NOTHING. Signature: `running 1 test`, silence, exit 1.
- The breadcrumb's own doc comment (`spt-daemon/src/endpoint.rs:77-83`) says: *"Not a liveness
  signal … a stale pid here is harmless because callers probe the socket, never this file."*
  `daemon.rs:390` writes it best-effort (`let _ = fs::write(…)`).

⭐⭐ **THE CLASS — the sharpest defect shape of the day: a value whose safety contract is "no one
acts on this" IS being acted on, and the contract is written down three files away from the code
that violates it.** Nobody was wrong locally — the doc comment is honest, the best-effort write is
honest, the test's intent is honest. **The defect exists only in the JOIN**, so no reviewer of any
single file could catch it. Distinct from the four silent-skip faces; it earns its own hazard entry.

**Why the victim's log cannot explain its own death:** the reason lives in the KILLER's process, not
the victim's. Signature to hunt: **position-dependent and pool-dependent rather than
content-dependent** — a signature we had never once looked for.

**RULED (doyle):**
1. **Identity before termination, by PATH not by pid.** Re-resolve the pid and refuse unless the
   target's executable is under the test's own target dir. The discriminator is already proven — the
   CI reap census prints exactly that split (`scoped=6` under `…spt-bs-core\target\debug\spt.exe`
   vs `unscoped=17` FOREIGN under `…AppData\Local\spt-core\bin\spt.exe`). A pid-scoped kill cannot
   express "mine"; a path-scoped one can. Self/ancestor refusal on top. Same principle as
   [[gate-rig-mechanisms-not-remembered-steps]] and todlando's proven sweep scoping.
2. **Read the exit code before theorizing.** libtest exits **101** on a failed assertion (with the
   panic text); **1** means terminated or explicit `process::exit`. That one number discriminates
   termination from assertion before any source reading. It falsified doyle's own fail-closed
   hypothesis outright.
3. **Every past red in a bounded Windows pool is now suspect.**
4. ⚠ **Flake-registry admission gate.** `activity_link_push_e2e.rs` is BOTH one of the 19
   breadcrumb-killers AND one of the two `flake-registry.json` entries (both `reported_by: doyle`).
   **If a named mechanism can explain a red, it is not a flake — it is a defect wearing a flake
   label, and the registry is laundering it**, which is worse than no registry because it converts
   an open defect into a closed decision. Neither entry retired on suspicion; both UNDER REVIEW.
   New gate: the reporter must state which mechanisms were considered and excluded. *A same-sha
   rerun passing establishes non-determinism, NOT that the cause is environmental.*
5. ⚠ **CANDIDATE, not a claim:** CI runs on the same box as every live agent's perch, so this can
   terminate a tree belonging to whoever holds a reused pid. **An unexplained perch loss on
   hfenduleam is a plausible victim** — touches [[emphasys-endpoint-loss-incident]]. Recorded so it
   is not rediscovered; nothing re-opened on suspicion.

**REPRO DESIGN (todlando, approved by doyle; rig = scratchpad `repro-worker-lifecycle.ps1`, fires only at the golden run's terminal state):** leg **A** = the test ALONE, repeated — the theory PREDICTS green, so a green here is a **DISCRIMINATION, not a null**; plus a libtest contrast (in-process, so a panic MUST print). Leg **B** = the same test inside the 19-file breadcrumb-killer cohort, bounded like CI's Windows Phase A — red in B + green in A excludes content. Leg **C** = an INSTRUMENTED copy in a SEPARATE worktree (never the candidate tree) that logs the breadcrumb pid's liveness, image path and parent chain BEFORE killing, and drops `/T` as the contrast: if the red survives without `/T`, tree semantics are not the mechanism. **Exit code recorded PER LEG, never reduced to pass/fail** — that number is the whole discriminator.

Kin: [[bystander-test-reads-process-global]] (4th bystander of that day),
[[no-machinewide-killon-shared-runner]], [[e2e-leaked-daemons-shared-box]],
[[verdict-from-probe-competence]], [[milestone-a-golden-landed]].
