212 lines
13 KiB
Markdown
212 lines
13 KiB
Markdown
# Tasks: Quality Gates & Code Hygiene
|
|
|
|
**Input**: Design documents from `/specs/031-quality-gates-hygiene/`
|
|
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, quickstart.md
|
|
|
|
**Tests**: No test tasks — feature spec does not request TDD or explicit tests. Verification is via `pnpm check`.
|
|
|
|
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
|
|
|
|
## Format: `[ID] [P?] [Story] Description`
|
|
|
|
- **[P]**: Can run in parallel (different files, no dependencies)
|
|
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
|
|
- Include exact file paths in descriptions
|
|
|
|
## Phase 1: Setup
|
|
|
|
**Purpose**: Install new dependencies and prepare infrastructure
|
|
|
|
- [x] T001 Install `@vitest/coverage-v8` as dev dependency via `pnpm add -D @vitest/coverage-v8` in root `package.json`
|
|
- [x] T002 Add `coverage/` to `.gitignore`
|
|
|
|
---
|
|
|
|
## Phase 2: User Story 1 — Constitution codifies early enforcement (Priority: P1) 🎯 MVP
|
|
|
|
**Goal**: The constitution and CLAUDE.md explicitly state that all automated quality gates MUST run at the earliest feasible enforcement point (currently pre-commit via Lefthook's `pnpm check`).
|
|
|
|
**Independent Test**: Read the updated constitution and CLAUDE.md and confirm the early-enforcement language is present.
|
|
|
|
### Implementation for User Story 1
|
|
|
|
- [x] T003 [P] [US1] Update the Development Workflow section of `.specify/memory/constitution.md` to add an early-enforcement rule: "All automated quality gates MUST run at the earliest feasible enforcement point (currently pre-commit via Lefthook). No gate may exist only as a CI step or manual process." Bump version 2.2.0 → 2.2.1 (PATCH). Update the "Last Amended" date.
|
|
- [x] T004 [P] [US1] Update the Conventions section of `CLAUDE.md` to add: "All 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." Also update the `pnpm check` comment in the Commands section to reflect the full set of gates once all stories are complete.
|
|
|
|
**Checkpoint**: Constitution and CLAUDE.md reflect the early-enforcement principle.
|
|
|
|
---
|
|
|
|
## Phase 3: User Story 2 — Test coverage thresholds (Priority: P1)
|
|
|
|
**Goal**: `pnpm check` enforces v8 coverage thresholds (lines: 70%, branches: 60%) with auto-ratchet.
|
|
|
|
**Independent Test**: Run `pnpm check` and verify coverage is reported, thresholds are enforced, and `thresholds.autoUpdate` is configured.
|
|
|
|
### Implementation for User Story 2
|
|
|
|
- [x] T005 [US2] Add `test.coverage` configuration to `vitest.config.ts`: provider `"v8"`, enabled `true`, thresholds `{ lines: 70, branches: 60, autoUpdate: true }`. See research.md R1 for exact syntax.
|
|
- [x] T006 [US2] Run `pnpm test` to verify coverage passes with the configured thresholds. If thresholds are too high for current coverage, lower them to just below actual coverage (the `autoUpdate` will ratchet them up). Commit any auto-updated threshold values in `vitest.config.ts`. Note in CLAUDE.md (during T019) that contributors must commit auto-ratcheted threshold changes as part of their changeset.
|
|
|
|
**Checkpoint**: `vitest run` reports coverage and enforces thresholds. No script changes needed — `vitest run` in `pnpm check` automatically includes coverage.
|
|
|
|
---
|
|
|
|
## Phase 4: User Story 3 — Cognitive complexity (Priority: P2)
|
|
|
|
**Goal**: Biome enforces `noExcessiveCognitiveComplexity` at threshold 15. All existing violations are refactored.
|
|
|
|
**Independent Test**: Run `biome check .` and verify no cognitive complexity violations.
|
|
|
|
### Implementation for User Story 3
|
|
|
|
- [x] T007 [US3] Enable `noExcessiveCognitiveComplexity` in `biome.json` under `linter.rules.complexity` with `level: "error"` and `options.maxAllowedComplexity: 15`. Nest inside existing `linter.rules` — add `"complexity"` key alongside `"recommended": true`.
|
|
- [x] T008 [P] [US3] Refactor `renderEntries` function (complexity 23) in `apps/web/src/adapters/bestiary-adapter.ts` to reduce cognitive complexity to ≤15. Extract helper functions for distinct entry type handling.
|
|
- [x] T009 [P] [US3] Refactor `loadEncounter` function (complexity 17) and rehydration callback (complexity 22) in `apps/web/src/persistence/encounter-storage.ts` to reduce cognitive complexity to ≤15. Extract field-rehydration logic into a helper function.
|
|
- [x] T010 [P] [US3] Refactor `checkLayerBoundaries` function (complexity 22) in `scripts/check-layer-boundaries.mjs` to reduce cognitive complexity to ≤15. Extract per-layer checking into separate functions.
|
|
- [x] T011 [P] [US3] Refactor `buildSourceMap` function (complexity 19) in `scripts/generate-bestiary-index.mjs` to reduce cognitive complexity to ≤15. Extract file-loading and source-parsing into helpers.
|
|
- [x] T012 [US3] Verify all 5 violations are resolved by running `npx biome lint --only='lint/complexity/noExcessiveCognitiveComplexity' .` and confirming zero errors.
|
|
|
|
**Checkpoint**: `biome check .` passes with cognitive complexity rule enabled.
|
|
|
|
---
|
|
|
|
## Phase 5: User Story 4 — Dependency audit (Priority: P2)
|
|
|
|
**Goal**: `pnpm check` includes `pnpm audit --audit-level=high` to catch high-severity CVEs at pre-commit.
|
|
|
|
**Independent Test**: Run the updated `pnpm check` and verify the audit step executes and passes.
|
|
|
|
### Implementation for User Story 4
|
|
|
|
- [x] T013 [US4] Add `pnpm audit --audit-level=high` to the `check` script in root `package.json`. Place it as the first step in the chain (before `knip`) for early failure on CVEs: `"check": "pnpm audit --audit-level=high && knip && biome check . && tsc --build && vitest run && jscpd"`.
|
|
|
|
**Checkpoint**: `pnpm check` runs audit as first gate.
|
|
|
|
---
|
|
|
|
## Phase 6: User Story 5 — Biome-ignore hygiene (Priority: P2)
|
|
|
|
**Goal**: Zero blanket `biome-ignore lint:` comments. Reduce a11y ignores in `combatant-row.tsx` from 8 to ≤4.
|
|
|
|
**Independent Test**: Search codebase for `biome-ignore lint:` (blanket form) — zero results. Count ignores in `combatant-row.tsx` — ≤4.
|
|
|
|
### Implementation for User Story 5
|
|
|
|
- [x] T014 [P] [US5] Fix the blanket `biome-ignore lint:` on line 65 of `packages/domain/src/set-initiative.ts`. Restructure the sort comparator to eliminate the need for non-null assertions: handle the `aHas && bHas` branch by extracting `a.c.initiative` and `b.c.initiative` into properly narrowed local variables (e.g., use an early-return pattern or explicit `as number` casts). The goal is to remove the ignore entirely, not replace it with a rule-specific one.
|
|
- [x] T015 [US5] Refactor `apps/web/src/components/combatant-row.tsx` to reduce the 8 a11y `biome-ignore` comments (4 pairs of `useKeyWithClickEvents` + `noStaticElementInteractions`). Strategy: the 3 inner wrapper divs (initiative, AC, HP sections) exist solely for `e.stopPropagation()` — replace them with a small reusable wrapper component or restructure the outer row's click handler to check `event.target`/`currentTarget` and skip propagation when a child interactive element is clicked. For the outer row div, add `role="button"`, `tabIndex={0}`, and an `onKeyDown` handler (Enter/Space) to satisfy both a11y rules. Target: ≤4 total ignores (down from 8).
|
|
- [x] T016 [US5] Verify no blanket `biome-ignore lint:` remains anywhere in the codebase by searching all `*.ts`, `*.tsx`, `*.js`, and `*.mjs` files.
|
|
|
|
**Checkpoint**: Zero blanket ignores. `combatant-row.tsx` has ≤4 ignores.
|
|
|
|
---
|
|
|
|
## Phase 7: User Story 6 — Biome a11y rules (Priority: P3)
|
|
|
|
**Goal**: Enable relevant non-recommended Biome a11y rules in `biome.json`.
|
|
|
|
**Independent Test**: Review `biome.json` for explicit a11y rule enablement. Run `biome check .` — no new violations.
|
|
|
|
### Implementation for User Story 6
|
|
|
|
- [x] T017 [US6] N/A — `noNoninteractiveElementInteractions` does not exist in Biome 2.0. All available a11y rules are already covered by `recommended: true`. No non-recommended a11y rules to enable. in `biome.json` under `linter.rules.a11y` with `level: "error"`. This is the only relevant non-recommended stable a11y rule in Biome 2.0 (research.md R3 confirmed no nursery a11y rules exist). Add `"a11y"` key alongside existing `"complexity"` under `linter.rules`.
|
|
- [x] T018 [US6] N/A — no new rule enabled, no violations to fix. from `noNoninteractiveElementInteractions` in existing code. Run `npx biome lint --only='lint/a11y/noNoninteractiveElementInteractions' .` to identify violations. Fix each by adding appropriate ARIA roles, converting to semantic elements, or adding rule-specific (never blanket) biome-ignore comments with justification.
|
|
|
|
**Checkpoint**: `biome check .` passes with the new a11y rule enabled.
|
|
|
|
---
|
|
|
|
## Phase 8: Polish & Cross-Cutting Concerns
|
|
|
|
**Purpose**: Final verification and documentation updates
|
|
|
|
- [x] T019 Update the `pnpm check` comment in the Commands section of `CLAUDE.md` to list all six gate types: `# Merge gate — must pass before every commit (audit + knip + biome + typecheck + test/coverage + jscpd)`
|
|
- [x] T020 Run `pnpm check` end-to-end and verify all gates pass: audit, knip, biome (including cognitive complexity + a11y rules), typecheck, vitest (with coverage thresholds), and jscpd.
|
|
- [x] T021 Clean up any agent-context markers added to `CLAUDE.md` by the speckit agent-context script (lines referencing `031-quality-gates-hygiene` with technology stack entries that duplicate existing Tech Stack documentation).
|
|
|
|
---
|
|
|
|
## Dependencies & Execution Order
|
|
|
|
### Phase Dependencies
|
|
|
|
- **Phase 1 (Setup)**: No dependencies — start immediately
|
|
- **Phase 2 (US1)**: No dependencies — can run in parallel with Phase 1
|
|
- **Phase 3 (US2)**: Depends on Phase 1 (needs `@vitest/coverage-v8` installed)
|
|
- **Phase 4 (US3)**: No dependencies on other phases — biome.json change + refactors are self-contained
|
|
- **Phase 5 (US4)**: No dependencies — `package.json` check script change is independent
|
|
- **Phase 6 (US5)**: No dependencies — biome-ignore fixes are independent
|
|
- **Phase 7 (US6)**: Should follow Phase 6 (US5) — combatant-row refactoring in US5 may affect which elements trigger the new a11y rule
|
|
- **Phase 8 (Polish)**: Depends on all previous phases — final verification
|
|
|
|
### User Story Dependencies
|
|
|
|
- **US1 (P1)**: Independent — documentation only
|
|
- **US2 (P1)**: Depends on Setup (T001)
|
|
- **US3 (P2)**: Independent — modifies `biome.json` + refactors
|
|
- **US4 (P2)**: Independent — modifies `package.json` check script
|
|
- **US5 (P2)**: Independent — modifies source files only
|
|
- **US6 (P3)**: Soft dependency on US5 — modifies `biome.json` (same file as US3, different section) and may interact with US5's combatant-row refactor
|
|
|
|
### Within Each User Story
|
|
|
|
- Config changes before code refactors (US3: enable rule → refactor violations)
|
|
- Verification task after implementation tasks
|
|
- Each story independently completable and verifiable
|
|
|
|
### Parallel Opportunities
|
|
|
|
**Cross-story parallelism** (after Setup):
|
|
- US1, US3, US4, US5 can all run in parallel (different files)
|
|
- US2 can run in parallel with all except must wait for T001
|
|
- US6 should follow US5 (shared file concerns)
|
|
|
|
**Within-story parallelism**:
|
|
- US3: T008, T009, T010, T011 (4 independent refactors across different files)
|
|
- US5: T014 can run in parallel with T015 (different files)
|
|
|
|
---
|
|
|
|
## Parallel Example: User Story 3
|
|
|
|
```text
|
|
# After T007 (biome.json rule enablement), launch all refactors in parallel:
|
|
Task: "Refactor renderEntries in apps/web/src/adapters/bestiary-adapter.ts"
|
|
Task: "Refactor loadEncounter + rehydration in apps/web/src/persistence/encounter-storage.ts"
|
|
Task: "Refactor checkLayerBoundaries in scripts/check-layer-boundaries.mjs"
|
|
Task: "Refactor buildSourceMap in scripts/generate-bestiary-index.mjs"
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Strategy
|
|
|
|
### MVP First (User Stories 1 + 2)
|
|
|
|
1. Complete Phase 1: Setup (install coverage dep)
|
|
2. Complete Phase 2: US1 — Constitution + CLAUDE.md
|
|
3. Complete Phase 3: US2 — Coverage thresholds
|
|
4. **STOP and VALIDATE**: `pnpm check` runs with coverage enforcement
|
|
5. The two P1 stories deliver the most impactful gates
|
|
|
|
### Incremental Delivery
|
|
|
|
1. Setup → US1 + US2 → Coverage + documentation MVP
|
|
2. Add US3 → Cognitive complexity enforced
|
|
3. Add US4 → Dependency audit enforced
|
|
4. Add US5 → Lint hygiene cleaned up
|
|
5. Add US6 → A11y rules comprehensive
|
|
6. Polish → Final verification
|
|
7. Each increment leaves `pnpm check` passing
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- [P] tasks = different files, no dependencies
|
|
- [Story] label maps task to specific user story for traceability
|
|
- No test tasks generated — verification is via `pnpm check` and manual search
|
|
- The `check` script in `package.json` is modified by US4 (T013) — be aware that US2's coverage wires in automatically via config, not script changes
|
|
- US3 and US6 both modify `biome.json` — if implementing in parallel, merge carefully (different rule sections: `complexity` vs `a11y`)
|
|
- Commit after each task or logical group
|