# RD-14 — Move `SaveState` beside its producer, delete `action-state.ts` Status: done Source: PLAN.md 1b#2b ## Why RD-12 and RD-13 moved both `ActionState` consumers into their machines, so **`ActionState` now has zero real users.** Word-anchored, it survives only in its own definition and in one doc-comment mention. `SaveState` is different and must survive: it has two genuine consumers that keep all four cases (`brief.page.ts:150` and `org-template.page.ts:102` both `switch` on it, and `brief.page.ts:77` reads `=== 'Error'`). The original plan called for deleting both types; that was corrected once the consumers were read. So the file's remaining job is to hold one type whose only producer lives elsewhere. Move `SaveState` next to `createDebouncedSave`, which is what sets it, and the file has no reason to exist. ## Read first - `libs/shared/src/application/action-state.ts` — 9 lines, both types - `libs/shared/src/application/debounced-save.ts` — `SaveState`'s new home; note the comment at line 16, which names `ActionState` - `apps/ssp/src/app/brief/application/brief.store.ts:4,57` and `org-template.store.ts:3,66` — the two importers ## Decisions (pre-made, don't relitigate) 1. **Delete `ActionState` outright.** Zero users after RD-12 and RD-13. Do not deprecate it, do not keep a re-export. 2. **Move `SaveState` verbatim into `debounced-save.ts`**, keeping its doc comment. That file already owns the debounced-autosave concern and `createDebouncedSave` is the only thing that drives the state, so the type belongs beside it. Keep the four cases exactly as they are — `Idle | Saving | Saved | Error`. 3. **Delete `libs/shared/src/application/action-state.ts`.** Nothing else lives in it. 4. **Update the two store imports** to `@shared/application/debounced-save`. Both stores already import from that module for `createDebouncedSave`, so this should merge into an existing import line rather than adding one. 5. **Reword `debounced-save.ts:16`**, which currently reads "it touches that store's `SaveState`/`ActionState` + adapter". Drop the `ActionState` half — the type will not exist. 6. **Change no UI file and no page.** `saveState`'s public signature on both stores stays identical, so the three consumer sites need no edit. ## Files - `libs/shared/src/application/debounced-save.ts` — gains `SaveState`, comment reworded - `libs/shared/src/application/action-state.ts` — **deleted** - `apps/ssp/src/app/brief/application/brief.store.ts` — import only - `apps/ssp/src/app/brief/application/org-template.store.ts` — import only No spec files. No UI files. No machine files. ## Steps 1. Move the `SaveState` declaration and its doc comment into `debounced-save.ts`. 2. Reword the `ActionState` mention at line 16 (decision 5). 3. Re-point both store imports (decision 4). 4. `git rm libs/shared/src/application/action-state.ts`. 5. Update this ticket's `Status:` to `done` and the README's RD-14 row to `done`. 6. Commit all of it together. ## Acceptance criteria Measured baselines, dry-run before handover. ```bash # The file is gone, and nothing imports it. ls libs/shared/src/application/action-state.ts # MUST be "No such file" git grep -l "application/action-state" -- apps libs # was 2 files -> MUST return nothing # ActionState is gone entirely, word-anchored (a name containing it would defeat a bare grep). git grep -nw "ActionState" -- apps libs # MUST return nothing # SaveState survives, in its new home, with all four cases. Anchor on the DECLARATION: # a bare `-w SaveState` grep already returns 1 today, from the line-16 comment. D=libs/shared/src/application/debounced-save.ts git grep -c "export type SaveState" -- $D # was 0 -> MUST be 1 git grep -c "'Idle'\|'Saving'\|'Saved'\|'Error'" -- $D # MUST be >= 4 # The render seam did not move: the three consumer sites are untouched. git diff --name-only c599fee | grep -c "brief/ui/" || true # MUST be 0 git grep -c "readonly saveState" -- \ apps/ssp/src/app/brief/application/brief.store.ts \ apps/ssp/src/app/brief/application/org-template.store.ts # still 1 each ``` ```bash npm run ci # exits 0 ``` ## Verification `npm run ci`. No story, no `.mdx`, no `libs/shared/src/ui/**`, so `--full` is not required. `dep:check` matters here: `debounced-save.ts` is in `libs/shared/src/application`, the same layer `action-state.ts` was in, so no boundary changes. If `dep:check` fails, the type landed in the wrong layer. If `dotnet test` fails with `SQLite Error 1: 'no such table: …'`, that is the stale `bigregister.db` artifact in this README's Troubleshooting section, unrelated to your change. ## Out of scope - Anything under `brief/ui/` (decision 6). - The machines. RD-12 and RD-13 already moved the action lifecycles. - `NO_SUBORGS` becoming `Empty` — optional RD-34. - `UploadStatus`'s `type:` discriminant — optional RD-35. ## Risks - **Do not delete `SaveState` along with the file.** It has two four-way consumers. The original plan said to delete both types; reading the consumers corrected that, and this ticket is the corrected version. - **Merge into the existing `debounced-save` import** in both stores rather than adding a second import line from the same module — lint will not complain, but it reads badly. - **This is the last ticket that touches `action-state.ts`.** After it, the phase's claim holds: two encodings survive, `RemoteData` for fetched data and each machine's own state union, plus `SaveState` as an explicitly-justified third for a different concern.