build: content-gate every committed generated artifact, not just three - #683
build: content-gate every committed generated artifact, not just three#683mparrett wants to merge 3 commits into
Conversation
The corefns registrar (#640) was reachable only through the Makefile's core_compiled.lgb prerequisite, which is an mtime rule. Once the committed registrar is newer than its sources that rule stops firing, so `make generate` left injected drift in place while `check-generated` — which regenerated the registrar directly — reported it stale. The remediation the failure printed ("run make generate") could not fix the failure it printed it for. Verified by injecting drift into the committed registrar: before this change `make generate` left it untouched, after it the file is regenerated. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`make check-generated` verified three of the six committed generated artifacts. It regenerated through `lgprimgen` and `lgbgen` directly, and three artifacts — `pkg/ir/op_generated.go`, `pkg/rt/ir_bridge_generated.go` and `pkg/rt/core/ir/data/generated.lg` — are produced only by `scripts/generate.lg`, so a gate that never ran it could not see them drift. Replace the three copy-pasted cmp stanzas with a single loop over a `GENERATED-TRACKED` list, regenerating through the full `make generate`. Using the whole pipeline rather than the two generators is what widens the coverage; `GENERATED-TRACKED` and `generate.lg` are now the same list. The gate is also non-mutating on every path. It stashes the working-tree bytes first and restores them on pass, on failure, and on generator error, so a failure no longer strands a half-regenerated multi-file tree that the reader has to `git checkout` back. It reports every stale artifact rather than exiting at the first, and a failing generator now surfaces the underlying error instead of `make[1]: *** [generate] Error 1`. `pkg/rt/generated.sums` is stashed and restored rather than compared, because lgbgen's writeBundle refreshes it on every regeneration. `check-generated-manifest` is no longer a prerequisite: the digest is a proxy, and a stale proxy should not abort the run before the content gate can give the real answer. This does not change whether a stale digest fails CI — the `build` job runs `check-generated-manifest` directly, as does `TestGeneratedArtifactsAreFresh`, and neither is touched here. Verified: passes clean on `main` reporting all six; catches injected drift in each of the five text artifacts, including the three the previous gate could not see; leaves the tree byte-identical to what it found in both the pass and the fail case. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Ran the gate rather than reading it. On this head all six The coverage gap is real: One bug. The comment at Ordering, and this one is on me. #641 is mine and it makes The two also both add a corefns line to One bug I found by running the gate rather than reading it, and it is caused by this PR. Both exit 0; one verified six artifacts and the other verified nothing. |
Ctrl-C during regeneration deleted the recovery copy without restoring the tree. A stray ./check-generated binary also made the gate a silent no-op. Co-authored-by: Cursor <cursoragent@cursor.com>
|
@nnunley Both bugs fixed in 8bc0888. The EXIT/INT/TERM trap now restores from the stash before removing it, and each restore Agreed on landing this ahead of #641; the gate needs unconditional generate until that side forces a full regen (or hashes output content). Happy to take the duplicate |
make check-generatedverified three of the six committed generated artifacts. It regenerated throughlgprimgenandlgbgendirectly, and three artifacts —pkg/ir/op_generated.go,pkg/rt/ir_bridge_generated.goandpkg/rt/core/ir/data/generated.lg— are produced only byscripts/generate.lg, so a gate that never ran it could not see them drift. That matters because a stale committed artifact means the bytecode andgogen_irengines run different versions of the IR pipeline, which is the failureparity-fullexists to catch and the gate exists to prevent.This replaces #634, which patched
cmd/lginterop/prims_emit.go— a file #639/#640 moved tointernal/primgen/, where the import-grouping bug it fixed has since been fixed independently. The thesis survived the move; the diff did not. Closing that one in favor of this.A second defect, found while widening the gate
make generatedid not regenerate the corefns registrar. It was reachable only through the Makefile'score_compiled.lgbprerequisite, an mtime rule that stops firing once the committed registrar is newer than its sources. Somake generateleft drift in place whilecheck-generated— which regenerated the registrar directly — reported it stale. The remediation the failure printed ("runmake generate") could not fix the failure it printed it for.That also means a gate regenerating solely through
make generatewould have passed corefns drift silently, so this had to be fixed for the widening to be sound.Change
GENERATED-TRACKEDlists the six committed artifacts. The gate stashes them, regenerates through the fullmake generate, andcmps each. Driving the whole pipeline rather than the two generators is what widens the coverage.generate.lgemits the corefns registrar explicitly, soGENERATED-TRACKEDandgenerate.lgare the same list.make[1]: *** [generate] Error 1.docs/contribution-policy.mddescribed the gate as bundle-and-lowered-tree only, which was already stale againstmain.On the
check-generated-manifestprerequisiteDropping it does not change whether a stale digest fails CI. It still does, in the
buildjob (which runscheck-generated-manifestdirectly) and inTestGeneratedArtifactsAreFresh. Neither is touched here.What changes is that a stale digest no longer aborts
check-generatedbefore the content gate can run. The digest is a proxy; thecmpis the check that binds sources to artifacts, and the proxy should not suppress the answer.pkg/rt/generated.sumsis stashed and restored rather than compared, because lgbgen'swriteBundlerefreshes it on every regeneration — without that, acheck-*target would mutate a tracked file.Verification
main, reporting all six artifacts in lockstep, with the tree byte-identical afterwards.generate.lgchange, injected drift survivedmake generate; after it, the file is regenerated.make check-generated-manifeststill passes standalone.Note on the recipe
It runs under plain
/bin/shwith no-e. The makeplus branch that setsSHELL := bashand-e -o pipefailis skipped whenevergois already on PATH, which is every CI run.mktempandcpfailures are checked explicitly and atrapremoves the temp dir on interrupt.Overlap with #641
#641 also adds corefns generation to
generate.lg. That one line will conflict; whichever lands second drops it in the rebase.