diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js index 7a7fe7fa..77659e09 100644 --- a/frontend/eslint.config.js +++ b/frontend/eslint.config.js @@ -8,9 +8,10 @@ import eslintComments from "@eslint-community/eslint-plugin-eslint-comments"; import vitest from "@vitest/eslint-plugin"; import playwright from "eslint-plugin-playwright"; -// Flat config (ESLint 9). Deliberately NARROW: the high-value rule here is -// react-hooks/exhaustive-deps — 33 suppressions across the app exist for it, and until this -// sprint nothing ran to make them mean anything. tsc already owns unused vars, undefined names +// Flat config (ESLint 9). Deliberately NARROW: the high-value rules here are react-hooks' (the +// hook rules and the React Compiler's diagnostics). The 33 inline `exhaustive-deps` suppressions this +// config first met are all gone (0 left, E32 review); what is still suppressed is suppressed inline, +// one site at a time, each naming its invariant. tsc already owns unused vars, undefined names // and types (noUnusedLocals/Parameters + strict), so typescript-eslint's non-type-checked // `recommended` is layered on but its overlap with tsc is turned off below to avoid double-reporting // and a churny diff. `eslint-config-prettier` is LAST so formatting rules never fight Prettier. @@ -543,7 +544,14 @@ export default tseslint.config( // the compiler SKIPS, silently — `panicThreshold` is "none" and there is no logger, so a lint // error is the only place the skip is said out loud. `todo` is the compiler's "cannot lower // this shape yet" (E32 S4 rewrote all 31 try statements it found); the rest had 0 hits when - // switched on and are tripwires. `todo` does NOT see every such shape — a conditional, a loop + // switched on. Most are tripwires, but three cannot report anything under + // eslint-plugin-react-hooks 7.1.1 (E32 review, read in its source and probed): + // `exhaustive-effect-dependencies` (its validation is compiled off — a missing effect dependency + // is reported by the classic `exhaustive-deps` only), `memoized-effect-dependencies` (nothing + // emits its category) and `rule-suppression` (lint mode hands it no suppression rules, so an + // inline disable is never named). They stay on for the plugin version that wires them up; a + // function the compiler skips over a suppression is caught by the coverage ratchet below. + // `todo` does NOT see every such shape — a conditional, a loop // or an optional call inside a try skips the function with no lint hit at all — so the full // per-function picture is components/compilerCoverage.contract.test.ts. "react-hooks/todo": "error", diff --git a/frontend/reactPlugin.ts b/frontend/reactPlugin.ts index 8a1f2843..8d898a04 100644 --- a/frontend/reactPlugin.ts +++ b/frontend/reactPlugin.ts @@ -16,8 +16,10 @@ import reactCompiler from "babel-plugin-react-compiler"; // it. This comment used to say "its rules are also linted"; it was false while `react-hooks/refs` was // off, and 95 functions sat uncompiled behind it (E32). What actually holds the line now is // src/components/compilerCoverage.contract.test.ts, which runs THIS compiler over the shipped source -// and fails on any skip not on its list; the react-hooks lint rules are the early warning, with the -// one still switched off recorded in docs/gates.md. `target` follows the installed React major and +// and fails on any skip not on its list; the react-hooks lint rules are the early warning. None of +// them is off (three run at the preset's warn, which `--max-warnings 0` fails — docs/gates.md), but +// three of the compiler's diagnostics cannot report under the installed plugin (eslint.config.js +// says which), so the ratchet is the line, not the lint. `target` follows the installed React major and // must move with it. // // The plugin is IMPORTED rather than named by the usual `"babel-plugin-react-compiler"` string. Two