# Foundry Monorepo Scopes

## Why this exists

`smom-dbis-138` has grown beyond the shape of a single small Foundry package:

- `258` Solidity files under `contracts/`
- `120` Solidity tests under `test/`
- `133` Solidity scripts under `script/`

In practice that means the root repo-wide `forge build` is a compatibility path, not a good inner-loop default. A clean full build in this workspace did not finish within `120s`, while scoped builds did:

- `treasury` scoped build: about `17s`
- `flash` scoped build: about `44s`
- `treasury` scoped test compile: `39` files instead of `338`

## Recommended workflow

Use the scope runner for day-to-day work:

```bash
bash scripts/forge/scope.sh list
bash scripts/forge/scope.sh build treasury
bash scripts/forge/scope.sh test treasury
bash scripts/forge/scope.sh script bridge/trustless script/bridge/trustless/DeployTrustlessBridge.s.sol:DeployTrustlessBridge --rpc-url "$RPC_URL_138"
bash scripts/forge/scope.sh script script/DeployOracle.s.sol:DeployOracle --rpc-url "$RPC_URL_138"
```

You can also drive it through npm scripts:

```bash
FORGE_SCOPE=treasury pnpm run forge:build
FORGE_SCOPE=treasury pnpm run forge:test
pnpm run forge:script -- script/DeployOracle.s.sol:DeployOracle --rpc-url "$RPC_URL_138"
pnpm run forge:scope:list
pnpm run forge:orphans
```

Or through `make`:

```bash
make contracts SCOPE=treasury
make test SCOPE=bridge/trustless
```

Many shell deployment scripts in this repo now get scoped Forge automatically through shared shell bootstrap files:

- `scripts/lib/init.sh`
- `scripts/lib/deployment/dotenv.sh`
- `scripts/load-env.sh`

At this point every shell script under `scripts/` that invokes `forge build`, `forge test`, or `forge script` is covered by one of those shared paths or calls the scope runner directly.

## How scopes work

The scope runner keeps the root `foundry.toml` for compatibility, but overrides the active package boundary via environment variables:

- `FOUNDRY_SRC=contracts/<scope>`
- `FOUNDRY_TEST=test/<scope>` when that directory exists
- `FOUNDRY_OUT=out/scopes/<scope>`
- `FOUNDRY_CACHE_PATH=cache/scopes/<scope>`
- `FOUNDRY_BROADCAST=broadcast/scopes/<scope>`

This keeps artifact churn local to the subtree you are editing and prevents unrelated domains from dominating compile time.

When you omit the scope, the runner tries to infer it from:

- `contracts/<scope>/...`
- `test/<scope>/...`
- `script/<scope>/...`
- `script/deploy/<scope>/...` where `<scope>` maps back to `contracts/<scope>/...`
- common root-level deployment scripts such as `script/DeployOracle.s.sol`, `script/DeployWETH.s.sol`, `script/DeployMulticall.s.sol`, and `script/DeployCCIPRouter.s.sol`

## Full repo builds

Use the full repo intentionally:

```bash
forge build
forge test
pnpm run forge:build:full
pnpm run forge:test:full
```

That is the right choice for:

- release validation
- repo-wide refactors
- remapping or compiler setting changes
- compatibility checks before CI changes

## Legacy contract archival

Use the reachability report before moving old Solidity out of `contracts/`:

```bash
python3 scripts/forge/report-contract-reachability.py
python3 scripts/forge/report-contract-reachability.py --json
```

The report highlights contracts that are unreachable from the repo's current Solidity tests or scripts. That is an archival queue, not proof that deletion is safe. Move those files in small batches and re-run the scoped build/test commands for the affected domain.

Archived Solidity that should stay out of the compile graph lives under `archive/solidity/`.

After the current archive passes, the reachability report is down to `29` unreachable contracts from `35`, with the bridge bucket reduced to `5`.

## Best-practice rules for this repo

1. Prefer `scripts/forge/scope.sh` for local work.
2. Keep root `forge build` and `forge test` as explicit full-graph checks.
3. Add new contracts under an existing domain whenever possible instead of expanding the root package mentally.
4. When a subtree no longer has active tests or scripts, move it toward archive only after confirming it is not referenced by deployment runbooks or external repos.
5. Avoid reintroducing broad compile paths in npm scripts, Make targets, or shell wrappers when a narrower scope is known.
