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
50 changes: 30 additions & 20 deletions .claude/agents/lint-format-validator.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
---
name: lint-format-validator
description: Run ESLint then Prettier via the Makefile, automatically fix any failures, and iterate until both pass cleanly
description: Run ESLint and Stylelint, then Prettier, via the Makefile, automatically fix any failures, and iterate until all pass cleanly
tools: Bash, Read, Edit, Glob, Grep
allowedTools: Bash, Read, Edit, Glob, Grep
model: sonnet
---

# Lint and format validator

You are a validation agent that runs ESLint and then Prettier, automatically fixes all failures, and iterates until both pass cleanly. ESLint runs first, then Prettier — this order matters because Prettier can undo ESLint autofixes if run in the wrong order.
You are a validation agent that runs the linters (ESLint and Stylelint) and then Prettier, automatically fixes all failures, and iterates until all of them pass cleanly. The linters run first, then Prettier — this order matters because Prettier can undo ESLint autofixes if run in the wrong order.

Run every command below from the repository root.

## Workflow

### Phase 1: ESLint
### Phase 1: ESLint and Stylelint

#### 1a. Run ESLint via the Makefile
#### 1a. Run the linters via the Makefile

```bash
cd /Users/administrator/Documents/PolicyEngine/policyengine-app-v2 && make lint 2>&1
make lint 2>&1
```

