Files
ECC/scripts/hooks
labeedsoft-cloud e58bb26647 fix(config-protection): protect shared/base linter configs, not just entry points
`PROTECTED_FILES` matches exact basenames, so it only ever guarded a tool's
canonical entry point. Real repos split flat config across files — a shared
`eslint.config.base.mjs` holding the ignore list and rule severities, imported
by per-workspace `eslint.config.mjs` files, is the common monorepo shape.

That meant the hook protected the leaves and left the trunk wide open:

    eslint.config.base.mjs        <- ignore list + rule severities   UNPROTECTED
    frontend/eslint.config.mjs    <- imports the base                protected
    backend/eslint.config.mjs     <- imports the base                protected

An agent blocked from touching the two leaves could silently rewrite every rule
severity in the file they both import. Hit in practice: two edits to
`eslint.config.js` were correctly blocked, then an edit to
`eslint.config.base.mjs` in the same repo went through unchallenged.

Adds `PROTECTED_PATTERNS` alongside the existing Set, covering
`<tool>.config.<qualifier>.<ext>` and `.<tool>rc.<qualifier>.<ext>` for the
linters and formatters already listed. Case-insensitive, for the same reason
the Set lookup is (#2543).

Deliberately NOT matched: `vite.config.ts`, `vitest.config.ts`,
`jest.config.js`, `playwright.config.ts`, `tsconfig.json`. This hook exists to
stop a LINTER config being weakened in place of fixing the code; editing a
bundler or test-runner config is ordinary work, and sweeping those in would
make the hook obstructive. A second test pins that boundary so a future
widening of the patterns cannot quietly cross it.

The exact-name Set is untouched, so nothing previously protected becomes
unprotected, and first-time creation stays allowed (the bootstrap path).

Tests: 11 pass. The new regression test was verified failing against the
unpatched hook first; the boundary test passes either way by design and is
there as the control.
2026-08-21 10:31:39 -04:00
..