Files
atomic-design-poc/docs/project/archive/backlog/WP-05-parse-boundaries.md
T
ehoandClaude Opus 5 12f17d9d73 docs: archive the finished backlogs (RD-30)
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>
2026-09-08 23:00:38 +02:00

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.md
  • src/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; add parseIntakePolicy(raw: unknown): Result<string, …> and a domain-side type
  • src/app/registratie/infrastructure/big-register.adapter.ts (~line 25) — n.type as AantekeningType → validated parse
  • src/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, extend big-register.adapter.spec.ts / brief.adapter.spec.ts (create if missing)
  • New src/docs/parse-dont-validate.mdx — title Foundations/Parse, don't validate

Steps

  1. For each hole: write the small parser (pattern: parseAanvraagStatus in applications.adapter.ts), wire it in, delete the cast.
  2. Spec each parser: valid shape, missing field, unknown tag/enum value → err.
  3. 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 to Partial<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.