From 28f9f309a3708af58d737d4e92bac84db4d68a27 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 6 Sep 2026 03:31:10 +0000 Subject: [PATCH] chore(lint): report unused eslint-disable directives as errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add one top-level `linterOptions: { reportUnusedDisableDirectives: 'error' }` object to `eslint.config.js`. ESLint's own default for the option is already `'warn'`, so this is a severity change on a check already running (1 -> 2), inert until now only because `.github/workflows/lint.yml` deliberately sets no `--max-warnings`. The object carries only `linterOptions` and no `files` key, which is what makes it reach every linted path — including the `.js/.mjs/.cjs` family that `lint:root` walks and that every rule-bearing object in this config skips. Precondition measured on this branch point, not assumed: all 47 of turbo's lint tasks run directly with `--report-unused-disable-directives-severity error` report 0 unused directives (4330 file rows, 0 errors, 11964 warnings). Part of objectui#4853 Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_013uAaxiwgYDybsTNV9xwa1M --- eslint.config.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/eslint.config.js b/eslint.config.js index 84a1f713e0..8a5d866a4e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -23,6 +23,31 @@ export default tseslint.config({ // Linting generated output only reports on the generator's choices. '**/.source', ], +}, { + // objectui#4853 — a stale `eslint-disable` is an ERROR, not a warning. + // + // ESLint's own default for this option is already `'warn'`, so every stale + // directive was reported on every CI run before this block existed; it was + // inert only because `.github/workflows/lint.yml` deliberately sets no + // `--max-warnings` (see the note at `lint.yml:20`, which this change does + // NOT touch — the threshold question is a separate card). So this is a + // severity change on a check already running, 1 -> 2, not a new check. + // + // Why it earns the ratchet: 49 stale directives had accumulated by #4833 + // (PR #4849 cleared them), and 2 more appeared in the 21 days after that + // (PR #7909 cleared those) with nobody touching those lines. A stale + // directive is a silent suppression of a rule that no longer fires there, + // so it hides the next real finding at that site. The red names the exact + // file:line, which makes the remedy mechanical: delete the directive. + // + // This object deliberately carries ONLY `linterOptions` and NO `files` key, + // which is what makes it apply to every linted path. The rule-bearing + // objects below are all scoped `**/*.{ts,tsx}` or narrower, so a + // `linterOptions` placed on any of them would leave the `.js/.mjs/.cjs` + // family — everything `pnpm lint:root` walks — uncovered. + linterOptions: { + reportUnusedDisableDirectives: 'error', + }, }, { extends: [js.configs.recommended, ...tseslint.configs.recommended], files: ['**/*.{ts,tsx}'],