docs(backend): correct IntakePolicy's false re-validation claim (WP-68 F5)

The doc-comment claimed "the backend re-validates on submit as the authority" —
it doesn't. Neither SubmitApplicationRequest nor IntakeRequest carries a scholing
answer at all, so there's nothing to re-validate; both submit paths only apply
SubmissionRules.RejectZeroUren. A crafted POST can bypass the scholing requirement
entirely. States the gap and points to WP-69 (opened, not yet planned) for the
enforcement, which needs a wire change.

Also strengthens the F2 concurrency test to assert the persisted status matches
whichever request actually won the race, and updates WP-68's own Decisions/
acceptance-criteria text to reflect two implementation choices that improved on
the original write-up once real constraints surfaced: ProcessingWindow stays on
ApplicationStore (StatusAt is already in the same file), and AanvraagStatusTag is
not given a Concept member (would have broken
AanvraagStatusTag_covers_the_published_lifecycle) — AanvraagStatus.Tag is nullable
instead, null exactly for Concept.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-08-05 15:42:21 +02:00
co-authored by Claude Opus 5
parent 31d4aa1848
commit 472a49f19f
5 changed files with 211 additions and 105 deletions
@@ -1,9 +1,18 @@
namespace BigRegister.Domain.Intake;
/// <summary>
/// SERVER-OWNED config value. Below this many NL work-hours the scholing question
/// is required. The frontend receives this value and applies it for instant UX
/// feedback, but the backend re-validates on submit as the authority.
/// Config value (ADR-0001's "config value" shape). Below this many NL work-hours the
/// scholing question is required. The frontend receives this value
/// (<c>GET /intake/policy</c>) and applies it for instant UX feedback
/// (<c>intake.machine.ts</c>'s <c>lageUren</c>).
///
/// WP-68 (F5): the class doc used to claim "the backend re-validates on submit as the
/// authority" — it doesn't. Neither <c>SubmitApplicationRequest</c> nor <c>IntakeRequest</c>
/// carries a scholing answer at all, so there is nothing for the server to re-validate;
/// both submit paths only apply <c>SubmissionRules.RejectZeroUren</c>. A crafted POST can
/// bypass the scholing requirement entirely. Enforcing this needs a wire change (the
/// request DTOs must carry the wizard's scholing answer) and is deferred to WP-69 — this
/// comment states the gap rather than a false guarantee.
/// </summary>
public static class IntakePolicy
{