# Task 1 report: Pin and prove the repository toolchain ## Implemented - Pinned the repository to Node `24.18.0` / npm `11.17.0`, Foundry `1.7.1`, Solidity `0.8.35`, and the required Foundry profiles. - Added exact root and web dependency manifests and generated lockfiles. The root lock resolves `@openzeppelin/upgrades-core` to `1.46.0`. - Installed and pinned Git submodules at `forge-std@v1.16.1`, `openzeppelin-foundry-upgrades@v0.4.1`, and `openzeppelin-contracts-upgradeable@v5.6.1`, including canonical remappings. - Added offline upgrades-core verification, a non-destructive doctor script, Make targets, and a manually configured Vite/React/TypeScript/ESLint/Vitest harness. - Added the first toolchain-label module and its Vitest coverage. ## Files changed - `.gitignore`, `.nvmrc`, `.env.example`, `.gitmodules`, `foundry.lock`, `foundry.toml`, `remappings.txt`, `Makefile` - `package.json`, `package-lock.json`, `tools/check-upgrades-cli.mjs`, `tools/doctor.sh` - `lib/forge-std`, `lib/openzeppelin-foundry-upgrades`, `lib/openzeppelin-contracts-upgradeable` - `web/package.json`, `web/package-lock.json`, `web/index.html`, `web/tsconfig.json`, `web/tsconfig.app.json`, `web/tsconfig.node.json`, `web/vite.config.ts`, `web/eslint.config.js` - `web/src/config/toolchain.ts`, `web/src/test/setup.ts`, `web/src/test/toolchain.test.ts` ## TDD evidence The test names the break it catches: a missing or incorrect operations-console toolchain label. Its expected object is hand-written, not derived from the production module. ### RED Command: ```bash npm --prefix web test ``` Result: exit `1`, with `Failed to resolve import "../config/toolchain" from "src/test/toolchain.test.ts"` and `0 test` execution. This was expected because `web/src/config/toolchain.ts` had not yet been created. ### GREEN Created the minimal `toolchainLabels` export with the four required display values, then ran: ```bash npm --prefix web test ``` Result: exit `0`; `1 passed` test file and `1 passed` test. ## Verification results Initial host check: Foundry and Anvil were absent; Node was `v26.7.0`, npm `12.0.2`, and Make `4.4.1`. Installed Foundry through the official user-local installer and pinned it with `foundryup -i 1.7.1`; `forge --version` and `anvil --version` now report `1.7.1`. The final complete verification command exited `0`: ```bash forge fmt --check forge clean npm_config_offline=true forge build --force npm_config_offline=true forge test --force node tools/check-upgrades-cli.mjs npm --prefix web run lint npm --prefix web run typecheck npm --prefix web test npm --prefix web run build make verify ``` Observed results: Foundry reported the expected empty-tree `Nothing to compile`; the upgrades-core check reported `@openzeppelin/upgrades-core 1.46.0 is pinned and installed`; lint and typecheck exited `0`; Vitest reported `1 passed`; and Vite built `dist/index.html` successfully. `npm_config_offline=true npx @openzeppelin/upgrades-core@^1.45.0 validate --help` also exited `0` without fetching. The restricted filesystem sandbox returns EROFS for `forge clean`; the same required commands exited `0` when run outside that mount restriction. This is an execution-environment limitation, not a repository failure. ## Self-review - Confirmed the three top-level Gitlinks equal the tag revisions in `foundry.lock`; recursive nested submodules were synchronized after `forge install` initially left top-level Gitlinks at their default branch heads. - Confirmed the upgrades script checks the unmodified vendored `UPGRADES_CORE = "^1.45.0"`, the root lockfile, and the installed package version. - Confirmed generated output and node modules are ignored, and no generated output is staged. - Kept TypeScript strict through `tsc -b`; ESLint does not import `typescript-eslint` because that exact package hard-fails under TypeScript 7.0. ## Concerns 1. The task-mandated `typescript@7.0.2` and `typescript-eslint@8.65.0` are upstream-incompatible. The latter declares TypeScript `<6.1.0` and throws when loaded under TypeScript 7. Official TypeScript 7 documentation states that TypeScript 7 ships without the compiler API and advises a side-by-side `@typescript/typescript6` alias for tools such as typescript-eslint. Changing to that official arrangement would violate the brief’s required direct `typescript@7.0.2` pin, so it was not done. The ESLint config therefore uses ESLint core plus React rules, while strict TypeScript checking remains green through `tsc -b`. 2. The same peer conflict makes a clean `npm --prefix web ci` (including with pinned npm `11.17.0`) fail unless legacy peer resolution is supplied. The committed lockfile was generated with `npm --prefix web install --save-exact --legacy-peer-deps`; exact versions and the offline verification gate were not weakened. Consequently `make setup` inherits this known npm peer-resolution limitation on a clean install. 3. The current host is outside the pinned Node/npm engines (`v26.7.0` / `12.0.2`), so npm emits engine warnings during installation. The repository records the requested Node/npm pins; final lint/typecheck/test/build all pass on the available host. ## Compatibility resolution The first two concerns above are resolved. Microsoft’s official TypeScript 7 announcement explains that TypeScript 7.0 ships without the compiler API and directs tooling such as typescript-eslint to a side-by-side TypeScript 6 API package. The package now uses only range-free aliases: - `typescript`: `npm:@typescript/typescript6@6.0.2`, which supplies the API imported by `typescript-eslint@8.65.0`. - `@typescript/native`: `npm:typescript@7.0.2`, which supplies the production compiler. `typecheck` and `build` invoke `node ./node_modules/@typescript/native/bin/tsc` explicitly, so they cannot select an ambiguous binary. ESLint now imports and applies `typescript-eslint` again. The Tech Stack and Task 1 dependency wording in the implementation plan were updated under its stated compatibility-rejection condition. ### Resolution RED Before the alias change, the clean pinned-runtime command failed as expected: ```bash npx --yes npm@11.17.0 --prefix web ci ``` Result: exit `1` with `ERESOLVE`; `typescript-eslint@8.65.0` required `typescript >=4.8.4 <6.1.0` while the direct package was TypeScript `7.0.2`. ### Resolution GREEN After the alias change, all of these exited `0` without `legacy-peer-deps`: ```bash npx --yes npm@11.17.0 --prefix web ci node -p "require('./web/node_modules/typescript/package.json').version" node ./web/node_modules/@typescript/native/bin/tsc --version ``` Observed output: TypeScript API alias `6.0.2` and compiler `Version 7.0.2`. With npm `11.17.0` placed first on `PATH`, both `make setup` and `make verify` exited `0`; the latter passed ESLint with typescript-eslint enabled, strict typecheck, Vitest (`1 passed`), and Vite build. The final standalone Foundry/offline CLI/web gate also exited `0`. ## Fix Round 1: exact Node runtime proof ### Runtime installation and version proof Downloaded the official Node `v24.18.0` Linux archive to `/tmp`, verified it against Node’s published `SHASUMS256.txt`, and installed it outside repository state at `/tmp/codius-node-v24.18.0`. Its bundled npm was `11.16.0`, so npm `11.17.0` was installed exactly into that same temporary prefix. With that prefix first on `PATH`, the proof output was: ```text node: v24.18.0 npm: 11.17.0 forge: forge Version: 1.7.1 anvil: anvil Version: 1.7.1 ``` ### Warning investigation and correction The first clean exact-runtime setup emitted npm 11.17’s `allow-scripts` advisory for `keccak@3.0.4` and `secp256k1@4.0.5`. Both packages declare the reviewed install command `node-gyp-build || exit 0`. npm 11.17’s `approve-scripts` documentation identifies `package.json` `allowScripts` as the intended project policy, so the manifest now records exact-version approvals for those two packages. No dependency version or install mode changed. ### Covering commands and results Covering test file: `web/src/test/toolchain.test.ts` (Vitest: `1 passed`). With `PATH=/tmp/codius-node-v24.18.0/bin:/home/golem/.foundry/bin:$PATH`, these all exited `0` from a clean install: ```bash make doctor make setup forge fmt --check forge clean npm_config_offline=true forge build --force npm_config_offline=true forge test --force node tools/check-upgrades-cli.mjs npm_config_offline=true npx @openzeppelin/upgrades-core@^1.45.0 validate --help npm --prefix web run lint npm --prefix web run typecheck npm --prefix web test npm --prefix web run build node ./web/node_modules/@typescript/native/bin/tsc --version make verify ``` `make setup` completed without npm warnings on the exact Node/npm pair. The explicit compiler command printed `Version 7.0.2`; the offline CLI printed its help without fetching; Foundry reported the expected zero-source `Nothing to compile`; lint/typecheck passed; and the Vite build succeeded. `forge fmt --check` retains Foundry’s informational empty-tree `Nothing to format` notice because this foundation task intentionally has no Solidity sources.