test record: an image move must carry its proof (09 decision 13, part 4)
gates / gates (push) Successful in 1s

update_ladder: in .felhom.yml, one JSON entry per line (spiked live on
controller v0.266.0 and v0.267.0 first). Two gates: check-test-record.py
(static, CI too) and check-test-record-move.py (history + registry for
moved refs only). 16 decoys, 3 red-proofs. The ONLY writer is
upgrade-test.py --write-ladder (bench AND box proven, digests resolved).
Harness v3: box fixtures on the bench, files_may_change.
Backfill: the 21 moves of 2026-09-22, 21 proven from their records.
No image: line moved.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-09-23 20:52:32 +02:00
parent cfcfe52784
commit 6db08a5eb3
38 changed files with 2944 additions and 37 deletions
+8
View File
@@ -115,6 +115,14 @@ deployed `app.yaml` (customer secrets) is never overwritten. Full deploy details
`.githooks/pre-push` with the push range; decoys in `scripts/test_gate_decoys.py`. **It needs a
parent commit**, and the CI runner fetches at `--depth 1` (the same gap as R-452 — not re-filed),
so on a shallow clone the runner skips it out loud; the hook is where it bites.
- **An `image:` move needs its TEST RECORD (night 2026-09-23, `09` §3 decision 13).** `.felhom.yml` carries
`update_ladder:` — one JSON entry per line, one per tested step (`scripts/ladder.py` documents the
fields). **Written only by `scripts/upgrade-test.py --write-ladder`, never by hand**: it refuses unless
the bench AND the box walk both say `proven`, resolves each ref's digest, moves the compose and sets
`catalog_since`. Two gates: `check-test-record.py` (static — every ladder well-formed and its newest step
IS the compose; runs in CI too) and `check-test-record-move.py` (history + the registry for MOVED refs
only — a move must add a proven entry whose digests the registry still serves; the hook). The 21 moves
of 2026-09-22 carry backfilled entries citing their records (`ladder_backfill.py`, one-off).
- **Taking an app out of circulation — use `lifecycle:`, never a directory move.** `.felhom.yml`
gains an optional `lifecycle:` field: `available` (default; absent/empty means this), `hidden`
(not offered for new installs, no explanation owed), `abandoned` (upstream stopped developing it —