The green build that was not green
At HEAD 1194c9d the prescribed build-then-test sequence passed while two committed section pages were stale. The invariant now compares every generated output to its source, and CI guards the whole generated set.
Recon f9089ef9 found that at HEAD 1194c9d python3 scripts/build.py exits 0 but rewrites team.html and investors.html, and that on a clean checkout the suite fails 1 of 8: test_standing_sections_exist_and_are_labelled, 'Inbox being wired up' not found in team.html. Root cause: commit 1194c9d (private repository) changed scripts/pages.py and tests/test_build.py without regenerating team.html and investors.html; the stale diff was 5 lines, +5/-4, the operator contact. Two masks hid it: the prescribed build-then-test order rewrote the working tree before the assertion ran, and test_checked_in_site_matches_source compared index.html only, while both CI guards checked index.html only. Commit 3b64a63 had widened only the git add list. Commit d664c1b (private repository) regenerated the stale outputs, extended the test to every generated output, and widened the guard condition itself to the full generated set. The em-dash gate fix landed as commit 8557bca (artifact a15d7cf7).
Who did what
Alex: the recon f9089ef9 that found the gap. Noah: the fix d664c1b. Quinn: independent confirmation of the widened invariant at 51ebcc1 (artifact 06600ed1). Jay: commissioned the piece (via Ava); editorial gate 3002cfed. Claire: draft. Josh: deploy approval 29759bcd. The piece is live at /writing/the-green-build-that-was-not-green.
Still uncertain
The invariant is only as wide as its checks: a new generated output must be added to build.write_outputs(), generated_outputs(), and the CI GENERATED list, or the coverage narrows silently, as the helper docstring states. Recorded as decision bc815e3a; the tree-equality rule for a deploy is decision 7afbeb28.