Files
familysync/.planning/phases/13-real-lint-gate-eslint/13-01-SUMMARY.md
T
Lucas Berger 982438dc10 style(13-03): apply Prettier formatting across repo
Mechanical reformat — no logic changes. 398 files changed, 19125
insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc
(singleQuote:true, semi:true, tabWidth:2, trailingComma:all,
printWidth:100). Isolated per D-13-08 for reviewability.
2026-06-11 20:35:18 -04:00

8.9 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
13-real-lint-gate-eslint 01 dev-tooling
eslint
prettier
lint-gate
typescript-eslint
react-hooks
flat-config
requires provides affects
eslint-flat-config
prettier-config
lint-scripts
format-scripts
ci-lint-slot
apps/api
apps/pwa
added patterns
eslint@9.39.4 (root devDep — pinned, ESLint 10 breaks eslint-plugin-react)
@eslint/js@9.39.4
typescript-eslint@8.61.0
eslint-plugin-react@7.37.5
eslint-plugin-react-hooks@7.1.1
eslint-config-prettier@10.1.8
prettier@3.8.4
ESLint flat config with tseslint.config() helper
projectService:true for multi-tsconfig monorepo (auto-discovers all tsconfigs)
disableTypeChecked override block for config files + API test dir
eslint-config-prettier/flat LAST to disable formatting rule conflicts
created modified
eslint.config.js
.prettierrc
.prettierignore
package.json (type:module + format/format:check scripts)
apps/api/package.json (lint script --max-warnings 0)
apps/pwa/package.json (lint script --max-warnings 0)
pnpm-lock.yaml
ESLint pinned to 9.39.4 (non-negotiable): eslint-plugin-react@7.37.5 declares peer ^9.7 and hits TypeError at runtime on ESLint 10 (getFilename removed)
react/react-in-jsx-scope explicitly disabled: flat.recommended enables it at error; codebase uses jsx:react-jsx (React 17+ transform) so React import is not required
apps/api/tests/** in disableTypeChecked block: excluded from apps/api/tsconfig.json so projectService cannot type-check them
eslint.config.js itself added to disableTypeChecked block as precaution (JS file, not in any TS project)
duration_minutes completed_date tasks_completed files_changed
8 2026-06-11 2 7

Phase 13 Plan 01: ESLint + Prettier Lint Gate Foundation Summary

Real ESLint flat config (type-aware via projectService) + Prettier installed and wired; both gates proven non-zero on deliberate violations (SC-1).

What Was Built

Task 1: Install devDependencies + author flat config + Prettier config

Installed 7 packages at pinned versions as root devDependencies. Authored eslint.config.js with the required 5-block structure per RESEARCH Pattern 1:

  1. Global ignores**/dist/**, **/node_modules/**, apps/api/src/db/migrations/**, pnpm-lock.yaml
  2. Base blockapps/**/*.{ts,tsx}, extends js.configs.recommended + tseslint.configs.recommendedTypeChecked, parserOptions.projectService: true + tsconfigRootDir: import.meta.dirname, @typescript-eslint/no-unused-vars rule with ^_ ignore patterns
  3. PWA-React blockapps/pwa/**/*.{ts,tsx} only, extends reactPlugin.configs.flat.recommended + reactHooks.configs.flat.recommended, react.version: 'detect', react/prop-types: 'off', react/react-in-jsx-scope: 'off'
  4. disableTypeChecked override — config files (drizzle.config, vitest.config, vite.config, playwright.config) + apps/api/tests/**/*.ts + eslint.config.js itself
  5. eslint-config-prettier/flat LAST — disables ESLint formatting rules that conflict with Prettier

Added "type": "module" to root package.json (required for eslint.config.js to parse as ESM). Added format/format:check scripts. Added lint script with --max-warnings 0 to both apps/api/package.json and apps/pwa/package.json.

Authored .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100) and .prettierignore.

Commit: df62d33

Task 2: SC-1 smoke proof — deliberate violations, both gates, throwaway cleanup

