test: the two front ends draw the same grid frame

The check gotcha 44's divergence never had. Each front end is driven the way
it is really driven — the widget into a ratatui buffer, the browser client
through a `Snapshot` of that same cache's `seed()` — and they are compared on
what they *draw*, not on what they were handed; comparing the caches would be
vacuous, since it is one cache.

Injected both faults and watched them fail before keeping it:
`labels: vec![rows.item(r).join("/")]` in the client's `render_model`, and the
same join in the widget's row header. Each names the row and both spellings.

`improvise-wasm-client` becomes a dev-dependency of the root crate for this.
It builds natively — that is how its own tests already run — and being a dev
dependency the terminal binary does not grow a wasm client.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Edward Langley
2026-09-19 22:43:52 -07:00
parent 301a74821a
commit 7013fbc398
3 changed files with 282 additions and 4 deletions
+9 -4
View File
@@ -243,10 +243,15 @@ handed a job the store should have done.
today.** Two front ends deriving the same fact will diverge, and the divergence
is invisible until someone compares them side by side. `improvise-edp` is the
worked example — the category tree was flattened twice, two different ways, and
the fix put `viewmodel::flatten_cat_tree` where both ends call it. Gotcha 44 is
the same defect still open: the TUI derives the grid's *frame* from
`GridLayout`, the browser cannot, and so the browser renders `Food/Alice` where
the TUI renders two header columns.
the fix put `viewmodel::flatten_cat_tree` where both ends call it. Gotcha 44
was the same defect and is now closed the same way (improvise-anr9): the grid's
*frame* — header levels, label tuples, group runs and their collapse state —
is `improvise_protocol::AxisFrame`, and both `src/ui/grid.rs` and
`improvise-wasm-client/src/render.rs` ask it rather than deriving one. Note
what the second cure cost that the first did not: a `Vec<String>` of labels
had to change **type**, and a shared derivation could not be added beside the
old one — `row_levels` next to `row_labels` would have been two answers to
"what are the labels", which is the disease and not the cure.
**Sharing the table beats testing two copies of it.** Where a front end must
turn input into actions, share the mapping rather than mirroring it: two