`make lint` runs ESLint in `app/`, then Stylelint on `app/`'s CSS (`stylelint '**/*.css'`, configured in `app/.stylelintrc.json`), then ESLint in `website/` and `calculator-app/`. These are the same linters as CI's Lint and format job. `make` stops at the first linter that fails, so the ones after it only run once it passes.

**IMPORTANT:** CI uses `eslint --max-warnings 0`, so warnings are failures too. Fix ALL warnings and errors.

#### 1b. If ESLint passes with zero errors and zero warnings, move to Phase 2.
#### 1b. If `make lint` passes with zero errors and zero warnings, move to Phase 2.

#### 1c. If there are errors or warnings, fix them:

Expand All @@ -40,46 +44,52 @@ For each ESLint issue:

**Do NOT add blanket eslint-disable comments.** Fix the underlying issue.

#### 1d. Re-run ESLint
For each Stylelint issue:
1. Read the CSS file at the reported line
2. Fix the declaration or selector the named rule reports (for example, `property-no-unknown` means a misspelled or invalid property)

**Do NOT add stylelint-disable comments or turn rules off in `app/.stylelintrc.json`.** Fix the CSS.

#### 1d. Re-run the linters

```bash
cd /Users/administrator/Documents/PolicyEngine/policyengine-app-v2 && make lint 2>&1
make lint 2>&1
```

#### 1e. Repeat 1c-1d until ESLint reports zero errors and zero warnings.
#### 1e. Repeat 1c-1d until `make lint` reports zero errors and zero warnings.

### Phase 2: Prettier

#### 2a. Run Prettier in write mode via the Makefile

```bash
cd /Users/administrator/Documents/PolicyEngine/policyengine-app-v2 && make format 2>&1
make format 2>&1
```

This automatically reformats all files. Prettier in write mode is idempotent — running it once should be sufficient.
This reformats the files CI checks: `.ts` and `.tsx` files in `app/`, and `.ts`, `.tsx`, `.mjs` and `.css` files in `website/` and `calculator-app/`. Prettier in write mode is idempotent — running it once should be sufficient.

#### 2b. Verify Prettier is clean by running the check
#### 2b. Verify Prettier is clean by running CI's three checks

```bash
cd /Users/administrator/Documents/PolicyEngine/policyengine-app-v2/app && bun run prettier 2>&1
(cd app && bun run prettier && cd ../website && bun run format:check && cd ../calculator-app && bun run format:check) 2>&1
```

If any files are listed as needing formatting, run `make format` again.

#### 2c. Repeat until the check reports no issues.
#### 2c. Repeat until the checks report no issues.

### Phase 3: Final verification

Run both checks one more time to confirm everything is clean:
Run the linters and the Prettier checks one more time to confirm everything is clean:

```bash
cd /Users/administrator/Documents/PolicyEngine/policyengine-app-v2 && make lint 2>&1 && make format 2>&1
make lint 2>&1 && (cd app && bun run prettier && cd ../website && bun run format:check && cd ../calculator-app && bun run format:check) 2>&1
```

### Phase 4: Report

When both pass, report:
- How many ESLint iterations it took
- What ESLint issues were fixed (brief summary)
When all pass, report:
- How many lint iterations it took
- What ESLint and Stylelint issues were fixed (brief summary)
- Whether Prettier made any changes
- Confirmation that both `make lint` and `make format` now pass cleanly
- Confirmation that `make lint` and the three Prettier checks now pass cleanly
8 changes: 6 additions & 2 deletions .claude/agents/typecheck-validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@ model: sonnet

You are a validation agent that runs TypeScript type checking and automatically fixes all errors, iterating until the check passes cleanly.

Run every command below from the repository root.

## Workflow

### 1. Run type checking via the Makefile

```bash
cd /Users/administrator/Documents/PolicyEngine/policyengine-app-v2 && make typecheck 2>&1
make typecheck 2>&1
```

This runs `tsc --noEmit` in `app/`, `website/` and `calculator-app/`, the same three checks as CI's Type checking job. `make` stops at the first project with errors, so a project after it is only checked once the ones before it pass.

### 2. If the check passes with no errors, report success and stop.

### 3. If there are errors, fix them:
Expand All @@ -36,7 +40,7 @@ For each type error reported:
### 4. Re-run type checking

```bash
cd /Users/administrator/Documents/PolicyEngine/policyengine-app-v2 && make typecheck 2>&1
make typecheck 2>&1
```

### 5. Repeat steps 3-4 until there are zero errors.
Expand Down
6 changes: 3 additions & 3 deletions .claude/commands/eslint.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
---
description: Run ESLint and optionally fix errors
description: Run ESLint and Stylelint and optionally fix errors
allowed-tools: Bash
---

Run `npm run eslint` from the app directory.
Run `make lint` from the repository root. It runs ESLint in `app/`, `website/` and `calculator-app/`, and Stylelint on `app/`'s CSS, the same linters as CI's Lint and format job. ESLint fails on warnings as well as errors (`--max-warnings 0`). `make` stops at the first linter that fails, so after fixing its errors, run it again to check the rest.

If there are ESLint errors, ask me if I should fix them. If I say yes, fix all the errors and keep running eslint until there are no more errors. If I say no, do nothing.
If there are ESLint or Stylelint errors, ask me if I should fix them. If I say yes, fix all the errors and keep running `make lint` until there are no more errors. If I say no, do nothing.

After everything is done, return to the original directory.
6 changes: 3 additions & 3 deletions .claude/commands/finalize-pr.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
description: Run all code quality checks (typecheck, eslint, prettier) with progress tracking
description: Run all code quality checks (type checks, ESLint and Stylelint, Prettier) with progress tracking
---

Run the following slash commands in order, showing progress after each:
Expand All @@ -8,6 +8,6 @@ Run the following slash commands in order, showing progress after each:
2. Run `/typecheck`
3. Say "✅ Typecheck complete (1/3 tasks completed)"
4. Run `/eslint`
5. Say "✅ ESLint complete (2/3 tasks completed)"
5. Say "✅ ESLint and Stylelint complete (2/3 tasks completed)"
6. Run `/prettier`
7. Say "✅ All tasks complete (3/3) - PR is ready! 🎉"
7. Say "✅ All tasks complete (3/3). CI also runs the tests (`make test`) and the build (`make build`)."
4 changes: 2 additions & 2 deletions .claude/commands/next-phase.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ Read the current plan from `.claude-plans/calculation-system-refactor.md` and do

1. Identify the current phase and move to the next phase
2. Execute all tasks in the next phase
3. Write or update unit tests for the code changes made in this phase, following the conventions in `app/src/tests/CLAUDE.md`:
3. Write or update unit tests for the code changes made in this phase, following the conventions in `docs/engineering/skills/testing.md`:
- Place tests in `app/src/tests/unit/` mirroring the source structure
- Use Given-When-Then naming pattern
- Import from `@test-utils` not `@testing-library/react`
- Use accessibility selectors (getByRole, etc.)
- Mock Plotly if needed
4. Ensure all mocks and test data have been moved to `app/src/tests/fixtures/` following the structure in CLAUDE.md
4. Ensure all mocks and test data have been moved to `app/src/tests/fixtures/` following the structure in `docs/engineering/skills/testing.md`
5. Update the plan file to mark this phase as complete
6. Provide a brief summary of:
- What was completed in this phase
Expand Down
2 changes: 1 addition & 1 deletion .claude/commands/prettier.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ description: Run Prettier to format code
allowed-tools: Bash
---

Run `npm run prettier:write` from the app directory, then return to the original directory.
Run `make format` from the repository root, then return to the original directory. It runs Prettier in write mode in `app/`, `website/` and `calculator-app/`, which CI's Lint and format job checks.
2 changes: 1 addition & 1 deletion .claude/commands/typecheck.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Run TypeScript type checking and optionally fix errors
allowed-tools: Bash
---

Run `npm run typecheck` from the app directory.
Run `make typecheck` from the repository root. It runs `bun run typecheck` (`tsc --noEmit`) in `app/`, `website/` and `calculator-app/`, the same three checks as CI's Type checking job. `make` stops at the first project with errors, so after fixing them, run it again to check the projects after it.

If there are type errors, ask me if I should fix them. If I say yes, fix all the errors and keep running typecheck until there are no more errors. If I say no, do nothing.

Expand Down
4 changes: 2 additions & 2 deletions .claude/commands/write-unit-tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Write unit tests for the files or features described by the user. Follow these s

## Step 1: Read the test guidelines

Read `app/src/tests/CLAUDE.md` in full. All tests MUST follow these conventions:
Read `docs/engineering/skills/testing.md` in full. All tests MUST follow these conventions:
- Import `render`, `screen`, `userEvent` from `@test-utils` (not `@testing-library/react`)
- Import `describe`, `test`, `expect`, `vi` from `vitest`
- Use Given-When-Then naming: `test('given X then Y', ...)`
Expand Down Expand Up @@ -58,7 +58,7 @@ If any violations are found, fix them by moving the code to the appropriate fixt

Run the specific test files that were created or modified using:
```
cd app && npx vitest run <space-separated list of test file paths relative to app/>
cd app && bun run vitest -- <space-separated list of test file paths relative to app/>
```

Do NOT run the entire test suite. Only run the tests you wrote or modified.
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ Run linters:
make lint
```

Type-check:

```bash
make typecheck
```

Format code:

```bash
Expand Down Expand Up @@ -116,7 +122,7 @@ Vercel builds and deploys two projects from this repository: `policyengine-websi

1. Create a new branch from main
2. Make your changes
3. Run tests and linting: `make test && make lint`
3. Format with `make format`, then run `make lint`, `make typecheck` and `make test`. CI checks formatting and runs the same linters, type checks and tests, plus a build (see "Before committing" in `docs/engineering/skills/repository-guidance.md`)
4. Create a pull request
5. Once approved and merged, changes deploy automatically

Expand Down
2 changes: 1 addition & 1 deletion docs/engineering/skills/repository-guidance.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,5 +125,5 @@ No route embeds a GitHub Pages site as a whole page any more: the 2025 year in r

1. Run `make format` to format `app/`, `website/` and `calculator-app/` with Prettier. `app/` has its own Prettier config; `website/` and `calculator-app/` use Prettier's defaults.
2. Run `make lint` to run ESLint (and Stylelint in `app/`) in all three.
3. Run `make typecheck` to type-check all three, and `make test` to run the `app/` and `website/` tests (`calculator-app/` has none). These match CI's type checking and tests jobs.
3. Run `make typecheck` to type-check all three, and `make test` to run the `app/` and `website/` tests (`calculator-app/` has none). These match CI's type checking and tests jobs. They don't match CI's Node version, though. vitest's launcher starts with `#!/usr/bin/env node`, so `bun run test` runs the tests on the `node` first on your PATH, not on Bun. CI's Tests job pins Node 26 (in `pr.yaml` and `push.yaml`) because `Intl` number formatting differs between Node versions. `make test` uses your local Node, and `app/.nvmrc` says v24.3.0, so a test that checks formatted numbers can pass locally and fail in CI, or the reverse. Run the tests on Node 26 to match CI.
4. CI fails on ESLint warnings as well as errors (`--max-warnings 0`), and on files Prettier would reformat, so fix all of them.
20 changes: 17 additions & 3 deletions docs/engineering/skills/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,27 @@

## Test commands

- Run tests: `bun run vitest`
From the repository root, `make test` runs the `app/` tests and then the `website/` tests, the same two suites as CI's Tests job. `calculator-app/` has no test suite of its own; tests of its code run in the `app/` suite (for example, under `app/src/tests/unit/calculator/`).

In `app/`:

- Run tests: `bun run vitest` (or `bun run test`)
- Run specific files: `bun run vitest -- <paths relative to app/>`
- Watch mode: `bun run vitest:watch`
- With coverage: `bun run vitest -- --coverage`
- Full check: `bun run check` (includes type checking, linting, and formatting verification)
- Coverage: `bun run vitest -- --coverage` fails with a missing dependency error, because `@vitest/coverage-v8` isn't installed. Add it as a dev dependency before measuring coverage.
- Full check: `bun run check` runs the type check, ESLint and the Prettier check. It doesn't run Stylelint or the tests; `make lint` and `make test` do.

In `website/`:

- Run tests: `bun run test`
- Watch mode: `bun run test:watch`

vitest runs on Node, not Bun, so results can depend on your Node version. See step 3 of "Before committing" in `repository-guidance.md`.

## Writing tests

Unless an item says otherwise, these conventions are for `app/`. `website/` tests live in `website/src/__tests__/`, import from `@testing-library/react` directly (`website/` has no `@test-utils`) and share the setup in `website/src/__tests__/setup.ts`.

1. **Always use @test-utils**: Import `render` and other utilities from `@test-utils`, not `@testing-library/react`

```typescript
Expand Down
Loading