refactor: strip WP-/RB- ticket refs from apps and libs (RD-18)

204 WP-NN/RB-NN comments named a closed ticket instead of the code they
sit next to. git blame already records history and stays correct when
code moves; the comment does not. This sweep removes the reference and
keeps the sentence, across 95 files in apps/ and libs/ plus the
behaviour-spec generator's header text.

Eleven references stay: five story files justify an a11y disable per
the README's rule, and one line in a11y.mdx documents that convention.
Two sentences needed a rewrite, not a deletion, so the reference's
meaning survives its removal. behaviour-spec.mdx is regenerated, not
hand-edited.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-09-04 21:23:07 +02:00
co-authored by Claude Sonnet 5
parent 3895588b9a
commit dd11eafe50
102 changed files with 361 additions and 197 deletions
@@ -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'));
@@ -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<RemoteData<Err, Aanvraag[]>>({ 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<string | null>(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();
@@ -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'));
@@ -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<RemoteData<Err, Aanvraag[]>>({ 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<string | null>(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') {
@@ -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 });
@@ -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.
@@ -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.
@@ -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;
}
@@ -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;
@@ -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<AanvraagSummaryDto[]> {
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<void> {
return this.client.cases(id);
}
@@ -117,7 +117,7 @@ function parseCommon(dto: AanvraagSummaryDto): Result<string, Aanvraag> {
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
});
}
@@ -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' })
@@ -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;
@@ -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.