test(auth): extract and spec the stored-session parse boundary (RB-10)

SessionStore.restore() — identical in both apps — read localStorage itself
and did the parse plus shape validation in the same module-private function,
invoked from a field initializer, so the storage read happened the instant
the singleton was constructed and no spec could feed it a raw string. The
logic it guards is a trust boundary, not incidental validation: the comment
above it names G1 (never persist the BSN) and G2 (validate the shape before
trusting it), and CLAUDE.md mandates a spec for boundary parse* adapters.
ssp/auth and bhp/auth were jointly the worst-covered frontend modules.

parseStoredSession(raw) moves into each app's auth/domain/session.ts, which
is pure TS and already had a spec, so no new scaffolding was needed;
restore() collapses to one line. Four cases: absent, non-JSON, wrong shape,
and — BIO-017's addition — a stored {"bsn":…,"naam":…} restoring with bsn
'', which makes the G1 guarantee executable rather than merely commented.
Verified red without the fix.

Landed twice, once per app, deliberately. TE-001 and BL-002 both say an
extract-to-shared here would contradict ADR-0002, which models the two
actors as different Principal variants and expects the two auth contexts to
diverge; RB-13 is what differentiates them.

Also specs redactProfile (BIO-017's second half) — a pure exported
PII-redaction function that had none.

behaviour-spec.mdx is regenerated, which also picks up the test names RB-07
added; that commit should have carried them and did not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-08-27 14:08:06 +02:00
co-authored by Claude Opus 5
parent e89525eef6
commit de349e702e
9 changed files with 257 additions and 28 deletions
+26 -2
View File
@@ -20,8 +20,8 @@ tested where._
Every bullet below is a real test name from the suite — an `it()` title (frontend) or a test
method name (backend), read as a sentence. Nothing here is hand-written prose: this page
**is** the suite, reshaped for a business reader. 402 frontend behaviours across
8 contexts; 225 backend behaviours across 38 test
**is** the suite, reshaped for a business reader. 415 frontend behaviours across
9 contexts; 228 backend behaviours across 38 test
classes.
## Frontend (by context)
@@ -35,6 +35,17 @@ classes.
- narrows a present session to Session
- reports no session as not authenticated
#### parseStoredSession
- returns null when nothing is stored
- returns null for a non-JSON string
- returns null when the stored shape is wrong (no naam)
- G1: a stored bsn is never restored, even if present in the raw value
- returns null when nothing is stored
- returns null for a non-JSON string
- returns null when the stored shape is wrong (no naam)
- G1: a stored bsn is never restored, even if present in the raw value
### behandeling
#### besluit reduce
@@ -781,6 +792,16 @@ classes.
- clears the key once the wrapped fn settles
- falls back to a generated uuid-shaped key when none is pending
### shell
#### redactProfile
- masks the BIG-nummer to its last 3 digits
- redacts the name on both the registration and the person
- redacts every date of birth
- redacts the address
- keeps structural/decision-relevant fields untouched
### showcase
#### highlightTs
@@ -825,6 +846,9 @@ classes.
- A denied admin action is recorded
- A reveal attempt is recorded
- An allowed admin action is recorded
- A feature flag toggle records which flag changed
- A refused brief transition is recorded
- No audit row carries a subjects bsn
- The audit schema carries no pii