Lint gate (SC-1 lint half):

  • Created apps/api/src/_lint-gate-test.ts with an unhandled Promise.resolve(1) expression
  • Ran pnpm --filter @familysync/api lintexit code 1, @typescript-eslint/no-floating-promises reported on the deliberate file
  • Deleted apps/api/src/_lint-gate-test.ts — never staged or committed

Format gate (SC-1 format half):

  • Created _format-gate-test.ts at repo root with double quotes + irregular indentation (opposite of .prettierrc settings)
  • Ran pnpm format:checkexit code 1, _format-gate-test.ts listed in warnings
  • Deleted _format-gate-test.ts — never staged or committed

Commit: 7a255ea

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug] react/react-in-jsx-scope unexpectedly enabled in reactPlugin.configs.flat.recommended

  • Found during: Task 2 (SC-1 smoke) — 404 react/react-in-jsx-scope errors in the PWA
  • Issue: RESEARCH.md (Assumption A1, Pitfall 8) stated that reactPlugin.configs.flat.recommended disables react/react-in-jsx-scope for React 17+ JSX transform. In practice, eslint-plugin-react@7.37.5 flat.recommended sets this rule to 2 (error). The PWA uses jsx: "react-jsx" (React 19 automatic transform) — React does not need to be in scope.
  • Fix: Added 'react/react-in-jsx-scope': 'off' alongside 'react/prop-types': 'off' in the pwa-react config block
  • Files modified: eslint.config.js
  • Commit: 7a255ea

SC-1 Evidence

Gate Deliberate Violation Exit Code Rule Reported
pnpm --filter @familysync/api lint Promise.resolve(1) — unhandled promise 1 (non-zero) @typescript-eslint/no-floating-promises
pnpm format:check double quotes + irregular indent (opposite of .prettierrc) 1 (non-zero) _format-gate-test.ts listed as unformatted

Both throwaway files confirmed absent and untracked (THROWAWAYS_ABSENT_AND_UNTRACKED).

First-Run Violation Inventory (for Plan 02)

Plan 02 consumes this inventory to scope fixes. No violations were fixed in this plan.

apps/api — 42 errors total

Rule Count Description
@typescript-eslint/no-unnecessary-type-assertion 24 Redundant as casts (mainly in outboxWorker.ts dispatcher blocks)
@typescript-eslint/no-unsafe-assignment 3 any assignment from ical.js property access
@typescript-eslint/no-unsafe-argument 4 any args from ical.js property values
@typescript-eslint/no-unused-vars 7 Test file variables assigned but unused
@typescript-eslint/no-misused-promises 1 sse.ts:96 — async callback in void context
@typescript-eslint/no-base-to-string 1 Template literal with possible [object Object]
@typescript-eslint/restrict-template-expressions 1 Record<string, unknown> in template literal
prefer-const 1 lists.ts:604let that is never reassigned

apps/pwa — 77 errors total

Rule Count Description
@typescript-eslint/require-await 23 Async functions with no await expression
@typescript-eslint/no-unnecessary-type-assertion 14 Redundant as casts
@typescript-eslint/no-floating-promises 11 Unhandled promises
@typescript-eslint/no-unused-vars 4 Unused variables
@typescript-eslint/no-unsafe-assignment 4 any assignments
@typescript-eslint/no-unsafe-member-access 3 Member access on any
@typescript-eslint/no-misused-promises 3 Async callbacks in void contexts
react/no-unescaped-entities 1 Unescaped ' in JSX

Total: 119 errors across both apps (0 warnings — --max-warnings 0 working).

Self-Check: PASSED

Created files exist:

  • eslint.config.js — FOUND
  • .prettierrc — FOUND
  • .prettierignore — FOUND

Commits exist:

  • df62d33 — FOUND (chore(13-01): install ESLint+Prettier, author flat config, wire lint/format scripts)
  • 7a255ea — FOUND (fix(13-01): disable react/react-in-jsx-scope for React 19 JSX transform)

Throwaway files absent: THROWAWAYS_ABSENT_AND_UNTRACKED confirmed.