docs(adr): land ADR-C-001, ADR-C-003, ADR-C-007 and ADR-C-009

The architect approved the four ADR-fix tickets. All four change what the
architecture documents claim. No code changes.

ADR-0001, ADR-C-001: the worked example claimed the POC has no real backend.
It rewrites against `backend/src/BigRegister.Api`. Every path it named is
repointed. The out-of-scope list drops two discharged bullets: 33 `parse*`
boundaries exist, and `npm run gen:api` is real.

ADR-0001, ADR-C-003: a new section states that the generated client is the wire
contract. A hand-written `contracts/*.dto.ts` is the exception for two cases
only. The four survivors stay, because NSwag emits every property as optional
and flattens `RegistrationStatusDto` into five optional strings. The `parse*`
trust boundary stays mandatory, because a generated type is a compile-time
claim about the wire and not a runtime guarantee.

ADR-0003, ADR-C-007: four paths moved in WP-67 and are repointed. Point 4 kept
the principle and changed its example to `skeleton` and `spinner`. Two of its
claims were false and the amendment says so: `app-alert` wraps the vendored
`.feedback` classes, and `site-header` composes the vendored `.titlebar`.

ADR-0004, ADR-C-009: the exception section states a four-part test instead of
one named exception. `OrgTemplateStore` and `FeatureFlagStore` both pass it. RB-07
gated this ticket, because clause 4 needs an audited allow path. RB-07 landed
that, so the ADR does not ratify a control that the code lacks.

Three tickets need a matching CLAUDE.md correction in the same diff. CLAUDE.md
section 2 loses the false `alert` example. Section 4 gets the generated-client
rule and the four-part test.

Two findings were wrong. ADR-C-001 asked to keep an out-of-scope bullet that
reads "SessionStore is in-memory". The session persists to `localStorage` now,
so the bullet covers multi-tab sync only. ADR-C-007 flagged one half of point 4
and missed that the other half is equally false.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-08-27 18:29:05 +02:00
co-authored by Claude Opus 5
parent 7fbac8fca5
commit 25a5d415a5
10 changed files with 458 additions and 68 deletions
@@ -0,0 +1,69 @@
# ADR-C-001 — rewrite ADR-0001's worked example against the shipped system
Status: **implemented** · 2026-08-27 · Source finding: `06-adr-conformance.md` §ADR-C-001
## What was wrong
ADR-0001's §"Worked example in this POC" opened with _"This POC has no real backend (static
mock JSON + fake submit timers), so the 'BFF output' is a static file"_. That premise is
false and every path the section cited was gone. The decision itself was intact; only the
description had drifted.
## What changed
| File | Change |
| -------------------------------------------------------- | --------------------------------------------------------------------------- |
| `docs/reference/architecture/0001-...md` §Worked example | rewritten against `backend/src/BigRegister.Api`; all six paths repointed |
| same file, §Out of scope here | 4 bullets → 2, plus a paragraph recording which two were discharged and why |
No code changed. No CLAUDE.md edit was required for this finding.
## Paths corrected, each verified
| Claimed | Actual |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| "no real backend … static file" | `backend/src/BigRegister.Api`, `var api = app.MapGroup("/api/v1")` at `Program.cs:168` |
| `public/mock/dashboard-view.json` | `GET /api/v1/dashboard-view` (`Program.cs:172`) |
| `public/mock/intake-policy.json` | `GET /api/v1/intake/policy` (`Program.cs:193`) |
| `src/app/registratie/contracts/dashboard-view.dto.ts` | `apps/ssp/src/app/registratie/contracts/dashboard-view.dto.ts` |
| `src/app/registratie/infrastructure/dashboard-view.adapter.ts` | `apps/ssp/.../infrastructure/dashboard-view.adapter.ts`, `parseDashboardView` at `:50` |
| `src/app/herregistratie/contracts/intake-policy.dto.ts` | **deleted** — the DTO is now the generated `IntakePolicyDto`; the adapter is `apps/ssp/src/app/herregistratie/infrastructure/intake-policy.adapter.ts` |
`apps/ssp/public/mock/` does not exist (`ls`: no such directory).
## The finding was wrong about one out-of-scope bullet
ADR-C-001 said to _"reduce §Out of scope to the two items still genuinely open (the
`BigProfileStore` optimistic-update race, and session persistence / multi-tab sync)"_,
carrying the original bullet's parenthetical **"`SessionStore` is in-memory"**. That
parenthetical is no longer true, so the bullet could not be kept verbatim.
- `apps/ssp/src/app/auth/application/session.store.ts:13` reads
`parseStoredPrincipal(localStorage.getItem(STORAGE_KEY))`, and `:41` writes it back.
Session persistence **has landed** (RB-10 extracted the parser, RB-13 renamed it
`parseStoredPrincipal`). The file even carries a `ponytail:` note explaining the choice of
`localStorage` over `sessionStorage`.
- Multi-tab sync has **not** landed: `grep` for a `storage` event listener across `apps` and
`libs` returns nothing.
The bullet was therefore narrowed to multi-tab sync only, and states that the session itself
now persists. Recording this because the finding, taken literally, would have re-asserted a
false claim in the same edit that removed two others.
The other two survivors were verified rather than assumed: `BigProfileStore` still holds
`pending` as a bare `signal(false)` with `begin`/`confirm`/`rollback` mutating it
(`big-profile.store.ts:61-74`), so the concurrent-submit race is real.
## Discharged bullets, both verified
- _"Runtime DTO validation on **every** endpoint (only the dashboard view has it)"_ — 33
distinct `export function parse*` boundary functions exist across `apps` and `libs`.
- _"Real OpenAPI/TypeSpec codegen toolchain"_ — `npm run gen:api` (`package.json:12`) runs
`dotnet swagger tofile` then `nswag run`, emitting
`libs/shared/src/infrastructure/api-client.ts` (2329 lines). CI's `api-client-drift` job
regenerates and runs `git diff --exit-code` (`.github/workflows/ci.yml:319-321`).
## Scope discipline
Descriptive drift only, as the finding states. The decision, the options table, the two
policy shapes and the migration sequence are untouched.