steps/ per ladder step: gate rule 4, writer, backfill (8); R-653, R-656; decoy suite reads live pins (R-663)
gates / gates (push) Successful in 2s

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-24 07:57:51 +02:00
parent 585a7cba22
commit 5ed599cd5f
16 changed files with 1150 additions and 22 deletions
+19
View File
@@ -30,8 +30,16 @@ AN ENTRY (all keys required unless marked):
backfilled (optional) "YYYY-MM-DD" — written by the backfill from an EXISTING record,
never by a new test; a new move may not carry it
STEP DEFINITIONS (`09` §6.4 part 5, controller v0.268.0): every entry but the NEWEST carries its own
complete compose file at `templates/<app>/steps/<step_key(to)>.yml` — the box climbs one step at a time
and pins exactly that file; the newest step's definition is the template's `docker-compose.yml`. The box's
catalog clone is `--depth 1`, so git history is not a place a box can read a step from, and the commit
that moved an image is not always the definition that works (romm 15f9ebf). `step_key` is computed the
SAME way by the controller (`stacks.StepKey`, pinned by TestLadder_StepKeyMatchesTheCatalog).
Every path that reads or writes the format is here, so the gate and the writer cannot disagree.
"""
import hashlib
import json
import re
@@ -191,3 +199,14 @@ def append_entry(felhom_text, e):
last = j
lines.insert(last + 1, line)
return "\n".join(lines) + "\n"
def step_key(to):
"""The 16-hex name of a step's definition: sha256 of `to` as canonical JSON (keys sorted, no spaces).
The controller computes the same string (stacks.StepKey)."""
return hashlib.sha256(json.dumps(to, sort_keys=True, separators=(",", ":")).encode()).hexdigest()[:16]
def step_file(to):
"""The step definition's path RELATIVE to the template directory."""
return "steps/%s.yml" % step_key(to)