Files
atomic-design-poc/docs/project/readable-codebase/README.md
T
ehoandClaude Sonnet 5 b9d572cfdc feat: add max-lines guard with self-cleaning exemptions (RD-02)
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>
2026-09-04 16:18:10 +02:00

10 KiB

Readable codebase — apply the dashboard pattern to the rest of the app

The dashboard refactor cut dashboard.page.ts from 340 lines to 42. It was built as a reference implementation: prove the pattern on one screen, then hold the rest of the app to the budget it establishes.

This arc applies that result. The full design record, with every measurement and every rejected alternative, is PLAN.md. Each ticket below is one commit.

Two findings shape the work:

  1. Pages are already thin (17 pages, median 88 lines). The remaining bulk sits one layer down, in organisms.
  2. The worst problem is not size. runIfSubmitting is copy-pasted into 5 components and must be called by hand after dispatch. Forgetting it fails silently. RD-06 fixes two user-facing bugs that follow from it.

Session protocol

  • One ticket per session. Read CLAUDE.md, this README, the ticket file, and the ticket's "Read first" list — then execute. Do not start the next ticket in the same session.
  • The Decisions block in each ticket is pre-made. Do not relitigate it. PLAN.md records why, including the alternatives that were rejected and the reasons.
  • Ticket files are written just in time, not all 35 up front. Writing one means choosing which decisions and which traps from PLAN.md belong in it, so the supervisor writes the ticket file (an Opus-shaped job) immediately before delegating it. The file lands in that ticket's own commit. Generating all 35 in advance would be speculative — later tickets are better written once the earlier ones have taught us something.
  • Match the model to the step (see CLAUDE.md, "Model routing for agent delegation"). Executing a ticket is written for the developer agent (Sonnet). Read-only checks go to task-runner (Haiku). Escalate to planner (Opus) only if a Decisions block turns out to be wrong — in which case stop, and fix PLAN.md first.
  • A ticket ends GREEN, with its acceptance criteria checked, its Status: set to done, and its README row updated — all in the same commit as the code. Never in a follow-up commit. This is what makes a restart safe: whatever is committed is done, and whatever is not is not.
  • Status: done carries no commit hash, because a commit cannot contain its own hash. The commit is recoverable when you need it: git log --oneline --diff-filter=A -- docs/project/readable-codebase/RD-NN-*.md.
  • No ticket leaves a check disabled without an inline reason and a reference to the ticket that removes it.

GREEN (global definition of done)

npm run ci

