Files
initiative/specs/031-quality-gates-hygiene/tasks.md

13 KiB

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

  • T001 Install @vitest/coverage-v8 as dev dependency via pnpm add -D @vitest/coverage-v8 in root package.json
  • 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

  • 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.
  • 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

  • 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.
  • 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

  • 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.
  • 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.
  • 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.
  • 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.
  • 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.
  • 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

  • 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

  • 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.
  • 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).
  • 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

  • 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.
  • 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

  • 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)
  • 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.
  • 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

# 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