Two backlog trees are complete: `docs/project/backlog/` (75 files, every WP done) and `docs/project/refactor-backlog-setup/` (the arc before it). Move both under `docs/project/archive/` with `git mv`, so history stays intact through `git log --follow`. `SHOWCASE-ROADMAP.md` moves with them, because it points at the now-archived backlog README. Add `docs/project/archive/README.md`. It states that these trees are historical and names the two directories that are still live. Repoint every inbound reference named in RD-30's Files table: CLAUDE.md, the root README, both backend READMEs, `LetterHtml.cs`, `a11y.mdx`, the `document-feature` and `new-ssp` skills, and the readable-codebase PLAN, README, and RD-19 ticket. Fix two upward-relative links inside the moved WP files (WP-68, WP-69) that gained a directory level and would otherwise break. Repoint `.prettierignore`'s two agent-prompt exclusions to their new path, so prettier keeps leaving those files' exact wording alone. Mark RD-30 done and check off its acceptance criteria; flip its README row to done. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2.6 KiB
2.6 KiB
WP-05 — Parse-don't-validate closure + MDX
Status: done Phase: 1 — FP/DDD core
Why
Three adapters trust the wire, contradicting the repo's flagship "parse, don't validate"
principle (every response through a hand-written parse* returning Result).
Read first
CLAUDE.md§3 + §4;docs/reference/architecture/0001-bff-lite-decision-dtos.mdsrc/app/registratie/infrastructure/applications.adapter.ts(+ its spec — the pattern to copy)- The three offenders below
Decisions (pre-made, don't relitigate)
- Unknown enum-ish values from the wire map to an explicit
Failure(never a silent fallback); specs pin that behavior. - The MDX curriculum page ships in this WP (the WP that establishes an invariant teaches it).
Files
src/app/herregistratie/infrastructure/intake-policy.adapter.ts— returns the raw DTO resource with no parse; addparseIntakePolicy(raw: unknown): Result<string, …>and a domain-side typesrc/app/registratie/infrastructure/big-register.adapter.ts(~line 25) —n.type as AantekeningType→ validated parsesrc/app/brief/infrastructure/brief.adapter.ts(~line 189) —dto.scope as PassageScope→ validated parse (the file is otherwise parse-heavy; this one field skips)- New co-located specs:
intake-policy.adapter.spec.ts, extendbig-register.adapter.spec.ts/brief.adapter.spec.ts(create if missing) - New
src/docs/parse-dont-validate.mdx— titleFoundations/Parse, don't validate
Steps
- For each hole: write the small parser (pattern:
parseAanvraagStatusinapplications.adapter.ts), wire it in, delete the cast. - Spec each parser: valid shape, missing field, unknown tag/enum value →
err. - MDX page: the principle, value objects (
registratie/domain/value-objects/), boundary parsers, linking the three real call sites just fixed (before/after snippet).
Acceptance criteria
- No unvalidated
as <DomainType>casts in**/infrastructure/**(the sanctioned "narrow unknown toPartial<Dto>then parse" entry-cast is fine). - Each new parser has a spec including a rejection case.
- MDX renders under Foundations in Storybook.
Verification
GREEN + npm run test-storybook:ci. Smoke: intake wizard still loads its policy
(npm start → /intake).
Out of scope
Runtime validation on every endpoint (explicitly out of scope for the POC per
CLAUDE.md); digid.adapter.ts (faked auth, sanctioned).
Risks
Seeded backend data containing values the new parsers reject → surfaces as Failure in
the UI; check the backend seed while writing the parsers and align the accepted set.