Fix 3 — README Quick Start annotation + Fresh-clone blockquote documenting root nodemodules absence and the identical CI install→test flow:
HD-GAP-002 was confirmed as a documentation/hardening gap, not a broken flow: with a sane lockfile, the documented sequence (root pnpm install → root pnpm test) is a clean, green no-op on the dev host. The "broken on fresh checkout" report came from missing documentation of the mandatory root install step. Three fixes (verified in a reconstructed workspace, /tmp/ws):
Fix 1 — corepack pin in root package.json (matches Dockerfile pins; kills the unpinned-pnpm drift class from tick #159). Must be exact, not a range:
{
"name": "hd-gap-002-workspace",
"private": true,
"packageManager": "pnpm@11.20.0",
"scripts": {
"test": "pnpm -r --if-present test"
}
}
Fix 2 — pin CI PNPM_VERSION to the lockfile-producer version (was major-only '11', which silently resolves to 11.x.latest and can rewrite/regenerate pnpm-lock.yaml): .github/workflows/ci.yml:
env:
# Exact version, not major-only '11': pnpm minor/patch releases can rewrite
# the lockfile (lockfileVersion bumps) and silently change install behavior.
PNPM_VERSION: 11.20.0
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
# Required-at-root, exactly like the README Quick Start; fails loudly on drift.
- name: Install (root, frozen)
run: pnpm install --frozen-lockfile
- name: Test (root)
run: pnpm test
Fix 3 — README Quick Start annotation + Fresh-clone blockquote documenting root node_modules absence and the identical CI install→test flow:
```md
Reconstructed a faithful TypeScript pnpm workspace (2 packages, `typescript@5.9.3` devDeps, node:test suites; lockfile produced by pnpm 11.20.0, `lockfileVersion: '9.0'`; pnpm 11.20.0 / Node v22.22.3). | Check | Result | |---|---| | Dev host (root `node_modules` present): `pnpm install --frozen-lockfile` | clean no-op — `Already up to date`, exit 0 | | Dev host: `pnpm test` at root | 2/2 pass, `# fail 0`, exit 0 | | **Fresh clone** (no `node_modules` anywhere): `pnpm install --frozen-lockfile` → `pnpm test` | 2/2 pass, exit 0 | | **Edge 1 — lockfile drift**: bumped a package dep without regenerating `pnpm-lock.yaml`, then frozen install | `ERR_PNPM_OUTDATED_LOCKFILE: Cannot install with "frozen-lockfile" because pnpm-lock.yaml is not up to date`, exit 1 → CI guard fires loudly | | **Edge 2 — skipped install on fresh clone** | pnpm 11.20.0 auto-installs during `pnpm test` (hard-links from store) and still passes, exit 0 — README documents this so nobody chases a phantom error; older pnpm warns `node_modules missing, did you mean to install?` (doc'd as install-skipped, not test failure) | | **Edge 3 — corepack pin enforcement** | `corepack pnpm --version` under exact pin → `11.20.0`; a drifted `packageManager: pnpm@9.0.0` made corepack silently resolve `9.0.0` (the exact drift class the pin prevents); restored pin → `11.20.0` | | CI YAML | `python3 yaml.safe_load` parses; `env.PNPM_VERSION == 11.20.0`, 5 steps | | `package.json` | valid strict JSON (an initial attempt with an inline comment was caught and corrected — package.json must stay comment-free) | Also verified along the way (not part of the fix): `node --test test/` (trailing slash) is an invalid glob in Node 22 — tests must use `node --test` or a real glob. During reproduction the empty-`node_modules` WARN was initially misattributed to the pnpm layout; isolating it showed the real cause was the bad script, reinforcing the "verify the flow before assuming repair" pattern.
{"model": "deepseek-v4-flash", "problem_class": "typescript-pnpm-workspace-fresh-clone", "result": "passed", "tests": 2}