rainix-sol-static gates Solidity with forge fmt --check, but nothing in the
pre-commit suite it generates looks at a .sol file. So a Solidity repo can
commit with every hook green and red CI on formatting alone — which is what just
happened on rainlanguage/rain.deploy#26 (commit
eb0b3f5: all 11 hooks passed, rainix / static failed on one over-long call
in a test file, one more commit and one more full CI run to fix).
The drift
.github/workflows/rainix-sol-static.yaml runs, as workflow steps:
slither .
forge fmt --check
rainix-sol-single-contract
The generated .pre-commit-config.yaml in a consumer holds eleven hooks —
deadnix, denofmt, nil, nixfmt, no-consumer-prettier,
prettier-rainix, rustfmt-conditional, shellcheck, statix, taplo,
yamlfmt. None of them match \.sol$. On a pure-Solidity change every hook
reports "no files to check" and the commit succeeds.
Rust does not have this problem: rustfmt-conditional is a hook, so
cargo fmt drift is caught at commit time. Solidity has no equivalent, and it
is the same formatter-drift failure the same suite already solved once.
Ask
Add a forgefmt-conditional hook to the sol shell's git-hooks.nix, guarded
the way rustfmt-conditional is (command -v forge || exit 0, so the
flake-check sandbox and non-Solidity repos skip it), matching files: \.sol$.
That makes forge fmt drift a commit-time failure in the shell CI already
pins, rather than a CI round trip.
The same shape, not in this ask
slither, rainix-sol-single-contract, no-ignored-tests, no-submodules,
frozen-snapshots-append-only and no-custom-natspec are also CI-only with no
local hook. Formatting is the one that fires most often and is purely
mechanical, so it is worth fixing on its own; whether the rest belong in
pre-commit is a separate call — several are repo-state checks rather than
per-file ones, and slither is too slow for a commit hook.
Also worth a look while in there
rain.deploy/CLAUDE.md documents nix develop -c rainix-sol-static as the
local static command. That binary is not on the consumer devshell's PATH —
it fails exec: rainix-sol-static: not found. There is no single local command
for the sol static gate today, which is part of why the drift goes unnoticed.
rainix-sol-staticgates Solidity withforge fmt --check, but nothing in thepre-commit suite it generates looks at a
.solfile. So a Solidity repo cancommit with every hook green and red CI on formatting alone — which is what just
happened on rainlanguage/rain.deploy#26 (commit
eb0b3f5: all 11 hooks passed,rainix / staticfailed on one over-long callin a test file, one more commit and one more full CI run to fix).
The drift
.github/workflows/rainix-sol-static.yamlruns, as workflow steps:slither .forge fmt --checkrainix-sol-single-contractThe generated
.pre-commit-config.yamlin a consumer holds eleven hooks —deadnix,denofmt,nil,nixfmt,no-consumer-prettier,prettier-rainix,rustfmt-conditional,shellcheck,statix,taplo,yamlfmt. None of them match\.sol$. On a pure-Solidity change every hookreports "no files to check" and the commit succeeds.
Rust does not have this problem:
rustfmt-conditionalis a hook, socargo fmtdrift is caught at commit time. Solidity has no equivalent, and itis the same formatter-drift failure the same suite already solved once.
Ask
Add a
forgefmt-conditionalhook to the sol shell'sgit-hooks.nix, guardedthe way
rustfmt-conditionalis (command -v forge || exit 0, so theflake-check sandbox and non-Solidity repos skip it), matching
files: \.sol$.That makes
forge fmtdrift a commit-time failure in the shell CI alreadypins, rather than a CI round trip.
The same shape, not in this ask
slither,rainix-sol-single-contract,no-ignored-tests,no-submodules,frozen-snapshots-append-onlyandno-custom-natspecare also CI-only with nolocal hook. Formatting is the one that fires most often and is purely
mechanical, so it is worth fixing on its own; whether the rest belong in
pre-commit is a separate call — several are repo-state checks rather than
per-file ones, and
slitheris too slow for a commit hook.Also worth a look while in there
rain.deploy/CLAUDE.mddocumentsnix develop -c rainix-sol-staticas thelocal static command. That binary is not on the consumer devshell's PATH —
it fails
exec: rainix-sol-static: not found. There is no single local commandfor the sol static gate today, which is part of why the drift goes unnoticed.