- 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
122 lines
5.7 KiB
Markdown
122 lines
5.7 KiB
Markdown
# 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.
|