Skip to content

Remove the submodule-era residue — dead foundry.lock, .gitmodules and lib/ references in a repo with no submodules #29

Description

@thedavidmeister

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 3 packages that land under dependencies/:

  • @openzeppelin-contracts 5.6.1
  • forge-std 1.16.1
  • rain-solmem 0.1.3

foundry.lock meanwhile still carries 2 submodule pins, both for a lib/ path that does not exist in the tree:

{
"lib/openzeppelin-contracts": {
"rev": "fcbae5394ae8ad52d8e580a3477db99814b9d565"
},
"lib/rain.solmem": {
"rev": "2e47e41af85a711d837b2518656db0efdae814c2"
}
}

Both pins contradict what the build actually uses. fcbae539 is openzeppelin-contracts v5.5.0 while soldeer resolves 5.6.1; 2e47e41 is not any tagged release of rain.solmem (v0.1.3 is ce03de80) while soldeer resolves rain-solmem0.1.3. The file is also incomplete against the real dependency set — it has no entry for forge-std, which is 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 — 2 warnings on every build here, verified in the pinned rainix#sol-shell:

Warning: Dependency 'lib/rain.solmem' not found at expected path
Warning: Dependency 'lib/openzeppelin-contracts' 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 19 — "foundry.lock", in the annotation path list
  • .soldeerignore line 19 — /foundry.lock

Submodule paths that no longer exist

  • REUSE.toml line 9 — ".gitmodules",. There is no .gitmodules in the tree and git ls-files --stage reports zero gitlinks.
  • .soldeerignore line 7 — .gitmodules, same absent file.
  • .soldeerignore line 21 — /lib. There is no lib/ directory. foundry.toml sets libs = ["dependencies"], so forge resolves everything under dependencies/ and never creates 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 further dangling REUSE.toml annotation, which also goes

  • REUSE.toml line 7 — ".vscode/**/". This repo tracks no .vscode/ directory, so the annotation matches nothing.

A misspelled .soldeerignore 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.

Absent, but not residue — this stays

  • .soldeerignore line 11 — CLAUDE.md. This repo has no CLAUDE.md, tracked or ignored. It is an ordinary file a repo gains later, so the entry is a live forward-looking rule and is left alone.

Deliberately not in scope..soldeerignore also names .DS_Store, .vscode, .pre-commit-config.yaml and the build/publish outputs (/out, /cache, /dependencies, /target, /result, /meta, /docs, /deployments). Those are absent from a clean checkout by design — OS junk, local developer files, or artifacts generated at forge soldeer install / forge build 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, remappings.txt, .gitignore, README.md and the rest of the tree were grepped and are clean. This repo has no CLAUDE.md, so there is no stale prose describing lib/ submodules to fix here.

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. That is why .vscode above goes from REUSE.toml while .vscode stays in .soldeerignore.

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 (the rainix-sollegal 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.string 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 bothfoundry.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

  • foundry.lock deleted
  • every REUSE.toml entry listed above removed
  • .soldeerignore lines 7 (.gitmodules), 19 (/foundry.lock) and 21 (/lib) removed
  • .soldeerignore line 2 corrected in place to .coderabbit.yaml, not deleted
  • every other .soldeerignore line left exactly as it is, CLAUDE.md and .vscode included
  • forge build no longer emits Dependency '...' not found at expected path
  • no reference to .gitmodules, lib/ or foundry.lock remains anywhere in the tree outside dependencies/
  • CI green (rainix-sol test / static / legal)

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions