Found while taking the stale-directive measurement the ruling on #4853 requires. Filed separately because it is out of that card's scope; ⛔ it is NOT a proposal to turn rules on — that is a gate-strength change, and this card's own history says who owns those. This is the measurement.
What was measured
Worktree at origin/main fa7d66c4, real pnpm install --frozen-lockfile, ESLint v10.8.1. eslint --print-config FILE counts the rules ESLint actually resolves for a path:
| file |
rules resolved |
scripts/github-slug.mjs |
0 |
scripts/check-lint-coverage.mjs |
0 |
eslint.config.js |
0 |
eslint-rules/index.js |
0 |
vitest.config.ts (control) |
116 |
apps/console/src/__tests__/bootSplash.test.ts (control) |
117 |
Why
Every rule-bearing config object in eslint.config.js is scoped to files: ['**/*.{ts,tsx}'] or narrower — including the no-console exemption block, which spells its scripts/** carve-out as scripts/**/*.{ts,tsx}. A JS-family file therefore matches no rule-bearing object and is linted against the empty rule set.
The scoping itself is already stated in the tree: .github/workflows/hook-selftests.yml says "eslint.config.js is scoped to **/*.{ts,tsx} throughout". ⭐ But it says it as an argument about shell scripts, which ESLint never walks at all. The JS-family files are different: eslint . does walk them, reports on them, and returns success.
The population
From lint:root's own JSON output in that run — 252 files linted:
.ts 160, .tsx 3 — 117 rules each
.mjs 66, .js 22, .cjs 1 — 89 files, 0 rules each
⇒ 89 of 252 (35%) of what lint:root walks is checked against nothing, and that 89 is where this repo keeps its gate scripts: all of scripts/*.mjs, eslint.config.js, and the custom rules in eslint-rules/*.js.
Why it matters here specifically
⚠️ The failure direction is this repo's least visible one: pnpm lint:root exits 0 having enforced nothing on that population. It does not fail, it reports. That is the same shape scripts/check-upstream-port-parity.mjs and objectui#4690 exist to argue against — a check that cannot see its input must never read as clean.
⚠️ pnpm lint:coverage cannot see this. It prints 46/46 packages linted, 0 with outstanding errors, but its predicate is whether a package runs ESLint, not whether ESLint has rules for the files that package walks. Both statements are true at once, which is what makes the gap survive.
⭐ It is not theoretical, and #4853's measurement is the proof: scripts/github-slug.mjs:44 carried a three-rule eslint-disable block naming no-control-regex, no-misleading-character-class and no-useless-escape over a vendored regex that genuinely contains control characters. The directive read as stale — not because the regex changed, but because those rules were never enabled for a .mjs file. An author wrote a suppression for a rule that was never watching. The same three rules ARE live at error in .ts files (packages/core/src/utils/export-filename.ts, packages/cli/src/__tests__/check-known-types.test.ts), so the suppression looked correct by comparison with its neighbours.
Not answered here
- Whether the JS family SHOULD get
js.configs.recommended (and what the existing red set would be) — unmeasured, and a gate-strength decision.
- Whether
eslint-rules/*.js linting itself is wanted.
Related: #4853, objectui#4690. Observation-class, unassigned, not claimed.
Filed by an agent dev seat; session reference session_013uAaxiwgYDybsTNV9xwa1M.
Generated by Claude Code
Found while taking the stale-directive measurement the ruling on #4853 requires. Filed separately because it is out of that card's scope; ⛔ it is NOT a proposal to turn rules on — that is a gate-strength change, and this card's own history says who owns those. This is the measurement.
What was measured
Worktree at
origin/mainfa7d66c4, realpnpm install --frozen-lockfile, ESLint v10.8.1.eslint --print-config FILEcounts the rules ESLint actually resolves for a path:scripts/github-slug.mjsscripts/check-lint-coverage.mjseslint.config.jseslint-rules/index.jsvitest.config.ts(control)apps/console/src/__tests__/bootSplash.test.ts(control)Why
Every rule-bearing config object in
eslint.config.jsis scoped tofiles: ['**/*.{ts,tsx}']or narrower — including theno-consoleexemption block, which spells itsscripts/**carve-out asscripts/**/*.{ts,tsx}. A JS-family file therefore matches no rule-bearing object and is linted against the empty rule set.The scoping itself is already stated in the tree:
.github/workflows/hook-selftests.ymlsays "eslint.config.jsis scoped to**/*.{ts,tsx}throughout". ⭐ But it says it as an argument about shell scripts, which ESLint never walks at all. The JS-family files are different:eslint .does walk them, reports on them, and returns success.The population
From
lint:root's own JSON output in that run — 252 files linted:.ts160,.tsx3 — 117 rules each.mjs66,.js22,.cjs1 — 89 files, 0 rules each⇒ 89 of 252 (35%) of what
lint:rootwalks is checked against nothing, and that 89 is where this repo keeps its gate scripts: all ofscripts/*.mjs,eslint.config.js, and the custom rules ineslint-rules/*.js.Why it matters here specifically
pnpm lint:rootexits 0 having enforced nothing on that population. It does not fail, it reports. That is the same shapescripts/check-upstream-port-parity.mjsand objectui#4690 exist to argue against — a check that cannot see its input must never read as clean.pnpm lint:coveragecannot see this. It prints46/46 packages linted, 0 with outstanding errors, but its predicate is whether a package runs ESLint, not whether ESLint has rules for the files that package walks. Both statements are true at once, which is what makes the gap survive.⭐ It is not theoretical, and #4853's measurement is the proof:
scripts/github-slug.mjs:44carried a three-ruleeslint-disableblock namingno-control-regex,no-misleading-character-classandno-useless-escapeover a vendored regex that genuinely contains control characters. The directive read as stale — not because the regex changed, but because those rules were never enabled for a.mjsfile. An author wrote a suppression for a rule that was never watching. The same three rules ARE live aterrorin.tsfiles (packages/core/src/utils/export-filename.ts,packages/cli/src/__tests__/check-known-types.test.ts), so the suppression looked correct by comparison with its neighbours.Not answered here
js.configs.recommended(and what the existing red set would be) — unmeasured, and a gate-strength decision.eslint-rules/*.jslinting itself is wanted.Related: #4853, objectui#4690. Observation-class, unassigned, not claimed.
Filed by an agent dev seat; session reference
session_013uAaxiwgYDybsTNV9xwa1M.Generated by Claude Code