Skip to content

Migrate to the rolling-candidate snapshot model - #5

Open
thedavidmeister wants to merge 3 commits into
mainfrom
2026-07-25-rolling-candidate-model
Open

Migrate to the rolling-candidate snapshot model#5
thedavidmeister wants to merge 3 commits into
mainfrom
2026-07-25-rolling-candidate-model

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Migrates this repo to the rolling-candidate model that
S01-Issuer/st0x.deploy#283
adopted, mirroring it rather than inventing a variant. Adapted to this repo's
shape: one contract, one generated pin lib, no multi-contract alias machinery.

What changes

src/generated/candidate/ is new and rolling. script/BuildPointers.sol
now writes it unconditionally — deployTag() went from
vm.parseTomlString(vm.readFile("foundry.toml"), ".package.version") to a pure
function returning the constant "candidate". It is regenerated in full on every
run and committed, so it always describes what the current source compiles to.

src/lib/LibCloneFactoryDeploy.sol aliases candidate/ instead of 0_1_5/.
This is a semantic no-op today: candidate/CloneFactory.pointers.sol is
byte-identical to 0_1_5/CloneFactory.pointers.sol (diff is empty), because
0_1_5 is what the current source compiles to. Same address
0x7053c1D000192f1FeC1fbe20350139F3300dBBaD, same codehash. What changes is the
rule: the consumer-facing pin now tracks the source instead of tracking a
version number.

script/cut-release.sh is new — the direct analogue of st0x's. It cp -rs
candidate to src/generated/<tag>/, refusing on a non-X.Y.Z version (the
append-only gate's tag filter is numeric-only, so a 0_1_7-rc1 dir would be an
orphan snapshot nothing protects) and refusing to overwrite an existing tag dir.
package-release.yaml's snapshot-generate-cmd becomes
bash script/cut-release.sh; the rest of the release wiring was already correct
(on: push: tags: sol-v*rainix-tag-release) and is untouched.

testCandidateSelfConsistent replaces the version↔snapshot coupling. New
test/src/lib/LibCloneFactoryDeployCandidate.t.sol pins the whole chain:

current source -> candidate CREATION_CODE -> candidate DEPLOYED_ADDRESS
               -> LibCloneFactoryDeploy.CLONE_FACTORY_DEPLOYED_ADDRESS

[package].version is no longer read by any Solidity in this repo, so the
{ access = "read", path = "./foundry.toml" } fs permission is dropped too.

Frozen snapshots: all three kept

0_1_5 MUST survive and does. It is the repo's headline pin, live on all
five supported chains, and the only implementation the current source can build
(ICloneableFactoryV3cloneDeterministic, keccak256(abi.encode(deployer, salt)) namespacing, 5-arg NewClone). It is unaudited, and st0x#283's "keep
only the audited snapshot" move would have deleted it. Deleting it would delete
the reason this repo exists. It stays, unaudited, on purpose.

0_1_3/0_1_4 also stay. They hold the Protofire-audited
ICloneableFactoryV2 bytecode (0x444acC29d63fa643E8adCC35FD9aa6DE111dCb39),
which is also live on all five chains and is the pin S01-Issuer/st0x.deploy
consumes in production (via the rain-factory 0.1.1 Soldeer package).

So this migration touches nothing under src/generated/0_1_*. Simulating the
gate's own diff against main:

$ git diff --no-renames --name-status --diff-filter=MD main...HEAD -- src/generated
(empty)

candidate is invisible to the gate by construction —
rainix-static/src/frozen_snapshots.rs:19-25 is_tag() requires exactly three
_-separated all-numeric parts, and "candidate".split('_') has one. So it can
roll forever without any rainix change. candidate/ was generated fresh, never
git mv'd from a numbered dir (the gate passes --no-renames, so a move would
have been recorded as a deletion and flagged).

0_1_4 is a byte-identical duplicate — and I am leaving it

0_1_3 and 0_1_4 are the same file (sha256
fa92b0caa1084172240189245d1f6f7f018a56bec1f2c3d884ffe0ee358d225a for both) —
one bytecode snapshotted twice by autopublish version bumps, exactly the noise
#283 deleted from st0x. Dropping it would break nothing functional: no Soldeer
consumer exists (this repo has zero published revisions), no git tag names
it, its address is identical to 0_1_3's so no deployment record would be lost,
and the only code referencing it is its own test pair in
LibCloneFactoryDeployTaggedConstants.t.sol.

