diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index ed0178fb..5de41670 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -61,15 +61,23 @@ npm run dev:backend # Docker npm run docker:dev -# Verify a change before declaring it done (mirrors CI: frontend lint + typecheck) +# Verify a change before declaring it done (mirrors CI: lint + typecheck + build) npm run verify ``` **Before declaring any change done, run `npm run verify`.** It runs the same -hermetic gates as CI (`.github/workflows/ci.yml`: frontend lint + typecheck), so -green locally means green on `main`. Build and the full-stack Playwright e2e are -not yet gated in CI (build hits a prisma-engine issue; e2e needs both servers + -a DB) — run those manually until wired. +hermetic gates as CI (`.github/workflows/ci.yml`: frontend lint + typecheck + +build), so green locally means green on `main`. + +The build is in the gate deliberately. It used to be deferred, and that gap has +a receipt: contentlayer 0.3.1 reaches into a React internal that React 19 +removed, so `/blog/[slug]` threw `d.getOwner is not a function` during prerender +and production sat on a stale build for weeks. Lint and typecheck were green the +whole time — only a build could have caught it. + +Note: the build needs Node 18 (`.nvmrc`); contentlayer crashes on exit under +Node 20+. The full-stack Playwright e2e is still not gated — it needs both +servers plus a seeded DB, so run it manually until that is wired. --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68cc5ed6..a0a86084 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -41,15 +41,18 @@ jobs: run: npm ci --legacy-peer-deps # SSOT: one definition of "verified" lives in the ROOT package.json - # `verify` (frontend lint + typecheck), run identically here and locally. - # Runs from repo root — the script cds into frontend itself. + # `verify` (lint + typecheck + build), run identically here and locally. + # Runs from repo root — the scripts cd into frontend themselves. + # + # Build is IN the gate as of 2026-08-04. It was deferred on a prisma-engine + # issue, and the cost of that gap was exact: contentlayer 0.3.1 reaches into + # a React internal that React 19 removed, so `/blog/[slug]` threw + # "d.getOwner is not a function" during prerender. lint and typecheck were + # both green — only a build could have caught it. The breakage sat on main + # while every CI run reported success. - name: Verify run: npm run verify - # Build is DEFERRED, not skipped silently. `prisma generate` currently - # fails in CI on a missing engine (query_engine_bg.postgresql.wasm) — a - # repo tooling issue to fix separately, not a gate-worthy signal. The - # full-stack Playwright e2e is also deferred (needs both servers + a DB). - # This floor gates the frontend signals that never ran before: - # lint + typecheck. Add build + e2e once the prisma engine is resolved - # (revampit e2e-local pattern in dotfiles/templates/ci/README.md). + # The full-stack Playwright e2e is still DEFERRED, not skipped silently: + # it needs both servers plus a seeded DB (lift revampit's e2e-local pattern + # from dotfiles/templates/ci/README.md once that is wired). diff --git a/package.json b/package.json index 9dbddee4..ef757119 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,8 @@ "test:debug": "npx playwright test --debug", "test:headed": "npx playwright test --headed", "test:report": "npx playwright show-report", - "verify": "npm run lint && cd frontend && npx tsc --noEmit" + "typecheck": "cd frontend && npx tsc --noEmit", + "verify": "npm run lint && npm run typecheck && npm run build" }, "keywords": [ "data-capture",