### IR-104 — checker 0.4.0 silently skips a FILE scan root under git enumeration: 81 doc stages read as missing, and a local 0.2.0 green hid it because the two versions disagree on what is evidence
…
- **Status:** FIXED UPSTREAM 2026-09-11 (traceable-reqs v0.4.1, PR #21 -> d9af11d, red-first cells);
…
- **Ripe when:** now — the #304 assembly. · **Size:** one pin fixup; one line in the gate runbook.

### IR-105 — an assertion derived from a MODEL of the fixture instead of read off the fixture can only be refuted by a run, and the lane convention that defers the run gives the class a one-window latency: the repair for the first instance carried the second

- **Status:** OPEN. Rule adopted 2026-09-11 (hertz, W1 close). Instrument = read the line, and read
  what the line LANDS on, before asserting either.
- **Instance 1 (hertz, `test/304-remote-friction`, `4ec34d1c`, 03:07Z):** `webserve_e2e.rs`
  `subnet_node_labels_shadow_only_the_docs_compat_alias_while_members` still asserted the pre-#301
  contract at the `/llms.txt/` line — a node root with an EMPTY remainder as `200`. Under the
  node-root arm (`webserve.rs:778-781`) that path is a `302`, so the case died `302 != 200` at the
  first assertion it reached and MASKED the five http calls after it. The `4823ae5d` sweep missed
  the line because the case's other redirects are BARE-NODE ones, which take `redirect_node` and
  are untouched by #301: I classified the case by its siblings and never read the line itself.
  Cost: one window.
- **Instance 2, inside the repair for instance 1 (`28d4eb68`, 03:19Z):** `4ec34d1c` was right about
  the redirect and wrong about what it lands on — it followed through to `GET /llms.txt/docs/` and
  asserted `200`. Measured at `71caedd4`: that is `404`, and the `404` is CORRECT. This fixture's
  docs dir holds `cli/reference.md` and the root-file labels and no `index.html`, and a docs root
  without one is a 404 by design — `webserve.rs:1028-1033` writes `index.html` precisely in order
  to get `200` at `/local/docs/`. So the new assertion pinned index-presence, which is not this
  case's subject. I asserted a property of a redirect TARGET without reading what the target
  contains. Cost: a second window.
- **The mechanism, stated once:** both assertions were derived from a model — the case's siblings in
  instance 1, the contract's shape in instance 2 — rather than read off the fixture in front of me.
  A model-derived assertion is indistinguishable from a correct one at authoring time AND at review
  time; only a run refutes it. This lane commits such work `UNCOMPILED AND UNRUN at commit time:
  written outside the window, measured in the next one` (both commit bodies carry that line
  verbatim), so the class has a one-window refutation latency BY CONSTRUCTION, and a repair authored
  inside that same blind interval inherits the defect it repairs. That is the register-worthy part:
  the fix for a from-a-model assertion was itself a from-a-model assertion, 12 minutes later.
- **Resolution:** `28d4eb68` drops the directory-root status and keeps the `302` + `Location` pair.
  The line AFTER it already fetches `/llms.txt/docs/llms.txt` and compares bytes — a real leaf
  fetched THROUGH the redirect target, which is stronger evidence the target is live than a status
  on the directory root ever was. Blast radius measured at `71caedd4`, producer 3: the case cleared
  the old line and the new pair and failed only on this one; the four sibling cases stayed green.
  Producer 3 GREEN @`28d4eb68`.
- **Third instance, caught BEFORE it shipped (same session, this entry's own id):** this file in the
  `#304` test lane ends at IR-97; main ends at IR-104. Numbering this entry from the register in
  front of me would have produced `IR-98` — a collision with a real entry, written while looking at
  a file that had every right to look complete. The id is `105` because it was read off main. Same
  mechanism, third direction: a stale local artifact IS a model of the shared one.
- **Rule:** assert against what the fixture CONTAINS, at a named line you have read, in the tree the
  claim will live in. Three corollaries earned here: a sweep must read every line it claims to have
  swept (classifying a case by its siblings is a model); following a redirect obliges you to read
  the target's contents before asserting its status (the target's shape is a model); and a register
  id, like any shared address, is read off the shared tree, never off your lane's copy.
- **Ripe when:** any test edit is authored outside the window that will measure it — which is this
  lane's normal mode. · **Size:** a read, not a tool; the deferred-run interval is the thing to
  shorten if it recurs.
- **Kin:** [[IR-101]] (its census read the rendered effect instead of the subject — same family,
  same morning, same file), [[IR-102]] (predicting against a blob nobody would run), memory
  "rig inherits the defect it studies", "verify the SUBJECT not just the measurement",
  "precise claim is falsifiable".

### IR-106 — a red set HANDED OVER in a message was reported as a POPULATION: both members verified, their lines and modes corrected, and the count still wrong by half

- **Status:** OPEN as a discipline line; the instance is closed (the run that refuted it is on file).
  Author and subject: todlando. Filed by doyle 2026-09-11 11:20Z from todlando's text; IR-105 lands
  from hertz's lane at the same assembly, which is why this number follows it.
- **Instance (2026-09-11, #304 W1 product lane).** todlando was handed a red set naming TWO cells in
  the spt-daemon webserve module. He opened each one, CORRECTED its line number and its failure mode,
  and reported the corrected pair as his prediction. The unfiltered run at 3e7eaf67 showed FOUR reds
  of the same mechanism (the retired `/local/` index twin): the two named, plus
  `corrupt_registry_is_loud_but_does_not_disable_unrelated_facets` (:1228, 302 vs 500) and
  `node_routing_reserves_facets_without_registry_fallback` (:1011, 302 vs 200). A post-run sweep
  mapping every single-segment node-root literal to its enclosing fn closed the population at four,
  by enumeration; two further cells touch a root and pass for stated reasons.
- **Why the verification is what hides it.** Checking a member answers "is this one real". It cannot
  answer "is this all of them": no amount of per-member rigour turns a received list into an
  enumeration, and correcting a handed-down set FEELS more rigorous than enumerating it.
- **Mirror instance one window later, other direction (hertz, same lane).** His enumeration was
  SOUND (every node-root literal in the module mapped to its enclosing fn) but its SCOPE was
  inherited from the one file he happened to be resolving; the merge also brought
  `bootstrap_firewall.rs` (+4) and `bootstrap_firewall/windows.rs` (+2), so his whole-suite count was
  short by six (predicted 981, measured 987). Same family: a sound instrument pointed at the wrong
  population.
- **Rule.** Before any COUNT enters a prediction, a START or an END, run the enumerating predicate
  YOURSELF, with a tool that can express the population you are claiming (an unfiltered run; a grep
  whose root is the crate, not the file you have open). A set received in a message is a lead.
- **Kin:** [[IR-100]] (a census counts what its filter could not answer for, separately from a no),
  [[IR-101]] (a per-lane green is silent about the population it did not select), [[IR-105]] (a
  from-a-model assertion is refuted only by a run), memory "a predicate without its tool is not evidence".
- **Ripe when:** now, a line in the window protocol, not a build. Fold into the START/END template
  beside the census. · **Size:** one entry, one clause; no code.

### IR-107 — a rig that redirects TMP INSIDE the checkout puts every tempdir fixture under a git toplevel, and cells whose premise is "outside any repo" resolve THIS repo's remote

- **Status:** RIG FIXED in hertz's lane (base now under `AppData/Local/Temp/hertz-304-rig/<label>`;
  `HERTZ_RIG_TMP_IN_REPO=1` restores the old placement on purpose as the negative control). Recorded
  2026-09-11 11:20Z (doyle, from hertz's and todlando's measurements); corrected 11:35Z on hertz's
  read. The A/B COMPLETED in window 7 at cba18cd5: arm A (base outside any repo) 2 run / 2 passed;
  arm B (base inside the checkout) 2 run / 2 FAILED at :1404 and :842 with the strings below, the two
  bases recorded and differing. Window 6's arm B was the non-measurement described below.
- **Instance.** hertz's first unfiltered `spt-daemon --lib` at 69438c01 redded two cells that neither
  lane touches and that todlando's unfiltered run had passed 8 minutes earlier on the same bytes and
  box: `registryhost::tests::recent_projects_for_dedups_newest_first_excludes_spt_internal` (:1404,
  got `["github-com-bigscreenvr-spt-bs-core"]`) and `projwriter::tests::batched_complexity_counters_hold`
  (:842, got `Some("spt-bs-core")`). Both fixtures require a directory outside any repo.
- **Mechanism, measured with a control.** `lane_run.py` set TMP/TEMP/TMPDIR/RUNNER_TEMP to
  `EVID/temp/<label>` inside the spt-core checkout; `git -C <that dir> rev-parse --show-toplevel`
  answers the checkout (remote `BigscreenVR/spt-bs-core`), while the same probe from the default TMP
  answers "not a git repository". `project_id_for_dir` is REMOTE-URL FIRST: `slug(remote)` and
  `display_from_url(remote)` are the two observed strings exactly, and the folder-name fallback could
  not have produced either (candidate folder names: 304-product, hertz-304, spt-core). So git got as
  far as step ONE of the derivation. The first mechanism offered ("any in-repo cwd") was killed by one
  datum: ci.yml:143 runs `kind(lib)` unfiltered on this runner with an in-repo cwd and passed at
  6a7dd6b7. The variable was the FIXTURE's location, never the process cwd.
- **Instrument defects in this lane today, all hertz's, all closed:** (window 5) `cargo ... | tail;
  echo $?` reports tail's status (memory "render-not-read-pipefail") — the compile gate was in fact
  green, so that reading was VOID evidence rather than a masked red; the same construct one command
  later printed 0 over a checker [must] finding, a true exit 1 — the hazard is that an exit read
  through a pipe certifies nothing, not that it hides reds. (window 4 START gate, 10:26Z) a negative
  control that returned at the refusal branch vouched for nothing about the send arm, which then
  crashed on a NameError on the first real launch (memory "make a new rig red on purpose",
  refinement). (window 8, premise lane, 12:14Z) a FOURTH void-exit instance in one day — `$?` and `${PIPESTATUS[0]}` both read a later command, a backgrounded python traceback surfaced as exit 0; every verdict rests on the producer's own recorded exit file or cargo's Finished line. Also: the window driver crashed at its END on a stale dict key AFTER json.dump had written the report — report-before-print is load-bearing and was right by accident; ordered the other way six measured arms evaporate at the summary line. (Linux cells lane, 12:46Z) fifth and sixth: a python driver died on a SyntaxError while the shell reported exit 0 (exposed only by STALE red logs from the previous sha), and a census script stalled mid-run while its ssh reported exit 0. Both caugh…
- **Third instrument defect, same window (hertz, 11:25Z):** a mutation driver's revert check was
  `git hash-object` plus `git diff --quiet`, and BOTH normalize line endings; `git checkout --`
  re-materialized docshost.rs as CRLF, the LF-written anchors then counted 0, and the driver REFUSED
  at arm 5 = w6-rdrop (the guard working: nothing written; rdrop and lib-full were measured in window
  7: rdrop RED at :683 with left Some(59827), lib-full 988/988) while the oid check reported an identical blob over
  bytes that had just changed. An oid check cannot see an eol rewrite; a revert proof records bytes,
  crlf and bare-lf counts beside the oids. Also: an arm whose switch reaches only the CHILD env while
  the base is chosen from the PARENT's ran the control arm's conditions and passed for its reason (a
  non-measurement, not a refutation) - the driver now refuses to call it a measurement if the two
  bases match.
- **Rule.** A rig's TMP resolves OUTSIDE every git toplevel, and the rig proves it once per box with
  `rev-parse --show-toplevel` expecting "not a git repository". A test whose premise is "no repo
  here" names that premise in its first assertion so the failure reads as environment, not product.
- **Kin:** [[IR-100]], [[IR-101]] (per-lane green silent about the unselected population; these two
  cells were invisible to the stock 21-name producer for the whole lane), [[IR-106]].
- **Ripe when:** now for the rig (done). The assertion-premise clause for the two cells rides a
  SEPARATE follow-up lane after W1 closes (ruled 11:35Z: neither #304 lane touches registryhost.rs or
  projwriter.rs, and a comment in two untouched modules does not widen the integration diff);
  hertz's rig also writes its admission record under a stale sha tag (`admission-61bfd85c.json`),
  the same family as a reused artifact path — fix in that lane. Consequence already paid: the
  window-5 and window-6 admission census records were silently OVERWRITTEN by the later windows
  writing the same path, so those two ENDs stand on the transcript alone, not on a record. · **Size:** one env line in the rig
  (done); two comment lines in tests; one filename in the rig.

- **Instances 9-11, all 2026-09-12, #304 W-2 (one night, three different surfaces).** NINTH (doyle's gate leg, 03:20Z): `cargo ... | tail` over non-interactive ssh to kitsubito returned 0 while cargo was off PATH in the non-login shell — already named in releases#304 comment 5643115673 and filed here for the count. TENTH (hertz, 05:30Z, while writing register entries about instruments that lie): `traceable-reqs check 2>&1 | tail -20; echo "CHECK_EXIT=$?"` printed `CHECK_EXIT=0` — tail's exit over a checker that exits 1, i.e. a 312-finding red read as clean. He re-ran it only because the register had made him suspicious of his own zero, which is the entry doing its job and not a skill. ELEVENTH (todlando, 05:20Z, a NEW surface — the harness itself): `cargo ne…

- **Linux consumer recurrence (todlando, 2026-09-13, #304 at `b8482445`).**
  My first consumer driver put `RUNNER_TEMP` under the checkout's preserved-evidence
  directory, then exported its child sandbox as TEMP/TMP/TMPDIR. Phase A ran 3417 cells:
  3414 passed (2 leaky), 3 failed, 1 skipped, exit 100. The two daemon premise
  assertions named this exact fault; `spt-store::project::tests::derivation_ladder`
  also derived the enclosing repository rather than its fixture folder. **That
  attempt is VOID, not a candidate regression.** The temp-root Git probe returned
  the enclosing checkout (exit 0); the replacement `/tmp/spt-consumer-304-b8482445-valid-*`
  root and every exported temp path returned "not a git repository" (exit 128).
  The replacement driver enforces that boundary before launching any producer.
  On unchanged candidate bytes, valid Phase A then ran 3417/3417 passed (1 leaky),
  1 skipped, exit 0; no main delta or source edit was needed. Original raw,
  `temp-premise-correction.json`, and the valid `attempt2/` receipts remain under
  `.spt/preserved/304-handoff/consumer-linux/`. This repeats the existing rule;
  preserving evidence inside the repository never licenses putting fixtures there.

- **Live-agent identity environment recurrence — Windows consumer (2026-09-13, #304).**
  Doyle reported in `5E3WTZ3N` that his live session's `OWL_SESSION_ID` reached the
  test driver: Windows consumer attempt 1 is **VOID, not a candidate regression**.
  Recorded by hertz from that report, not from an independent rerun. The current
  phase was to drain before a full scrubbed rerun; no corrected Windows result or
  BOX CLEAR is claimed here. A.2 remains held and the preparation clock unstarted.
  **Same mechanism, different input:** TMP placement changes a fixture's repository
  context; inherited session identity changes its caller context. In both cases
  the harness environment is part of the subject, not neutral launch plumbing.
  A clean checkout and pinned executable do not establish the intended test premise.
  **Rule:** construct the producer's child environment from its declared test/CI
  contract, removing inherited live-session identity inputs as a set before launch.
  Verify the effective environment handed to the actual test producer after all
  wrapper/sandbox setup; record names and presence/absence, never identity values.
  Fixtures that test identity must supply their own explicit fixture identity.
  Keep the live agent's own environment and lifecycle intact; this is test-driver
  isolation, not permission to evade a guard on real operational commands.
  Preserve the invalid attempt's logs and verdict separately from the corrected
  run; an environment-premise failure does not authorize a product patch.
  **Kin:** [[IR-22]] records the earlier identity-inheritance failure and its
  one-variable-at-a-time diagnostic trap; [[IR-122]] distinguishes a real rig's
  intentional live-session refusal from an isolated test's contaminated premise.

### IR-108 — four brainproc unit cells leak a process on every run; two others leak by ordering

- **Status:** OPEN, product-side backlog candidate (not #304's). Recorded 2026-09-11 11:35Z (doyle)
  from three unfiltered `spt-daemon --lib` runs on identical bytes on HFENDULEAM (todlando 10:52Z at
  3e7eaf67; hertz 11:00Z at 69438c01 and 11:27Z at cba18cd5), all green.
- **Cell-shaped (leak 3 of 3):** `brainproc::tests::clear_before_spawn_defeats_exact_generation_stale_file`,
  `ready_but_old_gen_never_drains_does_not_promote_rolls_back`, `stale_generation_minus_one_ready_never_promotes`,
  `trial_kills_alive_never_ready_candidate_before_rollback`. **Run-shaped:**
  `broker::tests::windows_session_is_zombie_sees_a_handle_held_corpse_as_dead` (2 of 3),
  `livehost::tests::legacy_psyche_sweep_guard_is_id_specific_and_fail_safe` (1 of 3).
- **Why it matters:** nextest's LEAK is a child that outlives the test; on a shared box that is a
  process census entry with no owner and a pool handle that can pin a worktree (memory
  worktree-pin-holder-triage). Every post-census this cycle read zero survivors, so the leaks reap
  themselves within the run's teardown; the hazard is the window between.
- **Count is PER RUN, not a set (corrected 12:28Z, doyle, on todlando's fold-lane read):** at 61d3459f (fold/304-w2-admission, 992/992) FOUR leaked — brainproc x3 (clear_before_spawn, ready_but_old_gen, stale_generation_minus_one) + broker windows_session_is_zombie — and `trial_kills_alive_never_ready_candidate_before_rollback` RAN (PASS 0.559s, 116/992) and did NOT leak. So "brainproc x4 cell-shaped" is 3-of-4 cell-shaped across four runs on three trees; the fourth is run-shaped. A leaky set carried from one END to the next without re-deriving is the inherited-claim habit (IR-106) at its mildest.
- **Discriminator before any fix:** run each cell alone with `--success-output immediate` and read what
  child it spawns and why it is not waited; a cell-shaped leak is a missing wait or kill in the
  fixture, a run-shaped one is teardown ordering.
- **Kin:** [[IR-100]], memory "e2e leaked daemons shared box", "rig ownership reap only your own".
- **Ripe when:** next product wave that touches brainproc, or a findings-backlog sweep. · **Size:**
  four fixture waits; unknown for the two run-shaped.

### IR-109 — a manifest `[placement] module_banner = "accept"` block LOOSENS the local checker to zero; CI's pinned checker is structurally blind to placement, so the loosening is invisible until the pin moves

- **Status:** OPEN, RATIFIED 12:33Z (doyle, releases#304) as a TRANSITIONAL policy for the #304 head: the 0.4.1 pin stays (a tightening for every new tag), the accept key exempts only the 312 legacy banner tags, and this entry is the retirement ticket. Recorded 2026-09-11 12:10Z (doyle) from hertz's A/B/C and 0.2.0 arms; the commit's "agreed" is corrected by the ruling, not by rewriting a measured sha.
- **Instance.** 33936943 "chore(traceability): enable agreed placement policy" (07:38Z, trailer todlando, on
  feat/304-remote-friction-product and test/304-remote-friction, NOT on main) adds `[placement] enforce = "on"`,
  `module_banner = "accept"`. The word "agreed" is UNRATIFIED: todlando cannot evidence it (his session that
  wrote it is gone) and doyle did not rule it.
- **Measured, same binary 0.4.1, same tree 4b54a95d, manifest the only variable:** as-is exit 1 / 312
  misplaced_tag; block added exit 0 / 0; `enforce = "on"` alone exit 1 / 312. `module_banner` is the sole
  load-bearing key; enforce is the default already. CI-pinned 0.2.0 (golden.yml WANT=0.2.0) at the same sha:
  exit 0 / 0 — the `misplaced_tag` kind does not exist in that version; placement lives only in its `review`
  subcommand, which `check` never reaches. asm-304 (0c05e722, 0.4.1 + the block): exit 0, bought by the key.
- **Why it matters.** AGENTS.md rule 1: tags sit on the evidence, never at file tops to satisfy coverage. The
  312 are banner tags that violate it; the accept key retires them by policy rather than by moving one tag, and
  the gate that CI actually runs cannot see either state.
- **Rule.** A checker config change that lowers a finding count is a loosening and is ruled on the record
  before it rides; "agreed" in a commit message is not a ruling. The honest statement of a zero under such a
  config names the config ("zero under a manifest that accepts module banners").
- **Kin:** memory checker-version-must-match-ci-pin (live instance), [[IR-104]].
- **CORRECTED 12:24Z (doyle):** the pin HAS moved on the W1 lane ancestry — 71caedd4 "ci: pin traceable-reqs to v0.4.1" (10:11Z) sits under 697eb398 (not on main), so ci.yml:253 and golden.yml:1424 both read WANT=0.4.1 at the integration head while origin/main reads WANT=0.2.0 at ci.yml:253 and golden.yml:1414. The accept key is therefore LIVE at the assembled golden gate today, not dormant: asm-304 reads 0 [must] under 0.4.1 because of the key. A lane off 697eb398 reads nine further [must] (code-stage tags in docs prose: F-035-CONFLICT, PUMP-W2-DESIGN, DEBUG-CONVERGE-PLAN, INFRA-REGISTER) that the assembly does not: measured at F-035-CONFLICT:47, 697eb398 carries the bracketed tags and origin/main carries them with brackets elided ("so the checker" clause),…
- **Ripe when:** now — the key rides #304 only as a labelled hole named in the golden hand-off; retire by relocating the 312 tags and deleting the key in a lane of its own. · **Size:** 312 tag moves; the key.

### IR-110 — the gater ruled a wave from origin/main's manifest while the milestone's own product lane already carried the surface; a second implementation was built to its W-1 END before the first was noticed

- **Status:** OPEN, STOP LINE on #304 W2 (comment 5634187958). Recorded 2026-09-11 12:10Z (doyle, own instance).
- **Instance.** feat/304-remote-friction-product @3e7eaf67 implements #297 TCP admission under
  REQ-WEB-LAN-BOOTSTRAP-FIREWALL (bootstrap_firewall.rs + windows.rs + linux.rs, lanhost/servehost/serveverb/cli
  call sites, docs-site section, ADR-0059 "Amendment 2" at d71df7aa): program-scoped Windows effector, all
  profiles, no remote restriction, zero tests in the module (six guard-level cells arrive with hertz 7b098cc2,
  none on scope). doyle deactivated its int stage the same morning and then ruled W2 fork (i) and let four
  REQ-LAN-BOOTSTRAP-* ids mint from ORIGIN/MAIN's manifest, where the id is absent (0 occurrences). todlando
  built build/304-w2-bootstrap-tcp @fe427497: a second, tested (E4 red at the bound-port assertion, 5/5, 981==981)
  netsh implementation, port+remote scoped, never program, a second "## Amendment 2" in the same ADR file.
  He found the collision at his W-1 END by reading the product lane, and touched nothing.
- **Mechanism.** IR-106 from the gater's chair: the population enumerated (main's manifest) was not the
  population the claim was about (the milestone head's). The tell was available all morning — the gater's own
  deactivation note names the id — and a grep of the assembly worktree (asm-304) instead of the main checkout
  would have returned 1.
- **Consequence.** The two texts disagree on a FACT (which rule shape admits TCP over the tailnet on this box;
  W-0 measured program scope admitting nothing for UDP only), both amendments share a heading, and an
  assembled head would run both start paths and write two rule sets.
- **Rule.** Before minting or activating any id for a milestone wave, enumerate the ASSEMBLY head's manifest
  (asm-<milestone>), not main's; a wave that "closes" a surface names the id it closes and greps the milestone
  head for it first. A fork ruling states the tree it enumerated.
- **Kin:** [[IR-106]], [[IR-107]] (same day, same class in three chairs).
- **Ripe when:** now — W-2a discriminating measurement in flight (arms A-D on the installed 5470 listener from
  kitsubito), then the fold ruling (one id, one ADR section, the tested decision seam + cells attached to the
  surviving effector). · **Size:** one measurement; one fold commit on the W2 lane; the ADR merge is a content
  decision, not a merge decision.
- **Labelled hole (12:14Z):** bootstrap_firewall/linux.rs (676 lines) has ZERO #[test]; all six cells sit in bootstrap_firewall.rs and windows.rs. Under cfg the Linux arm is invisible to this box's unit lane, so the surviving id's unit stage reads green over an untested Linux backend set. Closed by a hertz cells lane run on kitsubito against ufw_scope / owned / backend (queued 12:14Z; ten cells red-first at be99017f, 12:41Z). RULE learned there: `ci.yml` lint runs clippy `--all-targets -D warnings` on kitsubito ONLY, and `--all-targets` lints cells as hard as product — a Linux-only red that no Windows gate sees caught todlando's `needless_borrow` (linux.rs:293, fixed be99017f) and hertz's own `cloned_ref_to_slice_refs` (linux.rs:891, test module) one hour ap…

### IR-111 — the installed product's own inbound UDP rule reads Duplicate / Inactive in ActiveStore, shadowed by the fallback rule; a by-name probe reads it green

- **Status:** OPEN, product-side backlog candidate (REQ-INBOUND-WINDOWS-RULE-BINDER-PATH-MATCH family). Recorded
  2026-09-11 12:14Z (doyle) from an unelevated `Get-NetFirewallRule` read of both stores on HFENDULEAM.
- **Instance.** ActiveStore: `spt-core inbound UDP` (Program = installed spt.exe, Profile Any, UDP, Remote Any)
  Enabled=True, **Enforcement=Duplicate, PrimaryStatus=Inactive**; `spt-fallback inbound UDP` (same program,
  Profile Any) Enforcement=ProfileInactive Enforced, Status OK. PersistentStore shows both as
  Enforcement=NotApplicable, Status OK — the persistent view cannot see the shadowing at all.
- **Why it matters.** The product's reconcile and the `inbound_block_hint` probe key on the product rule's NAME.
  The rule that is doing the work is the other one; delete or repoint the fallback and the product rule may
  become the enforced one with no change in what the name probe reports, or the reverse. Kin to the W1
  effector's own comment ("never certify a rule which ActiveStore reports as ignored or ineffective") — the
  UDP side never reads ActiveStore.
- **Also seen, same read:** ~26 enforced program-scoped Private rules naming target/debug and actions-runner
  test binaries (spt_net-*, spt_daemon-*, spt.exe), Proto TCP+UDP, LPort Any, Remote Any — the rig-rule
  population the hfenduleam program-scope memory describes; none admits the tailnet.
- **Rule.** A rule probe that certifies anything reads ActiveStore EnforcementStatus, not PersistentStore
  presence and not the name.
- **Kin:** [[IR-110]], memory hfenduleam-program-scoped-firewall-rules-do-not-admit-tailnet.
- **Ripe when:** the next inbound-rule wave, or when the W1 CIM two-store query is generalised to the UDP side.
  · **Size:** one ActiveStore read in the probe; one dedupe decision.

### IR-112 — bare `cargo test -p spt-daemon --lib` reds two process-global cells on Linux at a sha where nextest is green; libtest is not a sound gate for this crate

- **Status:** OPEN, rig rule (CI unaffected: `ci.yml` runs `kind(lib)` under nextest). Recorded 2026-09-11 12:46Z
  (doyle) from hertz's Linux cells lane END on kitsubito.
- **Instance.** At 697eb398 on kitsubito: `cargo nextest list -p spt-daemon --lib` = 989 ids; `cargo test -p
  spt-daemon --lib` = 989 run, 987 passed, **2 FAILED, exit 101**:
  `answerop::tests::an_approval_notifies_a_plain_knocker_with_no_pre_authorization` (answerop.rs:324, "expected
  exactly one courtesy: [] left: 0 right: 1") and
  `brainproc::tests::the_ready_breadcrumb_tells_a_computed_hash_from_a_cached_one` (brainproc.rs:2347, "the FIRST
  ready write in a process pays for the digest"). Both PASS under nextest with the identical filter, exit 0.
- **Mechanism.** Process-per-test vs one shared libtest process: both cells read process-global state (the
  brainproc one says so in its own panic text); under libtest a sibling's write is visible. IR-108's leaky-cell
  class, measured on Linux. Kin memory bystander-test-reads-process-global, daemon-lib-tests-deadlock-on-live-host.
- **Rule.** A gate or rig over spt-daemon's lib runs NEXTEST; a `cargo test --lib` red on this crate is a rig
  fault until discriminated under nextest with the same filter. Count agreement (list == run) says nothing about
  exit agreement — check both.
- **Kin:** [[IR-108]], [[IR-100]].
- **Ripe when:** a sweep makes those two cells hermetic (the fix belongs to the cells, not the gate). · **Size:**
  two fixtures.

### IR-113 — a killed mutation arm does not unwind: the subject stays mutated and the NEXT arm measures a tree nobody declared; and a mutation that reds on a compile error is a void arm that "it compiled" cannot detect

- **Status:** OPEN, rig rule for every mutation driver. Recorded 2026-09-11 13:05Z (doyle) from todlando's FOLD-1b
  window (fold/304-w2-admission, windows.rs).
- **Instance.** A first M1 injected an early return through a struct literal naming a helper that does not exist —
  a mutation that would red on E0425, not at the cell's assertion, i.e. a void red-first arm. The job was stopped
  mid-run; the driver's restore is its LAST line, so the kill left the MUTATED file on disk: working oid d8ddfdf3
  against pristine 1f475a80, two residue markers present. Caught only because the next act was an oid compare, not
  the next arm. Restored and re-measured identical (residue 0, 786 == 786 lines). Second half: clippy on the
  mutated tree exited 0, so "it compiled" would not have exposed the void arm either.
- **Mechanism.** Mutate → run → restore is not transactional; any exit before the last line (kill, timeout, crash,
  nextest hang) strands the mutation. A void arm is one whose red is not AT the assertion the prediction named.
- **Rule.** (1) A mutation driver restores in a finally/trap path, and every arm BEGINS by asserting the subject's
  oid equals the declared pristine oid — the previous arm's revert is proven at the next arm's start, not trusted.
  (2) A red-first arm is accepted only when the artifact names the predicted assertion line; a compile-error red,
  a panic elsewhere, or a red at a different line is VOID, not a pass and not a fail. (3) Mutations are one-token
  edits with an anchor count asserted at 1; an arm that did not change the file voids itself loudly.
- **Kin:** [[IR-107]] (revert proven by oid AND byte shape), memory scripted-edit-zero-match-refusal,
  make-a-new-rig-red-on-purpose.
- **Ripe when:** now — the rule is cheap and the drivers exist; every lane's driver adopts it at its next edit. ·
  **Size:** a trap/finally and one oid compare per arm.

### IR-114 — three hands wrote one firewall rule set inside ninety seconds under two directors; every census was true at its instant and false a minute later

- **Status:** OPEN, procedure ruled 2026-09-12 00:50Z (doyle) on todlando's reconciliation; recorded 00:52Z.
- **Instance.** #304 W-2a arms on HFENDULEAM: ~00:44Z todlando asked the operator to delete spt-w2a-C so B would stand alone; ~00:45Z the operator said "C down" and todlando's census read B present / C absent (true then); 00:45:05Z liam ADDED C at doyle's direction (doyle had been idle 11 h and did not know the operator's window); 00:46:14Z liam DELETED B at doyle's direction; 00:49:09Z todlando re-measured C present / B absent. Nobody was wrong; the population was not stable. Every fetch todlando reported had an adjacent census and stands; a long background census that straddled the writes returned no spt-w2a rows at all and is UNMEASURED. Separately, doyle's drop-log arm crossed liam's revert in flight: three fetches ran with logging already off — a void a…
- **Mechanism.** Two directors (operator, gater) each driving a different elevated hand against the same shared host state, neither seeing the other's window; a census taken as a separate earlier step and carried forward.
- **Rule.** For any arm on shared host state: ONE WRITER; the census is taken BY THE FETCHER in the SAME command as the fetch, before and after; the prediction names the exact expected population (an unexpected row is a red); every write is announced with its UTC time to every party; a director resuming after a gap re-measures the population before issuing a write. Kin: memory verify-the-subject-not-just-the-measurement, name-the-file-and-sha.
- **Also measured tonight (todlando):** 'spt-core daemon' (proto Any, Private, remote Any, program = the listener's exe) covers the Private-classified Tailscale interface while TCP 5470 times out from kitsubito and the LAN address answers 200 with ICMP alive — so W-0 measured the tailnet ACL, not program scoping, and DESIRED_PROGRAM=false's cited justification is VOID (the constant may still be right; its citation is not). The shape question moves to a throwaway port and listener over the LAN (arm E).
- **Ripe when:** now — the rule costs nothing. · **Size:** procedure.

### IR-115 — a firewall census whose port test is DENIED reads every rule as port=Any and counts port-scoped rules as blanket; a `netsh show rule` without `verbose` omits Program and reads every rule as program=Any; a control count that merges two agents' reads is nobody's control

- **Status:** OPEN, mechanisms recorded 2026-09-12 01:14Z (doyle) from todlando's and liam's own corrections during #304 arm E.
- **Instances.** (1) todlando's first census A ("26 blanket rules") and B ("occupied LocalPort set: EMPTY"): `Get-NetFirewallPortFilter -All` returns "Access is denied" unelevated, the probe swallowed the denial, every rule read as port=Any, and B's positive control (the hand rule carries LocalPort 5470) is what caught it. (2) His replacement pass: `netsh advfirewall firewall show rule name=all` without `verbose` prints no Program line, so it reported 417 blankets and ZERO rules naming spt.exe — provably false, caught by the same control. The third pass (`dir=in verbose`) passed both controls (port-5470 rows = 1, spt.exe rows = 7) and was the census used. (3) doyle's fetcher: first census predicate listed port-covering and program-covering rules as two separ…
- **Mechanism.** A denied or under-scoped read does not error; it returns the permissive default for the field it could not see, so the census reads MORE admits than exist and a shape question gets decided on a phantom population. Kin: memory a-predicate-without-its-tool-is-not-evidence, verdict-from-probe-competence, zero-match-filter-reads-as-absent.
- **Rule.** A firewall census names its tool and privilege and carries two positive controls in the SAME dump: one rule known to carry a specific LocalPort, one known to name a specific Program. A census that cannot see both has not seen the population. The reaching predicate is port-covers AND program-covers AND LocalIP-covers AND profile-covers, one set. Every loopback and remote read records its curl exit code. Counts are per agent; a merged count is restated per agent or discarded.
- **Ripe when:** now — the rule costs one grep. · **Size:** procedure.

- **Addendum 2026-09-12 03:20Z (doyle, #304 W-2 A5/A4): the Windows Firewall event log is DIRECTION-BLIND, so a rig that keys "written" or "removed" on it cannot fail in the direction it claims.** Population controlled over one read (2011x48 / 2052x6 / 2097x6, a 400-event re-read of the same window returning the identical six): id 2052 fires on creates AND deletes in the observed population, id 2097 is create-specific, and NOTHING observed is delete-specific. The CENSUS carries the sign; the log carries only the instant. The same read established a MEASURED gap (zero events between A5's end and A4's start) and that nothing commits after the client dies — both usable, neither a direction. Kin: the firewall status fields do not discriminate either, since an ad…

### IR-116 — a watchdog that calls a killer and then echoes success reports a kill it never made; `pkill` is absent in msys, so the guard logged "stopped" while the arm it guarded ran on

- **Status:** OPEN, mechanism recorded 2026-09-12 01:24Z (todlando) from his own guard during #304 FOLD-2's Windows arm at 7357ea32; doyle asked for the line.
- **Instance.** todlando armed a watchdog to stop a test arm before it reached `cargo test --workspace --lib`, because spt-daemon lib tests deadlock on a live host. Shape: `if grep -q "CLIPPY_EXIT=" log; then pkill -f "bash /tmp/arms.sh" 2>/dev/null; echo "GUARD: arms.sh stopped after clippy at $(date -u)"`. It printed `GUARD: arms.sh stopped after clippy at 01:24:06Z`. Nothing was stopped: `pkill` does not exist in this msys/Git-Bash environment (`command not found`, exit 127), `2>/dev/null` ate the message, and the `echo` was never gated on the killer's exit. The arm ran on into its compile phase and was found by tailing the build log, not by the guard — whose only output was a green.
- **Mechanism.** Two defects stack, and either alone would have been caught by the other: a missing binary, and a success line that cannot fail. Same family as IR-107 seen from the other side — there a trailing command's exit was mistaken for the producer's; here no exit was consulted at all. The aggravating factor is WHERE it lives: a guard is written while thinking about the hazard it guards, not about the guard, and a guard that never fires looks identical to a guard that works. Kin: memory watchdog-reports-a-kill-it-never-made, verdict-from-exit-not-from-silence, a-predicate-without-its-tool-is-not-evidence.
- **Rule.** A watchdog asserts the POST-STATE and never echoes after the call: `kill …; sleep 1; if still_running; then echo "GUARD FAILED"; exit 1; fi`. On msys use `kill -9 <pid>` with a pid you resolved yourself, or `taskkill //PID <p> //T //F`; do not assume `pkill`/`pgrep` exist — check the tool before building a guard on it. Reap your own tree only: resolve the pid and its children, never a machine-wide sweep on a shared box.
- **Second-order, and it bit me inside this very entry.** `git checkout -- <file>` restores from the INDEX, not HEAD. Having staged a first draft, I "reverted" it and appended a rewrite — producing a file carrying BOTH. Caught by the diffstat (49 insertions for a ten-line entry). Restore from `HEAD --` when HEAD is what you mean; the diffstat is the control.
- **Corollary, accepted by doyle.** The killed arm reported `TEST_EXIT=137`. That is the SIGKILL, delivered during compilation with ZERO tests executed (last lines `Compiling acto / iroh-dns / wmi`) — a VOID arm, not a red. A 137 sitting in a log over a test arm is precisely the number quoted later as a product failure. Same family as IR-113 (a killed mutation arm does not unwind).
- **Instance 2 — a DIFFERENT tool surface, 2026-09-12 03:39Z (hertz).** The mechanism is not a property of todlando's guard. hertz ran a recursive `grep -rl` over the project tree; it exceeded the foreground timeout and the harness backgrounded it. `TaskStop` returned `{"message":"Successfully stopped task: bn74vtqn0"}` — a structured success from the harness itself, not a hand-rolled echo. The process was still in the table two minutes later: pid 35104, StartTime 03:37:20Z, **CPU 13.25 s**, killed only by an explicit `Stop-Process -Id 35104 -Force` and confirmed gone by a post-state count of 0 against a live positive control (`pwsh` count 12). So a first-party tool's success object is no better warranted than an `echo`, and the rule generalises: **read the …
- **Ripe when:** now — the rule costs three lines in any guard. · **Size:** procedure.

### IR-117 — a predicate that cannot fail: pre-registered outcomes whose branches are not mutually exclusive, and a requirement titled with the TASK instead of the INVARIANT

- **Status:** OPEN, mechanism recorded 2026-09-12 03:48Z (hertz, both instances his own; doyle ruled the second).
- **Instance 1 — the outcome set.** For the #304 W-2 packet capture hertz pre-registered four outcomes, of which (a) was "SYN retransmission despite the RST" and (b) was "above the wire in the Windows client path". The capture showed five SYNs at a flat ~511 ms, each RST'd in 18-25 us and each ignored — which is (a)'s packet shape with (b)'s locus. The two branches were the same answer told at two altitudes, so EITHER could have been declared "confirmed" and neither could have been refuted by the actual result. Pre-registration defends against fitting the story to the data; it does nothing against branches that cannot both be false.
- **Instance 2 — the requirement title.** hertz drafted `REQ-NET-WINDOWS-REFUSAL-BUDGET` titled "enumerate the spt paths that treat connection-refused as a fast negative on Windows". doyle refused it: that is the TASK, not the invariant. A requirement stated as a task is discharged by DOING the task — it would have gone green the instant the enumeration was written, whether or not one path was fixed, and would have had nothing to say about the NEXT connect bound anyone adds. The accepted title states a product invariant ("classified by its error kind, never by elapsed time; every connect bound documented against the measured floor"), which new code can violate.
- **Mechanism.** Both are the same defect at different altitudes: an instrument whose every reachable outcome is a pass. Kin on the outcome side: memory discriminator-question, refuse-mechanism-until-something-discriminates, one-sample-is-not-a-negative. Kin on the requirement side: the activation model itself (a stage that cannot go red is not coverage), gate-against-documented-design.
- **Rule.** Before registering an outcome set, name for EACH branch an observation that would refute it; if two branches share a refuter, they are one branch and the set is unfinished. Before adding a `REQ-*`, state it as something CODE can violate, never as work a person can complete — if the only way to make it red is to not write a document, it is a task and belongs in a lane, not the registry. Corollary from the same ruling: a measured constant may NOT enter product code as a threshold. The requirement forbids the interpretation (time as a proxy for error kind); it does not bless the number, which was measured on our machines and not on a user's.
- **Ripe when:** now — both checks are one sentence each at authoring time. · **Size:** procedure.

### IR-118 — an instrument read mid-flight, or through a filter that cannot match, returns a COMPLETE-LOOKING wrong answer with no error

- **Status:** OPEN, two instances one hour apart, 2026-09-12 (hertz); doyle asked for the filter line beside IR-117.
- **Instance 1 — the capture read in flight, and it would have inverted the verdict.** `tcpdump -w /tmp/hz-cap.pcap` was still running when the packets were wanted. The file was **8192 bytes** live and **11933 bytes** after `kill -TERM` flushed it; the 3741-byte tail WAS the four SYN retransmissions. Reading the live file would have yielded a well-formed pcap showing one SYN and one prompt RST — i.e. the pre-registered outcome (b), the WRONG answer, assembled entirely from the RIGHT answer's own evidence, with no truncation error and a plausible packet count. The tell was available and nearly missed: a block-aligned size (8192) is a flush boundary, not a record.
- **Instance 2 — the filter that cannot match, class instance 2.** Censusing Windows TCP settings, hertz piped `netsh int tcp show supplemental template=internet` through `Select-String -Pattern 'Template|Initial RTO|Max SYN|Retransmissions'`. It returned ONE line — the header — because none of those words appear in the table's rows (which read `Minimum RTO (msec)`, `Initial Congestion Window (MSS)`, …). Had it been trusted it would have reported "no retransmission settings exposed", which is the identical clean zero a CORRECT filter over an empty template returns. Recovered only by re-running the command raw.
- **Mechanism.** In both cases the instrument succeeded, exited 0, and returned a well-formed artefact that under-reports its population — a partial buffer and a non-matching pattern are indistinguishable from a complete capture and an empty table. Neither failure can be detected from the artefact alone; both need a second read of a different kind. Kin: memory zero-match-filter-reads-as-absent, count-predicate-needs-its-own-positive-control, verdict-from-probe-competence, absence-needs-sibling-probe.
- **Rule.** Terminate a `-w` capture and confirm the writer is gone BEFORE reading it, and quote the writer's own census (`N packets captured / N received by filter / 0 dropped by kernel`) beside the packet list; a block-aligned file size is evidence you are mid-flush. For any filtered dump, either carry a positive control the filter MUST match, or dump raw once and read the filter against the real field names — a filtered census that returns only its header has measured nothing.
- **Ripe when:** now — both rules cost one extra command. · **Size:** procedure.

### IR-119 — a control that only had to prove a ROUTE served a real directory; and a rig is not torn down until its last process is gone, whatever the analysis says

- **Status:** OPEN, mechanisms recorded 2026-09-12 05:46Z (doyle) from hertz's unprompted self-disclosure. The security remedy is an OPERATOR item, filed on releases#304 comment **5643876746** (rotate the kitsubito self-hosted runner's registration credential); this entry carries only the reusable mechanisms.
- **Instance.** The accepted-connection control for the W-2 packet capture was `python3 -m http.server 29472 --bind 0.0.0.0` with **cwd `/home/reavus`** — the self-hosted runner account's home — for **1 h 59 m 54 s**. The off-box bind was REQUIRED (the peer dialled from another machine); the working directory was the whole defect. An empty temp dir returns the identical HTTP 200 and proves exactly as much. `http.server` builds its index from `os.listdir` and filters nothing, so 20 dotfiles including the runner credential files were listed and fetchable; mode 0600 did not protect one of them, because the server ran AS that user. kitsubito's posture was separately verified as RSTing with **no** host filter (ufw inactive, nft input policy accept on both tables)…
- **Mechanism.** A route control and a file server are the SAME COMMAND, so the cheapest way to answer "can the peer reach this port" silently publishes whatever directory the shell was sitting in, and the excess is invisible in the result — the 200 looks identical either way. Same family as a pattern-kill that matches its own ssh line: a tool doing more than the measurement asked for.
- **Second mechanism, and it is why two hours passed rather than two minutes.** The author tore down the CAPTURE, named the outcome, and stopped — treating "the verdict is named" as "the leg is finished". **Naming an outcome is a milestone in the ANALYSIS, never in the RIG.** A rig is torn down when its last process is gone, and the artefact you are proud of is not the only thing you left running. Found only because a stale wake line replayed his own teardown list back to him two hours later.
- **Rule.** (1) A control that proves a route binds an EMPTY throwaway directory, never a home, a repo or a working dir, and it goes down in the SAME breath as the capture it controls. (2) Every rig's teardown is a list of PROCESSES asserted gone against a live positive control, never a list of conclusions. (3) A teardown note written BEFORE a ruling does not license deleting the ruling's cited evidence: `/tmp/hz-cap.pcap` and `/tmp/hz-cap.log` were KEPT by ruling, twice, because they are the primary record of a posted verdict.
- **Evidence quality worth copying.** The window was MEASURED (1 h 59 m 54 s), not estimated; the served-request record was complete (2 requests, both ours, `GET /`, no descent, no file fetch) and its LIMIT was stated rather than implied — a server log is evidence about requests SERVED, never about the network. An independent wire instrument (the pcap, 0 dropped by kernel) covered **4.4%** of the window, and that figure is the capture PROCESS LIFETIME: reading the 2.08 s packet span as the coverage would have understated the evidence 150-fold, because a running capture with no packets is still observing.
- **Kin:** [[IR-116]] (assert the post-state, never an echo), [[IR-118]] (an instrument complete about what it measures and silent about the rest), memory rig-ownership-reap-only-your-own, reap-root-needs-authenticated-ancestry.
- **Ripe when:** now — both rules are one line each in any rig. · **Size:** procedure.

### IR-120 — a claim named for the one axis nobody varied: six readings over two routes and two libraries, all on ONE box, reported as a property of the platform

- **Status:** OPEN, mechanism recorded 2026-09-12 05:47Z (doyle); the instance is liam's, refuted by hertz's own arm and conceded by its author.
- **Instance.** The ~2.05 s Windows refused-connect latency was filed as "the WINDOWS refusal latency" on six readings that varied ROUTE (loopback, LAN hop to Linux) and LIBRARY (curl, .NET TcpClient) and held HOST constant — every one on HFENDULEAM. Route- and library-independence were measured; "Windows" was the name of the box. A per-host WFP callout, endpoint agent or filter driver swallowing RSTs would have produced exactly those six readings on exactly those two routes and generalised nothing. Settled only by going to get the missing axis: a second Windows box (Win10 19045 against the first's Win11 26200) read 2077.3 ms, inside 30 ms of the band. The claim survived; it was not ENTITLED to until then.
- **The control the claim also lacked.** Nothing in the record distinguished "Windows pays 2 s" from "TCP to a closed port costs 2 s" or "curl reports refusals slowly" — because every reading was Windows, the word could not be earned from them, only assumed for want of an alternative. The Linux arm supplied it: closed port and open port within **66 microseconds** of each other on the same libraries, so the refusal costs ~0 there and cannot be told from an open port by latency at all. With that control "Windows" is measured; without it, it was a label.
- **Mechanism.** Breadth along the axes you happened to vary reads as generality. The check is cheap and nobody runs it: write the claim's subject noun, ask which axis that noun names, then ask whether that axis was varied. Second instance from the same author in one night (a PowerShell-edition confound priced as the product's cost), and a sibling shape in the same leg: "the box was quiet" inferred from the absence of ANNOUNCED work, when silence is exactly what an unannounced three-minute recursive grep produces — quiet was never measured for that window either.
- **Rule.** A claim names its population and its varied axes in the same sentence, and the axis in the claim's NOUN must be one of the varied ones. One host is a host, not a platform; one edition is an edition, not a cost. A quantity claimed as a property of a class carries a NEGATIVE CONTROL from outside that class, or it is a label. Corollary already ruled: a constant measured only on our boxes does not enter product code as a threshold — see [[IR-117]].
- **Kin:** memory verified-members-are-not-an-enumerated-population, one-sample-is-not-a-negative, tool-claim-must-name-its-environment, absence-needs-sibling-probe, windows-client-refused-connect-costs-2s.
- **Ripe when:** now — it is a sentence-shape check at authoring time. · **Size:** procedure.

### IR-121 — one declaration command expands every right-hand side before assigning any name, so a dependent id silently binds the CALLER'S GLOBAL and two arms collapse onto one artifact path; and `cat -A` behind msys `sed` is not a byte reader

- **Status:** OPEN, mechanisms recorded 2026-09-12 09:05Z. Instance 1 found by hertz in todlando's driver and confirmed by doyle; repaired as a separately pinned revision (v6 `dcfb732a…` → v7 `927eafb9…`) per the standing rule that a demonstrated execution incompatibility gets a new hash and renewed verification rather than an in-place accommodation. Instance 2 is todlando's own, found while reading the repair site.
- **Instance 1 — the id that looked right.** `trial()` opened with `local arm="$1" n="$2" id="$arm-$n"`. A single declaration command expands EVERY right-hand side before assigning any of its names, so `$arm` was still unset when `id` was built — but `$n` was **not** empty, because the caller is `for n in 1 2 3; do trial a "$n"; done` and `n` is a GLOBAL at that point. The id therefore read `-1`, not the empty-ish `-` that would have been noticed: a plausible, consistently-formed, wrong identity. Both arms produced `-1,-2,-3`, so every per-trial artifact keyed on id — captures, stop captures, census tags, portfields snapshots, cpu brackets — collided, and **Arm B overwrote Arm A in place** with nothing downstream able to tell them apart. `arm` itself was cor…
- **The audit the one fix does not discharge.** A predicate was written over the whole delivered set — any `local`/`declare`/`typeset`/`export`/`readonly` whose later right-hand side references a name assigned earlier in the SAME command — with a positive control broken on purpose (plain `local`, `declare`, and the `${name}` brace form: 3 arms) and a negative control of the same declarations split (0 hits). v6 = 2 hits, both that one line; v7 = 0; v5 = the same single site. Stated over-report: the predicate does not split on `;`, so two correct statements on one physical line read as a dependency — the real site was confirmed not to be that shape. The PowerShell and Python helpers got their own predicates (zero multi-target assignments across four `.ps1`, pr…
- **Instance 2 — the byte reader that was not one.** The repair site was first read with `sed -n '869,880p' file | cat -A`, which printed `$` at every line end — i.e. LF. The file is CRLF throughout (measured: 1117 CR = 1117 LF = 1117 CRLF). msys `sed` reads in text mode and drops the CRs, so `cat -A` faithfully rendered bytes that `sed` had already removed. The project's own rule ("after any scripted edit, verify the BYTES") was followed and still defeated, because the verification ran downstream of a text-mode filter.
- **Third consequence of instance 1, and the worse half of it (hertz, measured independently; re-measured here).** The bad id does not only collide the arms — it begins with a DASH, so every artifact is named `-1.out`, `-2.err`, `-1.stop.out`. Measured in a throwaway dir: `sha256sum *.out` over such a population exits 1 with `unknown option -- 1` and hashes NOTHING (control: the same command over `a-1.out` alone exits 0 and hashes it); `grep -c x -1.out` exits 2 having measured nothing; `sha256sum ./*.out` is the repair. That is the LOUD form. The dangerous form is the one hertz's own detector took: it returned a clean EMPTY snapshot — "0 artifacts altered" — in the arm that was supposed to be red, because its glob handed the dashes to a tool that consumed t…
- **Mechanism.** Both are a wrong answer with no error: a declaration whose dependency is satisfied by an unrelated variable that happens to exist, and a byte census whose bytes were filtered before they were counted. Neither is detectable from its own output — the id is well-formed, the `cat -A` dump is honest about what reached it.
- **Fourth instance, in the very commit that recorded this entry (todlando, self-reported).** The amendment above was applied with a Python text-mode read (`open(p).read()`, universal newlines) and written back with `newline='
'`. This register carried **two lone CR bytes** - `

- **Instances 9-11` and `

- **Addendum 2026-09-12 03:20Z` - present since at least `7cdcf5da`. Universal newlines translated each bare CR into a newline, so the commit silently rewrote two lines belonging to OTHER entries (net: 2 stray CRs removed, 2 blank lines added; markdown-harmless, still undeclared). Caught by reading the commit's own diff rather than trusting the insertion count: a one-bullet append that reports **5 insertions, 2 deletions** is telling you it touched something else. A text-mode read is a WRITE hazard, not only a measurement hazard - edit a file whose byte shape you have not measured in binary, and review the diff, never the intent.
- **Rule.** (1) A declaration that depends on a name is its OWN statement; never share a `local` with the name it reads. (2) Derive an identity used as an artifact key ONLY after its parts are assigned, and guard it against its expected shape — a key that can go wrong silently overwrites evidence rather than failing. (3) A negative control for an id scheme must carry the caller's real variable environment: with the caller's global `n` absent, this defect reads as the harmless `-` and is easy to dismiss. (4) Read bytes with a byte reader — `python3` on the raw file, or `od`/`xxd` — never through msys `sed`, `grep`, or any text-mode filter; if a CR/LF count is the claim, count CR and LF bytes and state both.
- **Kin:** [[IR-118]] (a complete-looking wrong answer from an instrument that succeeded), memory count-predicate-needs-its-own-positive-control, make-a-new-rig-red-on-purpose, scripted-edit-zero-match-refusal, render-not-read-pipefail, windows-firewall-census-clean-zeros.
- **Ripe when:** now — (1) and (4) are habits, (2) is three lines in any rig. · **Size:** procedure.

### IR-122 — the field rig's isolated-daemon stop cannot run from an spt-hosted session, so every run leaves a live daemon holding the subject exe inside the pool it just released

- **Status:** OPEN, recurring. Instance 1 attempt 2 (`rig/arm2-driver-stdout.txt`: `RIG_DAEMON_STOP_REFUSED_OR_ERRORED — reported, not forced`). Instance 2 run `20260912T231404Z` under frozen r10 (`rig_daemon_stop_EXIT=3`, `cleanup-failures.txt`, `rig-daemon-stop.err`). Recorded by hertz 2026-09-12 23:50Z at doyle's direction; **this is a RIG defect, and any product-surface change requires a separate contract review.**
…
