rainix-autopublish's only test step is Cargo test:
- name: Cargo test
if: ${{ (inputs.crates != '' || inputs.crate != '') && (steps.cargo.outputs.changed == 'true' || steps.npm.outputs.changed == 'true' || steps.soldeer.outputs.changed == 'true') }}
A Soldeer-only caller passes neither crates nor crate, so the condition is false and no test runs at all before forge soldeer push. rain.solmem's package-release.yaml passes only soldeer-package: rain-solmem.
Nothing else covers the gap on the caller's side either. package-release.yaml and the caller's rainix.yaml both fire on push: branches: [main], so the publish runs concurrently with the test suite, not after it. A merge that breaks forge test publishes an immutable Soldeer revision and creates the GitHub Release before the red check has a verdict.
Evidence
rain.solmem has published 12 revisions this way (sol-v0.1.4 .. sol-v0.1.15, 2026-07-25 to 2026-08-18). No publishing run executed forge test. Several of those revisions changed memory-writing assembly:
0.1.4 — unsafeExtend out-of-bounds write fix (both array libraries)
0.1.10 — unchecked mul(_, 0x20) word-scaling guards, matrix flatten allocation fix
0.1.13 — unsafeExtend(a, a) rerouted through the allocating path
Why gating is safe here, unlike #303
#303 argues against a full-suite gate in rainix-tag-release because a tag is spent once used, so a flaky test burns a release. rainix-autopublish has the opposite failure mode: on a failed run nothing is published, [package].version stays in-dev, and the next push to main retries the same version for free. A red gate costs a rerun, not a burned version.
Proposed fix
A Soldeer test step mirroring the Cargo one, before Publish to Soldeer:
- name: Sol test
if: ${{ inputs.soldeer-package != '' && steps.soldeer.outputs.changed == 'true' }}
run: nix develop github:rainlanguage/rainix/${{ env.RAINIX_SHA }}#sol-shell -c forge test
Gated on changed == 'true' for the same reason the Cargo step is: an unchanged push short-circuits without paying for the suite.
Spun out of rainlanguage/rain.solmem#87, which is fixed in-repo only as far as the changelog artifact goes. This half is shared CI and belongs here.
rainix-autopublish's only test step isCargo test:A Soldeer-only caller passes neither
cratesnorcrate, so the condition is false and no test runs at all beforeforge soldeer push. rain.solmem'spackage-release.yamlpasses onlysoldeer-package: rain-solmem.Nothing else covers the gap on the caller's side either.
package-release.yamland the caller'srainix.yamlboth fire onpush: branches: [main], so the publish runs concurrently with the test suite, not after it. A merge that breaksforge testpublishes an immutable Soldeer revision and creates the GitHub Release before the red check has a verdict.Evidence
rain.solmem has published 12 revisions this way (
sol-v0.1.4..sol-v0.1.15, 2026-07-25 to 2026-08-18). No publishing run executedforge test. Several of those revisions changed memory-writing assembly:0.1.4—unsafeExtendout-of-bounds write fix (both array libraries)0.1.10— uncheckedmul(_, 0x20)word-scaling guards, matrixflattenallocation fix0.1.13—unsafeExtend(a, a)rerouted through the allocating pathWhy gating is safe here, unlike #303
#303 argues against a full-suite gate in
rainix-tag-releasebecause a tag is spent once used, so a flaky test burns a release.rainix-autopublishhas the opposite failure mode: on a failed run nothing is published,[package].versionstays in-dev, and the next push tomainretries the same version for free. A red gate costs a rerun, not a burned version.Proposed fix
A Soldeer test step mirroring the Cargo one, before
Publish to Soldeer:Gated on
changed == 'true'for the same reason the Cargo step is: an unchanged push short-circuits without paying for the suite.Spun out of rainlanguage/rain.solmem#87, which is fixed in-repo only as far as the changelog artifact goes. This half is shared CI and belongs here.