diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ef509c..1017e3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,29 @@ -# Changelog +## the decoy sweep — can this gate be fooled by a label? (2026-09-01, R-421) — NOT A RELEASE + +**No product code, no version bump, no image, no golden.** A scripts change is not a release. + +Four times in one week a gate turned out to match a NAME instead of the thing it named — R-410 (a +`mkdir` turned the release gate green), R-400 (seven debug controls answering nothing), R-378 (a +status word inside a sentence), R-419 (a phrase inside prose, including prose saying the marker was +absent). **All four found by accident.** The gates enforce everything else here and were the one part +nothing had checked. + +**All 29 gate scripts read and decoyed. 16 were fooled.** 10 fixed here, 4 left with rows +(R-422..R-425), 6 could not be given a plausible decoy and are named (R-426 group d). + +**The largest single cause was mundane:** eight gates set their SCOPE with `os.listdir` (one level). +Green and correct today; blind the moment anyone adds `templates/partials/`. `mojibake` and +`docker-v` already used `os.walk`, caught the identical planted file, and are the control that +proves the cause was the listing rather than the decoy. + +Full survey table, and the five decoys withdrawn as illegitimate (mine, named): +`documentation/audits/AUDIT-gate-decoys-2026-09-01.md`. + +**In this repo:** no gate changed, and that is the result. `image-pins` was decoyed and is SOUND — +a real untagged `image:` line is convicted; the `x-image:` attempt was WITHDRAWN as illegitimate +because `x-` fields are inert in Compose, so the label had no fact behind it either way. +`image-resolvable` and `volume-persistence` need a container runtime and are named in the +decoy-coverage exemption list (R-426) as UNTESTED, not as sound. ## docs — the "CI is still owed" claim was stale; corrected (2026-08-06, R-229 part 2) — no version bump diff --git a/CLAUDE.md b/CLAUDE.md index 022da95..6269ea0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -78,3 +78,11 @@ deployed `app.yaml` (customer secrets) is never overwritten. Full deploy details server-side. An unknown value degrades to `available` with one WARN, so a typo can never brick a template. This supersedes the short-lived `retired/` directory move, which was wrong: removing a template orphans every customer already running it. + +**A gate ships with a decoy test that has been seen to fail (R-421).** A decoy is the LABEL without +the FACT — a directory with the right name and no bake log, a note whose prose mentions the marker it +lacks. `scripts/decoy_coverage_gate.py` refuses a new gate that has neither a decoy nor a named +exemption carrying its row. The four shapes, the 2026-09-01 sweep that fooled 16 of 29 gates, and the +decoys withdrawn as illegitimate: `documentation/audits/AUDIT-gate-decoys-2026-09-01.md` and +`felhom-controller/.claude/rules/gates.md`. **Scope is a fact too** — prefer `os.walk` over +`os.listdir`, and a glob over a hand-maintained list.