Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---

Expand Down
21 changes: 12 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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).
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading