refactor: fold machine-remote-data into remote-data.ts, PascalCase load lifecycle (RD-11)

`machine-remote-data.ts` defined a third encoding of an in-flight fetch:
`LoadLifecycle`. It had three call sites, all one identical line, and the type
was never imported by name. Move the mapping into `remote-data.ts` as
`fromLoadLifecycle`, beside its neighbour `fromResource` — a `RemoteData`
constructor, not a sixth encoding.

The lowercase `loading`/`failed`/`loaded` tags on `BriefState`,
`OrgTemplateState` and `StamdataEditorState` existed only because
`LoadLifecycle` required them. Now that the constraint is inline and
PascalCase, the three machines' load-lifecycle tags become `Loading`,
`Failed` and `Loaded` — matching their own PascalCase message tags in the
same file. `stamdata-editor.machine.spec.ts` no longer asserts a PascalCase
message producing a lowercase state.

`BriefStatus` (the letter's draft/submitted/approved/rejected/sent status,
parsed off the wire from `BriefViewDto`) is a separate tag family and is
untouched — its tag count stays 54 before and after this change.

Delete `machine-remote-data.ts` and merge its spec into `remote-data.spec.ts`.
Regenerate `behaviour-spec.mdx` (the `machineRemoteData` section heading
becomes `fromLoadLifecycle`) and confirm `gen:snippets` reports no drift, since
`remote-data.ts` carries a showcase region.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
eho
2026-09-04 18:07:00 +02:00
co-authored by Claude Sonnet 5
parent 11664d2efa
commit 827c655c1b
19 changed files with 303 additions and 139 deletions
+6 -6
View File
@@ -819,6 +819,12 @@ classes.
- is empty-safe: undefined, null, and empty string all yield the empty string
- returns empty for an unparseable string rather than "Invalid Date"
#### fromLoadLifecycle
- maps Loading → Loading
- maps Failed → Failure carrying an Error with the reason
- maps Loaded → Success carrying the whole loaded state
#### httpClientFetch
- sends the pending idempotency key as a header for a write, not a fresh one per attempt
@@ -836,12 +842,6 @@ classes.
- keeps query + hash on both targets
- the root maps nl → / and en → /en/
#### machineRemoteData
- maps loading → Loading
- maps failed → Failure carrying an Error with the reason
- maps loaded → Success carrying the whole loaded state
#### parseBsn (elfproef)
- accepts a valid BSN (passes the elfproef)
+4 -4
View File
@@ -69,7 +69,7 @@ The idiom this repo uses instead — see `brief.page.ts`, `dashboard.page.ts`,
// in the component class
protected readonly loaded = computed(() => {
const s = this.model(); // or store.someRemoteData()
return s.tag === 'loaded' ? s : undefined;
return s.tag === 'Loaded' ? s : undefined;
});
```
@@ -94,8 +94,8 @@ timing/outcome of `/api/*` calls. Try it on `/brief` or `/dashboard`.
A store's own state machine (its `*.machine.ts`) should own the **domain** lifecycle of
what it holds (draft → submitted → approved, in the brief's case) — not the network
fetch's loading/failure, which is a generic concern `RemoteData` already models. Where a
machine's own `loading`/`failed` tags purely mirror the fetch (nothing extra beyond "not
loaded yet" / "the GET failed"), project them onto a `RemoteData` computed at the store
layer for `<app-async>` to render, the way `BriefStore.remoteData` does — the machine
machine's own `Loading`/`Failed`/`Loaded` tags purely mirror the fetch (nothing extra
beyond "not loaded yet" / "the GET failed"), project them with `fromLoadLifecycle` at the
store layer for `<app-async>` to render, the way `BriefStore.remoteData` does — the machine
keeps deciding what the _letter_ is doing, `RemoteData` keeps deciding what the _fetch_ is
doing.