Skip to content

ci: one canonical generated-sources dir for all three mechanisms - #318

Open
thedavidmeister wants to merge 1 commit into
mainfrom
2026-08-16-issue-313
Open

ci: one canonical generated-sources dir for all three mechanisms#318
thedavidmeister wants to merge 1 commit into
mainfrom
2026-08-16-issue-313

Conversation

@thedavidmeister

Copy link
Copy Markdown
Contributor

Closes #313

What

Three rainix mechanisms each spelled out src/generated by hand, so moving the
canonical directory moves none of them — every restatement keeps matching
nothing, and the check it guards goes quietly inert instead of red:

  • rainix-copy-artifacts.yaml's [ -d src/generated ] currency guard — stops
    hard-failing a repo that commits generated sources without script/Build.sol;
  • frozen-snapshots-append-only's ls src/generated/*/*.pointers.sol probe —
    stops policing the frozen deploy-pin snapshots consumers pin constants from;
  • soldeer-gate's content exclusion (behind rainix-autopublish.yaml) — stops
    excluding generated files, so every regeneration reads as a content change and
    the package republishes on runs that changed nothing.

How

rainix-static generated-dir prints the one value, backed by a single
GENERATED_DIR constant at the crate root. The two workflow-side mechanisms ask
the binary for it; the two Rust-side ones (soldeer-gate's exclusion prefix and
snapshots-append-only's default --root) read the constant directly, so the
action no longer passes --root at all.

Both shell sites run under set -euo pipefail, so a failed lookup fails the step
rather than probing "" and skipping the guard it exists to enforce — that would
be the same silent disable this issue is about.

src/generated now appears exactly once as a value in rainix. The remaining
mentions are prose (the action's description, workflow comments, README)
describing the current path.

QA

  • Discriminating tests: the 8 cases in test/bats/action/generated-dir.test.bats
    (generated-dir prints the one directory…, copy-artifacts hard-fails on generated sources with no script/Build.sol, copy-artifacts does not guard a directory the binary does not name, copy-artifacts fails loudly when the canonical directory cannot be read, frozen-snapshots checks per-tag snapshots under the directory the binary names, frozen-snapshots skips snapshots outside the directory the binary names, frozen-snapshots fails loudly when the canonical directory cannot be read, snapshots-append-only defaults its root to the canonical directory) plus
    soldeer_gate::tests::norm_hash_excludes_the_canonical_generated_dir and
    …::norm_hash_excludes_only_that_dir. All 8 bats cases were run against the
    unfixed tree and all 8 failed (rainix-static: unknown subcommand "generated-dir"; both YAML mechanisms followed their own literal rather than
    the directory the binary named). The 2 Rust cases fail to compile on base —
    crate::GENERATED_DIR does not exist there.
  • Mutations applied: 8, each killed —
    (1) rainix-copy-artifacts.yaml [ -d "$GENERATED_DIR" ] -> [ -d src/generated ] -> tests 2, 3;
    (2) that step's set -euo pipefail -> deleted -> test 4;
    (3) frozen-snapshots-append-only/action.yml ls "$GENERATED_DIR"/*/*.pointers.sol -> ls src/generated/*/*.pointers.sol -> tests 5, 6;
    (4) that action's set -euo pipefail -> deleted -> test 7;
    (5) main.rs println!("{GENERATED_DIR}") -> println!("src/gen") -> tests 1, 8;
    (6) main.rs --root default GENERATED_DIR.to_string() -> "src/gen".to_string() -> test 8;
    (7) soldeer_gate.rs entries.retain(…) -> deleted -> norm_hash_excludes_the_canonical_generated_dir (108 passed, 1 failed);
    (8) soldeer_gate.rs format!("{}/", GENERATED_DIR) -> GENERATED_DIR.to_string() -> norm_hash_excludes_only_that_dir (108 passed, 1 failed).
  • Oracle: the issue's own failure scenario, not the implementation. Each
    mechanism is driven with gen/out — a directory that is neither src/generated
    nor a prefix or suffix of it — reported by a stubbed binary, and asserted to
    follow it AND to ignore a real src/generated sitting beside it. A hardcoded
    literal fails in both directions, so the test cannot pass by agreeing with the
    code it checks. The expected exit statuses come from what the issue says each
    mechanism must do (hard-fail, police, exclude), not from reading the scripts.
  • Category check: the issue names three mechanisms — the copy-artifacts guard,
    frozen-snapshots-append-only, and the autopublish soldeer content gate. All
    three covered, plus the fourth restatement the same defect had left in
    snapshots-append-only's default --root. The consumer-side half is
    explicitly tracked elsewhere (rain.sol.codegen#77) and is not in this diff.
  • nix develop -c bats test/bats/action/generated-dir.test.bats — 8/8 green. All
    8 were red before the fix (rainix-static: unknown subcommand "generated-dir",
    and both YAML mechanisms following their own literal rather than the directory
    the binary named).
  • nix develop .#rust-shell -c cargo test --manifest-path rainix-static/Cargo.toml
    — 109 passed, 0 failed, including the two new soldeer_gate cases.
  • nix develop -c default-shell-test — the full CI bats task from
    check-shell.yml, with the new file registered in it: every test green except
    the 3 prettier-bundle cases, which fail identically on unmodified
    origin/main in this environment ($prettier_entry resolves empty, so bash
    runs the fixture name as a command). Verified against a clean origin/main
    worktree, not assumed.
  • nix develop -c pre-commit run --all-files — nixfmt, no-consumer-prettier,
    prettier-rainix, shellcheck, statix, taplo and yamlfmt all pass. The
    rustfmt-conditional hook fails, and fails the same way on unmodified
    origin/main (it runs cargo fmt from the repo root, which has no
    Cargo.toml); the Rust in this PR is clean under
    cargo fmt --check --manifest-path rainix-static/Cargo.toml.
  • Confirmed empirically that both nix develop …#sol-shell -c rainix-static generated-dir and nix run …#rainix-static -- generated-dir put nothing but
    src/generated on stdout (devshell and build chatter go to stderr), so the two
    command substitutions capture the value and not shell-hook noise.
  • Mutation pass — eight mutants, each killed by the named test:
    1. copy-artifacts guard back to [ -d src/generated ] → tests 2, 3 red.
    2. copy-artifacts set -euo pipefail removed → test 4 red (the step exits 0
      with the guard silently skipped, which is exactly the failure mode).
    3. action probe back to ls src/generated/*/*.pointers.sol → tests 5, 6 red.
    4. action set -euo pipefail removed → test 7 red.
    5. generated-dir printing src/gen → tests 1, 8 red.
    6. snapshots-append-only default --root hardcoded to src/gen → test 8 red.
    7. norm_hash's exclusion retain deleted →
      soldeer_gate::tests::norm_hash_excludes_the_canonical_generated_dir FAILED
      (108 passed, 1 failed).
    8. exclusion prefix without the trailing /
      soldeer_gate::tests::norm_hash_excludes_only_that_dir FAILED (108 passed,
      1 failed).

Notes

The copy-artifacts currency guard, the frozen deploy-pin snapshot check and
the soldeer content gate each spelled out `src/generated` by hand. Move the
path moves nothing else: every restatement keeps matching nothing and each
check goes quietly inert instead of red.

`rainix-static generated-dir` is now the one value. The two workflow-side
mechanisms ask the binary for it (under `set -e`, so a failed lookup fails
the step rather than probing an empty path), and the Rust-side ones —
`soldeer-gate`'s content exclusion and `snapshots-append-only`'s default
`--root` — read the constant directly.

Closes #313
@thedavidmeister thedavidmeister self-assigned this Aug 16, 2026
@coderabbitai

coderabbitai Bot commented Aug 16, 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: 16 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3744f27f-20de-40e3-b67e-40289c185acf

📥 Commits

Reviewing files that changed from the base of the PR and between 7f223b4 and a815517.

📒 Files selected for processing (6)
  • .github/actions/frozen-snapshots-append-only/action.yml
  • .github/workflows/rainix-copy-artifacts.yaml
  • flake.nix
  • rainix-static/src/main.rs
  • rainix-static/src/soldeer_gate.rs
  • test/bats/action/generated-dir.test.bats

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.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Three rainix mechanisms hardcode src/generated independently instead of reading one canonical value

2 participants