WIP: evidence and context for improvise-ixxx
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
@@ -1411,6 +1411,12 @@ than a check; or this client has not been told the document's basis and so has
|
||||
nothing truthful to say about what it composed against (`BasisCache::claim`
|
||||
withholds rather than invents).
|
||||
|
||||
A **fifth** `None` is not a failure: the text is the seed the editor captured
|
||||
when it opened (improvise-ixxx). The page passes that seed as `typed_cell`'s
|
||||
fourth argument, and `resolve::untouched`, the one home beside `typed()`,
|
||||
decides. The argument is in `protocol.md` §3, "An untouched editor writes
|
||||
nothing".
|
||||
|
||||
**Nothing is folded there.** The new value comes back as a `GridUpdate::Cells`
|
||||
from the host, which is the side that formats it; guessing it locally is how the
|
||||
two ends drift apart.
|
||||
@@ -1565,7 +1571,7 @@ whether a typed string is a number. Five calls are the whole harness:
|
||||
| `client.set_viewport(rows, cols)` | the handshake frame, and every resize; also records the window so keys resolve here |
|
||||
| `client.on_frame(json)` | fold one frame, in arrival order |
|
||||
| `client.render_model()` | everything to paint, already decided |
|
||||
| `client.typed_cell(r, c, s)` | the frame for "the user typed s here" |
|
||||
| `client.typed_cell(r, c, s, seed)` | the frame for "the user typed s here", or none if `s` is still the `seed` the editor opened on |
|
||||
| `client.on_key_event(k,c,a,s,m)` | the frame for a keypress, folded locally first where this client may answer it |
|
||||
|
||||
**The two rules this file must not break are ordering and framing**: frames are
|
||||
|
||||
@@ -4332,6 +4332,15 @@ with no `SetBuffer`, then presses the keys: Enter must compose
|
||||
`an_edit_buffer_the_user_has_emptied_is_not_refilled_from_the_cell` fails,
|
||||
as it did against the same rival in `render.rs`.
|
||||
|
||||
**Amended by improvise-ixxx.** Its first `Enter` is untouched now, so it
|
||||
composes no write. The assertion that it "must not clear" is therefore
|
||||
`committed == None`, where `committed` is the first `Command::Model` of any
|
||||
kind. It still fails against the pre-ktlk tree:
|
||||
that tree's buffer is `""`, and `settle_editor` never ran, so no seed was
|
||||
captured and the empty buffer composes `ClearCell`. The typed-`5` half is
|
||||
unchanged. `settle_editor` now captures `OpenedEditor` beside the buffer,
|
||||
because the editor opens at that moment.
|
||||
|
||||
## improvise-dsxq — the browser's `yy` copies the value, not a string
|
||||
|
||||
PR #161 (improvise-lut7) made the browser's `yank` arm compose
|
||||
@@ -4491,3 +4500,77 @@ normal edges only, because a dev edge would unify the feature back in
|
||||
which fails naming that crate while the two tests above pass. Then removed from
|
||||
`improvise-ws-server` alone, which fails naming it. The native path runs
|
||||
without `--target`, so the two arms are different invocations.
|
||||
|
||||
### `an_untouched_browser_commit_writes_nothing_and_still_advances`
|
||||
|
||||
**improvise-ixxx**, browser keyboard. The fixture is a 3×1 grid with the cursor
|
||||
on row 1. For each seed in `"007"`, `"1e3"`, `"inf"`, `"ERR:boom"` and
|
||||
`"1.23456789"`, the test folds `i`, checks the buffer is that seed, and resolves
|
||||
`Enter`. The composed commands must contain no `Command::Model`. They must also
|
||||
contain `SetSelected { row: 2, col: 0 }`, the re-entry
|
||||
`ChangeMode(editing)`, and `SetOpenedEditor` capturing `"800"`, the cell it
|
||||
landed on.
|
||||
|
||||
Failed before the fix: `"007"` composed `SetCell(Number(7.0))`. **Rival:**
|
||||
`resolve::commit` returning `[ChangeMode(Normal)]` when untouched, which skips
|
||||
the advance along with the write. This test fails alone.
|
||||
|
||||
### `an_untouched_browser_edit_does_not_overwrite_a_write_made_while_it_was_open`
|
||||
|
||||
The captured-seed constraint, in the browser. The test opens the editor on
|
||||
`"007"`, then folds a `GridUpdate::Cells` that moves the cell to `"5"`. That is
|
||||
the projection another client's write produces. `Enter` with nothing typed must
|
||||
compose no `Command::Model`.
|
||||
|
||||
**Rival:** `written` comparing against `edit_seed(state)`, which re-reads the
|
||||
cache at commit time, instead of `ViewState::opened_editor`. This test fails
|
||||
alone, composing `SetCell(Number(7.0))`. The basis claim is taken when the
|
||||
commit is composed, so it would not have refused that write.
|
||||
|
||||
### `a_touched_browser_commit_still_writes`
|
||||
|
||||
Scope guard. The reviewer's fourth constraint says classification is out of
|
||||
scope. `Backspace` over the seed `"7"` and then typing `007` must still compose
|
||||
`SetCell(Number(7.0))`. It passes before and after. It is here so that a fix
|
||||
which suppressed number-shaped text in general, rather than untouched text,
|
||||
fails.
|
||||
|
||||
### `an_untouched_browser_edit_of_a_misread_value_writes_nothing`
|
||||
|
||||
The same shape as `an_untouched_browser_edit_stores_the_identical_value`, with
|
||||
the values `typed()` misreads: `Text("007")`, `Text("1e3")`, `Text("inf")` and a
|
||||
raw `Error("boom")`. It runs through the resolver and into a real host. Both
|
||||
tests share `untouched_browser_edit`, which now also asserts that the buffer
|
||||
after `i` is `value.edit_text()`. That assertion keeps the umi4 test
|
||||
discriminating once untouched commits write nothing (see
|
||||
`command.md`, `an_untouched_pivot_edit_of_a_misread_value_writes_nothing`).
|
||||
With `project.rs` seeding from `to_string()`, both umi4 browser tests fail.
|
||||
**Rival:** `untouched` always `false`. This test fails.
|
||||
|
||||
### `a_mouse_commit_of_the_untouched_seed_composes_nothing`
|
||||
|
||||
**improvise-ixxx**, browser mouse. `web/app.js`'s `edit()` holds `original`,
|
||||
captured when the editor opened, and used to call `typed_cell` without it. So
|
||||
an untouched click-edit re-sent the seed through `typed()`. Now
|
||||
`typed_cell_frame` takes the `OpenedEditor` and returns `None` for
|
||||
`"007"`, `"ERR:boom"` and `"1.23456789"` given as their own seeds. The control
|
||||
is `"007"` against a seed of `"7"`, which must compose a write, so a
|
||||
`typed_cell_frame` that never composes cannot pass.
|
||||
|
||||
### `a_mouse_commit_is_judged_against_the_seed_it_opened_with`
|
||||
|
||||
The captured-seed constraint, on the mouse path. The editor opened on `"1200"`.
|
||||
A projected write then moves the cell to `"5"`, and a guard asserts the cache
|
||||
really holds `"5"`. Committing `"1200"` must compose nothing. **Rival:**
|
||||
`typed_cell_frame` ignoring the passed seed and comparing against the cache's
|
||||
`edit_text`. This test and `a_mouse_commit_of_the_untouched_seed_composes_nothing`
|
||||
both fail.
|
||||
|
||||
The page half is `harness/tests/contract.spec.js`, "an untouched mouse editor
|
||||
sends no write, and a touched one does". It wraps `Worker.prototype.postMessage`,
|
||||
opens the editor on cell 4, and presses `Enter`. No `SetCell` may be posted.
|
||||
Then it types `1` and presses `Enter`, and exactly one must be. **Rivals, run
|
||||
against the served `app.js`:** passing `input.value` as the seed, and passing
|
||||
no seed at all. Both fail the control with 0 writes. The second fails because
|
||||
wasm-bindgen throws on the missing `String`, and the page swallows the throw
|
||||
inside `close`.
|
||||
|
||||
@@ -5138,3 +5138,66 @@ exactly that, because West had no record to drill into. It then asserts that
|
||||
the first message does not mention drilling. At `0ed2e41` it failed with the
|
||||
old text. The rival is restoring that text. Real drill paste, which means
|
||||
staging a typed `CellValue`, is still open as improvise-48jd.
|
||||
|
||||
### `an_untouched_pivot_edit_of_a_misread_value_writes_nothing`
|
||||
### `an_untouched_records_edit_of_a_misread_value_writes_nothing`
|
||||
|
||||
**improvise-ixxx.** After umi4 the seed was exact, but the commit still ran it
|
||||
through `typed()`, which reads text and not the cell the text came from. So
|
||||
`i` then `Enter` with nothing typed stored `Number(7.0)` over `Text("007")`,
|
||||
and `Text("ERR:boom")` over a raw `Error("boom")`. The values are the ones
|
||||
where `typed(edit_text(v)) != v`: `"007"`, `"1e3"`, `"inf"`, `"2024"` and a raw
|
||||
`Error`. They use `no_op_commit`, the umi4 tests' own path: the real key path,
|
||||
on (West, Revenue), which is row 1 and never the first cell.
|
||||
|
||||
Both failed before the fix. With the list as written they failed on
|
||||
`Text("007")` stored as `Number(7.0)`. With `Error("boom")` moved to the front
|
||||
they failed on it, stored as `Text("ERR:boom")`, so the error case is red on
|
||||
its own and not only behind the text one. **Rival:** `untouched` answering
|
||||
`false` always, i.e. the fix removed. Both fail again.
|
||||
|
||||
`no_op_commit` now also asserts that the buffer after `i` is
|
||||
`value.edit_text()`. **That assertion is what keeps the umi4 tests above
|
||||
alive.** With ixxx fixed, an untouched commit writes nothing, so a seed
|
||||
regressed to the rounded `Display` is never written either, and
|
||||
`an_untouched_{pivot,records}_edit_stores_the_identical_value` pass with umi4
|
||||
reverted. That was run: with the seed assertion removed and
|
||||
`display_value_in` seeding from `to_string()`, all six untouched tests pass.
|
||||
With the assertion in, both umi4 tests fail.
|
||||
|
||||
### `an_untouched_edit_does_not_overwrite_a_write_made_while_it_was_open`
|
||||
|
||||
The reviewer's first constraint on improvise-ixxx: the seed is the one
|
||||
**captured when the editor opened**. The test opens the editor on
|
||||
`Text("007")`, then applies a `SetCell(Number(5.0))` directly, standing in for
|
||||
another client's write that lands while the editor is open. Then it presses
|
||||
`Enter` with nothing typed. The cell must still be `5`.
|
||||
|
||||
Failed before the fix: the commit wrote `Number(7.0)`. **Rival:**
|
||||
`commit_at_cursor` taking the seed from `ctx.display_value`, which is
|
||||
recomputed at commit time, instead of `ctx.opened_editor`. This test fails
|
||||
alone, with `Number(7.0)`, and every other untouched test passes. So it is the
|
||||
only guard on the choice of seed, and a fixture where the cell does not move
|
||||
cannot tell the two seeds apart.
|
||||
|
||||
### `an_untouched_commit_still_advances_and_reopens_the_editor`
|
||||
|
||||
The reviewer's second constraint: only the **write** is skipped. The fixture
|
||||
puts `Text("007")` at (West, Cost), row 1 and column 0. `Enter` there advances
|
||||
to (0, 1) rather than aborting at the corner, which is where (West, Revenue)
|
||||
sits in pivot mode. The test asserts four things: the cell is unchanged, the
|
||||
cursor moved to (0, 1), the mode is editing again, and the reopened editor
|
||||
captured `"2"`, the cell it landed on.
|
||||
|
||||
**Rival:** `CommitAndAdvance::execute` returning straight after the mode change
|
||||
when untouched, which skips the advance along with the write. This test fails,
|
||||
and so do `tab_on_an_empty_new_measure_column_still_starts_a_record_row` and
|
||||
`ui::app::tests::tab_on_bottom_right_of_records_inserts_below`. Those two are
|
||||
the records Tab contract: the empty `+` column's seed is `""`, so an empty Tab
|
||||
there is now an untouched commit too.
|
||||
|
||||
The buffer after `Enter` is **not** asserted. The keymap welds `clear-buffer`
|
||||
after every commit key, so it empties the buffer `EnterEditAtCursor` has just
|
||||
seeded, and the reopened editor opens blank while its captured seed is `"2"`.
|
||||
That is existing behaviour (`enter_commits_the_cell_advances_and_re_enters_editing`
|
||||
in `clients.md`). It is reported on improvise-ixxx rather than fixed here.
|
||||
|
||||
Reference in New Issue
Block a user