What changes, and when
rainlanguage/rainix#392 adds a
codegen witness to the rainix-copy-artifacts reusable workflow. This repo's
.github/workflows/git-clean.yaml calls that workflow at @main, so the check
arrives the moment #392 merges — not when this repo chooses to adopt it. The
next push after that merge fails until a manifest is committed.
Why the check exists
rainix-copy-artifacts currency-checks committed generated sources by re-running
the codegen hooks and then git diff --exit-code. That proves the committed
content is current, but it is structurally blind to a generator that has
stopped emitting a file: the committed copy is already correct, so nothing is
rewritten, nothing differs, and the job is green over a dead emitter. Reproduced
with a control in
rainlanguage/rain.factory.deploy#35.
Seeing that needs an independent statement of which committed files are
generated. That is script/codegen-manifest.txt: one repo-relative path per line,
# comments and blank lines ignored. The witness marks every git-tracked file's
mtime before the first hook and verifys after the last, calling a file
written when it exists and its mtime moved. Any declared path nothing wrote
fails the job by name.
Why this repo is affected
Hooks present: script/Build.sol, script/CopyArtifacts.sol. No
script/codegen-manifest.txt today.
What to add
script/codegen-manifest.txt:
src/generated/candidate/Rainlang.sol
src/generated/candidate/RainlangExpressionDeployer.sol
src/generated/candidate/RainlangInterpreter.sol
src/generated/candidate/RainlangParser.sol
src/generated/candidate/RainlangStore.sol
src/generated/RainlangExpressionDeployerPointers.sol
src/generated/RainlangInterpreterPointers.sol
src/generated/RainlangParserPointers.sol
src/generated/RainlangStorePointers.sol
src/lib/LibRainlangReleased.sol
src/lib/LibRainlangExpressionDeployerReleased.sol
src/lib/LibRainlangInterpreterReleased.sol
src/lib/LibRainlangParserReleased.sol
src/lib/LibRainlangStoreReleased.sol
src/lib/LibReleasedSuites.sol
crates/bindings/abi/IExpressionDeployerV3.json
crates/bindings/abi/IInterpreterStoreV3.json
crates/bindings/abi/IInterpreterV4.json
crates/bindings/abi/IParserPragmaV1.json
crates/bindings/abi/IParserV2.json
crates/bindings/abi/Rainlang.json
crates/test_fixtures/abi/Rainlang.json
crates/test_fixtures/abi/RainlangExpressionDeployer.json
crates/test_fixtures/abi/RainlangInterpreter.json
crates/test_fixtures/abi/RainlangParser.json
crates/test_fixtures/abi/RainlangStore.json
crates/test_fixtures/abi/TestERC20.json
How that was derived
script/Build.sol declares five generated contracts — RainlangParser,
RainlangStore, RainlangInterpreter, RainlangExpressionDeployer, Rainlang.
Against rain-deploy-0.1.10's LibRainDeploySnapshot:
regenerateSnapshots() → writeSnapshot(..., CANDIDATE, <Contract>, ...)
→ src/generated/candidate/<Contract>.sol, one per contract.
regenerateLibs() calls writeReleasedSuitesLib (→ src/lib/Lib<Contract>Released.sol)
and writeReleasedSuitesAggregate (→ src/lib/LibReleasedSuites.sol). Note it
does not call writeAliasLib, so there is no Lib<Contract>Deploy.sol to
declare here — src/lib/deploy/LibInterpreterDeploy.sol is hand-maintained.
regenerateSnapshots() additionally calls four LibFs.buildFileForContract(...)
helpers → src/generated/{RainlangParser,RainlangStore,RainlangInterpreter,RainlangExpressionDeployer}Pointers.sol.
script/CopyArtifacts.sol walks LibCopyArtifacts.contracts() (11 names) and
writes each to LibCopyArtifacts.committedPaths(name): the five I* interfaces to
crates/bindings/abi/, Rainlang to both crates/bindings/abi/ and
crates/test_fixtures/abi/, and the four remaining concretes plus TestERC20 to
crates/test_fixtures/abi/. That is 12 committed JSON paths, all present in the
tree today. CopyArtifacts does vm.removeFile then vm.writeFile, so the file is
recreated on each run and the witness sees the mtime move.
Worth a look while you are here
script/BuildAuthoringMeta.sol exists, but rainix-copy-artifacts only runs
script/build-meta.sh / script/Build.sol / script/CopyArtifacts.sol /
script/build.sh — and this repo has no build-meta.sh or build.sh. So
meta/AuthoringMeta.rain.meta and meta/RainlangExpressionDeployer.rain.meta are
committed but never regenerated by CI, and are therefore not currency-checked
by anything today. They are deliberately left out of the manifest above (declaring
them would fail every run). Whether they should instead be brought under a
build-meta.sh hook is a separate question from this one.
Reconciling against the job
The failing verify step prints the manifest that run would justify — the set
of git-tracked files the hooks actually wrote in CI. Treat that printout as the
oracle and the list above as a cross-check derived by reading the hooks. A
difference either way is information, not noise:
- listed above, absent from the printout — that emitter may already be dead, or
the file is generated by something the copy-artifacts job does not run.
- printed, absent from above — an incidental write inside the witness window
(forge build is in there), or a generated file this reading missed.
Undeclared-but-written paths are a printed note, never a failure — the check is
a subset assertion, not set equality — so a conservative first manifest is safe and
an over-eager one is not.
Adoption
One commit adding script/codegen-manifest.txt. No workflow edit and no
RAINIX_SHA bump: #392 wires the witness as a composite action resolved at
@main, so nothing in this repo pins the check's version.
Filed while tracking the org-wide adoption cost of rainlanguage/rainix#392. The
paths above were derived by reading this repo's own hooks and committed tree, not
by running the job.
What changes, and when
rainlanguage/rainix#392 adds a
codegen witness to the
rainix-copy-artifactsreusable workflow. This repo's.github/workflows/git-clean.yamlcalls that workflow at@main, so the checkarrives the moment #392 merges — not when this repo chooses to adopt it. The
next push after that merge fails until a manifest is committed.
Why the check exists
rainix-copy-artifactscurrency-checks committed generated sources by re-runningthe codegen hooks and then
git diff --exit-code. That proves the committedcontent is current, but it is structurally blind to a generator that has
stopped emitting a file: the committed copy is already correct, so nothing is
rewritten, nothing differs, and the job is green over a dead emitter. Reproduced
with a control in
rainlanguage/rain.factory.deploy#35.
Seeing that needs an independent statement of which committed files are
generated. That is
script/codegen-manifest.txt: one repo-relative path per line,#comments and blank lines ignored. The witnessmarks every git-tracked file'smtime before the first hook and
verifys after the last, calling a filewritten when it exists and its mtime moved. Any declared path nothing wrote
fails the job by name.
Why this repo is affected
Hooks present:
script/Build.sol,script/CopyArtifacts.sol. Noscript/codegen-manifest.txttoday.What to add
script/codegen-manifest.txt:How that was derived
script/Build.soldeclares five generated contracts —RainlangParser,RainlangStore,RainlangInterpreter,RainlangExpressionDeployer,Rainlang.Against
rain-deploy-0.1.10'sLibRainDeploySnapshot:regenerateSnapshots()→writeSnapshot(..., CANDIDATE, <Contract>, ...)→
src/generated/candidate/<Contract>.sol, one per contract.regenerateLibs()callswriteReleasedSuitesLib(→src/lib/Lib<Contract>Released.sol)and
writeReleasedSuitesAggregate(→src/lib/LibReleasedSuites.sol). Note itdoes not call
writeAliasLib, so there is noLib<Contract>Deploy.soltodeclare here —
src/lib/deploy/LibInterpreterDeploy.solis hand-maintained.regenerateSnapshots()additionally calls fourLibFs.buildFileForContract(...)helpers →
src/generated/{RainlangParser,RainlangStore,RainlangInterpreter,RainlangExpressionDeployer}Pointers.sol.script/CopyArtifacts.solwalksLibCopyArtifacts.contracts()(11 names) andwrites each to
LibCopyArtifacts.committedPaths(name): the fiveI*interfaces tocrates/bindings/abi/,Rainlangto bothcrates/bindings/abi/andcrates/test_fixtures/abi/, and the four remaining concretes plusTestERC20tocrates/test_fixtures/abi/. That is 12 committed JSON paths, all present in thetree today.
CopyArtifactsdoesvm.removeFilethenvm.writeFile, so the file isrecreated on each run and the witness sees the mtime move.
Worth a look while you are here
script/BuildAuthoringMeta.solexists, butrainix-copy-artifactsonly runsscript/build-meta.sh/script/Build.sol/script/CopyArtifacts.sol/script/build.sh— and this repo has nobuild-meta.shorbuild.sh. Someta/AuthoringMeta.rain.metaandmeta/RainlangExpressionDeployer.rain.metaarecommitted but never regenerated by CI, and are therefore not currency-checked
by anything today. They are deliberately left out of the manifest above (declaring
them would fail every run). Whether they should instead be brought under a
build-meta.shhook is a separate question from this one.Reconciling against the job
The failing
verifystep prints the manifest that run would justify — the setof git-tracked files the hooks actually wrote in CI. Treat that printout as the
oracle and the list above as a cross-check derived by reading the hooks. A
difference either way is information, not noise:
the file is generated by something the copy-artifacts job does not run.
(
forge buildis in there), or a generated file this reading missed.Undeclared-but-written paths are a printed note, never a failure — the check is
a subset assertion, not set equality — so a conservative first manifest is safe and
an over-eager one is not.
Adoption
One commit adding
script/codegen-manifest.txt. No workflow edit and noRAINIX_SHAbump: #392 wires the witness as a composite action resolved at@main, so nothing in this repo pins the check's version.Filed while tracking the org-wide adoption cost of rainlanguage/rainix#392. The
paths above were derived by reading this repo's own hooks and committed tree, not
by running the job.