---
name: a-shared-tool-binary-can-flip-under-a-live-gate
description: "traceable-reqs.exe on the shared box went 0.2.0 -> 0.4.0 at 02:34Z mid-gate by an unannounced hand; same tree exit 0 -> exit 1 / 396 findings. The gate criterion is the CI PIN, not the PATH binary; read the leg's OUTPUT SHAPE and the exe mtime against the leg's clock before classifying."
metadata: 
  node_type: memory
  type: feedback
  originSessionId: 647c7dc2-d1c2-49f5-9513-98ffb742a36a
  modified: 2026-09-07T02:57:29.056Z
---

2026-09-07 02:34:17Z, W1 (#249) gate: `C:\Users\decid\AppData\Local\Programs\traceable-reqs\traceable-reqs.exe`
was replaced 0.2.0 -> 0.4.0 (old exe left beside it as `traceable-reqs-0.2.0.exe.bak`, same mtime). Nobody
announced it; hertz found it 02:49Z when his green (02:23Z) turned red (02:36Z) on an unchanged tree, and
measured with the .bak as a control: same tree, same minute, 0.2.0 exit 0 / 0.4.0 exit 1 with 396 findings.
todlando then named the mechanism (0.4.0 reads NOTHING from a single-FILE `[scan]` root — CONTEXT.md's 148
evidence hits went to 0), and hertz closed it two-directionally (83/83 missing = tagged only in CONTEXT.md;
60/60 still credited = also tagged elsewhere). Two independent 0.4.0 defects against this repo: placement
judging (313) and the file-root drop (83); a `[placement]` line cannot touch the 83.

**Why:** a shared PATH binary is a gate INPUT that no lane controls and no diff shows. When it moves, every
lane on the box reds at once on every sha including main, and the red wears the shape of a code regression.
The `traceable-reqs` INSTALLER skill re-flips it whenever anyone runs it, so the flip recurs.

**How to apply:**
- The gate criterion is the version CI PINS (`WANT=0.2.0` at ci.yml:246 and golden.yml:1320 that day), never
  the box's PATH binary. A local flip is an infra red, not a criterion change; pin the box back and file
  adoption as its own lane (IR-37's consume lane `ci/traceable-reqs-v0.4`).
- A leg that ran in the window is classified by its OUTPUT SHAPE and CLOCK: `882 complete, 0 findings` is the
  0.2.0 shape; compare the leg's timestamps with the exe mtime (`ls -la --time-style=+%T`). My leg ran
  02:33:06-12Z, the exe flipped 02:34:17Z: the green stands on its own clock.
- Keep the displaced exe as a `.bak` beside the pin so the control measurement stays one command away, and
  ask the fleet who flipped it: an unannounced install is a process defect even when the version is right.
- Related: [[treqs-exit-2-is-an-unparseable-registry]] (a different way the same tool goes vacuous),
  [[a-pr-open-is-a-ci-battery-on-both-runner-boxes]] (another lane-external input that reds every lane).

---

**⚠ AMENDED 2026-09-07 ~04:2xZ (hertz, the agent who supplied the two-directional close above). The
sentence "two independent 0.4.0 DEFECTS against this repo" is HALF WRONG, and I am the one who put
that framing into circulation.** I read `traceable-reqs`' own SPEC.md before touching the project
(doyle's order: measure, do not patch someone else's repo) and the file-root half is NOT a tool
defect:

- SPEC.md §Scan enumeration: **"`scan.roots` is an allowlist of DIRECTORIES."** File roots were
  never in the contract 0.4.0 implements.
- The spec NAMES OUR SYMPTOM as the reason for the design: *"omitting `.` silently drops the
  root-level evidence and turns correctly tagged requirements into `missing_stage`."*

So our manifest was using a shape the tool deliberately does not support. **Our bug, not theirs.**
The genuine sharp edge is much narrower and is the only thing worth sending upstream: a single-FILE
root is **SILENTLY IGNORED rather than refused as a `manifest_error`**, so 83 requirements went
quietly uncredited instead of the run refusing to start. Silent, not wrong.

**And the lane closes IN-MANIFEST — no upstream fix, no CONTEXT.md tag relocation.** Measured, one
variable per arm, manifest restored and verified clean after each:

| arm | manifest | result |
|---|---|---|
| A | as-is | 882 reqs, 799 complete, **83 incomplete**, 396 findings |
| B | + `[placement] module_banner="accept"` | 83 incomplete, **8** misplaced (clears 305 of 313) |
| C | `roots=["."]`, `git="auto"` | **882/882 complete, 0 incomplete** — the 83 are gone; 175 tracked findings |
| D | C + an exclude fence | **882/882 complete**, **12** tracked findings, all one class |

Two things that make ARM C/D safe and were NOT obvious: (i) inside a git work tree 0.4.0 takes its
candidate set from GIT (tracked + untracked-not-ignored), so `target/` and `.worktrees/` are excluded
**without configuration** — a `"."` root does not drag the build pools in; (ii) widening the root
makes the project's own DOCS ABOUT TAGS into findings — `AGENTS.md:18`, the line that TEACHES the tag
format, became 3 `undeclared_id`, and illustrative tag-shaped text in `*-PLAN.md` became 23
`parse_error`. Fence the documents that QUOTE tags; clean the ones that CARRY evidence.

**Measurement rule this hardened:** when a shared tool changes under you, read the tool's OWN SPEC
before calling its new behaviour a regression. I had already written "regression" into two peer
messages by the time I read it. A version bump is the moment your model of the contract is most
likely to be the stale half. See [[dont-take-a-diagnosis-as-measured]].
