# WP-31 — Shared store helpers (audit: apply high-value) Status: done Phase: 7 — refinements ## Why A code audit found real duplication across the editor stores. This WP extracts the four highest-value shared helpers and rewires the stores to them (behaviour unchanged), and **reports** the lower-value / riskier DDD items as deferred backlog. Extracting `createHistory` here also unblocks WP-32 (stamdata undo) so it needn't copy-paste the brief pattern. ## Decisions (pre-made, don't relitigate) - Extract into `shared/application/` (importable by every context; must not import back). - Apply the four concrete extractions + reuse; **do not** chase the deferred DDD items in this phase (bound the diff). Behaviour must be identical — the existing store specs are the gate. ## Files - New (each with a co-located spec): `shared/application/action-state.ts` (`ActionState`/ `SaveState`), `history.ts` (`createHistory`), `debounced-save.ts` (`createDebouncedSave`), `machine-remote-data.ts` (`machineRemoteData`). - Rewired: `brief/application/brief.store.ts` (all four), `brief/application/org-template.store.ts` (types + debounced-save + remote-data), `beheer/application/stamdata.store.ts` (remote-data). ## Acceptance criteria - [x] `ActionState`/`SaveState` defined once; both brief stores import them. - [x] `createHistory` backs brief undo/redo (identical semantics; specs pass). - [x] `createDebouncedSave` backs both brief stores' autosave, integrating `PendingSave`. - [x] `machineRemoteData` backs the RemoteData projection in all three stores. - [x] `npm run ci` green; all pre-existing store specs still pass (no behaviour change). ## Deferred (reported, not built) — audit findings for a later WP - **`contracts/` folder inconsistency:** only `beheer/` + `registratie/` have a `contracts/` folder; `brief/`/`herregistratie/`/`auth/` declare wire DTOs inline in adapters. Decide whether inline DTOs are a sanctioned exception or should be normalized. - **`parse*` traverse combinator:** ~35 `parse*` boundary fns repeat an array-parse-and-collect shape; a shared `traverse`/`parseAll` `Result` combinator would collapse the common idiom. - **`Seed { state }` msg boilerplate:** the `Seed`/`return m.state` pair repeats in 6 machines — cheap and per-machine typed; extract only if it earns its keep. ## Out of scope - The deferred items above (this WP only applies the four extractions). ## Risks - Behaviour drift in the central stores — mitigated: the extractions are 1:1 with the originals and gated by the existing brief/org-template/stamdata specs (all green).