diff --git a/CLAUDE.md b/CLAUDE.md index f41015d..9acfc4a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -5,7 +5,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Commands ```bash -pnpm check # Merge gate — must pass before every commit (audit + knip + biome + oxlint + typecheck + test/coverage + jscpd) +pnpm check # Merge gate — must pass before every commit (audit + knip + biome + oxlint + typecheck + test/coverage + jscpd + jsinspect) pnpm oxlint # Type-aware linting (oxlint — complements Biome) pnpm knip # Unused code detection (Knip) pnpm test # Run all tests (Vitest) @@ -30,7 +30,7 @@ apps/web (React 19 + Vite) → packages/application (use cases) → packages - **Domain** — Pure functions, no I/O, no framework imports. All state transitions are deterministic. Errors returned as values (`DomainError`), never thrown. Adapters may throw only for programmer errors. - **Application** — Orchestrates domain calls via port interfaces (`EncounterStore`, `BestiarySourceCache`). No business logic here. -- **Web** — React adapter. Implements ports using hooks/state. All UI components, routing, and user interaction live here. +- **Web** — React adapter. Implements ports using hooks/state. All UI components and user interaction live here. Layer boundaries are enforced by `scripts/check-layer-boundaries.mjs`, which runs as a Vitest test. Domain and application must never import from React, Vite, or upper layers. @@ -60,7 +60,7 @@ docs/agents/ RPI skill artifacts (research reports, plans) - React 19, Vite 6, Tailwind CSS v4 - Lucide React (icons) - `idb` (IndexedDB wrapper for bestiary cache) -- Biome 2.4 (formatting + linting), oxlint (type-aware linting), Knip (unused code), jscpd (copy-paste detection) +- Biome 2.4 (formatting + linting), oxlint (type-aware linting), Knip (unused code), jscpd (copy-paste detection), jsinspect-plus (structural duplication) - Vitest (testing, v8 coverage), Lefthook (pre-commit hooks) ## Conventions @@ -72,9 +72,9 @@ docs/agents/ RPI skill artifacts (research reports, plans) - **Domain events** are plain data objects with a `type` discriminant — no classes. - **Tests** live in `packages/*/src/__tests__/*.test.ts`. Test pure functions directly; map acceptance scenarios and invariants from specs to individual `it()` blocks. - **Feature specs** live in `specs/NNN-feature-name/` with spec.md (and optionally plan.md, tasks.md for new work). Specs describe features, not individual changes. The project constitution is at `.specify/memory/constitution.md`. -- **Component props** — max 8 explicitly declared props per component interface (enforced by `scripts/check-component-props.mjs`). Use React context for shared state; reserve props for per-instance config (data items, layout variants, refs). +- **Component props** — max 8 explicitly declared props per component interface (enforced by `scripts/check-component-props.mjs` using the TypeScript compiler API). Use React context for shared state; reserve props for per-instance config (data items, layout variants, refs). - **Export format compatibility** — When changing `Encounter`, `Combatant`, `PlayerCharacter`, or `UndoRedoState` types, verify that previously exported JSON files (version 1) still import correctly. If not, bump the `ExportBundle` version and add migration logic in `validateImportBundle()`. -- **Quality gates** are enforced at pre-commit via Lefthook's `pnpm check` — the project's single earliest enforcement point. No gate may exist only as a CI step or manual process. +- **Quality gates** are enforced at pre-commit via Lefthook (parallel jobs). No gate may exist only as a CI step or manual process. ## Self-Review Checklist