The dashboard refactor proved a page can be 42 lines. This rule holds
the rest of the app to that budget, before the split work in RD-20
through RD-26 begins.
Add max-lines at 250 (skipBlankLines, skipComments), scoped to
{apps,libs}/**/*.{page,component,section,step}.ts. The glob includes
section and step, the file kinds the dashboard refactor invented, so
new files from this arc do not escape the guard.
Add linterOptions.reportUnusedDisableDirectives: 'error' repo-wide.
ESLint 9 only warns on an unused disable by default, so a stale
exemption would not fail the build. At 'error', every later file
split must delete its own exemption or the build goes red.
Add a dated /* eslint-disable max-lines */ header to each of the
seven files that exceed the budget today, each with a reason and the
ticket that removes it. letter-canvas keeps its disable after RD-26,
because most of its lines are CSS and the rest is one letter.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6.3 KiB
RD-02 — max-lines guard with a self-cleaning exemption list
Status: done Source: PLAN.md section 3a
Why
The dashboard refactor proved a page can be 42 lines. Nothing stops the next one being 340 again, and nothing stops this arc itself adding a new oversized file. The guard therefore lands before the work it protects, not after.
Seven files exceed the budget today. Each becomes a visible, dated to-do rather than a silent one.
Read first
eslint.config.mjs— a flat array of 4 config objects. You add a 5th.docs/project/readable-codebase/README.md— the session protocol and GREEN.- CLAUDE.md, "Enforced, not just hoped-for".
Decisions (pre-made, don't relitigate)
-
The rule.
max-linesat 250,skipBlankLines: true,skipComments: true, scoped to['{apps,libs}/**/*.{page,component,section,step}.ts']. -
The glob must include
sectionandstep.*.{page,component}.tsdoes not match*.section.ts— the file kind the dashboard refactor invented, and the kind RD-22 through RD-26 create most of. Omitting them lets every new file this arc produces escape the guard. This is the single most important line of the ticket. -
Add
linterOptions: { reportUnusedDisableDirectives: 'error' }, in this same commit. ESLint 9 only warns by default, andnpm run lintdoes not fail on warnings. Aterror, a disable that is no longer needed becomes a lint failure — so every later split commit is forced to delete its own exemption or go red. The exemption list cannot rot into permanent debt. Verified clean on the current tree, so it lands green. -
250 is chosen because the dashboard proves it is reachable, not from a style guide.
-
Seven files, not eight or nine. The original plan counted with
wc -l; this rule counts without blank lines or comments.behandel-scherm.component.ts(232) andstamdata-table-editor.component.ts(236) were on the old list and already pass — leave them alone. -
Each disable names its reason and the ticket that removes it, per CLAUDE.md's standing rule. Use the exact mapping in Files below. Note
letter-canvasis the one file whose disable is expected to stay — RD-26 rewrites its reason rather than deleting it, because 77 of its lines are CSS and the rest is one letter (PLAN.md 3d).
Files
Add the config block to eslint.config.mjs, then a /* eslint-disable max-lines */ header
with a one-line reason to each of these seven. Verified counts under the rule:
| Rule lines | File | Removed by |
|---|---|---|
| 574 | apps/ssp/src/app/registratie/ui/registratie-wizard/registratie-wizard.component.ts |
RD-23 |
| 472 | apps/ssp/src/app/showcase/concepts.page.ts |
RD-24 |
| 414 | apps/ssp/src/app/brief/ui/letter-canvas/letter-canvas.component.ts |
RD-26 (rewrites, keeps) |
| 368 | apps/ssp/src/app/herregistratie/ui/intake-wizard/intake-wizard.component.ts |
RD-22 |
| 329 | apps/ssp/src/app/brief/ui/org-template-editor/org-template-editor.component.ts |
RD-25 |
| 253 | libs/shared/src/ui/rich-text-editor/rich-text-editor.component.ts |
RD-21 |
| 252 | apps/ssp/src/app/herregistratie/ui/herregistratie-wizard/herregistratie-wizard.component.ts |
RD-20 |
Steps
- Add the 5th config object to
eslint.config.mjswith the rule from decision 1, and a short comment saying why 250 and that the exemptions are the to-do list. - Add
linterOptions: { reportUnusedDisableDirectives: 'error' }so it applies repo-wide. - Add the seven disable headers, each of the form
/* eslint-disable max-lines */ // <why> — removed by RD-NN. - Update this ticket's
Status:todoneand the README's RD-02 row todone. - Commit all of it together.
Acceptance criteria
Commands, not judgements:
npm run lint # exits 0
npm run ci # exits 0
Then prove the guard actually bites, and that the glob covers section files:
# 1. A new oversized section file must FAIL. Expect a max-lines error, then delete the file.
printf '/* x */\nexport class X {\n%s\n}\n' "$(for i in $(seq 260); do echo " p$i = $i;"; done)" \
> apps/ssp/src/app/registratie/ui/dashboard/tmp-probe.section.ts
npx eslint apps/ssp/src/app/registratie/ui/dashboard/tmp-probe.section.ts # must report max-lines
rm apps/ssp/src/app/registratie/ui/dashboard/tmp-probe.section.ts
# 2. Removing any one disable must FAIL (proves all 7 are load-bearing, none is decoration).
Verification
npm run ci. This ticket touches no story, no .mdx and no libs/shared/src/ui/**
content, so --full is not required — but rich-text-editor.component.ts does live under
libs/shared/src/ui/, and adding a comment line to it is harmless. Skip --full.
Out of scope
- Splitting any of the seven files. That is RD-20 through RD-26.
behandel-scherm.component.tsandstamdata-table-editor.component.ts— already compliant.- The 7 non-component files over 250 lines (
brief.adapter.ts408,upload.machine.spec.ts364,brief.store.spec.ts357,registratie-wizard.machine.spec.ts287,registratie-wizard.machine.ts285,upload.machine.ts256). The glob deliberately does not reach specs, adapters or machines — this budget is about components.
Risks
- The inline-template processor can make
max-linesfire twice per file (once for the.ts, once for the extracted virtual.html). Measured: it does not with this glob, because the virtual path ends in.htmland the glob ends in.ts. If a doubled report appears, the glob is wrong — do not "fix" it by raising the limit. reportUnusedDisableDirectivesis repo-wide, so it also polices the generatedapi-client.tsheader. That file is already inignores, so it is out of reach. Confirmed clean before this change.