diff --git a/apps/behandelportal/src/app/app.routes.ts b/apps/behandelportal/src/app/app.routes.ts index 96c85a2..80106c6 100644 --- a/apps/behandelportal/src/app/app.routes.ts +++ b/apps/behandelportal/src/app/app.routes.ts @@ -20,7 +20,7 @@ export const routes: Routes = [ }, { path: 'aanvraag/:id', - // Same capability the werkvoorraad list itself is gated by (WP-64/65) — the + // Same capability the werkvoorraad list itself is gated by — the // detail page is reachable only from a row already filtered to that capability. canActivate: [capabilityGuard('aanvraag:beoordelen')], loadComponent: () => @@ -36,14 +36,14 @@ export const routes: Routes = [ }, { path: 'beheer/audit', - // Admin-only authz/PII-reveal audit trail (WP-41/42). capabilityGuard denies-by-default + // Admin-only authz/PII-reveal audit trail. capabilityGuard denies-by-default // unless GET /me resolved `cases:manage` (reused for audit read). Backend re-enforces. canActivate: [capabilityGuard('cases:manage')], loadComponent: () => import('@beheer/ui/audit.page').then((m) => m.AuditPage), }, { path: 'beheer/functies', - // Admin-only feature-flag toggles (WP-47), gated by `flags:manage`. + // Admin-only feature-flag toggles, gated by `flags:manage`. canActivate: [capabilityGuard('flags:manage')], loadComponent: () => import('@beheer/ui/feature-flags.page').then((m) => m.FeatureFlagsPage), diff --git a/apps/behandelportal/src/app/auth/infrastructure/medewerker.adapter.ts b/apps/behandelportal/src/app/auth/infrastructure/medewerker.adapter.ts index 85cc7ee..9b3493a 100644 --- a/apps/behandelportal/src/app/auth/infrastructure/medewerker.adapter.ts +++ b/apps/behandelportal/src/app/auth/infrastructure/medewerker.adapter.ts @@ -4,7 +4,7 @@ import { MEDEWERKER_ID, currentRollen } from './medewerker'; /** * Infrastructure: resolves the current medewerker identity into a `Principal` - * (ADR-C-004/RB-13). Stands in for a real employee-SSO redirect flow (ADR-0002 §3, + * (ADR-C-004). Stands in for a real employee-SSO redirect flow (ADR-0002 §3, * "out of scope here") — there is no credential to enter and, unlike `DigidAdapter`'s * BSN check, no format to reject, so `authenticate()` takes no input and returns the * `Principal` directly rather than a `Result` with an error variant that can never diff --git a/apps/behandelportal/src/app/auth/ui/login-form/login-form.component.ts b/apps/behandelportal/src/app/auth/ui/login-form/login-form.component.ts index 6d9b5ce..3867ae8 100644 --- a/apps/behandelportal/src/app/auth/ui/login-form/login-form.component.ts +++ b/apps/behandelportal/src/app/auth/ui/login-form/login-form.component.ts @@ -2,7 +2,7 @@ import { Component, output } from '@angular/core'; import { ButtonComponent } from '@shared/ui/button/button.component'; /** - * Organism: employee-SSO-style mock login (ADR-C-004/RB-13). No real auth — and, + * Organism: employee-SSO-style mock login (ADR-C-004). No real auth — and, * unlike the SSP's DigiD form, no credential to enter at all: a Behandelaar has no * BSN, and this app has no password of its own to check either way. There is * nothing to compose beyond one button, which is itself evidence for the ADR — the diff --git a/apps/behandelportal/src/app/behandeling/application/beoordeling.store.ts b/apps/behandelportal/src/app/behandeling/application/beoordeling.store.ts index da5befc..c908b0b 100644 --- a/apps/behandelportal/src/app/behandeling/application/beoordeling.store.ts +++ b/apps/behandelportal/src/app/behandeling/application/beoordeling.store.ts @@ -8,7 +8,7 @@ import { type Err = Error | undefined; -/** One aanvraag's beoordeling detail (WP-65) — a root singleton like `WerkvoorraadStore`. +/** One aanvraag's beoordeling detail — a root singleton like `WerkvoorraadStore`. Keyed by id: navigating to a different case resets to Loading. */ @Injectable({ providedIn: 'root' }) export class BeoordelingStore { diff --git a/apps/behandelportal/src/app/behandeling/application/werkvoorraad.store.ts b/apps/behandelportal/src/app/behandeling/application/werkvoorraad.store.ts index 19b2509..e5ba8ca 100644 --- a/apps/behandelportal/src/app/behandeling/application/werkvoorraad.store.ts +++ b/apps/behandelportal/src/app/behandeling/application/werkvoorraad.store.ts @@ -8,7 +8,7 @@ import { type Err = Error | undefined; -/** The behandelaar's queue (WP-64) — a root singleton like `AdminCasesStore`'s ssp +/** The behandelaar's queue — a root singleton like `AdminCasesStore`'s ssp counterpart. Fetch + parse at the trust boundary, publish as RemoteData. */ @Injectable({ providedIn: 'root' }) export class WerkvoorraadStore { diff --git a/apps/behandelportal/src/app/behandeling/domain/beoordeling-view.ts b/apps/behandelportal/src/app/behandeling/domain/beoordeling-view.ts index 091ee01..1594c86 100644 --- a/apps/behandelportal/src/app/behandeling/domain/beoordeling-view.ts +++ b/apps/behandelportal/src/app/behandeling/domain/beoordeling-view.ts @@ -2,8 +2,8 @@ import { formatDatumNl } from '@shared/kernel/datum'; import { AanvraagType } from './werkvoorraad-item'; import { BeoordelingStatus, BeoordelingView } from './beoordeling'; -/** View-model mapping shared by the werkvoorraad list (WP-64) and the beoordeling - detail screen (WP-65): type/status → labels. Pure, no Angular. Lives here (not in +/** View-model mapping shared by the werkvoorraad list and the beoordeling + detail screen: type/status → labels. Pure, no Angular. Lives here (not in `werkvoorraad-item-view.ts`) because `BeoordelingStatus` is the wider of the two status unions — `werkvoorraad-item-view.ts` re-exports these for its own use. */ diff --git a/apps/behandelportal/src/app/behandeling/domain/beoordeling.ts b/apps/behandelportal/src/app/behandeling/domain/beoordeling.ts index 5a1bb7e..5c42963 100644 --- a/apps/behandelportal/src/app/behandeling/domain/beoordeling.ts +++ b/apps/behandelportal/src/app/behandeling/domain/beoordeling.ts @@ -1,8 +1,8 @@ import { AanvraagType } from './werkvoorraad-item'; /** - * A case's full status lifecycle as the beoordeling detail screen sees it (WP-65) — - * wider than `WerkvoorraadStatus` (WP-64), which only ever sees the two "still open" + * A case's full status lifecycle as the beoordeling detail screen sees it — + * wider than `WerkvoorraadStatus`, which only ever sees the two "still open" * tags. This is the same five-tag union ssp's `AanvraagStatus` models (minus `Concept` * — the detail endpoint 404s a Concept, it isn't a case a behandelaar can treat yet). */ diff --git a/apps/behandelportal/src/app/behandeling/domain/besluit.machine.ts b/apps/behandelportal/src/app/behandeling/domain/besluit.machine.ts index ef9a56c..3462602 100644 --- a/apps/behandelportal/src/app/behandeling/domain/besluit.machine.ts +++ b/apps/behandelportal/src/app/behandeling/domain/besluit.machine.ts @@ -1,6 +1,6 @@ import { Result, assertNever } from '@shared/kernel/fp'; -/** The three actions the beoordeling screen offers a behandelaar (WP-65b) — mirrors the +/** The three actions the beoordeling screen offers a behandelaar — mirrors the backend's `Besluit` enum member names 1:1 (the wire convention: a string, not a raw enum — see `RecordBesluitRequest`). */ const BESLUIT_TAGS = ['Goedkeuren', 'Afwijzen', 'MeerInfoOpvragen'] as const; diff --git a/apps/behandelportal/src/app/behandeling/domain/werkvoorraad-item.ts b/apps/behandelportal/src/app/behandeling/domain/werkvoorraad-item.ts index b5fcb35..1aed5a7 100644 --- a/apps/behandelportal/src/app/behandeling/domain/werkvoorraad-item.ts +++ b/apps/behandelportal/src/app/behandeling/domain/werkvoorraad-item.ts @@ -1,5 +1,5 @@ /** - * A queue entry as the behandelportal sees it (WP-64) — the parsed, domain-side view + * A queue entry as the behandelportal sees it — the parsed, domain-side view * of the backend's cross-owner `GET /werkvoorraad`. Pure types, no Angular. * * The status union is narrower than the SSP's full `AanvraagStatus` (ssp's diff --git a/apps/behandelportal/src/app/behandeling/infrastructure/beoordeling.adapter.ts b/apps/behandelportal/src/app/behandeling/infrastructure/beoordeling.adapter.ts index fbb0d5d..85a379b 100644 --- a/apps/behandelportal/src/app/behandeling/infrastructure/beoordeling.adapter.ts +++ b/apps/behandelportal/src/app/behandeling/infrastructure/beoordeling.adapter.ts @@ -13,7 +13,7 @@ import { import { AanvraagType } from '@behandeling/domain/werkvoorraad-item'; /** - * Infrastructure adapter for the beoordeling detail read (WP-65) — the only place its + * Infrastructure adapter for the beoordeling detail read — the only place its * HTTP lives (ADR-0001 anti-corruption boundary). The untrusted response is validated + * mapped to domain by the parse* boundary below. */ diff --git a/apps/behandelportal/src/app/behandeling/infrastructure/besluit.adapter.ts b/apps/behandelportal/src/app/behandeling/infrastructure/besluit.adapter.ts index 0af191f..bee51d2 100644 --- a/apps/behandelportal/src/app/behandeling/infrastructure/besluit.adapter.ts +++ b/apps/behandelportal/src/app/behandeling/infrastructure/besluit.adapter.ts @@ -3,7 +3,7 @@ import { ApiClient } from '@shared/infrastructure/api-client'; import { Valid } from '@behandeling/domain/besluit.machine'; /** - * Infrastructure adapter for recording a behandelaar's decision (WP-65b) — the single + * Infrastructure adapter for recording a behandelaar's decision — the single * place its HTTP lives. No return value: a successful call means the server accepted * the transition; the caller reloads `BeoordelingStore` to see the new status (the * server, not this adapter, re-validates and is the authority). diff --git a/apps/behandelportal/src/app/behandeling/infrastructure/werkvoorraad.adapter.ts b/apps/behandelportal/src/app/behandeling/infrastructure/werkvoorraad.adapter.ts index c48346b..99a099b 100644 --- a/apps/behandelportal/src/app/behandeling/infrastructure/werkvoorraad.adapter.ts +++ b/apps/behandelportal/src/app/behandeling/infrastructure/werkvoorraad.adapter.ts @@ -8,7 +8,7 @@ import { } from '@behandeling/domain/werkvoorraad-item'; /** - * Infrastructure adapter for the behandelportal's queue read (WP-64) — the only + * Infrastructure adapter for the behandelportal's queue read — the only * place its HTTP lives (ADR-0001 anti-corruption boundary). The untrusted response * is validated + mapped to the (narrower) queue domain shape by the parse* boundary * below; a case whose status isn't `Ingediend`/`InBehandeling` is a parse error, not diff --git a/apps/behandelportal/src/app/behandeling/ui/beoordeling-documenten/beoordeling-documenten.component.ts b/apps/behandelportal/src/app/behandeling/ui/beoordeling-documenten/beoordeling-documenten.component.ts index d8c4210..5acfc73 100644 --- a/apps/behandelportal/src/app/behandeling/ui/beoordeling-documenten/beoordeling-documenten.component.ts +++ b/apps/behandelportal/src/app/behandeling/ui/beoordeling-documenten/beoordeling-documenten.component.ts @@ -1,7 +1,7 @@ import { Component, input } from '@angular/core'; import { BeoordelingDocument } from '@behandeling/domain/beoordeling'; -/** Organism: the documents linked to an aanvraag (WP-65) — plain links to the existing +/** Organism: the documents linked to an aanvraag — plain links to the existing (pre-existing, unauthenticated — same as ssp's own document previews) content endpoint. No new shared atom: a context-local list, not a reusable building block. */ @Component({ diff --git a/apps/behandelportal/src/app/behandeling/ui/beoordeling.page.ts b/apps/behandelportal/src/app/behandeling/ui/beoordeling.page.ts index 8922f77..1a39d01 100644 --- a/apps/behandelportal/src/app/behandeling/ui/beoordeling.page.ts +++ b/apps/behandelportal/src/app/behandeling/ui/beoordeling.page.ts @@ -14,8 +14,8 @@ import { BeoordelingDocumentenComponent } from '@behandeling/ui/beoordeling-docu import { BesluitFormComponent } from '@behandeling/ui/besluit-form/besluit-form.component'; /** - * Page: one aanvraag's beoordeling detail (WP-65). The werkvoorraad list (WP-64) links - * here. `canBesluiten` (server-computed, ADR-0001) gates the decision form (WP-65b) — + * Page: one aanvraag's beoordeling detail. The werkvoorraad list links + * here. `canBesluiten` (server-computed, ADR-0001) gates the decision form — * the page never recomputes the lifecycle itself. On a recorded decision the form emits * `decided`, and the page just reloads (the server is the authority on the new status). */ diff --git a/apps/behandelportal/src/app/behandeling/ui/besluit-form/besluit-form.component.ts b/apps/behandelportal/src/app/behandeling/ui/besluit-form/besluit-form.component.ts index 8087f7a..db12c5d 100644 --- a/apps/behandelportal/src/app/behandeling/ui/besluit-form/besluit-form.component.ts +++ b/apps/behandelportal/src/app/behandeling/ui/besluit-form/besluit-form.component.ts @@ -14,7 +14,7 @@ import { BesluitState, BesluitMsg, initial, reduce } from '@behandeling/domain/b import { createSubmitBesluit } from '@behandeling/application/submit-besluit'; /** - * Organism: the decision form (WP-65b) — goedkeuren/afwijzen/meer-info-opvragen. Same + * Organism: the decision form — goedkeuren/afwijzen/meer-info-opvragen. Same * idiom as every other form in this house (`change-request-form`): all state in one * signal driven by the pure `reduce` (besluit.machine.ts), submitted via a `submit-*` * command returning `Result`. The server re-validates the transition and is the diff --git a/apps/behandelportal/src/app/behandeling/ui/werkvoorraad-list/werkvoorraad-list.component.ts b/apps/behandelportal/src/app/behandeling/ui/werkvoorraad-list/werkvoorraad-list.component.ts index c40cf68..95ff32f 100644 --- a/apps/behandelportal/src/app/behandeling/ui/werkvoorraad-list/werkvoorraad-list.component.ts +++ b/apps/behandelportal/src/app/behandeling/ui/werkvoorraad-list/werkvoorraad-list.component.ts @@ -4,9 +4,9 @@ import { ApplicationLinkComponent } from '@shared/ui/application-link/applicatio import { WerkvoorraadItem } from '@behandeling/domain/werkvoorraad-item'; import { werkvoorraadRow } from '@behandeling/domain/werkvoorraad-item-view'; -/** Organism: the behandelaar's queue as CIBG "aanvragen" rows (WP-64) — composition +/** Organism: the behandelaar's queue as CIBG "aanvragen" rows — composition of the two existing shared/ui molecules, no new atom. Each row links to the - beoordeling detail page (WP-65). */ + beoordeling detail page. */ @Component({ selector: 'app-werkvoorraad-list', imports: [ApplicationListComponent, ApplicationLinkComponent], diff --git a/apps/behandelportal/src/app/behandeling/ui/werkvoorraad.page.ts b/apps/behandelportal/src/app/behandeling/ui/werkvoorraad.page.ts index b52e8f6..70b3e91 100644 --- a/apps/behandelportal/src/app/behandeling/ui/werkvoorraad.page.ts +++ b/apps/behandelportal/src/app/behandeling/ui/werkvoorraad.page.ts @@ -10,10 +10,10 @@ import { WerkvoorraadStore } from '@behandeling/application/werkvoorraad.store'; import { WerkvoorraadListComponent } from '@behandeling/ui/werkvoorraad-list/werkvoorraad-list.component'; /** - * Page: the behandelaar's werkvoorraad (WP-64) — the behandelportal's landing page. + * Page: the behandelaar's werkvoorraad — the behandelportal's landing page. * Deny-by-default capability gate (`aanvraag:beoordelen`), same idiom as ssp's * AdminCasesPage: a denial alert for a non-behandelaar, the queue for one. Opening - * a case's detail is out of scope here (WP-65). + * a case's detail is out of scope here. */ @Component({ selector: 'app-werkvoorraad-page', @@ -69,7 +69,7 @@ export class WerkvoorraadPage { private loadRequested = false; constructor() { // Load once the capability resolves to allowed (a 403 GET would be wasted otherwise) — - // same guard-against-the-loop idiom as AdminCasesPage (WP-26 lesson). + // same guard-against-the-loop idiom as AdminCasesPage. effect(() => { if (this.canBeoordelen() && !this.loadRequested) { this.loadRequested = true; diff --git a/apps/behandelportal/src/app/shell/nav.config.ts b/apps/behandelportal/src/app/shell/nav.config.ts index 456019b..c8b4e6b 100644 --- a/apps/behandelportal/src/app/shell/nav.config.ts +++ b/apps/behandelportal/src/app/shell/nav.config.ts @@ -8,7 +8,7 @@ export const NAV_ITEMS: readonly HeaderNavItem[] = [ /** This app's admin pages — provided to the shared site header via HEADER_ADMIN_LINKS. No huisstijl (that's the SSP's brief context) or zaken entry — inherited as-is from - WP-61's bootstrap trim, not revisited by this migration. */ + the bootstrap trim, not revisited by this migration. */ export const ADMIN_LINKS: readonly AdminLink[] = [ { label: $localize`:@@header.nav.stamdata:Stamdata`, diff --git a/apps/ssp/src/app/app.routes.ts b/apps/ssp/src/app/app.routes.ts index 610ca24..0a546fa 100644 --- a/apps/ssp/src/app/app.routes.ts +++ b/apps/ssp/src/app/app.routes.ts @@ -61,7 +61,7 @@ export const routes: Routes = [ }, { path: 'brief/huisstijl', - // Admin-only org-template editor (WP-26): capabilityGuard denies-by-default + // Admin-only org-template editor: capabilityGuard denies-by-default // unless GET /me resolved `orgtemplate:edit` (Admin role). Backend re-enforces // via the OrgAdmin gate — the guard just avoids loading a page that would 403. canActivate: [capabilityGuard('orgtemplate:edit')], @@ -78,7 +78,7 @@ export const routes: Routes = [ }, { path: 'beheer/zaken', - // Admin-only cases overview + delete (WP-36): capabilityGuard denies-by-default + // Admin-only cases overview + delete: capabilityGuard denies-by-default // unless GET /me resolved `cases:manage` (Admin role). Backend re-enforces via the // CasesAdmin gate — the guard just avoids loading a page that would 403. The page // lives in registratie/ui (which owns the Aanvraag aggregate); routed under /beheer. @@ -88,14 +88,14 @@ export const routes: Routes = [ }, { path: 'beheer/audit', - // Admin-only authz/PII-reveal audit trail (WP-41/42). capabilityGuard denies-by-default + // Admin-only authz/PII-reveal audit trail. capabilityGuard denies-by-default // unless GET /me resolved `cases:manage` (reused for audit read). Backend re-enforces. canActivate: [capabilityGuard('cases:manage')], loadComponent: () => import('@beheer/ui/audit.page').then((m) => m.AuditPage), }, { path: 'beheer/functies', - // Admin-only feature-flag toggles (WP-47), gated by `flags:manage`. + // Admin-only feature-flag toggles, gated by `flags:manage`. canActivate: [capabilityGuard('flags:manage')], loadComponent: () => import('@beheer/ui/feature-flags.page').then((m) => m.FeatureFlagsPage), diff --git a/apps/ssp/src/app/auth/infrastructure/digid.adapter.ts b/apps/ssp/src/app/auth/infrastructure/digid.adapter.ts index 652622c..52d6c60 100644 --- a/apps/ssp/src/app/auth/infrastructure/digid.adapter.ts +++ b/apps/ssp/src/app/auth/infrastructure/digid.adapter.ts @@ -7,7 +7,7 @@ import { Principal } from '../domain/principal'; @Injectable({ providedIn: 'root' }) export class DigidAdapter { // ponytail: fake DigiD — any elfproef-valid BSN authenticates to a fixed identity. - // Real BSN validation (parseBsn, WP-40) is the trust boundary; swap the fixed identity + // Real BSN validation (parseBsn) is the trust boundary; swap the fixed identity // for a real OIDC redirect flow when there's an IdP. async authenticate(bsn: string): Promise> { const r = parseBsn(bsn); diff --git a/apps/ssp/src/app/brief/application/brief.store.spec.ts b/apps/ssp/src/app/brief/application/brief.store.spec.ts index b27dd61..94d7f63 100644 --- a/apps/ssp/src/app/brief/application/brief.store.spec.ts +++ b/apps/ssp/src/app/brief/application/brief.store.spec.ts @@ -54,7 +54,7 @@ const caseContext: CaseContext = { const view: BriefView = { brief, availablePassages: [], decisions, orgTemplate, caseContext }; -/** A recording fake of BLOB_PRESENTER (RB-28/TE-006) — records every call instead of +/** A recording fake of BLOB_PRESENTER (TE-006) — records every call instead of touching the DOM, so a spec can assert a command's success path directly. */ function fakeBlobPresenter() { const opened: Blob[] = []; @@ -158,7 +158,7 @@ describe('BriefStore action state (Idle | Busy | Failed)', () => { }); }); -// --- WP-27: undo/redo history + rejection diff --- +// --- Undo/redo history + rejection diff --- function block(id: string, text: string): LetterBlock { return { @@ -308,7 +308,7 @@ describe('BriefStore rejection diff', () => { describe('BriefStore.previewLetter', () => { afterEach(() => vi.restoreAllMocks()); - it('opens the composed letter via BLOB_PRESENTER on success (RB-28)', async () => { + it('opens the composed letter via BLOB_PRESENTER on success', async () => { const { presenter, opened } = fakeBlobPresenter(); const store = setup( { @@ -412,11 +412,11 @@ describe('BriefStore.flushPending (CanDeactivate guard / beforeunload)', () => { }); }); -// --- RB-22 (CQ-007 expand half): a 404 from GET /brief tolerates by calling the -// existing reset() command, exactly once. Today's backend never 404s (RB-23 adds -// that); this fake adapter is what exercises the branch until then. --- +// --- CQ-007's expand half: a 404 from GET /brief tolerates by calling the +// existing reset() command, exactly once. Today's backend never 404s yet; +// this fake adapter is what exercises the branch until then. --- -describe('BriefStore.load — 404 tolerance (RB-22)', () => { +describe('BriefStore.load — 404 tolerance', () => { const notFound: Result = { ok: false, error: { tag: 'notFound' } }; const resetOk: Result = { ok: true, value: view }; diff --git a/apps/ssp/src/app/brief/application/brief.store.ts b/apps/ssp/src/app/brief/application/brief.store.ts index a556947..7ab3bc1 100644 --- a/apps/ssp/src/app/brief/application/brief.store.ts +++ b/apps/ssp/src/app/brief/application/brief.store.ts @@ -55,8 +55,8 @@ export class BriefStore implements PendingSave { /** Surfaced autosave state for the indicator + aria-live region. */ readonly saveState = signal({ tag: 'Idle' }); - /** Undo/redo is SHELL state, not machine state (WP-27): a `createHistory` stack of - `Brief` snapshots (WP-31 extracted the mechanics). Only CONTENT edits are recorded + /** Undo/redo is SHELL state, not machine state: a `createHistory` stack of + `Brief` snapshots (the mechanics live in a shared helper). Only CONTENT edits are recorded (they flow through `edit()`); status transitions never enter history, or undo would replay workflow state. Restore re-dispatches the existing `Seed` Msg — zero machine changes. */ @@ -64,7 +64,7 @@ export class BriefStore implements PendingSave { readonly canUndo = this.history.canUndo; readonly canRedo = this.history.canRedo; - /** The letter as it stood when it was REJECTED, captured shell-side (WP-27). The + /** The letter as it stood when it was REJECTED, captured shell-side. The approver diffs it against the resubmitted letter. POC limit: in-memory only, so a full page reload loses it — a real system would persist the rejected revision. */ private rejectionSnapshot = signal(null); @@ -81,7 +81,7 @@ export class BriefStore implements PendingSave { ); readonly hasRejectionDiff = computed(() => this.blockDiffs().size > 0); - /** The org template the letter renders with (WP-24). Server-owned appearance data, + /** The org template the letter renders with. Server-owned appearance data, not letter state — held beside the machine, never inside it (`brief.machine.ts` stays untouched by design). Set from every server view that carries it. */ readonly orgTemplate = signal(null); @@ -125,7 +125,7 @@ export class BriefStore implements PendingSave { return !!b && canSubmit(b) && !hasBlockingErrors(this.diagnostics()); }); - /** True once a 404-triggered recovery has been attempted (RB-22, CQ-007's expand + /** True once a 404-triggered recovery has been attempted (CQ-007's expand half — see `recoverFromMissingBrief`). This is the structural once-only bound: a repeated 404 falls straight to the `error` branch below and can never reach `adapter.reset()` a second time, regardless of how many times `load()` runs. */ @@ -200,7 +200,7 @@ export class BriefStore implements PendingSave { } // 600ms debounced autosave (the server is the store of record). Timer mechanics live in - // the shared helper; `flushSave` below is the store-specific write + save-state (WP-31). + // the shared helper; `flushSave` below is the store-specific write + save-state. private debouncedSave = createDebouncedSave({ canSave: () => this.canEdit(), flush: () => this.flushSave(), @@ -223,7 +223,7 @@ export class BriefStore implements PendingSave { } } - /** Retry a failed autosave — reuses the existing flush path, no new state (WP-27). */ + /** Retry a failed autosave — reuses the existing flush path, no new state. */ retrySave() { void this.flushSave(); } @@ -311,7 +311,7 @@ export class BriefStore implements PendingSave { this.store.dispatch({ tag: 'Approved', by: s.approvedBy, at: s.approvedAt, decisions }); break; case 'rejected': - // Capture the letter as-rejected for the resubmission diff (WP-27). This is the + // Capture the letter as-rejected for the resubmission diff. This is the // "before" snapshot the approver later compares against. this.rejectionSnapshot.set(brief); this.store.dispatch({ diff --git a/apps/ssp/src/app/brief/application/org-template.store.spec.ts b/apps/ssp/src/app/brief/application/org-template.store.spec.ts index f5decef..014a2fe 100644 --- a/apps/ssp/src/app/brief/application/org-template.store.spec.ts +++ b/apps/ssp/src/app/brief/application/org-template.store.spec.ts @@ -32,7 +32,7 @@ const subOrgs: SubOrgSummary[] = [ { subOrgId: 'cibg-registers', orgName: 'CIBG', publishedVersion: 1 }, ]; -/** A recording fake of BLOB_PRESENTER (RB-28/TE-006) — records every call instead of +/** A recording fake of BLOB_PRESENTER (TE-006) — records every call instead of touching the DOM, so a spec can assert a command's success path directly. */ function fakeBlobPresenter() { const opened: Blob[] = []; @@ -70,10 +70,10 @@ function setup( return TestBed.inject(OrgTemplateStore); } -// --- RB-28 (TE-006): proefbrief() ends in BLOB_PRESENTER.open, not a raw +// --- TE-006: proefbrief() ends in BLOB_PRESENTER.open, not a raw // window.open(URL.createObjectURL(...)) call, so both outcomes are assertable. --- -describe('OrgTemplateStore.proefbrief (RB-28)', () => { +describe('OrgTemplateStore.proefbrief', () => { it('opens the rendered proefbrief via BLOB_PRESENTER on success', async () => { // Given a loaded sub-org template. const { presenter, opened } = fakeBlobPresenter(); diff --git a/apps/ssp/src/app/brief/application/org-template.store.ts b/apps/ssp/src/app/brief/application/org-template.store.ts index 87ce84a..1ec5f0d 100644 --- a/apps/ssp/src/app/brief/application/org-template.store.ts +++ b/apps/ssp/src/app/brief/application/org-template.store.ts @@ -28,7 +28,7 @@ const LOGO_CATEGORY = 'org-logo'; const NO_SUBORGS = $localize`:@@orgTemplate.noSubOrgs:Er zijn geen organisatiesjablonen om te beheren.`; /** - * Root singleton for the admin org-template editor (WP-26). The Elm machine owns the + * Root singleton for the admin org-template editor. The Elm machine owns the * editable draft; commands here do the debounced save, publish (impact-confirm), * rollback and proefbrief, then dispatch the outcome — the reducer stays pure. The * logo upload reuses the shared upload transport; its completion mutates the draft @@ -151,7 +151,7 @@ export class OrgTemplateStore implements PendingSave { this.debouncedSave.schedule(); } - // 600ms debounced autosave (same idiom as BriefStore, WP-31). Timer mechanics live in the + // 600ms debounced autosave (same idiom as BriefStore). Timer mechanics live in the // shared helper; `flushSave` below is the store-specific write + save-state. private debouncedSave = createDebouncedSave({ canSave: () => this.loaded() !== null, diff --git a/apps/ssp/src/app/brief/domain/brief-diff.ts b/apps/ssp/src/app/brief/domain/brief-diff.ts index d41aa63..b21b947 100644 --- a/apps/ssp/src/app/brief/domain/brief-diff.ts +++ b/apps/ssp/src/app/brief/domain/brief-diff.ts @@ -2,7 +2,7 @@ import { Brief, LetterBlock, allBlocks } from './brief'; /** * The rejection diff as a PURE function over two immutable `Brief` values — the whole - * teaching payload of WP-27: because state is one value, "what changed since the letter + * teaching payload here: because state is one value, "what changed since the letter * was rejected" is just a fold over two snapshots, no change-tracking bookkeeping. * * Blocks are matched by `blockId` (stable `local-N`/seed ids): diff --git a/apps/ssp/src/app/brief/domain/org-template.machine.ts b/apps/ssp/src/app/brief/domain/org-template.machine.ts index 8c63953..96a5ca2 100644 --- a/apps/ssp/src/app/brief/domain/org-template.machine.ts +++ b/apps/ssp/src/app/brief/domain/org-template.machine.ts @@ -3,7 +3,7 @@ import { Margins, OrgTemplate, OrgTemplateAdminView, OrgTemplateVersion } from ' import { UploadMsg, UploadState, initialUpload, reduceUpload } from '@shared/domain/upload.machine'; /** - * The admin org-template editor as one Elm-style machine (WP-26, PRD Brief v2 §5) — + * The admin org-template editor as one Elm-style machine (PRD Brief v2 §5) — * the same idiom as the wizards. The DRAFT org template is form state (edited in * place on the canvas); publish/rollback are effects that come back as `DraftLoaded`. * `dirty` tracks unsaved edits (the store debounce-saves them). The logo upload is diff --git a/apps/ssp/src/app/brief/domain/org-template.ts b/apps/ssp/src/app/brief/domain/org-template.ts index 0153f43..b8f05ef 100644 --- a/apps/ssp/src/app/brief/domain/org-template.ts +++ b/apps/ssp/src/app/brief/domain/org-template.ts @@ -1,9 +1,9 @@ /** - * The organization template (Brief v2 PRD §3, WP-23/24): the SECOND template axis — + * The organization template (Brief v2 PRD §3): the SECOND template axis — * appearance/identity per sub-organization (letterhead, footer, signature, margins). * Orthogonal to the case-type template (sections + placeholders); the two only meet * at render time, on the letter canvas. Server-owned: the FE renders it verbatim, - * never edits it here (the admin editor is WP-26). + * never edits it here (the admin editor does). */ export interface Margins { @@ -30,7 +30,7 @@ export interface OrgTemplate { readonly version: number; } -// --- admin editor (WP-26) --- +// --- admin editor --- /** A published snapshot in the version history: who is faked, `publishedAt` is real. */ export interface OrgTemplateVersion { diff --git a/apps/ssp/src/app/brief/infrastructure/brief.adapter.ts b/apps/ssp/src/app/brief/infrastructure/brief.adapter.ts index 02d3fad..dd0f174 100644 --- a/apps/ssp/src/app/brief/infrastructure/brief.adapter.ts +++ b/apps/ssp/src/app/brief/infrastructure/brief.adapter.ts @@ -38,9 +38,9 @@ import { Mark, Paragraph, RichTextBlock, RichTextNode } from '@shared/kernel/ric * (ProblemDetails → error string, plus the Idempotency-Key mint), then parses the * returned brief. `load` (the only read) does its own try/catch instead of the * shared `runResult` fold, because it needs one extra bit `runResult` throws away: - * whether the failure was an HTTP 404 (see `BriefLoadFailure` — RB-22, CQ-007's - * expand half). Today's backend never 404s `GET /brief` (RB-23 adds that), so the - * `notFound` branch is unreached until RB-23 ships; this adapter is ready in advance. + * whether the failure was an HTTP 404 (see `BriefLoadFailure` — CQ-007's + * expand half). Today's backend never 404s `GET /brief`, so the + * `notFound` branch is unreached until it does; this adapter is ready in advance. */ export interface BriefView { @@ -66,7 +66,7 @@ export const BRIEF_ACTION_FAILED = $localize`:@@brief.action.failed:De actie is /** True when the thrown value carries an HTTP 404 status — matches both the generic `SwaggerException` (today's shape, since `GET /brief` declares no 404 response yet) and a parsed `ProblemDetails` (RFC 7807 `status`, the shape once - RB-23 gives the endpoint a documented 404 response). */ + the endpoint gets a documented 404 response). */ function isHttpNotFound(e: unknown): boolean { return !!e && typeof e === 'object' && (e as { status?: unknown }).status === 404; } diff --git a/apps/ssp/src/app/brief/infrastructure/letter-preview.adapter.ts b/apps/ssp/src/app/brief/infrastructure/letter-preview.adapter.ts index d777d7d..3b7f9b9 100644 --- a/apps/ssp/src/app/brief/infrastructure/letter-preview.adapter.ts +++ b/apps/ssp/src/app/brief/infrastructure/letter-preview.adapter.ts @@ -14,19 +14,19 @@ export const PREVIEW_FAILED = $localize`:@@brief.preview.failed:De voorvertoning * to keep the NSwag-generated client JSON-only (same seam as uploads) — so this is a * hand-written fetch, not the `ApiClient`. That also means it bypasses `HttpClient`'s * `roleInterceptor` AND `subjectInterceptor`, so both `X-Role` and `X-Subject` are set - * here explicitly (WP-74 — without `X-Subject` this always previewed + * here explicitly (without `X-Subject` this always previewed * `DocumentStore.DemoOwner`'s letter regardless of who was actually logged in). Both are * dev-only identity stand-ins (`role.ts`/`subject.ts`) and are sent only under * `isDevMode()`, mirroring how the interceptors themselves are only registered in dev * (`app.config.ts`) — a production build sends neither header from this call (BIO-012). * - * `cache: 'no-store'` (WP-74): the endpoint has no `Cache-Control`, only a CORS-driven + * `cache: 'no-store'`: the endpoint has no `Cache-Control`, only a CORS-driven * `Vary: Origin`, and its content changes at the SAME URL as the letter moves * draft → sent. Explicitly bypassing the HTTP cache is the correct default for any - * mutable resource served under one unversioned URL — independent of WP-74's - * identity work, and not a complete fix by itself: see the KNOWN GAP note below. + * mutable resource served under one unversioned URL — independent of the + * identity work above, and not a complete fix by itself: see the KNOWN GAP note below. * - * KNOWN GAP (WP-74, not fixed here): under a non-`DocumentStore.DemoOwner` `X-Subject`, + * KNOWN GAP (not fixed here): under a non-`DocumentStore.DemoOwner` `X-Subject`, * this repo's own e2e run against a real backend observed this endpoint's SENT * response still carrying the draft watermark, even though (a) the outgoing request * carried the correct `X-Subject`, and (b) `curl` against the same backend at the @@ -34,7 +34,7 @@ export const PREVIEW_FAILED = $localize`:@@brief.preview.failed:De voorvertoning * did not change the outcome, so it is very unlikely a client-side caching artifact — * it looks like a genuine backend-side staleness/race in `BriefStore`'s SQLite-backed * read path, reproducible for MULTIPLE distinct owners and NOT reproducible for - * `DemoOwner`, which needs backend-side investigation (out of WP-74's file scope — + * `DemoOwner`, which needs backend-side investigation (out of this file's scope — * see `e2e/brief-v2.spec.ts`'s header comment, which keeps that spec on the shared * `zorgverlener` identity until this is root-caused). */ diff --git a/apps/ssp/src/app/brief/ui/brief.page.ts b/apps/ssp/src/app/brief/ui/brief.page.ts index b5f1a48..0892b14 100644 --- a/apps/ssp/src/app/brief/ui/brief.page.ts +++ b/apps/ssp/src/app/brief/ui/brief.page.ts @@ -167,7 +167,7 @@ export class BriefPage { void this.store.resetDemo(); } - /** Typed narrowing for the `` loaded slot — see WP-06: a structural + /** Typed narrowing for the `` loaded slot: a structural directive's context can't inherit a generic from a sibling host input, so the Success value is unwrapped here instead of through `let-`. */ protected readonly loaded = computed(() => { @@ -179,7 +179,7 @@ export class BriefPage { void this.store.load(); } - /** Ctrl/Cmd+Z = undo, Ctrl/Cmd+Shift+Z = redo (WP-27). Ignored while focus is in the + /** Ctrl/Cmd+Z = undo, Ctrl/Cmd+Shift+Z = redo. Ignored while focus is in the rich-text editor or a form control, so the browser's own text undo keeps working there — our shell-level undo is for structural edits (add/remove/reorder blocks). */ protected onKey(e: KeyboardEvent) { diff --git a/apps/ssp/src/app/brief/ui/letter-canvas/letter-canvas.component.ts b/apps/ssp/src/app/brief/ui/letter-canvas/letter-canvas.component.ts index b5aca9a..bebded2 100644 --- a/apps/ssp/src/app/brief/ui/letter-canvas/letter-canvas.component.ts +++ b/apps/ssp/src/app/brief/ui/letter-canvas/letter-canvas.component.ts @@ -53,9 +53,9 @@ const A4_HEIGHT_PX = (297 * 96) / 25.4; footer around the case-type template's sections. `editableRegions` picks who edits what: `'content'` hosts the editable letter-sections in place (drafter), `'none'` renders everything read-only (approver/locked, absorbs the old letter-preview), - `'template'` reserves the org-identity regions for the admin editor (WP-26). + `'template'` reserves the org-identity regions for the admin editor. Letter typography/geometry come from the shared `public/letter.css` contract — - the same file the backend preview renderer inlines (WP-25). */ + the same file the backend preview renderer inlines. */ @Component({ selector: 'app-letter-canvas', imports: [NgTemplateOutlet, ButtonComponent, PlaceholderChipComponent], @@ -82,7 +82,7 @@ const A4_HEIGHT_PX = (297 * 96) / 25.4; color: var(--rhc-color-foreground-subtle); font-variant-numeric: tabular-nums; } - /* Rejection-diff badge (WP-27): a small pill above a changed/added block. */ + /* Rejection-diff badge: a small pill above a changed/added block. */ .diff-block.diff-changed { border-inline-start: 3px solid var(--rhc-color-oranje-500); padding-inline-start: var(--rhc-space-max-sm); @@ -98,7 +98,7 @@ const A4_HEIGHT_PX = (297 * 96) / 25.4; background: var(--rhc-color-oranje-500); } .diff-badge.added { - /* added = white on groen-700 (6.4:1); dark text on any green fails 4.5:1 (WP-29 axe). */ + /* added = white on groen-700 (6.4:1); dark text on any green fails 4.5:1 (axe). */ color: var(--rhc-color-wit); background: var(--rhc-color-groen-700); } @@ -345,12 +345,12 @@ export class LetterCanvasComponent { brief = input.required(); orgTemplate = input.required(); /** Who edits what on the surface: read-only ('none', the drafter preview + approver - view) or admin editor ('template', WP-26). Authoring moved to letter-editor. */ + view) or admin editor ('template'). Authoring moved to letter-editor. */ editableRegions = input<'template' | 'none'>('none'); diagnostics = input([]); - /** Initial zoom; the in-canvas controls take over from here (WP-27). */ + /** Initial zoom; the in-canvas controls take over from here. */ zoom = input(1); - /** Blocks changed/added/removed since the letter was rejected (WP-27); badged when + /** Blocks changed/added/removed since the letter was rejected; badged when `showDiff` is on. Removed blocks aren't in the map's rendered set — they no longer exist in the letter — the composer surfaces them as a count. */ blockDiffs = input>(new Map()); @@ -445,7 +445,7 @@ export class LetterCanvasComponent { constructor() { // ponytail: whole-surface height / A4-interval — ignores that a break never truly - // falls mid-line; the caption says "±" and WP-25's server preview is authoritative. + // falls mid-line; the caption says "±" and the server preview is authoritative. const observer = new ResizeObserver(([entry]) => { // ~1cm tolerance so a letter ending on a page boundary gets no edge-hugging mark. const pages = Math.ceil((entry.target.scrollHeight - 40) / A4_HEIGHT_PX); diff --git a/apps/ssp/src/app/brief/ui/letter-canvas/letter-canvas.stories.ts b/apps/ssp/src/app/brief/ui/letter-canvas/letter-canvas.stories.ts index 8d57118..e137fb9 100644 --- a/apps/ssp/src/app/brief/ui/letter-canvas/letter-canvas.stories.ts +++ b/apps/ssp/src/app/brief/ui/letter-canvas/letter-canvas.stories.ts @@ -127,12 +127,12 @@ export const ReadOnlyZonderBevindingen: Story = { args: { editableRegions: 'none', diagnostics: [] }, }; -/** Admin editor focus (consumer arrives in WP-26): body read-only, no "not yours" tint. */ +/** Admin editor focus: body read-only, no "not yours" tint. */ export const TemplateMode: Story = { args: { editableRegions: 'template' } }; export const Zoomed: Story = { args: { editableRegions: 'none', zoom: 0.6 } }; -/** Approver's "Toon wijzigingen": blocks changed/added since rejection are badged (WP-27). */ +/** Approver's "Toon wijzigingen": blocks changed/added since rejection are badged. */ export const WithDiff: Story = { args: { editableRegions: 'none', @@ -150,14 +150,14 @@ export const PageBreak: Story = { args: { editableRegions: 'none', brief: longBrief, diagnostics: [] }, }; -// Inline SVG so the story needs no backend/upload round-trip (WP-26 logo upload). +// Inline SVG so the story needs no backend/upload round-trip (the logo upload). const sampleLogo = 'data:image/svg+xml;utf8,' + encodeURIComponent( 'CIBG', ); -/** Published org logo (WP-26 AC2): the letterhead shows it above the org name. */ +/** Published org logo: the letterhead shows it above the org name. */ export const MetLogo: Story = { args: { editableRegions: 'none', diagnostics: [], logoUrl: sampleLogo }, }; diff --git a/apps/ssp/src/app/brief/ui/letter-composer/letter-composer.component.ts b/apps/ssp/src/app/brief/ui/letter-composer/letter-composer.component.ts index 6e36532..8366949 100644 --- a/apps/ssp/src/app/brief/ui/letter-composer/letter-composer.component.ts +++ b/apps/ssp/src/app/brief/ui/letter-composer/letter-composer.component.ts @@ -137,7 +137,7 @@ export class LetterComposerComponent { canReject = input(false); canSend = input(false); busy = input(false); - /** Rejection diff (WP-27): the changed/added/removed blocks and their count. The + /** Rejection diff: the changed/added/removed blocks and their count. The "Toon wijzigingen" toggle only appears when there's something to show. */ blockDiffs = input>(new Map()); removedCount = input(0); diff --git a/apps/ssp/src/app/brief/ui/letter-composer/letter-composer.stories.ts b/apps/ssp/src/app/brief/ui/letter-composer/letter-composer.stories.ts index 3dc7314..ef93868 100644 --- a/apps/ssp/src/app/brief/ui/letter-composer/letter-composer.stories.ts +++ b/apps/ssp/src/app/brief/ui/letter-composer/letter-composer.stories.ts @@ -181,7 +181,7 @@ export const Sent: Story = { }), }; -/** Approver's "Toon wijzigingen" (WP-27): a resubmitted letter with blocks changed, +/** Approver's "Toon wijzigingen": a resubmitted letter with blocks changed, added and removed since the last rejection. */ export const RejectionDiff: Story = { render: () => diff --git a/apps/ssp/src/app/brief/ui/org-template-editor/org-template-editor.component.ts b/apps/ssp/src/app/brief/ui/org-template-editor/org-template-editor.component.ts index 7cd9b69..59c303c 100644 --- a/apps/ssp/src/app/brief/ui/org-template-editor/org-template-editor.component.ts +++ b/apps/ssp/src/app/brief/ui/org-template-editor/org-template-editor.component.ts @@ -70,7 +70,7 @@ export const SAMPLE_LETTER_BRIEF: Brief = { }; /** - * Organism (WP-26): the admin org-template editor. The mirror of the drafter's + * Organism: the admin org-template editor. The mirror of the drafter's * composer — the letter canvas runs in `editableRegions='template'` so the * letterhead/signature/footer are edited in place, while the content is a read-only * sample. Margins, logo upload, version history and the publish bar sit around it. diff --git a/apps/ssp/src/app/brief/ui/org-template-editor/org-template-editor.stories.ts b/apps/ssp/src/app/brief/ui/org-template-editor/org-template-editor.stories.ts index 11fca36..f6bdd7a 100644 --- a/apps/ssp/src/app/brief/ui/org-template-editor/org-template-editor.stories.ts +++ b/apps/ssp/src/app/brief/ui/org-template-editor/org-template-editor.stories.ts @@ -87,12 +87,12 @@ const sampleLogo = 'CIBG', ); -/** Published logo (WP-26 AC2): the letterhead canvas shows it above the org name. */ +/** Published logo: the letterhead canvas shows it above the org name. */ export const MetLogo: Story = { args: { logoUrl: sampleLogo }, }; -/** Client-side upload rejection (existing `rejectReason`, WP-26 AC5) — type/size caught +/** Client-side upload rejection (existing `rejectReason`) — type/size caught before the file ever reaches the backend. */ export const LogoUploadFout: Story = { args: { diff --git a/apps/ssp/src/app/brief/ui/org-template.page.ts b/apps/ssp/src/app/brief/ui/org-template.page.ts index 697f19d..82a2865 100644 --- a/apps/ssp/src/app/brief/ui/org-template.page.ts +++ b/apps/ssp/src/app/brief/ui/org-template.page.ts @@ -7,7 +7,7 @@ import { AccessStore } from '@shared/application/access.store'; import { OrgTemplateStore } from '@brief/application/org-template.store'; import { OrgTemplateEditorComponent } from '@brief/ui/org-template-editor/org-template-editor.component'; -/** Page: thin container for the admin org-template editor (WP-26). Deny-by-default +/** Page: thin container for the admin org-template editor. Deny-by-default capability gate (`orgtemplate:edit`) — a denial alert for non-admins, the editor for admins. Loads once the capability resolves; wires store commands to the organism. */ @Component({ diff --git a/apps/ssp/src/app/brief/ui/passage-picker/passage-picker.component.ts b/apps/ssp/src/app/brief/ui/passage-picker/passage-picker.component.ts index 080b004..591b9d7 100644 --- a/apps/ssp/src/app/brief/ui/passage-picker/passage-picker.component.ts +++ b/apps/ssp/src/app/brief/ui/passage-picker/passage-picker.component.ts @@ -10,8 +10,8 @@ import { LibraryPassage } from '@brief/domain/brief'; inserts ALL checked passages at once (a single message upstream) — there is no single-insert path. Presentational: emits the chosen passages in list order. - Superseded by `besluit-panel` (WP-27's guided drafting): no consumer left in - `src/app` outside its own story (WP-28 audit). Kept for now rather than deleted + Superseded by `besluit-panel`'s guided drafting: no consumer left in + `src/app` outside its own story. Kept for now rather than deleted in-flight of an unrelated WP; a future cleanup can remove it. */ @Component({ selector: 'app-passage-picker', @@ -87,7 +87,7 @@ export class PassagePickerComponent { protected checked = signal>({}); protected query = signal(''); /** Client-side filter on label + rendered content text — the library is small, so no - server search (WP-27). Placeholder keys are searchable too (see `textOf`). */ + server search. Placeholder keys are searchable too (see `textOf`). */ protected filtered = computed(() => { const q = this.query().trim().toLowerCase(); if (!q) return this.passages(); diff --git a/apps/ssp/src/app/herregistratie/domain/intake.acceptance.spec.ts b/apps/ssp/src/app/herregistratie/domain/intake.acceptance.spec.ts index cfb926b..a08cf36 100644 --- a/apps/ssp/src/app/herregistratie/domain/intake.acceptance.spec.ts +++ b/apps/ssp/src/app/herregistratie/domain/intake.acceptance.spec.ts @@ -147,7 +147,7 @@ describe('intake acceptance journeys', () => { }); }); - it('raising uren above the threshold after answering scholing drops both fields (WP-69 §6)', () => { + it('raising uren above the threshold after answering scholing drops both fields', () => { // Given a journey that answered the scholing question while uren was low. const atReview = givenIntake( { tag: 'SetAnswer', key: 'buitenlandGewerkt', value: 'nee' }, @@ -170,7 +170,7 @@ describe('intake acceptance journeys', () => { ); // Then the submission succeeds, and BOTH the stale answer and its punten are gone — - // exactly the crafted-POST-shaped payload WP-69's server rule rejects. + // exactly the crafted-POST-shaped payload the server rule rejects. expect(done.tag).toBe('Submitted'); expect(done.tag === 'Submitted' && done.data.aanvullendeScholing).toBeUndefined(); expect(done.tag === 'Submitted' && done.data.punten).toBeUndefined(); diff --git a/apps/ssp/src/app/herregistratie/domain/intake.machine.spec.ts b/apps/ssp/src/app/herregistratie/domain/intake.machine.spec.ts index a4a48d8..ac64e01 100644 --- a/apps/ssp/src/app/herregistratie/domain/intake.machine.spec.ts +++ b/apps/ssp/src/app/herregistratie/domain/intake.machine.spec.ts @@ -171,7 +171,7 @@ describe('submit', () => { expect(withScholing.data.punten).toBe(200); }); - it('does not require punten for a hidden question (WP-69 §6)', () => { + it('does not require punten for a hidden question', () => { // scholingGevolgd is a stale 'ja' from when uren was low, but uren is now above // threshold — the template hides the question, so punten must not be required either. const staleScholingNoPunten = givenIntake( @@ -183,7 +183,7 @@ describe('submit', () => { expect(good.data.aanvullendeScholing).toBeUndefined(); }); - it('drops punten when raising uren hides the question (WP-69 §6)', () => { + it('drops punten when raising uren hides the question', () => { // Same stale answer, but this time punten was also filled in while uren was low. const staleScholingWithPunten = givenIntake( { tag: 'SetAnswer', key: 'buitenlandGewerkt', value: 'nee' }, diff --git a/apps/ssp/src/app/herregistratie/domain/intake.machine.ts b/apps/ssp/src/app/herregistratie/domain/intake.machine.ts index 883f661..54d9a23 100644 --- a/apps/ssp/src/app/herregistratie/domain/intake.machine.ts +++ b/apps/ssp/src/app/herregistratie/domain/intake.machine.ts @@ -116,7 +116,7 @@ function validateStep(step: StepId, a: Answers, scholingThreshold: number): Resu // visible (lageUren) AND scholing was followed — matching the template's // `@if (scholingZichtbaar())`. Without the `lageUren` guard, answering 'ja' and then // raising uren above the threshold left an error on a field the template no longer - // renders (WP-69 §6). + // renders. if (lageUren(a, scholingThreshold) && a.scholingGevolgd === 'ja') { const p = parseUren(a.punten ?? ''); if (!p.ok) errors.punten = p.error; @@ -149,8 +149,8 @@ function validateAll(a: Answers, scholingThreshold: number): Result(initial, reduce, { Submitting: async (s, store) => { this.profile.beginHerregistratie(); - // WP-69: the scholing answer rides along so the server can re-validate it as the + // The scholing answer rides along so the server can re-validate it as the // authority (IntakePolicy.RejectIncompleteScholing) — undefined members are dropped by // JSON.stringify, so a wizard above the threshold sends neither field. const r = await this.draftSync.submit({ diff --git a/apps/ssp/src/app/registratie/application/aanvragen.store.spec.ts b/apps/ssp/src/app/registratie/application/aanvragen.store.spec.ts index 8147917..e9c5123 100644 --- a/apps/ssp/src/app/registratie/application/aanvragen.store.spec.ts +++ b/apps/ssp/src/app/registratie/application/aanvragen.store.spec.ts @@ -46,8 +46,8 @@ describe('AanvragenStore', () => { expect(store.lastError()).toBeNull(); }); - // RB-20: a failed cancel must not be silent — the row rolls back AND the store - // surfaces the error the page renders. Before RB-20 this only rolled back + // A failed cancel must not be silent — the row rolls back AND the store + // surfaces the error the page renders. Before this fix it only rolled back // (bare `catch { this.state.set(before) }`), so `lastError()` stayed null forever. it('rolls back the removal and surfaces the error when the cancel fails', async () => { const cancel = vi.fn().mockRejectedValue(new Error('boom')); diff --git a/apps/ssp/src/app/registratie/application/aanvragen.store.ts b/apps/ssp/src/app/registratie/application/aanvragen.store.ts index 0095cc7..8ff931f 100644 --- a/apps/ssp/src/app/registratie/application/aanvragen.store.ts +++ b/apps/ssp/src/app/registratie/application/aanvragen.store.ts @@ -14,7 +14,7 @@ type Err = Error | undefined; * change-detection timing, HTTP caching, or a resource `reload()`. `reload()` re-fetches * so a page revisit reflects auto-approval (Concept → In behandeling → Goedgekeurd is * computed server-side on read). Cancel goes through `runSubmit` and rolls back plus - * surfaces `lastError` on failure (RB-20). + * surfaces `lastError` on failure. */ @Injectable({ providedIn: 'root' }) export class AanvragenStore { @@ -23,7 +23,7 @@ export class AanvragenStore { private state = signal>({ tag: 'Loading' }); readonly aanvragen = this.state.asReadonly(); - /** Set on a failed cancel (RB-20): the optimistic removal already rolled back by + /** Set on a failed cancel: the optimistic removal already rolled back by then, this is only the message for the alert the page renders above the list. */ private error = signal(null); readonly lastError = this.error.asReadonly(); @@ -55,7 +55,7 @@ export class AanvragenStore { /** Cancel a Concept: drop it now (synchronous, guaranteed), then confirm the DELETE. No resync — the delete succeeded, so the optimistic removal is authoritative. On - failure, roll back AND surface the error (RB-20) — a silent reappearance leaves the + failure, roll back AND surface the error — a silent reappearance leaves the user guessing why the block came back. */ async cancel(id: string) { const before = this.state(); diff --git a/apps/ssp/src/app/registratie/application/admin-cases.store.spec.ts b/apps/ssp/src/app/registratie/application/admin-cases.store.spec.ts index 851368d..f238358 100644 --- a/apps/ssp/src/app/registratie/application/admin-cases.store.spec.ts +++ b/apps/ssp/src/app/registratie/application/admin-cases.store.spec.ts @@ -44,8 +44,8 @@ describe('AdminCasesStore', () => { expect(s.tag === 'Success' && s.value.map((c) => c.id)).toEqual(['b']); }); - // RB-20: a failed delete must not be silent — the row rolls back AND the store - // surfaces the error the page renders. Before RB-20 this only rolled back + // A failed delete must not be silent — the row rolls back AND the store + // surfaces the error the page renders. Before this fix it only rolled back // (bare `catch { this.state.set(before) }`), so `lastError()` stayed null forever. it('rolls back the removal and surfaces the error when the delete fails', async () => { const deleteAny = vi.fn().mockRejectedValue(new Error('boom')); diff --git a/apps/ssp/src/app/registratie/application/admin-cases.store.ts b/apps/ssp/src/app/registratie/application/admin-cases.store.ts index a3b0ad5..71fd1f5 100644 --- a/apps/ssp/src/app/registratie/application/admin-cases.store.ts +++ b/apps/ssp/src/app/registratie/application/admin-cases.store.ts @@ -7,11 +7,11 @@ import { AanvragenAdapter, parseAanvragen } from '@registratie/infrastructure/aa type Err = Error | undefined; /** - * Admin view of ALL cases across owners (WP-36; `cases:manage`) — the back-office + * Admin view of ALL cases across owners (`cases:manage`) — the back-office * counterpart of the user-facing `AanvragenStore`. Same shape: one root singleton * owns the list as a writable RemoteData signal, delete removes the row synchronously * (optimistic), goes through `runSubmit`, and rolls back plus surfaces `lastError` on - * failure (RB-20). Admin delete removes any case (any owner, submitted or not — the + * failure. Admin delete removes any case (any owner, submitted or not — the * server enforces the capability). */ @Injectable({ providedIn: 'root' }) @@ -21,7 +21,7 @@ export class AdminCasesStore { private state = signal>({ tag: 'Loading' }); readonly cases = this.state.asReadonly(); - /** Set on a failed delete (RB-20): the optimistic removal already rolled back by + /** Set on a failed delete: the optimistic removal already rolled back by then, this is only the message for the alert the page renders above the list. */ private error = signal(null); readonly lastError = this.error.asReadonly(); @@ -47,7 +47,7 @@ export class AdminCasesStore { } /** Delete a case: drop it now (synchronous), then confirm the DELETE; roll back on error - AND surface it (RB-20) — a silent reappearance leaves the admin guessing why. */ + AND surface it — a silent reappearance leaves the admin guessing why. */ async delete(id: string) { const before = this.state(); if (before.tag === 'Success') { diff --git a/apps/ssp/src/app/registratie/application/draft-sync.spec.ts b/apps/ssp/src/app/registratie/application/draft-sync.spec.ts index c69ee82..e862381 100644 --- a/apps/ssp/src/app/registratie/application/draft-sync.spec.ts +++ b/apps/ssp/src/app/registratie/application/draft-sync.spec.ts @@ -96,7 +96,7 @@ describe('createDraftSync', () => { expect(r.ok).toBe(false); }); - it('recovers from a create conflict by adopting the existing Concept (WP-35)', async () => { + it('recovers from a create conflict by adopting the existing Concept', async () => { // Server enforces one Concept per type: a stale/cross-tab create is rejected (409), // and ensureId adopts the existing Concept from the list instead of erroring. const create = vi.fn().mockRejectedValue({ status: 409 }); diff --git a/apps/ssp/src/app/registratie/application/draft-sync.ts b/apps/ssp/src/app/registratie/application/draft-sync.ts index 07b5b18..dcb33a7 100644 --- a/apps/ssp/src/app/registratie/application/draft-sync.ts +++ b/apps/ssp/src/app/registratie/application/draft-sync.ts @@ -63,7 +63,7 @@ export function createDraftSync(deps: DraftSyncDeps) { if (id) return id; ensuring ??= adapter .create(deps.type) - // WP-35: one Concept per type is server-enforced. Within a tab the resumeGate + // One Concept per type is server-enforced. Within a tab the resumeGate // already prevents a second create, but a cross-tab/stale race can still hit the // server's guard (409) — recover by adopting the existing Concept instead of // erroring. Only recover when one actually exists; otherwise surface the failure. diff --git a/apps/ssp/src/app/registratie/application/find-concept.ts b/apps/ssp/src/app/registratie/application/find-concept.ts index dfbe364..35042a4 100644 --- a/apps/ssp/src/app/registratie/application/find-concept.ts +++ b/apps/ssp/src/app/registratie/application/find-concept.ts @@ -3,7 +3,7 @@ import { AanvragenAdapter, parseAanvragen } from '@registratie/infrastructure/aa /** * Read half of the Concept lookup that `createDraftSync` (`draft-sync.ts`) needs - * before it can start writing (RB-21 / CQ-001). Free functions that take the adapter + * before it can start writing (CQ-001). Free functions that take the adapter * as a parameter, not `inject()`, so they get a direct spec without Angular TestBed. * `createDraftSync` keeps the closure state (`id`, `resumeGate`) and the write path; * these two functions only read. diff --git a/apps/ssp/src/app/registratie/domain/aanvraag.ts b/apps/ssp/src/app/registratie/domain/aanvraag.ts index 7e906ae..7295204 100644 --- a/apps/ssp/src/app/registratie/domain/aanvraag.ts +++ b/apps/ssp/src/app/registratie/domain/aanvraag.ts @@ -10,8 +10,8 @@ */ export type AanvraagType = 'registratie' | 'herregistratie' | 'intake'; -// Ingediend/MeerInfoGevraagd (ADR-0002/WP-63) are widened into the union so the parse -// boundary + renderers are ready, but no backend path emits them yet — that's WP-65's +// Ingediend/MeerInfoGevraagd (ADR-0002) are widened into the union so the parse +// boundary + renderers are ready, but no backend path emits them yet — that's the // behandelaar-facing transition endpoint. export type AanvraagStatus = | { tag: 'Concept'; stepIndex: number; stepCount: number } @@ -29,7 +29,7 @@ export interface Aanvraag { createdAt: string; updatedAt: string; submittedAt?: string; - /** The case owner (a BSN). Only populated by the admin cross-owner list (WP-36); + /** The case owner (a BSN). Only populated by the admin cross-owner list; the user's own list leaves it undefined. */ owner?: string; } diff --git a/apps/ssp/src/app/registratie/domain/change-request.machine.ts b/apps/ssp/src/app/registratie/domain/change-request.machine.ts index 6fae12a..4590d2d 100644 --- a/apps/ssp/src/app/registratie/domain/change-request.machine.ts +++ b/apps/ssp/src/app/registratie/domain/change-request.machine.ts @@ -5,7 +5,7 @@ import { } from '@registratie/domain/value-objects/telefoonnummer'; /** What the user is typing (raw, possibly invalid). The BRP address is NOT part of - the form — it is authoritative and shown read-only (WP-34); only the phone number + the form — it is authoritative and shown read-only; only the phone number is editable here. */ export interface Draft { telefoon: string; diff --git a/apps/ssp/src/app/registratie/infrastructure/aanvragen.adapter.ts b/apps/ssp/src/app/registratie/infrastructure/aanvragen.adapter.ts index a0fa92f..6e70c34 100644 --- a/apps/ssp/src/app/registratie/infrastructure/aanvragen.adapter.ts +++ b/apps/ssp/src/app/registratie/infrastructure/aanvragen.adapter.ts @@ -32,12 +32,12 @@ export class AanvragenAdapter { return this.client.aanvragenAll(); } - /** Admin: every case across all owners (WP-36; `cases:manage`). Parsed at the boundary. */ + /** Admin: every case across all owners (`cases:manage`). Parsed at the boundary. */ listAll(): Promise { return this.client.casesAll(); } - /** Admin: delete ANY case (any owner, submitted or not — WP-36). */ + /** Admin: delete ANY case (any owner, submitted or not). */ deleteAny(id: string): Promise { return this.client.cases(id); } @@ -117,7 +117,7 @@ function parseCommon(dto: AanvraagSummaryDto): Result { createdAt: dto.createdAt, updatedAt: dto.updatedAt, submittedAt: dto.submittedAt, - owner: dto.owner, // only present on the admin cross-owner list (WP-36) + owner: dto.owner, // only present on the admin cross-owner list }); } diff --git a/apps/ssp/src/app/registratie/infrastructure/change-request.adapter.ts b/apps/ssp/src/app/registratie/infrastructure/change-request.adapter.ts index fe66b8b..7d61037 100644 --- a/apps/ssp/src/app/registratie/infrastructure/change-request.adapter.ts +++ b/apps/ssp/src/app/registratie/infrastructure/change-request.adapter.ts @@ -6,7 +6,7 @@ import { Valid } from '@registratie/domain/change-request.machine'; * Infrastructure adapter for the telefoonwijziging POST (`/api/v1/change-requests`) — * the single place the network client lives for contact changes, so the command * and the UI never touch `ApiClient`. The BRP address is authoritative and not - * submitted (WP-34); only the phone number is. Returns the server reference; the + * submitted; only the phone number is. Returns the server reference; the * server re-validates and is the authority. */ @Injectable({ providedIn: 'root' }) diff --git a/apps/ssp/src/app/registratie/ui/admin-cases.page.ts b/apps/ssp/src/app/registratie/ui/admin-cases.page.ts index cc051ac..0b1ac71 100644 --- a/apps/ssp/src/app/registratie/ui/admin-cases.page.ts +++ b/apps/ssp/src/app/registratie/ui/admin-cases.page.ts @@ -13,7 +13,7 @@ import { TYPE_LABELS, statusLabel, referentie } from '@registratie/domain/aanvra import { AdminCasesStore } from '@registratie/application/admin-cases.store'; /** - * Admin page: every case across all owners, with an admin delete (WP-36). Lives in + * Admin page: every case across all owners, with an admin delete. Lives in * `registratie` (which owns the Aanvraag aggregate) — the back-office counterpart of the * user's dashboard, reusing the same view labels + trust-boundary parse. Deny-by-default * capability gate (`cases:manage`): a denial alert for non-admins, the list for admins. @@ -109,7 +109,7 @@ export class AdminCasesPage { private loadRequested = false; constructor() { // Load once the capability resolves to allowed (a 403 GET would be wasted otherwise). - // Depends only on canManage() + a plain flag — never the store model (WP-26 loop lesson). + // Depends only on canManage() + a plain flag — never the store model (the loop lesson). effect(() => { if (this.canManage() && !this.loadRequested) { this.loadRequested = true; diff --git a/apps/ssp/src/app/registratie/ui/change-request-form/change-request-form.component.ts b/apps/ssp/src/app/registratie/ui/change-request-form/change-request-form.component.ts index c7bf467..92ab814 100644 --- a/apps/ssp/src/app/registratie/ui/change-request-form/change-request-form.component.ts +++ b/apps/ssp/src/app/registratie/ui/change-request-form/change-request-form.component.ts @@ -20,7 +20,7 @@ import { createSubmitChangeRequest } from '@registratie/application/submit-chang /** * Organism: contact-change (telefoonwijziging) form. The BRP address is authoritative - * and shown READ-ONLY (WP-34) — you change your address at the gemeente, not here — so + * and shown READ-ONLY — you change your address at the gemeente, not here — so * only the phone number is editable. Uses the SAME idiom as the wizards: all state in * one signal driven by the pure `reduce` (change-request.machine.ts), submitted via a * `submit-*` command returning `Result`. The server re-validates. diff --git a/apps/ssp/src/app/shell/debug-state/debug-state.component.ts b/apps/ssp/src/app/shell/debug-state/debug-state.component.ts index b3faf88..b258acc 100644 --- a/apps/ssp/src/app/shell/debug-state/debug-state.component.ts +++ b/apps/ssp/src/app/shell/debug-state/debug-state.component.ts @@ -136,7 +136,7 @@ export class DebugStateComponent { pendingHerregistratie: this.profileStore?.pendingHerregistratie(), })); - // Dev switchers (WP-33): flip role/scenario without hand-editing the URL. Both are + // Dev switchers flip role/scenario without hand-editing the URL. Both are // read per-request in interceptors, so a reload re-runs them and re-fetches decisions. protected readonly roles = ROLES; protected readonly scenarios = SCENARIOS; @@ -158,7 +158,7 @@ export class DebugStateComponent { this.applyAndReload(); } - // Strip the dev params from the URL before reloading (WP-37) so a stale ?scenario=/?role= + // Strip the dev params from the URL before reloading so a stale ?scenario=/?role= // in the address bar can't override the value the switcher just stored (currentScenario/ // currentRole read the URL first) — otherwise a switch to "default"/"drafter" gets stuck. private applyAndReload(): void { diff --git a/apps/ssp/src/app/showcase/highlight-ts.ts b/apps/ssp/src/app/showcase/highlight-ts.ts index 77ad118..756b05c 100644 --- a/apps/ssp/src/app/showcase/highlight-ts.ts +++ b/apps/ssp/src/app/showcase/highlight-ts.ts @@ -1,5 +1,5 @@ /** - * Tiny, dependency-free TS highlighter for the teaching showcase (WP-39). Escapes HTML, + * Tiny, dependency-free TS highlighter for the teaching showcase. Escapes HTML, * then wraps line-comments, strings, and a fixed keyword set in `.c`/`.s`/`.k` spans (the * classes `concepts.page` styles). Deliberately naive — good enough for the short, curated * snippets shown here; not a real tokenizer. Input is always our OWN source (extracted by diff --git a/apps/ssp/src/index.html b/apps/ssp/src/index.html index 7dea9cb..4d5a3d3 100644 --- a/apps/ssp/src/index.html +++ b/apps/ssp/src/index.html @@ -10,8 +10,8 @@ url(../fonts|icons|images) refs resolve against the vendored folder at runtime. Licensed Rijksoverheid fonts are not used — styles.scss overrides the stack to system-ui. --> - +