--- name: mutation-command description: Add a write/submit operation — infrastructure adapter method plus an application command factory returning Result, keeping the reducer pure. Use for any POST/PUT/DELETE a form or action triggers. --- # Mutation command Reducer = "what the new state is"; command = "go do it, then say what happened". The UI holds an application command, never the network client (lint-enforced). ## Skeleton **Adapter method** (`/infrastructure/.adapter.ts`) — takes the machine's `Valid` type, returns the server's answer, no parse (server is authority): ```ts @Injectable({ providedIn: 'root' }) export class ChangeRequestAdapter { private client = inject(ApiClient); async changeRequest(data: Valid): Promise { /* → server reference */ } } ``` **Command factory** (`/application/submit-.ts`) — binds the adapter in an injection context; `runSubmit` is the one try/catch + ProblemDetails mapping: ```ts export function createSubmitChangeRequest() { const adapter = inject(ChangeRequestAdapter); return (data: Valid): Promise> => runSubmit(() => adapter.changeRequest(data), SUBMIT_FAILED); } ``` **Caller** (organism, field initializer — same shape as `createStore`): on the machine's `Submitting` state, run the command, then dispatch `SubmitConfirmed` / `SubmitFailed { error }`. Never throw into the template. ## Optimistic updates on shared state When a root store's view must reflect the write before the server confirms: `begin*` (flip pending) → `confirm*` (clear + `resource.reload()`) / `rollback*` (undo). See `src/app/registratie/application/big-profile.store.ts`. ## Worked examples - `src/app/registratie/infrastructure/change-request.adapter.ts` - `src/app/registratie/application/submit-change-request.ts` - `src/app/registratie/application/draft-sync.ts` — `createDraftSync(...)` bundles draft persistence + submit for wizard flows; prefer it when the form has a draft. - `src/app/shared/application/submit.ts` — `runSubmit`, `SUBMIT_FAILED`. ## Verify ```bash npm test && npm run lint && npm run build # exercise the failure path in the browser: ?scenario=error on the submitting page ```