But the frozen-snapshots-append-only gate would block it.
parse_offenders flags status D as well as M, so deleting
src/generated/0_1_4/CloneFactory.pointers.sol produces an offender and turns
rainix-sol / static red. st0x#283 got past exactly this by being merged
red
under a one-off human sign-off. I am not doing that here: it is a separate
decision from the model migration, and it would trade a green PR for a cosmetic
cleanup. 0_1_4 stays. If you want it collapsed, that is its own
deliberately-red PR with its own sign-off.

Supersedes #4

#4 (17b69fb,
"Enforce that [package].version, its snapshot and the deploy lib agree")
implements the model this PR removes. It should be closed when this merges.
Its three assertions, disposed of individually:

  1. testDeployTagDEPLOY_TAG == foundry.toml [package].version. Dropped,
    not folded.
    The candidate model deliberately abolishes that invariant:
    DEPLOY_TAG is now the literal "candidate" and the version names nothing on
    disk, so the assertion would be false by design. This is also the weakness
    that motivates the change — it compares a name to a name, so editing
    CloneFactory without regenerating leaves it green while the pins silently
    misdescribe the source.
  2. testDeployTagSnapshotExistsfolded as a compile-time guarantee. The
    candidate test imports
    ../../../src/generated/candidate/CloneFactory.pointers.sol directly, so a
    missing snapshot is a compile error, not a runtime assertion. Enforce that [package].version, its snapshot and the deploy lib agree #4 needed
    vm.exists only because its DEPLOY_TAG string was decoupled from any
    import.
  3. testDeployTagSnapshotHoldsTheAliasedPinsfolded, and strengthened.
    Enforce that [package].version, its snapshot and the deploy lib agree #4 grepped the snapshot's file text for the rendered literals. The
    equivalent here is testCandidateIsTheAliasedSnapshot, which asserts the
    identity in Solidity against the imported constants — no file parsing — and it
    catches the real hazard Enforce that [package].version, its snapshot and the deploy lib agree #4 was aiming at: the generated lib left pointing at a
    frozen dir while candidate moves on. Mutation-proven below.

The DEPLOY_TAG constant itself — #4's genuinely good idea, making the aliased
snapshot readable without reading an import path — is kept, generated as
"candidate".

Mutation proof

A self-consistency test nobody has seen fail is worthless, so both directions
were broken and restored.

Mutant 1 — candidate disagrees with current source. One nibble flipped in
candidate/CloneFactory.pointers.sol line 21 col 300
(…90f35b61004b6100……90f35b61f04b6100…), i.e. the committed pin no longer
records what the source compiles to:

Ran 4 tests for .../LibCloneFactoryDeployCandidate.t.sol:LibCloneFactoryDeployCandidateTest
[FAIL: assertion failed: 0x872733555ced48eF5766e9e0601fE65FE6EfD58E != 0x7053c1D000192f1FeC1fbe20350139F3300dBBaD] testCandidateCreationDeploysToPinnedAddress()
[PASS] testCandidateIsTheAliasedSnapshot()
[PASS] testCandidateRuntimeHashesToBytecodeHash()
[FAIL: assertion failed: 0x6080…61f04b6100823660046104…56 != 0x6080…61004b6100823660046104…56] testCandidateSelfConsistent()
Suite result: FAILED. 2 passed; 2 failed; 0 skipped

Mutant 2 — generated lib left pointing at a frozen dir. Import repointed from
../generated/candidate/ to ../generated/0_1_3/ — the stale-headline-pin
scenario #4's third assertion was written for:

Ran 4 tests for .../LibCloneFactoryDeployCandidate.t.sol:LibCloneFactoryDeployCandidateTest
[PASS] testCandidateCreationDeploysToPinnedAddress()
[FAIL: assertion failed: 0x444acC29d63fa643E8adCC35FD9aa6DE111dCb39 != 0x7053c1D000192f1FeC1fbe20350139F3300dBBaD] testCandidateIsTheAliasedSnapshot()
[PASS] testCandidateRuntimeHashesToBytecodeHash()
[PASS] testCandidateSelfConsistent()
Suite result: FAILED. 3 passed; 1 failed; 0 skipped

