test: the third edit of improvise-0x9u's repair, and two evidence corrections

`close` restores the DRAWN cell text rather than the seed, and reverting that
one line left the whole suite green while `18400` sat where `18,400` had been
on the shipped demo. Asserted after the second click, proved by that revert.

improvise-o31u's desktop arm cannot fail for the reason its evidence gave:
both named mechanisms were measured and neither moves it (`#cast-pivot` is
966px at 1280, so an 880px floor is inert wherever it is placed). The entry
now says it is forward-looking, and credits the phone arm with the fault it
actually catches.

Plus three one-liners: UNCALLED's source-scan blindness, the gzip -9 proxy in
the improvise-cl7y table, and why `view-back` is not one of its five siblings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
Edward Langley
2026-09-20 21:15:49 -07:00
parent 0889166fc7
commit a69b0bca86
5 changed files with 55 additions and 6 deletions
+5
View File
@@ -598,6 +598,11 @@ building the bundle both ways:
| with `improvise-formula` | 634,515 | 238,973 | | with `improvise-formula` | 634,515 | 238,973 |
| cost | **+130,661 (+25.9%)** | **+47,360 (+24.7%)** | | cost | **+130,661 (+25.9%)** | **+47,360 (+24.7%)** |
The raw column is exact and byte-verified; the gzipped one is a `gzip -9`
**proxy** and not what a visitor downloads, since GitHub Pages serves brotli.
The conclusion is unaffected — the raw figure alone carries it — but do not
quote "+47,360 gzipped" as a transfer size.
A quarter of the download, for a status string. That is the evidence for the A quarter of the download, for a status string. That is the evidence for the
other route — the host addressing a status back to the composer, the way other route — the host addressing a status back to the composer, the way
`ClientFrame::Save`'s rejection already does — and it costs no dependency. `ClientFrame::Save`'s rejection already does — and it costs no dependency.
+42 -6
View File
@@ -2084,6 +2084,26 @@ tell that apart from the original bug — same symptom, different cause — so i
the debug run rather than the test that separated them. `close` therefore no the debug run rather than the test that separated them. `close` therefore no
longer repaints, and the `blur` arm checks `closed` before dismissing. longer repaints, and the `blur` arm checks `closed` before dismissing.
Third — and this is the edit the repair nearly shipped unguarded — **the fix is
three edits, not two**, and the third is the one with the most careful comment:
`close` restores `td.textContent` (the *drawn* value) instead of `seed` (the
*stored* one), because `close` no longer repaints and `repaint()` early-returns
for as long as `editing` is set. Reverting that one line to
`td.replaceChildren(original)` left the whole suite green, and the defect was on
the front page: `web/demo.improv` carries `format: ,.0` over `18400`, and this
test's own two clicks — no Escape between them — leave cell 0 reading `18400`
where the page had drawn `18,400`, for as long as the second editor stays open.
The assertion added for it is `toHaveText("18,400")` after the second click, and
the injection is exactly that revert: it fails with `unexpected value "18400"`,
naming this test and no other.
The pattern is worth carrying past this entry. A repair of N edits whose N−1
guarded ones pass is not a guarded repair, and the unguarded edit is reliably
the one the author understood best — which is why it carries the clearest
comment and why it felt covered. For each distinct edit, name the test that
fails when only that edit is reverted; a line with a comment and no answer to
that question is the line to inject.
#### "the widgets the demo document fills are drawn, in the state that fills them" #### "the widgets the demo document fills are drawn, in the state that fills them"
The `#doc-name` row is improvise-5jna, and the reason it belongs in a **browser** The `#doc-name` row is improvise-5jna, and the reason it belongs in a **browser**
@@ -2144,12 +2164,28 @@ be the thing that scrolls, which is what separates "contained the overflow" from
#### "a desktop viewport is unchanged by the phone fix" #### "a desktop viewport is unchanged by the phone fix"
The negative arm, and it is not ceremony: the same media query written without The negative arm, and **it is forward-looking: no fault available today makes it
a `max-width` bound, or with the `min-width` on `.player` itself rather than on fail.** The entry previously named two mechanisms and both were measured, at a
its child, changes the desktop rendering too — and desktop at 13.11px was the 1280px viewport, against the shipped page:
one thing about these players that was already right. It also asserts that a
desktop player has nothing to scroll, so a fix that left the 880px floor in - `@media (max-width: 900px)` → `@media all`: this test **passes** (13.1131px,
place at every width would fail here rather than passing both. `scrollWidth === clientWidth`).
- `min-width: 880px` moved from `.player > *` onto `.player`: this test
**passes**; the *phone* arm fails instead, on `scrolls.page === 0`.
The arithmetic is why, and it is worth stating rather than re-deriving: at
1280px `#cast-pivot` measures `clientWidth === scrollWidth === 966`, so an 880px
floor is inert at desktop wherever it is placed. The floor would have to exceed
the ~966px the player actually gets — or the content column would have to
narrow — before either assertion here could move. That is a real future fault
and the reason to keep the test: it pins 13.11px and "nothing to scroll" against
a floor raised past the player's own width. It is not a reason to claim the arm
currently discriminates between the two placements, because it does not.
Note also that the **phone** arm is stronger than this entry used to credit it
with: the misplaced-`min-width` fault, attributed here to the desktop arm, is
caught there. `scrolls.page === 0` is the assertion that separates "contained
the overflow" from "moved it onto the document".
#### "no cast carries the recording machine's shell, clock or geometry" #### "no cast carries the recording machine's shell, clock or geometry"
+2
View File
@@ -236,6 +236,8 @@ fn declined(name: &str, args: &[String]) -> Option<String> {
"toggle-records-mode" => "records mode", "toggle-records-mode" => "records mode",
"add-record-row" => "adding a record row", "add-record-row" => "adding a record row",
"delete-formula-at-cursor" => "deleting a formula", "delete-formula-at-cursor" => "deleting a formula",
// NOT "not built": it commits a drill first, so composing it would
// commit another client's typing. Needs addressed commands — clients.md.
"view-back" => "stepping back to the previous view", "view-back" => "stepping back to the previous view",
// A door this client will not open still has to say so: entering is // A door this client will not open still has to say so: entering is
// resolvable and the commit behind it is not. // resolvable and the commit behind it is not.
+4
View File
@@ -237,6 +237,10 @@ test.describe("a pointer event reaches the client and its answer is painted", ()
await cells.nth(4).click(); await cells.nth(4).click();
await expect(cells.nth(4).locator("input")).toHaveCount(1); await expect(cells.nth(4).locator("input")).toHaveCount(1);
await expect(cells.nth(0).locator("input")).toHaveCount(0); await expect(cells.nth(0).locator("input")).toHaveCount(0);
// The third edit of the same repair: `close` restores the DRAWN text, not
// the seed. `repaint` early-returns while `editing` is set, so a `18400`
// put back here stays on screen (improvise-0x9u).
await expect(cells.nth(0)).toHaveText("18,400");
await page.keyboard.press("Escape"); await page.keyboard.press("Escape");
await expect(cells.nth(4)).toHaveClass(/selected/); await expect(cells.nth(4)).toHaveClass(/selected/);
+2
View File
@@ -89,6 +89,8 @@ test("the page still reaches the client through a handful of calls", () => {
/// Methods on `Client` the page does not call, each with the reason it is /// Methods on `Client` the page does not call, each with the reason it is
/// still exported. A door with no caller and no entry here is improvise-seik: /// still exported. A door with no caller and no entry here is improvise-seik:
/// the dangerous kind, because calling the wrong one of a pair is silent. /// the dangerous kind, because calling the wrong one of a pair is silent.
// What this CANNOT see, exactly as UNPAINTED cannot: `callsOn` is a source
// scan, so a `client.foo()` inside a function nothing calls reads as called.
const UNCALLED = { const UNCALLED = {
free: "wasm-bindgen's own destructor, not ours to remove", free: "wasm-bindgen's own destructor, not ours to remove",
initSync: "wasm-bindgen's own module loader, beside the default export", initSync: "wasm-bindgen's own module loader, beside the default export",