Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
171 lines
12 KiB
Markdown
171 lines
12 KiB
Markdown
---
|
|
phase: 13-real-lint-gate-eslint
|
|
plan: 03
|
|
type: execute
|
|
wave: 3
|
|
depends_on:
|
|
- 13-02
|
|
files_modified:
|
|
- .gitea/workflows/ci.yml
|
|
- apps/api/src/**
|
|
- apps/pwa/src/**
|
|
- apps/pwa/e2e/**
|
|
- apps/api/tests/**
|
|
autonomous: true
|
|
requirements: []
|
|
must_haves:
|
|
truths:
|
|
- "All files are reformatted by Prettier as ONE isolated mechanical commit, separate from Plan 02's logic fixes, for reviewability (D-13-08)"
|
|
- 'CI fast-checks job gains a `Format check` step running `pnpm format:check`, inserted after Lint and before Typecheck; the stale no-op lint comment is removed (SC-2)'
|
|
- 'Baseline gate ends green: `pnpm lint` exits 0 AND `pnpm format:check` exits 0 across both apps (SC-3)'
|
|
- 'CI lint step now genuinely blocks a PR to main on violations (no longer the --if-present no-op), and the new format:check step blocks on format violations (SC-2)'
|
|
artifacts:
|
|
- path: '.gitea/workflows/ci.yml'
|
|
provides: 'fast-checks job with a Format check step after Lint; stale no-op comment removed'
|
|
contains: 'format:check'
|
|
key_links:
|
|
- from: '.gitea/workflows/ci.yml fast-checks job'
|
|
to: 'root package.json lint + format:check scripts'
|
|
via: 'pnpm lint / pnpm format:check steps'
|
|
pattern: 'pnpm format:check'
|
|
---
|
|
|
|
<objective>
|
|
Close the phase: (1) run Prettier across the whole repo as a single isolated reformat commit (D-13-08), (2) add the `Format check` CI step to the fast-checks job and remove the now-false no-op lint comment (SC-2), (3) assert the green baseline — `pnpm lint` AND `pnpm format:check` both exit 0 across both apps (SC-3). This is the last wave; after it, the lint+format gate is real, green, and wired into CI.
|
|
|
|
Purpose: SC-3 requires the first real run's baseline to end green; SC-2 requires the CI gate to actually block PRs to main. The reformat is isolated from logic fixes (Plan 02) so the large mechanical diff is reviewable on its own.
|
|
Output: reformatted tree (isolated commit), updated ci.yml, green lint + format baseline.
|
|
</objective>
|
|
|
|
<execution_context>
|
|
@$HOME/.claude/gsd-core/workflows/execute-plan.md
|
|
@$HOME/.claude/gsd-core/templates/summary.md
|
|
</execution_context>
|
|
|
|
<context>
|
|
@.planning/PROJECT.md
|
|
@.planning/ROADMAP.md
|
|
@.planning/STATE.md
|
|
@.planning/phases/13-real-lint-gate-eslint/13-CONTEXT.md
|
|
@.planning/phases/13-real-lint-gate-eslint/13-RESEARCH.md
|
|
@.planning/phases/13-real-lint-gate-eslint/13-PATTERNS.md
|
|
@.planning/phases/13-real-lint-gate-eslint/13-02-SUMMARY.md
|
|
@.gitea/workflows/ci.yml
|
|
</context>
|
|
|
|
<artifacts_this_phase_produces>
|
|
No NEW files. MODIFIES:
|
|
|
|
- The whole source tree (Prettier reformat — isolated commit).
|
|
- `.gitea/workflows/ci.yml` — adds the `Format check` step; removes the stale 3-line no-op lint comment (ci.yml lines 28-30).
|
|
|
|
This completes the phase's full artifact set across all three plans:
|
|
|
|
- New config files (Plan 01): eslint.config.js, .prettierrc, .prettierignore
|
|
- New scripts (Plan 01): root format/format:check + type:module; apps/api & apps/pwa lint
|
|
- New CI step (Plan 03): Format check
|
|
- State: lint-clean (Plan 02) + format-clean (Plan 03) baseline, green in CI.
|
|
</artifacts_this_phase_produces>
|
|
|
|
<tasks>
|
|
|
|
<task type="auto">
|
|
<name>Task 1: Prettier reformat — single isolated mechanical commit (D-13-08)</name>
|
|
<files>apps/api/src/**, apps/api/tests/**, apps/pwa/src/**, apps/pwa/e2e/**, root config files Prettier owns</files>
|
|
<read_first>
|
|
- 13-RESEARCH.md "Prettier Configuration" (the .prettierrc settings + .prettierignore exclusions, so you know what gets formatted and what is skipped).
|
|
- 13-CONTEXT.md D-13-08 (isolate the reformat commit from logic fixes for reviewability).
|
|
</read_first>
|
|
<action>
|
|
Run `pnpm format` (`prettier --write .`) at the repo root. This reformats every file Prettier owns, respecting `.prettierignore` (dist/, node_modules/, pnpm-lock.yaml, apps/api/src/db/migrations/, *.html are skipped). Because `.prettierrc` sets `singleQuote: true` to match the existing codebase, the diff should be whitespace/wrapping/trailing-comma churn, not a mass quote flip.
|
|
|
|
This reformat MUST be its own commit, isolated from Plan 02's lint fixes (D-13-08) — do not mix any logic change into it. After formatting, run `pnpm lint` to confirm the reformat did NOT introduce any lint violation (eslint-config-prettier means ESLint does not fight Prettier, so this should stay green from Plan 02). If `pnpm lint` is non-zero after reformat, a formatting/lint conflict exists — investigate the eslint-config-prettier placement (must be last) before proceeding; do not blanket-disable.
|
|
|
|
Record `git diff --stat` (file count + line churn) in the SUMMARY as evidence of the mechanical reformat.
|
|
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/luc/Projects/familysync && pnpm format:check && pnpm lint && echo FORMAT_AND_LINT_GREEN_AFTER_REFORMAT</automated>
|
|
</verify>
|
|
<done>`pnpm format` ran; the whole tree is Prettier-clean (`pnpm format:check` exits 0) and still lint-clean (`pnpm lint` exits 0 — no eslint/prettier conflict). The reformat is staged as its own isolated commit with no logic changes mixed in. `git diff --stat` recorded in SUMMARY. The verify gate prints FORMAT_AND_LINT_GREEN_AFTER_REFORMAT.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 2: Add CI Format check step + remove stale no-op lint comment (SC-2)</name>
|
|
<files>.gitea/workflows/ci.yml</files>
|
|
<read_first>
|
|
- .gitea/workflows/ci.yml — the fast-checks job, the existing `Lint` (lines 31-32) and `Typecheck` (lines 34-35) steps, and the stale no-op comment at lines 28-30.
|
|
- 13-PATTERNS.md ".gitea/workflows/ci.yml — adding a Format check step" (exact step shape + the comment to remove) + the "CI step insertion" shared pattern (`- name: Verb noun` / ` run: pnpm <script>`).
|
|
- 13-RESEARCH.md "CI Wiring" (ordering rationale: lint → format:check → typecheck → tests).
|
|
</read_first>
|
|
<action>
|
|
Edit ONLY the fast-checks job in `.gitea/workflows/ci.yml`:
|
|
1. Remove the now-false 3-line comment above the Lint step (the "lint is currently a no-op … out of this phase's scope" block at lines 28-30) — it is no longer true now that real package lint scripts exist.
|
|
2. Insert a new step between `Lint` and `Typecheck`, matching the existing step idiom exactly:
|
|
`- name: Format check` / ` run: pnpm format:check`.
|
|
Final fast-checks step order: Install dependencies → Lint → Format check → Typecheck → PWA unit tests.
|
|
Do NOT touch the `api` or `harness` jobs, the `name: CI` line, or the `fast-checks` job id — those job ids are the required branch-protection contexts (STATE / memory: gitea main is protected, contexts must stay valid). No other CI change. No cache (D-PROBE-04 — the comment already documents why; leave it).
|
|
|
|
Validate the YAML parses after the edit.
|
|
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/luc/Projects/familysync && grep -q "Format check" .gitea/workflows/ci.yml && grep -q "pnpm format:check" .gitea/workflows/ci.yml && ! grep -q "out of this phase's scope" .gitea/workflows/ci.yml && python3 -c "import yaml,sys; yaml.safe_load(open('.gitea/workflows/ci.yml'))" && grep -q "fast-checks:" .gitea/workflows/ci.yml && echo CI_FORMAT_STEP_WIRED</automated>
|
|
</verify>
|
|
<done>ci.yml fast-checks job has a `Format check` step (`pnpm format:check`) between Lint and Typecheck; the stale no-op lint comment is gone; the `name: CI` line, `fast-checks` job id, and the api/harness jobs are unchanged (branch-protection contexts preserved). YAML parses. The verify gate prints CI_FORMAT_STEP_WIRED.</done>
|
|
</task>
|
|
|
|
<task type="auto">
|
|
<name>Task 3: Green-baseline assertion (SC-3) + full pre-verify suite</name>
|
|
<files>(verification only)</files>
|
|
<read_first>
|
|
- 13-VALIDATION.md "Validation Sign-Off" + "Full suite command" (`pnpm lint && pnpm format:check && pnpm typecheck && pnpm test`).
|
|
</read_first>
|
|
<action>
|
|
Final phase gate (SC-3). Run, from the repo root, the full validation suite and confirm every command exits 0: `pnpm lint`, `pnpm format:check`, `pnpm typecheck`, `pnpm --filter @familysync/api test`, `pnpm --filter @familysync/pwa test`. This is the baseline-green proof: the lint AND format gates both pass across both apps, and nothing regressed. If any command is non-zero, fix forward within this plan (a residual format/lint/type issue) — the phase is not done until all are green (D-13-05).
|
|
</action>
|
|
<verify>
|
|
<automated>cd /home/luc/Projects/familysync && pnpm lint && pnpm format:check && pnpm typecheck && pnpm --filter @familysync/api test && pnpm --filter @familysync/pwa test && echo BASELINE_GREEN</automated>
|
|
</verify>
|
|
<done>SC-3 met: `pnpm lint` AND `pnpm format:check` both exit 0 across both apps; typecheck + both test suites green. CI is wired to block PRs on lint and format violations (SC-2, asserted by Task 2's wiring). The verify gate prints BASELINE_GREEN. Phase 13 is complete.</done>
|
|
</task>
|
|
|
|
</tasks>
|
|
|
|
<threat_model>
|
|
|
|
## Trust Boundaries
|
|
|
|
| Boundary | Description |
|
|
| ------------------- | ---------------------------------------------------------------------------------- |
|
|
| PR → main (CI gate) | The fast-checks job is the quality boundary; lint/format failures must block merge |
|
|
|
|
Dev-tooling/CI-config phase: no runtime, network, auth, or user-data surface. The only sensitive concern is preserving the branch-protection job-id contexts.
|
|
|
|
## STRIDE Threat Register
|
|
|
|
| Threat ID | Category | Component | Disposition | Mitigation Plan |
|
|
| --------- | -------------------------------------------- | --------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| T-13-05 | Tampering / Denial of Service (CI integrity) | renaming the fast-checks job id or CI name while editing ci.yml | mitigate | Task 2 explicitly forbids touching `name: CI`, the `fast-checks` job id, and the api/harness jobs — those are the required branch-protection contexts (gitea main is protected; a renamed context would silently un-gate main). Verify gate asserts `fast-checks:` still present. |
|
|
| T-13-06 | Tampering | format:check step that never fails (mis-wired) | mitigate | SC-1 (Plan 01) already proved `pnpm format:check` exits non-zero on an unformatted file; Plan 03 only adds the step that runs that proven command. Green baseline (Task 3) confirms it exits 0 on the clean tree. |
|
|
|
|
</threat_model>
|
|
|
|
<verification>
|
|
- `pnpm format:check` exit 0 (whole tree Prettier-clean after the isolated reformat commit).
|
|
- `pnpm lint` exit 0 (reformat introduced no eslint/prettier conflict).
|
|
- ci.yml: `Format check` step present after Lint, stale no-op comment removed, YAML valid, `fast-checks` job id + `name: CI` unchanged.
|
|
- Full suite (lint + format:check + typecheck + api test + pwa test) all exit 0 — SC-3 baseline green.
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
|
|
- D-13-08: reformat is one isolated mechanical commit, separate from logic fixes.
|
|
- SC-2: CI fast-checks job has a real lint step (blocks on violations) + a new format:check step; stale comment removed; branch-protection contexts intact.
|
|
- SC-3: `pnpm lint` AND `pnpm format:check` both exit 0 across both apps; baseline gate ends green.
|
|
</success_criteria>
|
|
|
|
<output>
|
|
Create `.planning/phases/13-real-lint-gate-eslint/13-03-SUMMARY.md` when done. Record: `git diff --stat` of the reformat (files + line churn), the exact ci.yml step ordering after the edit, and the final green exit codes for lint / format:check / typecheck / tests (SC-3 evidence). Note that SC-2's "CI actually blocks the PR" confirmation is a one-time observation on the next real PR to main (per 13-VALIDATION.md Manual-Only table) — flag it for the operator.
|
|
</output>
|