Both restored with git checkout -- <file>, green again:

Ran 4 tests for .../LibCloneFactoryDeployCandidate.t.sol:LibCloneFactoryDeployCandidateTest
[PASS] testCandidateCreationDeploysToPinnedAddress() (gas: 316633)
[PASS] testCandidateIsTheAliasedSnapshot() (gas: 3708)
[PASS] testCandidateRuntimeHashesToBytecodeHash() (gas: 879)
[PASS] testCandidateSelfConsistent() (gas: 4706)
Suite result: ok. 4 passed; 0 failed; 0 skipped

Generator is reproducible

From the committed tree, regenerating produces no diff:

$ forge script ./script/BuildPointers.sol && forge fmt
$ git status --porcelain
(empty)

Docs

README.md said [package].version and the snapshot "only ever move together"
and implied a release history. Neither was true — Soldeer has zero
rain-factory-deploy revisions; nothing has ever been released from this repo.

(sol-v0.1.6 exists as a tag but its run died before publishing anything.)
README and CLAUDE.md now describe the candidate model, and foundry.toml
carries a note that version = "0.1.5" coincides with src/generated/0_1_5/ by
history, not by rule.

I deliberately did not bump the version: which number the first real release
carries is yours to pick, and it is worth knowing sol-v0.1.6 is already taken
as a tag even though it published nothing.

Open ruling for you — not decided here

st0x#283 could delete every unaudited snapshot because there audited == live ==
depended-on. Here they diverge:

pin audited live on 5 chains consumed in prod
0x444acC29… (0_1_3/0_1_4, V2) yes (Protofire, 1a92a86 + v0.1.1) yes yes (st0x.deploy, via rain-factory 0.1.1)
0x7053c1D0… (0_1_5, V3) no yes no

The repo's headline pin and only buildable implementation is unaudited, and the
audited implementation is not in the current source at all. Whether to audit V3
or revert to V2 is your call and this PR deliberately does not touch it
— which
is a further argument for the add-only shape: the migration is orthogonal to that
ruling and pre-empts it in neither direction.

One adjacent fact worth seeing: the split is incomplete. rain.factory main
still carries the entire deploy half (src/concrete/CloneFactory.sol,
src/generated/0_1_3|0_1_4|0_1_5, src/lib/LibCloneFactoryDeploy.sol,
script/BuildPointers.sol, script/Deploy.sol and all four test files), so both
pins currently have two owners.

Behaviour change to be aware of

Because the pin lib now tracks candidate, any change to CloneFactory's
bytecode makes the five LibCloneFactoryDeployProdTest fork tests red until that
bytecode is deployed. Previously they asserted "prod matches 0_1_5"; now they
assert "prod matches HEAD". That is the deploy-before-merge coupling made
explicit, and it is documented in CLAUDE.md.

Verification

forge build, forge fmt --check and reuse lint all pass. forge test is
24/24 green locally, including all five fork tests run against public RPC
endpoints — which also confirms candidate (== 0_1_5) matches prod on every
supported chain.

In CI expect exactly one red: testProdDeployArbitrum, failing with
lb.drpc.live … error code -32001 — an exhausted drpc quota on the
RPC_URL_ARBITRUM_FORK secret. It is pre-existing on main and unrelated to
this change; Arbitrum is confirmed green on chain by direct cast code probe, so
the red is purely the RPC. rainix-sol / static should be green — this PR
adds only, so the append-only gate has nothing to flag.

🤖 Generated with Claude Code


Corrections, 2026-08-13

