Files
troupe-standup/recoveries/helm-cli-entry-point.md
T
Merlin adfff7a39a Q30 DONE: the renderer's entry point runs, and it refuses production by default
- reproduced the defect first: python3 helm-render.py exits 1 with
  NameError: name 'build_page' is not defined (guard at :90-91 above
  def build_page at :232), same with --out, no file written
- moved the __main__ guard to the end of helm-render.py (:495 of 495);
  --out/--as-of semantics unchanged; fixed renderer 21,766 B sha256
  5c67473d89283c3d4434928dc96d45ff48a41d8f443ecc3c98e9236be8b597f9
- destination gate per the 09:21Z control-plane addendum: OUT_DEFAULT is
  production, so main() resolves the destination and refuses without
  --deploy (exit 2, message naming the path and flag); parse_args now
  returns (out, now, explicit_out, deploy)
- gate G7: the CLI executed in a subprocess, asserting emitted bytes
  (exit 0, file exists, bytes equal build_page()'s at the pinned clock,
  byte count matches, --as-of honoured, live root untouched); production
  destination refused by default and by explicit --out at the prod path
  (resolve(), not string equality); --deploy branch exercised against a
  patched OUT_DEFAULT; source-order guard so the defect cannot return
- gates re-run: 119 passed, 0 failed (102 before; G7 adds 17); the gate
  discriminates - the same command against the pre-fix file exits 1
- CONTRACT.md appended append-only: transcripts, digests, gate, and a
  revision note on :213-214 (deploy is now --deploy)
- nothing deployed: live page 9,865 B / 427b7b54c69b18d2... and snapshot
  aa842b0fd88037f8... unchanged before and after every run; --deploy
  alone never executed
2026-10-11 11:16:20 +00:00

5.7 KiB
Raw Blame History

Q30 — the renderer's entry point: fixed, gated, and nothing deployed

(Merlin, 2026-10-11 ≈09:50–11:20 UTC. Helm lane. All figures measured on this host; nothing in this record is testimony from another runtime.)

The claim under test

python3 /root/.helm/bin/helm-render.py — the usage line in the module's own docstring (:6-7), the reproduce block in CONTRACT.md (:102), and the §4 deploy sentence (CONTRACT.md:213-214) — had never executed. The if __name__ == "__main__": guard sat at :90-91, above def build_page at :232.

1. The defect, reproduced before the fix (measured 2026-10-11 ~09:50Z)

$ python3 /root/.helm/bin/helm-render.py
Traceback (most recent call last):
  File "/root/.helm/bin/helm-render.py", line 91, in <module>
    sys.exit(main(sys.argv))
  File "/root/.helm/bin/helm-render.py", line 78, in main
    html, report = build_page(now)
                   ^^^^^^^^^^^^^^^
NameError: name 'build_page' is not defined
exit=1

$ python3 /root/.helm/bin/helm-render.py --out /tmp/helm-cli-probe.html --as-of 2026-10-11T12:00:00Z
…same NameError, same traceback…
exit=1
$ ls -la /tmp/helm-cli-probe.html
ls: cannot access '/tmp/helm-cli-probe.html': No such file or directory

Pre-fix file: 18,929 B, sha256 00d14453d95234ef49a1d8758ab2de76143e848191331bfec38603e6263403e6. Production was never at risk from this failure — it lands before out.write_text — and the live page stayed at 427b7b54… throughout.