For any ticket whose "--full?" column says yes — it touches a story, an .mdx, or libs/shared/src/ui/** — additionally:

npm run ci --full

npm run ci does not build Storybook. Only --full does, and a broken .mdx story import is invisible until it runs. RD-27 in particular must not be pushed without it.

Recovery after a restart

A fresh session with no context needs three commands:

git log --oneline -8
grep -rn '^Status:' docs/project/readable-codebase/RD-*.md | grep -v done   # next work
npm run ci                                                                  # is HEAD green?

Then read PLAN.md for the design record, and the first todo ticket for the work.

The agent loop

One supervisor session drives it; one developer agent executes each ticket:

  1. Read the Order table. Pick the first todo whose dependencies are all done.
  2. Spawn one developer agent: "Read CLAUDE.md, then docs/project/readable-codebase/README.md, then RD-NN.md and its Read-first list. Execute it. End GREEN. Update the ticket Status and the README row in the same commit as the code. Do not start another ticket."
  3. Verify with task-runner: npm run ci, git log -1 --stat, and that Status: now reads done. Never mark a ticket done on an agent's report alone — the check is the exit code.
  4. Green: next iteration. Red: stop and surface it.

Run tickets sequentially. Three properties make concurrent writes to one branch hostile: behaviour-spec.mdx and snippets.generated.ts are regenerated and drift-checked, so two agents regenerating conflict by construction; every ticket writes this README's Order table; and the file sets overlap (the three wizards appear in RD-06, RD-07, RD-22 and RD-23).

Parallel work pays only for genuinely disjoint tickets, in separate git worktrees, merged deliberately — RD-18/RD-19 (the ticket sweep) and the Phase 5 doc tickets qualify. Cap at two. Note that RD-15 exists because 22 abandoned agent worktrees are still on disk.

Order

ID Ticket Deps --full? Status
RD-01 Scaffold this backlog: README, PLAN, ticket template done
RD-02 max-lines rule + reportUnusedDisableDirectives + 7 disables 01 done
RD-03 overzicht context: page + 2 nav sections, boundary edge, admin-links token 02 yes todo
RD-04 Story titles to Domein/<Context>/<Name>; add the missing stories 03 yes todo
RD-05 createStore gains the effect map + specs 02 todo
RD-06 Bug fix: 2 single-step forms to the effect map + retry affordance 05 yes todo
RD-07 Add Primary to the 3 wizard machines + specs 05 todo
RD-08 Migrate the 3 wizards to the effect map + Primary 07 yes todo
RD-09 Docs + generator: form-machine.hbs, ARCHITECTURE, fp-tea, skill 08 todo
RD-10 WizardStatus to a payload-carrying WizardPhase 08 yes todo
RD-11 Fold the lifecycle projection into remote-data.ts; PascalCase 3 machines 01 todo
RD-12 ActionState becomes action on BriefState.Loaded 11 todo
RD-13 Same for org-template, folding pendingPublish in 12 todo
RD-14 Move SaveState to debounced-save.ts; delete action-state.ts 13 todo
RD-15 Remove 22 abandoned agent worktrees (4.7 GB) 01 todo
RD-16 parseDashboardView returns BigProfile; delete DashboardView 01 todo
RD-17 successOf/successOr sweep — 10 sites, 8 files 01 todo
RD-18 Ticket-reference sweep, frontend — 181 refs, 100 files 01 todo
RD-19 Ticket-reference sweep, backend — 370 refs, 86 files 01 todo
RD-20 wizard-errors.ts + spec, adopted by all 3 wizards 02 todo
RD-21 rich-text-dom.ts helpers + spec cases 02 yes todo
RD-22 intake-wizard to 3 step components 08, 20 yes todo
RD-23 registratie-wizard to 3 steps + the upload-controller move 08, 20 yes todo
RD-24 concepts.page to 6 sections + concept-card + globals + code tokens 02 yes todo
RD-25 org-template-editor to sample-letter.ts + labels + 2 children 02 yes todo
RD-26 letter-canvas: inline the labels + letter-line; keep one disable 02 yes todo
RD-27 The layer move: 33 git mv + 28 specifiers + 8 MDX imports 21 yes todo
RD-28 Layer-tag fixes + the libs/beheer title rule 27 todo
RD-29 The 3 atomic-ladder rules in dependency-cruiser 27 todo
RD-30 Archive the finished backlogs (16,300 lines) + an archive README 01 todo
RD-31 ARCHITECTURE.md section 6a: symbols not lines, 2 dead paths, new names 03, 08, 16 todo
RD-32 fp-tea-atomic-design.md: 11 broken paths + the broken anchor 27 todo
RD-33 CLAUDE.md + atomic-design.mdx + the ui-component skill 03, 27, 29 yes todo
RD-34 (optional) NO_SUBORGS/NO_TABLES become RemoteData.Empty 11 todo
RD-35 (optional, last, alone) upload type: discriminant to tag: 27 todo

The ID order already respects every dependency, so it is the recommended running order.

Independent tickets. RD-15 through RD-19 depend only on RD-01. Pull them forward to fill a short session. Take RD-15 early: it makes every later repository search faster.

Two ordering traps the table encodes. RD-01 must precede RD-30, because RD-01 copies its ticket template out of the directory that RD-30 archives. And four tickets edit the same two documents in different sections — RD-09 rewrites the submit-idiom teaching, while RD-31 and RD-32 fix section 6a and the stale paths. Sequential is fine. Never put those pairs in parallel worktrees.

Ticket template

# RD-NN — Title

Status: todo | in-progress | done
Source: PLAN.md section <n>

## Why

## Read first

## Decisions (pre-made, don't relitigate)

## Files

## Steps

## Acceptance criteria

## Verification

## Out of scope

## Risks

Three rules when you write a ticket file, because the agent reads its ticket and not PLAN.md:

  1. Copy the decision, never a pointer to it. The verdict goes in the Decisions block, verbatim.
  2. Inline the traps that apply to that ticket. A trap recorded only in PLAN.md's global Risks section is a trap that fires.
  3. State acceptance as a command, not a sentence. "Lands about 230 lines" is a design estimate and nothing can check it. npm run lint has an exit code.