You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
The published package is never compiled as published, and ships a file whose import it excludes #76
Three reviewers found this independently, from three different artifacts:
the published 0.1.11 zip (twice) and a vendored 0.1.6 at /home/gildlab/code/rain-deploy-15a/dependencies/rain-sol-codegen-0.1.6.
.soldeerignore is a second, hand-maintained definition of "what this library
is", disjoint from the source graph forge build compiles. Nothing checks the
two agree, so the published artifact can be broken or incomplete with a green
main.
.soldeerignore excludes /test but not /script or src/generated. script/Build.sol:8 imports {CodeGennable} from "../test/concrete/CodeGennable.sol". The published zip contains script/Build.sol and src/generated/CodeGennable.sol, and no test/. The
shipped script/Build.sol therefore cannot compile in any consumer. No CI step
ever builds the filtered tree, so this has been true across releases with no red.
Nothing breaks today because foundry only compiles dependency files something
imports — but the repo's only worked example of the library, the thing a
consumer copies, cannot be compiled from the package.
The latent import is the symptom; the shape is what lands next. Add src/lib/LibNewThing.sol imported by LibCodeGen.sol, and add any .soldeerignore pattern that happens to match it (the file already mixes
anchored /audit with unanchored .github, so pattern edits are easy to get
wrong) — the package publishes without it, every consumer's forge build breaks
on the next soldeer install, and this repo's own CI stays green because the
local tree is complete.
Proposed fix
Two halves:
Compile the package as published, in CI, on every push — a job that unpacks
what .soldeerignore would ship into a scratch project and builds it, failing
on any unresolved import.
Remove the inconsistency now: either move CodeGennable to src/concrete/CodeGennable.sol (its generated counterpart src/generated/CodeGennable.sol already ships) and update the imports in script/Build.sol, test/lib/LibFs.buildFileForContract.t.sol:8 and test/lib/LibCodeGen.bytecodeHashConstantString.t.sol:8 (both test/src/lib/
after Move every .t.sol into the test/src/lib mirror tree #56) — or add /script to .soldeerignore, which drops the example from the package
altogether.
Closing: one clause is void, the other is not this repo's to land.
"ships a file whose import it excludes" — void.#138 deleted script/Build.sol and src/generated/CodeGennable.sol under the ruling that the
worked example leaves this repo. Verified against the real artifact rather than
the repo tree: rain-sol-codegen~0.1.34 installed from the Soldeer registry
contains exactly eleven files —
no script/, no src/generated/, no test/. Every import under src/ resolves
inside src/ or to forge-std-1.16.2; nothing shipped points into test/.
Copied to a scratch consumer with the three build-config files .soldeerignore
excludes, forge soldeer install && forge build gives Compiling 8 files with Solc 0.8.25 / Compiler run successful!, exit 0.
PR #129, the repo-side attempt at this clause, was closed unmerged: its own diff
was empty against post-#138 main, and landing it would have pushed a test-only
fixture into the published package.
"never compiled as published" — upstream, and needs no wiring here. rainlanguage/rainix#316 adds uses: rainlanguage/rainix/.github/actions/soldeer-package-build@main inside the
existing static job of rainix-sol-static.yaml, with rainix-sha as its only
input — no consumer inputs, no opt-in. This repo's .github/workflows/ is two
files with zero steps of their own, both calling rainix reusables, so the gate
starts running on every push here the moment #316 merges. A local job would be
this repo's first inline CI and would fork shared CI into a consumer.
Same rule as #89 and #82: the thing that owns a fact is where it gets fixed.
Shared CI lives in rainix's reusables, not re-implemented per consumer.
One gap neither covers, noted rather than filed. #316 catches a .soldeerignore exclusion that something shipped imports. Nothing anywhere
makes a positive statement of what the library's public surface is, so an
accidental omission — a file that should ship and does not — stays invisible.
That is a third concern, not in this issue's scope, and is worth its own issue if
it matters.
Activity
thedavidmeister commentedon Aug 17, 2026
Closing: one clause is void, the other is not this repo's to land.
"ships a file whose import it excludes" — void. #138 deleted
script/Build.solandsrc/generated/CodeGennable.solunder the ruling that theworked example leaves this repo. Verified against the real artifact rather than
the repo tree:
rain-sol-codegen~0.1.34installed from the Soldeer registrycontains exactly eleven files —
no
script/, nosrc/generated/, notest/. Every import undersrc/resolvesinside
src/or toforge-std-1.16.2; nothing shipped points intotest/.Copied to a scratch consumer with the three build-config files
.soldeerignoreexcludes,
forge soldeer install && forge buildgivesCompiling 8 files with Solc 0.8.25 / Compiler run successful!, exit 0.PR #129, the repo-side attempt at this clause, was closed unmerged: its own diff
was empty against post-#138 main, and landing it would have pushed a test-only
fixture into the published package.
"never compiled as published" — upstream, and needs no wiring here.
rainlanguage/rainix#316addsuses: rainlanguage/rainix/.github/actions/soldeer-package-build@maininside theexisting static job of
rainix-sol-static.yaml, withrainix-shaas its onlyinput — no consumer inputs, no opt-in. This repo's
.github/workflows/is twofiles with zero steps of their own, both calling rainix reusables, so the gate
starts running on every push here the moment #316 merges. A local job would be
this repo's first inline CI and would fork shared CI into a consumer.
Same rule as #89 and #82: the thing that owns a fact is where it gets fixed.
Shared CI lives in rainix's reusables, not re-implemented per consumer.
One gap neither covers, noted rather than filed. #316 catches a
.soldeerignoreexclusion that something shipped imports. Nothing anywheremakes a positive statement of what the library's public surface is, so an
accidental omission — a file that should ship and does not — stays invisible.
That is a third concern, not in this issue's scope, and is worth its own issue if
it matters.