#!/usr/bin/env python3 """steps_backfill.py — ONE-OFF (2026-09-24, `09` §6.4 part 5): write `steps/.yml` for every ladder entry that is not the newest, from git history. WHICH COMMIT, and why not "the commit of the step": the definition a box must pin for a step is the one the catalog SERVED while that step was the head — the NEWEST commit whose compose images equal the step's `to`, i.e. the step's images WITH every fix that flowed after they moved. The commit that MOVED the image can be the broken one: romm's 15f9ebf (5.0.0 -> 5.3.0, 512M, four workers) OOM-looped on demo-hp; the working definition is the same images under f4eb94f's template (768M, two workers). Prints one line per step: app, entry, step key, the commit it came from. Never overwrites a step file. """ import os import subprocess import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import ladder # noqa: E402 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) def git(*a): return subprocess.run(["git", "-C", ROOT] + list(a), capture_output=True, text=True, check=True).stdout def main(): wrote = 0 for app in sorted(os.listdir(os.path.join(ROOT, "templates"))): d = os.path.join(ROOT, "templates", app) fy = os.path.join(d, ".felhom.yml") if not os.path.isfile(fy): continue entries, _, errs = ladder.parse(open(fy, encoding="utf-8").read()) if errs or len(entries) < 2: continue rel = "templates/%s/docker-compose.yml" % app commits = git("log", "--format=%H", "--", rel).split() # newest first for i, e in enumerate(entries[:-1]): dst = os.path.join(d, ladder.step_file(e["to"])) if os.path.exists(dst): print("SKIP %-10s entry %d: %s exists" % (app, i + 1, ladder.step_file(e["to"]))) continue found = None for c in commits: body = git("show", "%s:%s" % (c, rel)) if ladder.images_in(body) == e["to"]: found = (c, body) break # newest first: the last definition served for this step if not found: print("MISS %-10s entry %d: no commit's compose names %s" % (app, i + 1, e["to"])) continue os.makedirs(os.path.dirname(dst), exist_ok=True) open(dst, "w", encoding="utf-8").write(found[1]) print("WROTE %-10s entry %d/%d -> %s from %s (%s)" % (app, i + 1, len(entries), ladder.step_file(e["to"]), found[0][:12], git("log", "-1", "--format=%s", found[0]).strip()[:70])) wrote += 1 print("steps_backfill: %d step definition(s) written" % wrote) return 0 if __name__ == "__main__": sys.exit(main())