feat(fp): WP-05 — parse-don't-validate closure + MDX

Close the three remaining unvalidated `as <DomainType>` casts at the wire
boundary (intake-policy, big-register aantekening type, brief passage scope),
each replaced by a Result-returning parser with a rejection-case spec, plus
the Foundations/Parse, don't validate curriculum page.
This commit is contained in:
eho
2026-07-03 21:02:15 +02:00
parent 5d6a78d4ec
commit 34d34512b3
11 changed files with 2323 additions and 1994 deletions
@@ -1,4 +1,6 @@
import { Injectable, inject, resource } from '@angular/core';
import { Result, ok, err } from '@shared/kernel/fp';
import { IntakePolicy } from '@herregistratie/domain/intake.machine';
import { ApiClient } from '@shared/infrastructure/api-client';
/**
@@ -11,6 +13,21 @@ export class IntakePolicyAdapter {
private client = inject(ApiClient);
policyResource() {
return resource({ loader: () => this.client.policy() });
return resource({
loader: async () => {
const parsed = parseIntakePolicy(await this.client.policy());
if (!parsed.ok) throw new Error(parsed.error);
return parsed.value;
},
});
}
}
/** Trust-boundary parse: an unrecognized/missing threshold is an explicit Failure. */
export function parseIntakePolicy(json: unknown): Result<string, IntakePolicy> {
if (typeof json !== 'object' || json === null) return err('intake-policy: not an object');
const dto = json as { scholingThreshold?: unknown };
if (typeof dto.scholingThreshold !== 'number')
return err('intake-policy: missing scholingThreshold');
return ok({ scholingThreshold: dto.scholingThreshold });
}