The "Open ruling for you" table above is out of date on one row. It said 0x7053c1D0… (0_1_5, V3) was unaudited. It is not: Protofire r3.0, filed in rain.factory on 2026-07-31 (rainlanguage/rain.factory#49), audits commit c29d5827 / tag sol-v0.1.5 with src/concrete/CloneFactory.sol and src/lib/LibCloneFactoryDeploy.sol in scope and zero findings at every severity. src/generated/0_1_5/CloneFactory.pointers.sol at that audited commit is byte-identical to this repo's copy (sha256 d3def164…), so the audited tree pins the same address and codehash. The "audit V3 or revert to V2" ruling the table asked for therefore does not arise — V3 is audited, clean. #6 carries the inherited record.

The "Known CI red" note is also stale. The drpc-quota red is gone: rainix landed an archive-aware fork-RPC failover preflight (rainlanguage/rainix#289, merged 2026-08-08, plus #295 on 08-11), and this PR is now green on all three checks.

QA

Adding the evidence block the vetter rejected 5640894 for.

Discriminating tests. test/src/lib/LibCloneFactoryDeployCandidate.t.sol (4), pinning each link of current source -> candidate CREATION_CODE -> candidate DEPLOYED_ADDRESS -> LibCloneFactoryDeploy.CLONE_FACTORY_DEPLOYED_ADDRESS:

  • testCandidateSelfConsistent — the committed candidate snapshot's CREATION_CODE equals type(CloneFactory).creationCode. This is the gate that makes a rolling snapshot safe: edit CloneFactory without regenerating and it fails.
  • testCandidateIsTheAliasedSnapshotDEPLOY_TAG == "candidate" and the lib's address/codehash equal the candidate snapshot's. Catches the generated lib being left aliasing a frozen numbered dir while candidate moves on. Asserted in Solidity against imported constants, not by grepping file text.
  • testCandidateRuntimeHashesToBytecodeHashkeccak256(RUNTIME_CODE) == BYTECODE_HASH, the same internal consistency the frozen tags are held to.
  • testCandidateCreationDeploysToPinnedAddress — deploying the recorded CREATION_CODE through the etched Zoltu factory lands at the recorded DEPLOYED_ADDRESS with the recorded codehash, so freezing candidate at release time records a reproducible deployment.

Mutations applied, and what killed each. Applied one at a time to the committed tree, whole suite run, tree restored, baseline green.

mutation killed by
candidate/CREATION_CODE byte flipped (snapshot stale vs source) testCandidateSelfConsistent, testCandidateCreationDeploysToPinnedAddress
generated lib re-aliased to ../generated/0_1_5/ while candidate moves on testCandidateIsTheAliasedSnapshot
DEPLOY_TAG set to a version string instead of "candidate" testCandidateIsTheAliasedSnapshot
candidate/BYTECODE_HASH hand-edited testCandidateRuntimeHashesToBytecodeHash, testCandidateIsTheAliasedSnapshot
candidate/DEPLOYED_ADDRESS hand-edited testCandidateCreationDeploysToPinnedAddress, testCandidateIsTheAliasedSnapshot
deployTag() returning a numbered dir instead of the constant regeneration writes a numbered dir, testCandidateSelfConsistent then fails on the unchanged candidate

The freeze path, which the vetter flagged as untested bash, is now covered by an in-script assertion and was exercised directly. script/cut-release.sh was also wrong in ordering and is fixed in 7288d30: it froze the numbered dir from the committed candidate and only then regenerated, so a candidate that had drifted from source would be frozen stale into an append-only dir while the regeneration silently moved candidate on — publishing one address and permanently recording another, with nothing downstream able to catch it (testCandidateSelfConsistent checks the regenerated candidate; no test compares a numbered dir to candidate). Now regenerate → forge fmt → copy → diff -r assertion that the frozen dir and candidate are byte-identical.

Exercised with forge stubbed, since the bash is what is under test:

STUB forge script ./script/BuildPointers.sol
STUB forge fmt
cut-release: freezing candidate -> src/generated/0_9_9
exit=0
--- diff candidate vs 0_9_9 ---
IDENTICAL
--- re-run must refuse ---
cut-release: src/generated/0_9_9 already exists — refusing to overwrite a frozen release snapshot
exit=1

Also covered by the same run: the strict X.Y.Z version guard, the missing-candidate guard, and a clean tree afterwards.

OracleS01-Issuer/st0x.deploy#283 as the model being mirrored, rainix-static/src/frozen_snapshots.rs is_tag() read directly for why candidate is invisible to the append-only gate (three _-separated all-numeric parts; "candidate" has one), and rainix-tag-release.yaml at main read directly for the release step order the script has to slot into. All independent of this diff.

Category check. The ask is to migrate this repo to the rolling-candidate model. Covered: candidate/ added and rolling, the pin lib aliases it, [package].version no longer read by any Solidity (and its fs_permissions read dropped), cut-release.sh freezes at release time, package-release.yaml wired to it, docs rewritten, and all three frozen 0_1_* snapshots untouched (git diff --diff-filter=MD main...HEAD -- src/generated is empty).

Still open for the human, not decided here: the vetter's point that cut-release.sh hand-rolls the freeze in bash rather than using a shared LibSnapshot mechanism stands. The ordering bug above is an argument in its favour. It is a cross-repo refactor, not this PR.

BuildPointers now writes src/generated/candidate/ unconditionally instead of a
dir named after [package].version, and LibCloneFactoryDeploy aliases it, so the
pins consumers import always describe the current source. script/cut-release.sh
freezes candidate as src/generated/<tag>/ at release time and is the only thing
that creates a numbered snapshot. LibCloneFactoryDeployCandidateTest ties the
candidate snapshot to the source, to its own recorded address, and to the lib.

The three existing frozen snapshots are untouched: 0_1_5 is the live headline
pin and 0_1_3/0_1_4 hold the audited bytecode, all live on all five chains.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Jul 25, 2026
@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@thedavidmeister, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 105 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 387269f7-410a-41a2-91cb-0e73dc730feb

📥 Commits

Reviewing files that changed from the base of the PR and between 6173d3e and a4548f9.

⛔ Files ignored due to path filters (1)
  • src/generated/candidate/CloneFactory.pointers.sol is excluded by !**/generated/**
📒 Files selected for processing (10)
  • .gas-snapshot
  • .github/workflows/package-release.yaml
  • CLAUDE.md
  • README.md
  • foundry.toml
  • script/BuildPointers.sol
  • script/cut-release.sh
  • src/lib/LibCloneFactoryDeploy.sol
  • test/src/lib/LibCloneFactoryDeployCandidate.t.sol
  • test/src/lib/LibCloneFactoryDeployTaggedConstants.t.sol
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-07-25-rolling-candidate-model

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@thedavidmeister

Copy link
Copy Markdown
Contributor Author

CI landed exactly as predicted at 5640894.

  • rainix-sol / staticpass. The frozen-snapshots-append-only gate had nothing to flag: this PR adds src/generated/candidate/ and touches no 0_1_* dir.
  • rainix-sol / legalpass.
  • rainix-sol / test23 passed, 1 failed (24 total), the one red being the known pre-existing drpc quota:
Ran 4 tests for test/src/lib/LibCloneFactoryDeployCandidate.t.sol:LibCloneFactoryDeployCandidateTest
Suite result: ok. 4 passed; 0 failed; 0 skipped

Ran 5 tests for test/src/lib/LibCloneFactoryDeployProd.t.sol:LibCloneFactoryDeployProdTest
[FAIL: vm.createSelectFork: could not instantiate forked environment with provider lb.drpc.live; server returned an error response: error code -32001: You've reached the usage limit for your current plan...] testProdDeployArbitrum() (gas: 3212)
Suite result: FAILED. 4 passed; 1 failed; 0 skipped

Ran 5 test suites: 23 tests passed, 1 failed, 0 skipped (24 total tests)

That is an RPC quota on the RPC_URL_ARBITRUM_FORK secret, not a pin mismatch — Arbitrum is confirmed live at the pinned address by direct cast code probe, and locally the same suite is 24/24 green against public endpoints. The other four fork tests (Base, Base Sepolia, Flare, Polygon) pass in CI, which is itself confirmation that candidate matches production.

@thedavidmeister thedavidmeister added the ai:needs-work AI vetter: needs rework (code issue) label Jul 28, 2026
@thedavidmeister

Copy link
Copy Markdown
Contributor Author

🤖 ai:vetter
Reviewed 5640894: reject — Missing QA evidence block (QA-GUIDE §8) — no ## QA section in body or trusted producer comment. Substance audits sound (candidate==0_1_5 verified, mutation-proven test chain, frozen tags untouched); note for the human ruling: cut-release.sh hand-rolls the freeze in untested bash vs the shared LibSnapshot mechanism (st0x#283-conformant). Supersedes #4 — do not land both.
cost 638 — release-model migration, freeze-path bash

@thedavidmeister thedavidmeister added ai:blocked-on AI producer: blocked on a dependency PR and removed ai:needs-work AI vetter: needs rework (code issue) labels Jul 28, 2026
@thedavidmeister

Copy link
Copy Markdown
Contributor Author

🤖 ai:producer
Blocked-on: Blocked on rainlanguage/rainix#289 (fork-RPC failover preflight), which is now ai:design pending a human ruling. The single failing test is testProdDeployArbitrum and it fails entirely upstream of this diff: vm.createSelectFork could not instantiate a forked environment because drpc returned error code -32001, You've reached the usage limit for your current plan. 23 of 24 tests pass. Foundry maps one rpc_endpoints alias to exactly one URL and --fork-retries only re-hits that same dead URL, so no code change in this repo can route around an exhausted vendor quota. Goes green once the failover lands on rainix main.

script/cut-release.sh is what rainix-tag-release runs as its snapshot-generate-cmd,
so this is the code that will cut this repo's first real release (rain.factory#46
step 3). It froze the numbered snapshot from the committed candidate and only
then re-ran BuildPointers.

That order is silently wrong whenever the committed candidate has drifted from
the source. The copy freezes the stale bytes into src/generated/<tag>/, which the
frozen-snapshots-append-only gate then protects forever, and the regeneration
immediately moves candidate on to the real ones. The release publishes a
LibCloneFactoryDeploy aliasing the new address while permanently recording the
old one as what that version shipped.

Nothing downstream catches it. testCandidateSelfConsistent compares the
REGENERATED candidate to the source, so it is green either way, and no test
compares a numbered dir to candidate. The append-only gate only sees an added
dir. The failure is invisible until someone tries to reproduce the release.

Reordered so the frozen dir is a copy of a candidate already known to match the
source, with forge fmt also moved ahead of the copy so the two are byte-identical
rather than differing by formatting. Added a diff -r assertion after the copy so
the property is checked, not assumed.

No behaviour change when candidate is already fresh, which is the normal case CI
enforces on main. This is the abnormal case: tagging while main is red.

Docs corrected to match — CLAUDE.md stated the old order in two places.
…for the first release

This branch's README already said "sol-v0.1.6 exists as a tag but its release run
failed before publishing anything" without saying why. The why matters, because
cutting the first real release (rain.factory#46 step 3) is the next human action
in this repo and the same failure would eat it.

Run 30097157490 reached "Verify live chain matches the fresh pins" and died with
all five fork tests reporting `vm.createSelectFork: environment variable
<NETWORK>_RPC_URL not found`. rainix-tag-release exported the endpoints under the
SECRET names (RPC_URL_<NETWORK>_FORK) while foundry.toml's [rpc_endpoints] read
the <NETWORK>_RPC_URL form, so every one resolved empty. Publish, commit-back and
GitHub Release were skipped -- hence a tag with no revision, no release and no
0_1_6 snapshot.

That was a rainix defect, since fixed there: the reusable now runs rpc-preflight,
binding each env name foundry reads to an endpoint probed healthy at that moment.

Recorded with the two consequences a releaser needs: sol-v0.1.6 is spent (it
names a commit five behind main; cut a fresh tag, though the 0.1.6 version number
is still free on the registry since nothing published), and the fork RPCs still
gate the release -- they are currently intermittent, and a transient failure
there means tagging again, not rerunning.

Also corrected the cut-release.sh description one paragraph up to match the
regenerate-then-freeze order this branch now uses.
@thedavidmeister

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

This PR has never been reviewed — CodeRabbit has zero reviews on it (it began reviewing this repo around 2026-08-08, after this PR was opened on 07-25, and did not retro-review). Requesting a full review of the current head before it is considered for merge.

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

@thedavidmeister I will review the current head of this pull request.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai:blocked-on AI producer: blocked on a dependency PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant