What foundry.lock is
foundry.lock is Foundry's git submodule lockfile. It records the commit each dependency vendored under lib/ is pinned to, so forge install / forge update can restore identical submodule revisions. It is only meaningful in a repo that vendors dependencies as git submodules.
Why it is dead in this repo
There is no .gitmodules and no lib/ directory on main. Dependencies come from soldeer: foundry.toml sets libs = ['dependencies'], and soldeer.lock is the live lockfile for the 7 packages that land under dependencies/:
@openzeppelin-contracts 5.6.1
forge-std 1.16.1
rain-datacontract 0.1.0
rain-deploy 0.1.3
rain-sol-codegen 0.1.0
rain-solmem 0.1.3
rain-string 0.2.0
foundry.lock meanwhile still carries 6 submodule pins, every one of them for a lib/ path that does not exist in the tree:
{
"lib/forge-std": {
"rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6"
},
"lib/rain.datacontract": {
"rev": "3bff30782e408386f73b9353c5122e2e0ab24df2"
},
"lib/rain.deploy": {
"rev": "ccfdb378d2ab1ed95461ecf1355682250e487e4c"
},
"lib/rain.math.fixedpoint": {
"rev": "8308cbb6da0e231c6f3437f1861e66eff7ea2b00"
},
"lib/rain.sol.codegen": {
"rev": "dfe95884edfde3d4faf51046dc392aa9221bb0a7"
},
"lib/rain.string": {
"rev": "488f237cd59874e4eb91b5a4f747bd57578fec7f"
}
}
It is stale in two distinct ways:
- It contradicts the live pins.
1801b054 is forge-std v1.14.0 while soldeer resolves 1.16.1.
- It describes a different dependency set. It pins
lib/rain.math.fixedpoint, which has no counterpart in soldeer.lock at all, and it has no entry for @openzeppelin-contracts or rain-solmem, which are live.
Nothing reconciles any of it, because nothing reads the foundry.lock side.
Submodules also cannot come back: rainix CI runs a no-submodules check that fails on a root .gitmodules or any committed gitlink, so there is no future in which these pins become live again.
It is not silent
forge build emits one warning per entry in this file — 6 warnings on every build here, verified in the pinned rainix#sol-shell:
Warning: Dependency 'lib/forge-std' not found at expected path
Warning: Dependency 'lib/rain.datacontract' not found at expected path
Warning: Dependency 'lib/rain.deploy' not found at expected path
Warning: Dependency 'lib/rain.math.fixedpoint' not found at expected path
Warning: Dependency 'lib/rain.sol.codegen' not found at expected path
Warning: Dependency 'lib/rain.string' not found at expected path
Everything dangling in this repo
foundry.lock is not the only thing the submodule → soldeer migration left behind. Every reference below names a path that does not exist on main — but absence on its own is not what makes a reference removable, and REUSE.toml and .soldeerignore do not behave the same way. Read Which of these actually get removed below before deleting anything.
The dead lockfile and its references
foundry.lock — the file itself
REUSE.toml line 30 — "foundry.lock", in the annotation path list
.soldeerignore line 22 — /foundry.lock
Submodule paths that no longer exist
REUSE.toml line 15 — ".gitmodules",. There is no .gitmodules in the tree and git ls-files --stage reports zero gitlinks.
.soldeerignore line 8 — .gitmodules, same absent file.
.soldeerignore line 24 — /lib. There is no top-level lib/ directory. foundry.toml sets libs = ['dependencies'], so forge resolves everything under dependencies/ and never creates one. (src/lib/ exists and is unrelated — this pattern is anchored with a leading /, so it only ever matched the repo-root lib/.)
None of these can come back. rainix CI runs a no-submodules check that fails on a root .gitmodules or any committed gitlink.
A misspelled entry — corrected in place, not dropped
.soldeerignore line 2 — .coderabbitai.yaml. No such file exists, and it never will: the CodeRabbit config filename is .coderabbit.yaml (as used in raindex, rainlang, rainlang.interface, rain.verify and rain.tofu.erc20-decimals). This is a misspelling, so if a real .coderabbit.yaml is ever added here it will be published to soldeer rather than ignored. Correct the spelling in place. Deleting the line does not fix that — it removes the protection instead of restoring it.
Checked and clean. CLAUDE.md is not stale here. Its lib/... bullets sit under the ### Solidity Layer (src/) heading and correctly describe src/lib/, and line 132 already states dependencies are soldeer-managed (libs = ['dependencies']), "not git submodules". Leave it alone.
Deliberately not in scope. .soldeerignore also names .DS_Store, .pre-commit-config.yaml and the build/publish outputs (/out, /cache, /dependencies, /target, /node_modules, /dist, /docs). Those are absent from a clean checkout by design — OS junk, local developer files, or artifacts generated at forge soldeer install / forge build / cargo build / forge doc time and therefore present when soldeer push runs. They are correct ignores and must stay.
Nothing else references any of it. .github/workflows/, flake.nix, foundry.toml, Cargo.toml, crates/, script/, scripts/, package.json, remappings.txt, .gitignore, README.md and the rest of the tree were grepped and are clean.
Which of these actually get removed
REUSE.toml and .soldeerignore fail in opposite directions, so the same absent path is residue in one and a live rule in the other.
REUSE.toml describes files that exist. An annotation naming a path that is not there describes nothing, so it is residue and it goes. reuse lint (the rainix-sol legal job) tolerates a dangling annotation, which is why these survived; what it does not tolerate is the reverse, dropping the annotation of a file that is there. Proved live in rain.lib.memkv — removing the annotation for the tracked soldeer.lock makes reuse lint exit 1.
.soldeerignore is a publish filter, not a description of the tree. An entry naming an absent path is a forward-looking rule: it is the thing that keeps that path out of the published package if anyone ever adds it. So the test for deleting an entry is impossible, not absent — an entry may only go if the path it names can never exist again.
Three entries pass that test, and they pass it structurally rather than by observation: rainix CI's no-submodules check fails the build on a root .gitmodules or any committed gitlink, /lib is that same vendored-submodule directory, and foundry.lock is only ever written for lib/ submodule dependencies. While that check stands none of the three can be recreated, so their filter entries can never match anything again. Those are genuinely dead, and they are the only .soldeerignore lines this issue removes.
Every other entry — .coderabbit.yaml, CLAUDE.md, /target, .cargo, .envrc, whatever a given repo happens to list — is merely not yet added. Deleting one cleans nothing up; it arms a leak, so that the day someone adds the file it ships inside the published soldeer package. Proved live in rain.lib.memkv — dropping the /soldeer.lock line took forge soldeer push --dry-run from 14 entries to 15, with soldeer.lock now inside the package.
A misspelled entry is the one case that is edited rather than deleted, for the same reason: .coderabbitai.yaml protects nothing today, and dropping it leaves the repo just as unprotected. Correcting the spelling is what closes the hole.
Nothing catches an over-deletion. No CI job reads .soldeerignore, so the mistake goes green and only surfaces later, when someone adds the file and it silently publishes.
Context
This is the tail of an unfinished migration, not a convention.
Across the repos that consume rain.solmem via soldeer, nine have already dropped foundry.lock (raindex, rain.verify, rain.tofu.erc20-decimals, rain.flare, rain.dia, rain.erc4626.words, rainlang, rain.merkle, S01-Issuer/st0x.deploy) and eight still carry one: rain.solmem, rainlang.interface, rain.extrospection, rain.math.float, rain.string, rain.lib.memkv, rain.intorastring, rain.datacontract. This issue covers rain.math.float only.
Deleting the file was never the whole job. Every one of those nine left dangling .gitmodules and/or lib/ references behind — rain.merkle, for instance, deleted foundry.lock yet still annotates both foundry.lock and .gitmodules in REUSE.toml, and its legal job is green. That is why this issue covers the residue as well as the lockfile, and why each of those nine now has an issue of its own.
The same residue exists in a further 17 rainlanguage repos outside that consumer set, 10 of which also still carry a dead foundry.lock. They are out of scope here. flow and rain.tier.interface genuinely still use git submodules, so their .gitmodules and lib/ entries are correct and must be left alone.
Done when
What
foundry.lockisfoundry.lockis Foundry's git submodule lockfile. It records the commit each dependency vendored underlib/is pinned to, soforge install/forge updatecan restore identical submodule revisions. It is only meaningful in a repo that vendors dependencies as git submodules.Why it is dead in this repo
There is no
.gitmodulesand nolib/directory onmain. Dependencies come from soldeer:foundry.tomlsetslibs = ['dependencies'], andsoldeer.lockis the live lockfile for the 7 packages that land underdependencies/:@openzeppelin-contracts5.6.1forge-std1.16.1rain-datacontract0.1.0rain-deploy0.1.3rain-sol-codegen0.1.0rain-solmem0.1.3rain-string0.2.0foundry.lockmeanwhile still carries 6 submodule pins, every one of them for alib/path that does not exist in the tree:{ "lib/forge-std": { "rev": "1801b0541f4fda118a10798fd3486bb7051c5dd6" }, "lib/rain.datacontract": { "rev": "3bff30782e408386f73b9353c5122e2e0ab24df2" }, "lib/rain.deploy": { "rev": "ccfdb378d2ab1ed95461ecf1355682250e487e4c" }, "lib/rain.math.fixedpoint": { "rev": "8308cbb6da0e231c6f3437f1861e66eff7ea2b00" }, "lib/rain.sol.codegen": { "rev": "dfe95884edfde3d4faf51046dc392aa9221bb0a7" }, "lib/rain.string": { "rev": "488f237cd59874e4eb91b5a4f747bd57578fec7f" } }It is stale in two distinct ways:
1801b054is forge-stdv1.14.0while soldeer resolves 1.16.1.lib/rain.math.fixedpoint, which has no counterpart insoldeer.lockat all, and it has no entry for@openzeppelin-contractsorrain-solmem, which are live.Nothing reconciles any of it, because nothing reads the
foundry.lockside.Submodules also cannot come back: rainix CI runs a
no-submodulescheck that fails on a root.gitmodulesor any committed gitlink, so there is no future in which these pins become live again.It is not silent
forge buildemits one warning per entry in this file — 6 warnings on every build here, verified in the pinnedrainix#sol-shell:Everything dangling in this repo
foundry.lockis not the only thing the submodule → soldeer migration left behind. Every reference below names a path that does not exist onmain— but absence on its own is not what makes a reference removable, andREUSE.tomland.soldeerignoredo not behave the same way. Read Which of these actually get removed below before deleting anything.The dead lockfile and its references
foundry.lock— the file itselfREUSE.tomlline 30 —"foundry.lock",in the annotationpathlist.soldeerignoreline 22 —/foundry.lockSubmodule paths that no longer exist
REUSE.tomlline 15 —".gitmodules",. There is no.gitmodulesin the tree andgit ls-files --stagereports zero gitlinks..soldeerignoreline 8 —.gitmodules, same absent file..soldeerignoreline 24 —/lib. There is no top-levellib/directory.foundry.tomlsetslibs = ['dependencies'], so forge resolves everything underdependencies/and never creates one. (src/lib/exists and is unrelated — this pattern is anchored with a leading/, so it only ever matched the repo-rootlib/.)None of these can come back. rainix CI runs a
no-submodulescheck that fails on a root.gitmodulesor any committed gitlink.A misspelled entry — corrected in place, not dropped
.soldeerignoreline 2 —.coderabbitai.yaml. No such file exists, and it never will: the CodeRabbit config filename is.coderabbit.yaml(as used in raindex, rainlang, rainlang.interface, rain.verify and rain.tofu.erc20-decimals). This is a misspelling, so if a real.coderabbit.yamlis ever added here it will be published to soldeer rather than ignored. Correct the spelling in place. Deleting the line does not fix that — it removes the protection instead of restoring it.Checked and clean.
CLAUDE.mdis not stale here. Itslib/...bullets sit under the### Solidity Layer (src/)heading and correctly describesrc/lib/, and line 132 already states dependencies are soldeer-managed (libs = ['dependencies']), "not git submodules". Leave it alone.Deliberately not in scope.
.soldeerignorealso names.DS_Store,.pre-commit-config.yamland the build/publish outputs (/out,/cache,/dependencies,/target,/node_modules,/dist,/docs). Those are absent from a clean checkout by design — OS junk, local developer files, or artifacts generated atforge soldeer install/forge build/cargo build/forge doctime and therefore present whensoldeer pushruns. They are correct ignores and must stay.Nothing else references any of it.
.github/workflows/,flake.nix,foundry.toml,Cargo.toml,crates/,script/,scripts/,package.json,remappings.txt,.gitignore,README.mdand the rest of the tree were grepped and are clean.Which of these actually get removed
REUSE.tomland.soldeerignorefail in opposite directions, so the same absent path is residue in one and a live rule in the other.REUSE.tomldescribes files that exist. An annotation naming a path that is not there describes nothing, so it is residue and it goes.reuse lint(therainix-sollegaljob) tolerates a dangling annotation, which is why these survived; what it does not tolerate is the reverse, dropping the annotation of a file that is there. Proved live in rain.lib.memkv — removing the annotation for the trackedsoldeer.lockmakesreuse lintexit 1..soldeerignoreis a publish filter, not a description of the tree. An entry naming an absent path is a forward-looking rule: it is the thing that keeps that path out of the published package if anyone ever adds it. So the test for deleting an entry is impossible, not absent — an entry may only go if the path it names can never exist again.Three entries pass that test, and they pass it structurally rather than by observation: rainix CI's
no-submodulescheck fails the build on a root.gitmodulesor any committed gitlink,/libis that same vendored-submodule directory, andfoundry.lockis only ever written forlib/submodule dependencies. While that check stands none of the three can be recreated, so their filter entries can never match anything again. Those are genuinely dead, and they are the only.soldeerignorelines this issue removes.Every other entry —
.coderabbit.yaml,CLAUDE.md,/target,.cargo,.envrc, whatever a given repo happens to list — is merely not yet added. Deleting one cleans nothing up; it arms a leak, so that the day someone adds the file it ships inside the published soldeer package. Proved live in rain.lib.memkv — dropping the/soldeer.lockline tookforge soldeer push --dry-runfrom 14 entries to 15, withsoldeer.locknow inside the package.A misspelled entry is the one case that is edited rather than deleted, for the same reason:
.coderabbitai.yamlprotects nothing today, and dropping it leaves the repo just as unprotected. Correcting the spelling is what closes the hole.Nothing catches an over-deletion. No CI job reads
.soldeerignore, so the mistake goes green and only surfaces later, when someone adds the file and it silently publishes.Context
This is the tail of an unfinished migration, not a convention.
Across the repos that consume
rain.solmemvia soldeer, nine have already droppedfoundry.lock(raindex, rain.verify, rain.tofu.erc20-decimals, rain.flare, rain.dia, rain.erc4626.words, rainlang, rain.merkle, S01-Issuer/st0x.deploy) and eight still carry one: rain.solmem, rainlang.interface, rain.extrospection, rain.math.float, rain.string, rain.lib.memkv, rain.intorastring, rain.datacontract. This issue covers rain.math.float only.Deleting the file was never the whole job. Every one of those nine left dangling
.gitmodulesand/orlib/references behind — rain.merkle, for instance, deletedfoundry.lockyet still annotates bothfoundry.lockand.gitmodulesinREUSE.toml, and itslegaljob is green. That is why this issue covers the residue as well as the lockfile, and why each of those nine now has an issue of its own.The same residue exists in a further 17 rainlanguage repos outside that consumer set, 10 of which also still carry a dead
foundry.lock. They are out of scope here.flowandrain.tier.interfacegenuinely still use git submodules, so their.gitmodulesandlib/entries are correct and must be left alone.Done when
foundry.lockdeletedREUSE.tomlentry listed above removed.soldeerignorelines 8 (.gitmodules), 22 (/foundry.lock) and 24 (/lib) removed.soldeerignoreline 2 corrected in place to.coderabbit.yaml, not deleted.soldeerignoreline left exactly as it isforge buildno longer emitsDependency '...' not found at expected path.gitmodules, rootlib/orfoundry.lockremains anywhere in the tree outsidedependencies/rainix-soltest / static / legal)