docs: close WP-72..75, regenerate behaviour spec
CI / changes (push) Successful in 8s
CI / lint (push) Successful in 1m9s
CI / frontend (push) Successful in 2m27s
CI / backend (push) Successful in 1m56s
CI / e2e (push) Successful in 3m16s
CI / semgrep (push) Successful in 1m7s
CI / api-client-drift (push) Successful in 1m50s
CI / storybook-a11y (push) Successful in 11m4s
CI / changes (push) Successful in 8s
CI / lint (push) Successful in 1m9s
CI / frontend (push) Successful in 2m27s
CI / backend (push) Successful in 1m56s
CI / e2e (push) Successful in 3m16s
CI / semgrep (push) Successful in 1m7s
CI / api-client-drift (push) Successful in 1m50s
CI / storybook-a11y (push) Successful in 11m4s
Four close-outs and their README rows. The behaviour spec is regenerated once here rather than per-track — it derives from every test name in the repo, so any track running it would have conflicted with the other three. Records two findings the arc surfaced but did not cause: the /brief/preview staleness for non-DemoOwner identities (blocking per-spec identity isolation in brief-v2.spec.ts), and that WP-72/73 had to share a commit because both edit Program.cs — separate execution waves prevented build collisions but did not produce separable diffs. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# WP-75 — Close the remaining FE/BE seams
|
||||
|
||||
Status: done (6fa27d1)
|
||||
Phase: 12 — DDD hardening
|
||||
|
||||
## Why
|
||||
|
||||
WP-71 added `scripts/check-seam.sh` guarding one literal pair (the scholing threshold) and
|
||||
documented three further FE/BE duplications that nothing tested across the seam. This closes
|
||||
them — two by deletion, one by a guard, one by an actual fix.
|
||||
|
||||
## Decisions (pre-made)
|
||||
|
||||
1. **Dead reference impls get deleted, and `CLAUDE.md` is amended.** This overturns the
|
||||
documented policy that server-owned rules "stay in `domain/*.policy.ts` as reference impl +
|
||||
unit test". That policy is precisely what kept dead code alive. Blast radius is small:
|
||||
`registration.policy.ts` is the only `*.policy.ts` in the repo.
|
||||
2. Guard the `Besluit` tag list by **extending** `check-seam.sh`, not adding a second script.
|
||||
3. The phone seam gets a **contract test**, not a grep check — see below.
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [x] `isHerregistratieEligible` deleted (uncalled; dead by its own doc-comment) along with
|
||||
`isStatusConsistent` (also uncalled — WP-71 had added a spec for it the session before).
|
||||
The three live exports (`statusLabel`, `statusColor`, `herregistratieDeadline`) stay, and
|
||||
`herregistratieDeadline` gained direct coverage it previously only had transitively.
|
||||
- [x] `CLAUDE.md` amended: server-owned rules live **only** on the server; the FE may mirror a
|
||||
server-supplied _value_ (a threshold, a bound) for instant feedback, but never
|
||||
reimplements the _algorithm_. ADR-0001's matching claim aligned.
|
||||
- [x] `check-seam.sh` guards the `Besluit` tag list, **proven to fail** when a fourth member is
|
||||
added to the C# enum only, naming both files and both lists. Anchored on the full
|
||||
declaration so it avoids the "greps all matches" trap WP-69 documented.
|
||||
- [x] Phone contract test added and green; backend stripping fixed.
|
||||
|
||||
## The phone divergence was real, not latent
|
||||
|
||||
WP-71 recorded this as latent because the Angular app normalises before sending — true of _that_
|
||||
path. The contract test proved the two sides genuinely disagreed: the backend returned **422**
|
||||
for `+31612345678` and `(06) 12345678`, both of which the FE's own `parseTelefoonnummer`
|
||||
accepts. Any non-Angular client, crafted POST, or future FE change would have hit it.
|
||||
|
||||
`SubmissionRules.RejectPhoneChange` now strips exactly what the FE strips (`[\s\-()]`, then a
|
||||
leading `+31` → `0`) before applying the shared `^0\d{9}$`. The FE value object was not touched —
|
||||
it is the more permissive and correct side.
|
||||
|
||||
**Why a contract test rather than a grep check:** both sides carry the identical `^0\d{9}$`
|
||||
literal, so a drift check would have compared them, found them equal, and reported all clear.
|
||||
The divergence was in the _normalisation before_ the regex — invisible to text comparison. Worth
|
||||
remembering when choosing between the two guard styles: grep checks catch drifting **constants**,
|
||||
contract tests catch drifting **behaviour**.
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
npm run check:seam # both checks OK
|
||||
npm run ci
|
||||
cd backend && dotnet test BigRegister.slnx --filter "Category!=Integration"
|
||||
```
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- Making `Besluit` flow through the generated client as an enum rather than a `string` would
|
||||
remove that seam entirely rather than guarding it — a wire change, so not done here.
|
||||
- The herregistratie-eligibility seam is closed by deletion; if a FE mirror is ever reintroduced,
|
||||
the disjoint-fixture problem returns and would need a contract test, not a grep check.
|
||||
Reference in New Issue
Block a user