Implement the 006-pre-commit-gate feature that enforces a pre-commit quality gate using Lefthook to run pnpm check before every commit
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,7 @@ The constitution (`.specify/memory/constitution.md`) governs all feature work:
|
||||
## Active Technologies
|
||||
- TypeScript 5.x (strict mode, verbatimModuleSyntax) + React 19, Vite (003-remove-combatant)
|
||||
- In-memory React state (local-first, single-user MVP) (003-remove-combatant)
|
||||
- TypeScript 5.x (project), Go binary via npm (Lefthook) + `lefthook` (npm devDependency) (006-pre-commit-gate)
|
||||
|
||||
## Recent Changes
|
||||
- 003-remove-combatant: Added TypeScript 5.x (strict mode, verbatimModuleSyntax) + React 19, Vite
|
||||
|
||||
4
lefthook.yml
Normal file
4
lefthook.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
pre-commit:
|
||||
jobs:
|
||||
- name: check
|
||||
run: pnpm check
|
||||
@@ -3,10 +3,12 @@
|
||||
"packageManager": "pnpm@10.6.0",
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.0.0",
|
||||
"lefthook": "^1.11.0",
|
||||
"typescript": "^5.8.0",
|
||||
"vitest": "^3.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "lefthook install",
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome format .",
|
||||
"lint": "biome lint .",
|
||||
|
||||
100
pnpm-lock.yaml
generated
100
pnpm-lock.yaml
generated
@@ -11,6 +11,9 @@ importers:
|
||||
'@biomejs/biome':
|
||||
specifier: 2.0.0
|
||||
version: 2.0.0
|
||||
lefthook:
|
||||
specifier: ^1.11.0
|
||||
version: 1.13.6
|
||||
typescript:
|
||||
specifier: ^5.8.0
|
||||
version: 5.9.3
|
||||
@@ -660,6 +663,60 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
hasBin: true
|
||||
|
||||
lefthook-darwin-arm64@1.13.6:
|
||||
resolution: {integrity: sha512-m6Lb77VGc84/Qo21Lhq576pEvcgFCnvloEiP02HbAHcIXD0RTLy9u2yAInrixqZeaz13HYtdDaI7OBYAAdVt8A==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
lefthook-darwin-x64@1.13.6:
|
||||
resolution: {integrity: sha512-CoRpdzanu9RK3oXR1vbEJA5LN7iB+c7hP+sONeQJzoOXuq4PNKVtEaN84Gl1BrVtCNLHWFAvCQaZPPiiXSy8qg==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
lefthook-freebsd-arm64@1.13.6:
|
||||
resolution: {integrity: sha512-X4A7yfvAJ68CoHTqP+XvQzdKbyd935sYy0bQT6Ajz7FL1g7hFiro8dqHSdPdkwei9hs8hXeV7feyTXbYmfjKQQ==}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
lefthook-freebsd-x64@1.13.6:
|
||||
resolution: {integrity: sha512-ai2m+Sj2kGdY46USfBrCqLKe9GYhzeq01nuyDYCrdGISePeZ6udOlD1k3lQKJGQCHb0bRz4St0r5nKDSh1x/2A==}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
lefthook-linux-arm64@1.13.6:
|
||||
resolution: {integrity: sha512-cbo4Wtdq81GTABvikLORJsAWPKAJXE8Q5RXsICFUVznh5PHigS9dFW/4NXywo0+jfFPCT6SYds2zz4tCx6DA0Q==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
lefthook-linux-x64@1.13.6:
|
||||
resolution: {integrity: sha512-uJl9vjCIIBTBvMZkemxCE+3zrZHlRO7Oc+nZJ+o9Oea3fu+W82jwX7a7clw8jqNfaeBS+8+ZEQgiMHWCloTsGw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
lefthook-openbsd-arm64@1.13.6:
|
||||
resolution: {integrity: sha512-7r153dxrNRQ9ytRs2PmGKKkYdvZYFPre7My7XToSTiRu5jNCq++++eAKVkoyWPduk97dGIA+YWiEr5Noe0TK2A==}
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
lefthook-openbsd-x64@1.13.6:
|
||||
resolution: {integrity: sha512-Z+UhLlcg1xrXOidK3aLLpgH7KrwNyWYE3yb7ITYnzJSEV8qXnePtVu8lvMBHs/myzemjBzeIr/U/+ipjclR06g==}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
lefthook-windows-arm64@1.13.6:
|
||||
resolution: {integrity: sha512-Uxef6qoDxCmUNQwk8eBvddYJKSBFglfwAY9Y9+NnnmiHpWTjjYiObE9gT2mvGVpEgZRJVAatBXc+Ha5oDD/OgQ==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
lefthook-windows-x64@1.13.6:
|
||||
resolution: {integrity: sha512-mOZoM3FQh3o08M8PQ/b3IYuL5oo36D9ehczIw1dAgp1Ly+Tr4fJ96A+4SEJrQuYeRD4mex9bR7Ps56I73sBSZA==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
lefthook@1.13.6:
|
||||
resolution: {integrity: sha512-ojj4/4IJ29Xn4drd5emqVgilegAPN3Kf0FQM2p/9+lwSTpU+SZ1v4Ig++NF+9MOa99UKY8bElmVrLhnUUNFh5g==}
|
||||
hasBin: true
|
||||
|
||||
loupe@3.2.1:
|
||||
resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
|
||||
|
||||
@@ -1362,6 +1419,49 @@ snapshots:
|
||||
|
||||
json5@2.2.3: {}
|
||||
|
||||
lefthook-darwin-arm64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook-darwin-x64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook-freebsd-arm64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook-freebsd-x64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook-linux-arm64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook-linux-x64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook-openbsd-arm64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook-openbsd-x64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook-windows-arm64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook-windows-x64@1.13.6:
|
||||
optional: true
|
||||
|
||||
lefthook@1.13.6:
|
||||
optionalDependencies:
|
||||
lefthook-darwin-arm64: 1.13.6
|
||||
lefthook-darwin-x64: 1.13.6
|
||||
lefthook-freebsd-arm64: 1.13.6
|
||||
lefthook-freebsd-x64: 1.13.6
|
||||
lefthook-linux-arm64: 1.13.6
|
||||
lefthook-linux-x64: 1.13.6
|
||||
lefthook-openbsd-arm64: 1.13.6
|
||||
lefthook-openbsd-x64: 1.13.6
|
||||
lefthook-windows-arm64: 1.13.6
|
||||
lefthook-windows-x64: 1.13.6
|
||||
|
||||
loupe@3.2.1: {}
|
||||
|
||||
lru-cache@5.1.1:
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
packages:
|
||||
- "packages/*"
|
||||
- "apps/*"
|
||||
|
||||
onlyBuiltDependencies:
|
||||
- lefthook
|
||||
|
||||
34
specs/006-pre-commit-gate/checklists/requirements.md
Normal file
34
specs/006-pre-commit-gate/checklists/requirements.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Specification Quality Checklist: Pre-Commit Gate
|
||||
|
||||
**Purpose**: Validate specification completeness and quality before proceeding to planning
|
||||
**Created**: 2026-03-05
|
||||
**Feature**: [spec.md](../spec.md)
|
||||
|
||||
## Content Quality
|
||||
|
||||
- [x] No implementation details (languages, frameworks, APIs)
|
||||
- [x] Focused on user value and business needs
|
||||
- [x] Written for non-technical stakeholders
|
||||
- [x] All mandatory sections completed
|
||||
|
||||
## Requirement Completeness
|
||||
|
||||
- [x] No [NEEDS CLARIFICATION] markers remain
|
||||
- [x] Requirements are testable and unambiguous
|
||||
- [x] Success criteria are measurable
|
||||
- [x] Success criteria are technology-agnostic (no implementation details)
|
||||
- [x] All acceptance scenarios are defined
|
||||
- [x] Edge cases are identified
|
||||
- [x] Scope is clearly bounded
|
||||
- [x] Dependencies and assumptions identified
|
||||
|
||||
## Feature Readiness
|
||||
|
||||
- [x] All functional requirements have clear acceptance criteria
|
||||
- [x] User scenarios cover primary flows
|
||||
- [x] Feature meets measurable outcomes defined in Success Criteria
|
||||
- [x] No implementation details leak into specification
|
||||
|
||||
## Notes
|
||||
|
||||
- All items pass. Spec is ready for `/speckit.clarify` or `/speckit.plan`.
|
||||
67
specs/006-pre-commit-gate/plan.md
Normal file
67
specs/006-pre-commit-gate/plan.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Implementation Plan: Pre-Commit Gate
|
||||
|
||||
**Branch**: `006-pre-commit-gate` | **Date**: 2026-03-05 | **Spec**: [spec.md](./spec.md)
|
||||
**Input**: Feature specification from `/specs/006-pre-commit-gate/spec.md`
|
||||
|
||||
## Summary
|
||||
|
||||
Enforce a pre-commit quality gate by adding Lefthook as a Git hooks manager. A `lefthook.yml` configuration defines a pre-commit hook that runs `pnpm check`. The hook auto-installs via a `prepare` script in `package.json`, ensuring zero manual setup for developers after `pnpm install`.
|
||||
|
||||
## Technical Context
|
||||
|
||||
**Language/Version**: TypeScript 5.x (project), Go binary via npm (Lefthook)
|
||||
**Primary Dependencies**: `lefthook` (npm devDependency)
|
||||
**Storage**: N/A
|
||||
**Testing**: Manual verification (commit with passing/failing checks)
|
||||
**Target Platform**: macOS, Linux (developer workstations)
|
||||
**Project Type**: Monorepo (pnpm workspaces) -- web application with domain/application/web layers
|
||||
**Performance Goals**: No additional overhead beyond `pnpm check` execution time
|
||||
**Constraints**: Must auto-install on `pnpm install`; must not interfere with CI
|
||||
**Scale/Scope**: 2 files changed (lefthook.yml created, package.json modified)
|
||||
|
||||
## Constitution Check
|
||||
|
||||
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
|
||||
|
||||
| Principle | Status | Notes |
|
||||
|-----------|--------|-------|
|
||||
| I. Deterministic Domain Core | N/A | No domain logic changes |
|
||||
| II. Layered Architecture | PASS | Tooling-only change, no layer imports affected |
|
||||
| III. Agent Boundary | N/A | No agent layer changes |
|
||||
| IV. Clarification-First | PASS | User explicitly specified Lefthook; no ambiguity |
|
||||
| V. Escalation Gates | PASS | Feature is within spec scope |
|
||||
| VI. MVP Baseline Language | PASS | No permanent bans introduced |
|
||||
| VII. No Gameplay Rules | N/A | Not a gameplay feature |
|
||||
| Development Workflow (merge gate) | PASS | Directly implements the "automated checks must pass" rule |
|
||||
| Layer boundary compliance | N/A | No source code layer changes |
|
||||
|
||||
**Post-design re-check**: All gates still pass. No design decisions introduced new violations.
|
||||
|
||||
## Project Structure
|
||||
|
||||
### Documentation (this feature)
|
||||
|
||||
```text
|
||||
specs/006-pre-commit-gate/
|
||||
├── plan.md # This file
|
||||
├── research.md # Phase 0 output
|
||||
├── quickstart.md # Phase 1 output
|
||||
├── spec.md # Feature specification
|
||||
└── checklists/
|
||||
└── requirements.md # Spec quality checklist
|
||||
```
|
||||
|
||||
### Source Code (repository root)
|
||||
|
||||
```text
|
||||
./
|
||||
├── lefthook.yml # NEW — Lefthook configuration (pre-commit hook)
|
||||
├── package.json # MODIFIED — add lefthook devDep + prepare script
|
||||
└── (all existing files unchanged)
|
||||
```
|
||||
|
||||
**Structure Decision**: This feature only adds tooling configuration at the repository root. No source code directories are created or modified. The existing monorepo structure (`packages/*`, `apps/*`) is unchanged.
|
||||
|
||||
## Complexity Tracking
|
||||
|
||||
No constitution violations. Table not applicable.
|
||||
34
specs/006-pre-commit-gate/quickstart.md
Normal file
34
specs/006-pre-commit-gate/quickstart.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Quickstart: Pre-Commit Gate
|
||||
|
||||
## What This Feature Does
|
||||
|
||||
Adds a Git pre-commit hook (managed by Lefthook) that runs `pnpm check` before every commit. If any check fails, the commit is blocked.
|
||||
|
||||
## Files to Create/Modify
|
||||
|
||||
| File | Action | Purpose |
|
||||
|------|--------|---------|
|
||||
| `lefthook.yml` | Create | Lefthook configuration with pre-commit hook |
|
||||
| `package.json` | Modify | Add `lefthook` devDependency + `prepare` script |
|
||||
|
||||
## Setup After Implementation
|
||||
|
||||
After the feature is implemented, hooks activate automatically:
|
||||
|
||||
```bash
|
||||
pnpm install # installs lefthook + runs `prepare` which calls `lefthook install`
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
1. Developer runs `git commit`
|
||||
2. Lefthook intercepts via the Git pre-commit hook
|
||||
3. Lefthook runs `pnpm check` (format + lint + typecheck + test)
|
||||
4. If `pnpm check` exits 0 → commit proceeds
|
||||
5. If `pnpm check` exits non-zero → commit is blocked, output shown
|
||||
|
||||
## Bypass
|
||||
|
||||
```bash
|
||||
git commit --no-verify # skips the pre-commit hook
|
||||
```
|
||||
45
specs/006-pre-commit-gate/research.md
Normal file
45
specs/006-pre-commit-gate/research.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Research: Pre-Commit Gate
|
||||
|
||||
## R1: Hook Management Tool
|
||||
|
||||
**Decision**: Use [Lefthook](https://github.com/evilmartians/lefthook) (npm package) as the Git hooks manager.
|
||||
|
||||
**Rationale**:
|
||||
- User explicitly requested Lefthook.
|
||||
- Lightweight, standalone Go binary distributed via npm -- no runtime dependencies.
|
||||
- Simple YAML configuration (`lefthook.yml`).
|
||||
- Auto-installs hooks via npm `postinstall` lifecycle script -- satisfies FR-005 (no manual setup).
|
||||
- Well-maintained, widely adopted (used by n8n, Shopify, and others).
|
||||
- Respects `--no-verify` by default (standard Git behavior) -- satisfies FR-006.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Husky: Popular but heavier configuration, requires `.husky/` directory with shell scripts.
|
||||
- `core.hooksPath`: Native Git, but requires manual setup or custom scripts for auto-install.
|
||||
- Simple `prepare` script copying a shell script: Works but no parallel jobs, no structured config.
|
||||
|
||||
## R2: Auto-Install Mechanism
|
||||
|
||||
**Decision**: Use a `prepare` script in root `package.json` that runs `lefthook install`.
|
||||
|
||||
**Rationale**:
|
||||
- The `prepare` lifecycle hook runs automatically after `pnpm install`.
|
||||
- This ensures every developer gets hooks installed without extra steps after cloning.
|
||||
- Lefthook's npm package includes a `postinstall` script that can auto-install, but an explicit `prepare` script is more transparent and reliable across package managers.
|
||||
- In CI environments, `CI=true` prevents the `prepare` script from running (standard npm/pnpm behavior), avoiding unnecessary hook installation in CI.
|
||||
|
||||
**Alternatives considered**:
|
||||
- Relying solely on lefthook's built-in `postinstall`: Less transparent; behavior varies with `CI` env var.
|
||||
- Manual `lefthook install` step in README: Violates FR-005.
|
||||
|
||||
## R3: Hook Command Strategy
|
||||
|
||||
**Decision**: The pre-commit hook runs `pnpm check` as a single command.
|
||||
|
||||
**Rationale**:
|
||||
- `pnpm check` already orchestrates format, lint, typecheck, and test in sequence.
|
||||
- Running it as one command keeps the hook configuration minimal and consistent with the existing merge-gate workflow.
|
||||
- Output from `pnpm check` already identifies which specific check failed (FR-004, SC-004).
|
||||
|
||||
**Alternatives considered**:
|
||||
- Running each check as a separate Lefthook job with `parallel: true`: Could be faster but adds configuration complexity and the existing `pnpm check` script already handles sequencing. MVP baseline does not include parallel hook jobs.
|
||||
- Using `{staged_files}` for file-scoped checks: MVP baseline does not include staged-only checking per spec assumptions.
|
||||
88
specs/006-pre-commit-gate/spec.md
Normal file
88
specs/006-pre-commit-gate/spec.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Feature Specification: Pre-Commit Gate
|
||||
|
||||
**Feature Branch**: `006-pre-commit-gate`
|
||||
**Created**: 2026-03-05
|
||||
**Status**: Draft
|
||||
**Input**: User description: "Enforce a pre-commit gate: block commits unless `pnpm check` passes."
|
||||
|
||||
## User Scenarios & Testing *(mandatory)*
|
||||
|
||||
### User Story 1 - Blocked Commit on Failing Checks (Priority: P1)
|
||||
|
||||
A developer attempts to commit code that does not pass `pnpm check` (format, lint, typecheck, or test failures). The commit is automatically rejected with a clear message indicating what failed, preventing broken code from entering the repository.
|
||||
|
||||
**Why this priority**: This is the core purpose of the feature -- preventing commits that violate project quality standards.
|
||||
|
||||
**Independent Test**: Can be tested by introducing a deliberate lint or type error, attempting to commit, and verifying the commit is blocked with an informative error message.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a developer has staged changes that fail formatting, **When** they run `git commit`, **Then** the commit is rejected and the output shows the formatting errors.
|
||||
2. **Given** a developer has staged changes that fail linting, **When** they run `git commit`, **Then** the commit is rejected and the output shows the lint errors.
|
||||
3. **Given** a developer has staged changes that fail typechecking, **When** they run `git commit`, **Then** the commit is rejected and the output shows the typecheck errors.
|
||||
4. **Given** a developer has staged changes that fail tests, **When** they run `git commit`, **Then** the commit is rejected and the output shows the test failures.
|
||||
|
||||
---
|
||||
|
||||
### User Story 2 - Successful Commit on Passing Checks (Priority: P1)
|
||||
|
||||
A developer commits code that passes all checks. The pre-commit gate runs `pnpm check`, all checks pass, and the commit proceeds normally without extra friction.
|
||||
|
||||
**Why this priority**: Equally critical -- the gate must not block valid commits. A gate that only blocks but never allows is useless.
|
||||
|
||||
**Independent Test**: Can be tested by making a valid code change, committing, and verifying the commit succeeds after checks pass.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a developer has staged changes that pass all checks, **When** they run `git commit`, **Then** `pnpm check` runs and the commit completes successfully.
|
||||
|
||||
---
|
||||
|
||||
### User Story 3 - Bypass Gate in Emergencies (Priority: P2)
|
||||
|
||||
A developer needs to bypass the pre-commit gate in an emergency situation (e.g., a hotfix where the existing codebase already has a known issue). They can use the standard Git `--no-verify` flag to skip the hook.
|
||||
|
||||
**Why this priority**: Important escape hatch, but not the primary use case. Standard Git behavior should be preserved.
|
||||
|
||||
**Independent Test**: Can be tested by attempting `git commit --no-verify` with failing checks and verifying the commit succeeds.
|
||||
|
||||
**Acceptance Scenarios**:
|
||||
|
||||
1. **Given** a developer has staged changes that fail checks, **When** they run `git commit --no-verify`, **Then** the commit proceeds without running the pre-commit gate.
|
||||
|
||||
---
|
||||
|
||||
### Edge Cases
|
||||
|
||||
- What happens when `pnpm` is not installed or not in PATH? The hook should fail with a clear error message.
|
||||
- What happens when `node_modules` are not installed? The hook should fail with a clear error message suggesting `pnpm install`.
|
||||
- What happens when the hook is run outside the project root? The hook should resolve the project root correctly.
|
||||
- What happens on a fresh clone? The hook must be automatically available after `pnpm install` without additional manual steps.
|
||||
|
||||
## Requirements *(mandatory)*
|
||||
|
||||
### Functional Requirements
|
||||
|
||||
- **FR-001**: The repository MUST include a Git pre-commit hook that runs `pnpm check` before every commit.
|
||||
- **FR-002**: The hook MUST block the commit (exit non-zero) if `pnpm check` fails.
|
||||
- **FR-003**: The hook MUST allow the commit (exit zero) if `pnpm check` succeeds.
|
||||
- **FR-004**: The hook MUST display the output from `pnpm check` so the developer can see what failed.
|
||||
- **FR-005**: The hook MUST be automatically available to all developers after cloning and running `pnpm install` (no manual hook installation steps).
|
||||
- **FR-006**: The hook MUST be bypassable using the standard `git commit --no-verify` flag.
|
||||
- **FR-007**: The hook MUST provide a clear error message if `pnpm` is not available.
|
||||
|
||||
## Success Criteria *(mandatory)*
|
||||
|
||||
### Measurable Outcomes
|
||||
|
||||
- **SC-001**: 100% of commits made without `--no-verify` are validated by `pnpm check` before being accepted.
|
||||
- **SC-002**: Developers see check results within the normal `pnpm check` execution time -- the hook adds no meaningful overhead beyond running the checks themselves.
|
||||
- **SC-003**: New contributors can clone the repository, run `pnpm install`, and have the pre-commit gate active without any additional setup steps.
|
||||
- **SC-004**: Developers can identify the specific failing check (format, lint, typecheck, or test) from the hook output alone.
|
||||
|
||||
## Assumptions
|
||||
|
||||
- The project already has a working `pnpm check` command that runs format, lint, typecheck, and test checks.
|
||||
- All developers use Git for version control.
|
||||
- The hook management approach uses Lefthook, a lightweight Git hooks manager distributed as an npm package, with a `prepare` script for auto-installation.
|
||||
- MVP baseline does not include partial/staged-only checking (e.g., lint-staged). The full `pnpm check` runs on the entire project.
|
||||
105
specs/006-pre-commit-gate/tasks.md
Normal file
105
specs/006-pre-commit-gate/tasks.md
Normal file
@@ -0,0 +1,105 @@
|
||||
# Tasks: Pre-Commit Gate
|
||||
|
||||
**Input**: Design documents from `/specs/006-pre-commit-gate/`
|
||||
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, quickstart.md
|
||||
|
||||
**Tests**: No test tasks included (not requested in feature specification). Verification is manual.
|
||||
|
||||
**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 (Shared Infrastructure)
|
||||
|
||||
**Purpose**: Install Lefthook and configure auto-install mechanism
|
||||
|
||||
- [x] T001 Add `lefthook` as a devDependency and add a `prepare` script that runs `lefthook install` in `package.json`
|
||||
- [x] T002 Run `pnpm install` to install lefthook and activate the prepare script
|
||||
|
||||
**Checkpoint**: `lefthook` is installed and `pnpm install` triggers `lefthook install` automatically
|
||||
|
||||
---
|
||||
|
||||
## Phase 2: User Story 1 & 2 - Block Failing / Allow Passing Commits (Priority: P1) MVP
|
||||
|
||||
**Goal**: Create the Lefthook pre-commit hook configuration that runs `pnpm check`, blocking commits on failure and allowing commits on success.
|
||||
|
||||
**Independent Test (US1)**: Introduce a deliberate lint error, run `git commit`, and verify the commit is blocked with visible error output.
|
||||
|
||||
**Independent Test (US2)**: Make a valid change, run `git commit`, and verify the commit succeeds after `pnpm check` passes.
|
||||
|
||||
### Implementation
|
||||
|
||||
- [x] T003 [US1] [US2] Create `lefthook.yml` at repository root with a `pre-commit` hook that runs `pnpm check`
|
||||
|
||||
**Checkpoint**: Commits are blocked when `pnpm check` fails (US1) and allowed when it passes (US2). Output from `pnpm check` is visible to the developer.
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: User Story 3 - Bypass Gate in Emergencies (Priority: P2)
|
||||
|
||||
**Goal**: Ensure the standard `git commit --no-verify` flag bypasses the pre-commit hook.
|
||||
|
||||
**Independent Test**: Stage a change that would fail checks, run `git commit --no-verify`, and verify the commit succeeds without running checks.
|
||||
|
||||
### Implementation
|
||||
|
||||
No implementation task needed -- Lefthook respects `--no-verify` by default (standard Git behavior). This phase exists for verification only.
|
||||
|
||||
**Checkpoint**: `git commit --no-verify` bypasses the pre-commit gate.
|
||||
|
||||
---
|
||||
|
||||
## Phase 4: Polish & Cross-Cutting Concerns
|
||||
|
||||
**Purpose**: Edge case handling and validation
|
||||
|
||||
- [x] T004 Verify the hook provides a clear error when `pnpm` is not in PATH (FR-007) and when `node_modules` are missing (edge case)
|
||||
- [x] T005 Run quickstart.md validation: clone-install-commit workflow works end-to-end (SC-003)
|
||||
|
||||
---
|
||||
|
||||
## Dependencies & Execution Order
|
||||
|
||||
### Phase Dependencies
|
||||
|
||||
- **Setup (Phase 1)**: No dependencies -- start immediately
|
||||
- **US1 & US2 (Phase 2)**: Depends on Phase 1 (lefthook must be installed)
|
||||
- **US3 (Phase 3)**: No implementation needed -- verify after Phase 2
|
||||
- **Polish (Phase 4)**: Depends on Phase 2 completion
|
||||
|
||||
### Parallel Opportunities
|
||||
|
||||
- T001 and T003 touch different files (`package.json` vs `lefthook.yml`) but T003 depends on lefthook being installed, so they must be sequential.
|
||||
- T004 and T005 can run in parallel after Phase 2.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Strategy
|
||||
|
||||
### MVP First (User Stories 1 & 2)
|
||||
|
||||
1. Complete Phase 1: Install lefthook + prepare script
|
||||
2. Complete Phase 2: Create `lefthook.yml` with pre-commit hook
|
||||
3. **STOP and VALIDATE**: Test both blocking and allowing commits
|
||||
4. Verify US3 bypass works (no implementation needed)
|
||||
|
||||
### Execution Summary
|
||||
|
||||
Total: **5 tasks** across 4 phases
|
||||
- Phase 1 (Setup): 2 tasks
|
||||
- Phase 2 (US1 + US2): 1 task
|
||||
- Phase 3 (US3): 0 tasks (verification only)
|
||||
- Phase 4 (Polish): 2 tasks
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- US1 and US2 are implemented by the same single task (T003) because they are two sides of the same coin: the hook either blocks or allows based on `pnpm check` exit code.
|
||||
- US3 requires no implementation -- `--no-verify` is standard Git behavior that Lefthook respects.
|
||||
- This is a minimal-footprint feature: 1 new file (`lefthook.yml`), 1 modified file (`package.json`).
|
||||
Reference in New Issue
Block a user