2. The fix (two parts)

  1. The guard moved to the end of the file — :495 of 495 lines, below build_page() (:273). --out / --as-of semantics unchanged.
  2. The destination is gated (the control plane's 2026-10-11 09:21Z addendum). OUT_DEFAULT is the live document root, so main() resolves the destination and refuses a production write without --deploy, returning 2 with a message naming the path and the flag. parse_args() now returns (out, now, explicit_out, deploy).
file bytes sha256 (measured 2026-10-11T11:14Z)
/root/.helm/bin/helm-render.py 21,766 5c67473d89283c3d4434928dc96d45ff48a41d8f443ecc3c98e9236be8b597f9
/root/.helm/bin/helm-selftest.py 33,647 7ed1bca8f9da624f69b03313506097a0ce9b1130cbad9511908776e5015a0f46
/root/.helm/CONTRACT.md 17,657 2c527635ff96eb677e7419ef5b15516811e05cedfa1f072f84dcf67c10214f91

3. The CLI transcript, after the fix (exit codes from unpiped runs)

$ python3 /root/.helm/bin/helm-render.py --out /tmp/helm-cli-evidence.html --as-of 2026-10-11T12:00:00Z
rendered -> /tmp/helm-cli-evidence.html (11806 bytes)
render clock 2026-10-11T12:00:00+00:00  snapshot age 2d 18h 47m
verdict at render: 0 green / 6 not green  (5 stale, 1 unreachable)
exit=0
$ sha256sum /tmp/helm-cli-evidence.html
8b839754b9e33911ec6d74834e4899a8f77f71c361eec98757d6ef08ad891839  /tmp/helm-cli-evidence.html

$ python3 /root/.helm/bin/helm-render.py
refused: this render would write the live document root (/var/www/alexander-whitestone/helm/index.html) and --deploy was not given.
  staged render : --out /path/index.html
  deploy        : --deploy   (an operator's call under §4; nothing here authorises it)
exit=2

$ python3 /root/.helm/bin/helm-render.py --out /var/www/alexander-whitestone/helm/index.html --as-of 2026-10-11T12:00:00Z
…same refusal (the destination is matched by resolve(), not string equality)…
exit=2

$ python3 /root/.helm/bin/helm-render.py --deploy --out /tmp/helm-cli-evidence2.html --as-of 2026-10-11T12:00:00Z
…renders the staged path…
exit=0

--deploy alone (which would write production) was not executed. It is exercised inside gate G7 against a patched OUT_DEFAULT.

4. Gate G7 — the CLI, executed

python3 /root/.helm/bin/helm-selftest.py → helm-selftest: 119 passed, 0 failed, VERDICT: ALL GATES PASS. G7 adds 17 assertions (102 before):

  • exit 0 on a staged render; the file exists; its bytes equal build_page()'s at the same pinned clock; the reported byte count matches the file; --as-of is honoured; the live document root is untouched.
  • the default (production) destination is refused (exit ≠ 0), the refusal names the path and --deploy, and nothing is written; an explicit --out <production path> is refused too.
  • the --deploy branch runs against a patched OUT_DEFAULT (a temp path), never the real one.
  • a source-order guard asserts the __main__ guard sits below def build_page, so the Q30 defect cannot silently return.

The gate discriminates: the exact G7 subprocess command, run against the pre-fix file, exited 1 with NameError (transcript in §1); the same command now exits 0 and emits 11,806 bytes.

5. Nothing deployed (measured before and after every run in this tick)

target state
/var/www/alexander-whitestone/helm/index.html 9,865 B, sha256 427b7b54c69b18d270288910fc810732463129f48ec4bdd7dbc75cdb22997ce4, mtime 2026-10-11 08:57:14.017837233Z (the 08:57:14 write is this lane's earlier byte-exact restore, not a deploy)
/root/.helm/data/snapshot.json 14,039 B, sha256 aa842b0fd88037f83115b4a54d617f27666f4de06ef84f9a64c8fd0a5f04656d, mtime 2026-10-08T17:12:59.475780303Z

The collector was not re-run; no cron job was added; both remain Alexander's call under §4.

6. Revision note on the deploy sentence (CONTRACT.md:213-214)

The sentence "Deploying is python3 /root/.helm/bin/helm-render.py — one command" is true of every revision up to and including 00d14453d952…. As of 5c67473d89283c3d… the bare command is refused with exit 2, and deploying is python3 /root/.helm/bin/helm-render.py --deploy — still Alexander's call under §4, now an explicit flag rather than the default behaviour of running the script. The old text was not rewritten; the note is appended.