docs: record the CI episode — three instrument defects, and the two-homes rule (R-260)
gates / gates (push) Failing after 13m54s
gates / gates (push) Failing after 13m54s
The gate's third instrument defect and the reusable lesson underneath it: a gate needing a sibling clone passes on a workstation and is INCONCLUSIVE in CI, and a gate must not shell out to a tool the CI image may not have. Three red runs (260-262), each of which mailed the operator, before 263 went green. CONTEXT S-38 gains the two-homes rule.
This commit is contained in:
@@ -76,12 +76,36 @@ turned out blind to one of the three shapes it was written for:
|
||||
`--selftest` plants an unreachable tag on a real root in a throwaway copy and asserts conviction:
|
||||
**exit 1, planted tag named**; unplanted tree **exit 0**.
|
||||
|
||||
**Two instrument defects the CONTROL caught before the gate was trusted:**
|
||||
**THREE instrument defects this gate's own controls caught before it was trusted.** None was found
|
||||
by review; each was found by making the gate prove something.
|
||||
|
||||
1. **A substring false negative** — `grep -F healed_at` also matched `privsep_healed_at`. R-260 named
|
||||
`healed_at`, so its absence from the output was the tell. Now a whole-token regex; 40 not 39.
|
||||
`healed_at`, so its absence from the output was the tell. Whole-token now; 40, not 39.
|
||||
2. **`dr_recipe` is not wholly opaque** — its top-level section keys ARE decoded, through allow-lists
|
||||
that already swallowed `offsite_restic` for months (R-122). Now opaque only **below depth 1**.
|
||||
3. **The search shelled out to `grep` and read its failure as a finding.** CI convicted **all 174**
|
||||
checked tags while the pre-push hook was green. The CI runner's image carries python3 and git and
|
||||
deliberately little else, and its `grep` does not support `--include`, so stdout was empty and
|
||||
empty was read as "absent". **A gate that silently turns a tool failure into a finding is worse
|
||||
than no gate**, and its green would have been as untrustworthy as its red. Removed the dependency
|
||||
rather than working around it: the search is pure Python now, one token index per receiving repo.
|
||||
|
||||
**The BEFORE capture was RE-VERIFIED, not re-generated** — the stronger claim. All 40 recorded fields
|
||||
were re-tested against the new implementation: **agree=40, disagree=0**, i.e. exactly the four this
|
||||
session fixed are now present and the other 36 still absent. The number stands under both
|
||||
implementations.
|
||||
|
||||
**And the reusable half, which is about the gates and not about this gate.** The pre-push hook runs on
|
||||
a workstation where every sibling repo is a real clone; CI checks out one repo, shallow. **A gate
|
||||
that needs a sibling passes locally and is INCONCLUSIVE in CI — the two automated homes are not
|
||||
interchangeable, and a new gate must be checked in BOTH.** The workflow's own alarm mail says a
|
||||
hook-versus-CI disagreement "outranks whatever the push was for"; it did. Fixed by fetching the agent
|
||||
clone in CI (`.gitea/workflows/gates.yml`), never by letting the gate skip when a sibling is absent —
|
||||
that is the fail-open shape and would leave it running in neither home (R-29).
|
||||
|
||||
**Cost, stated plainly:** three CI runs went red (260, 261, 262) and each sent the operator an alarm
|
||||
mail before run **263** went green. The alarm working is the system behaving correctly; the noise was
|
||||
mine.
|
||||
|
||||
## 6. What `oobDegraded` says when it fails
|
||||
|
||||
|
||||
Reference in New Issue
Block a user