From 6973a89815dad22b4d50ab881af879f9d2792382 Mon Sep 17 00:00:00 2001 From: iris <2+iris@noreply.localhost> Date: Sun, 6 Sep 2026 18:40:25 -0400 Subject: [PATCH] docs: the verification pass over Tasks A and B, and the composer background withdrawn RUST.md gains the pass's findings with their commits and the numbers: the block model held under a per-character prefix property, the size-independent hit-box defect and its fix, the tail-rebuild selection gap, why the three new debug_asserts are whole-set, the text-shape counter that turns "a delta costs one block" into a measurement, and the verification bench run. IRIS_TODO.md's "the bar's own grey background is not drawn" is withdrawn: decoding the screencap puts it at rgb(41,40,49), full width, y2245..y2365 -- drawn, and dark on black, which is most likely what the earlier reading was. Co-Authored-By: Claude Fable 5.1 --- docs/IRIS_TODO.md | 14 +++++--- docs/RUST.md | 83 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 4 deletions(-) diff --git a/docs/IRIS_TODO.md b/docs/IRIS_TODO.md index d5f12fe..9229326 100644 --- a/docs/IRIS_TODO.md +++ b/docs/IRIS_TODO.md @@ -223,10 +223,16 @@ agent takes them without colliding with that pass's `bench_client.rs`/ `Scroll` itself turned out to measure the right number by a misleading route -- it is written against `painter.px_size()` now, and the claim below that it "measures against the window" was wrong. - **Still open, and pre-existing:** the bar's own grey background is not - drawn on this build (the `Stack{StackSize::Child(1)}` behind the field), - so the message reads as white text over the transcript. Present in the - build *before* this change too, so it is not the scroll area's doing. + **The grey background was not missing** -- that note (written here on + 2026-09-06 and repeated as still open) is withdrawn. Re-measured the + same day on the same AVD by decoding the screencap rather than reading + it: the bar is `rgb(41,40,49)`, the declared `UiColor::new(40, 40, 46)` + after sRGB rounding, **full width and y2245..y2365** on 1080x2424, with + the field at `31,2277..1048,2329` and the 63px nav strip below it. It + is dark by design and sits on black, which is very likely what the + earlier reading was: at a glance the band and the background are hard + to tell apart. If it should read as a bar rather than as a slightly + different black, the colour is the thing to change, not the tree. ## From the phone, 2026-09-06, 11:39 (build delivered 02:07, commit 543f6d9) diff --git a/docs/RUST.md b/docs/RUST.md index 0fffea1..3489614 100644 --- a/docs/RUST.md +++ b/docs/RUST.md @@ -180,6 +180,89 @@ moves least, which is consistent -- a delta into a *short* message never cost much. **The phone number is Iris's to take**; nothing here is a statement about her device. +### Verification pass over Tasks A and B, 2026-09-06 + +Read of `git diff fb6b459..HEAD -- iris/ client-core/` against LAYOUT.md, +TEXTURES.md, IRIS.md/DECISIONS.md's 2026-09-06 entries and CODE_RULES.md, +with the emulator. **Verdict: deliverable to the phone.** One real defect +found and fixed, two missing guards added, one open item closed as stale. + +1. **The block model is correct.** `split_blocks` was checked against the + shapes a real transcript has -- a fence with blank lines, a `---` + inside a fence, a nested list, a fence directly under a heading, a + table, a quote -- and against the property `apply_delta` rests on, at + **every character boundary** of a message containing all of them: + growing a message may rewrite its last block and never an earlier one, + or `common_prefix` says so. No defect (`client-core`'s + `every_prefix_of_a_streamed_message_keeps_all_but_its_last_block`, + commit `a56a928`). A delta closing a fence, a delta mid-word and a + stream ending inside an unterminated fence are each their own test. + +2. **`iris/core/src/ui/render_state.rs`, `draw_inner`'s size-independent + fast path: fixed** (commit `e63e923`). It rewrites the widget's own + primitives in place and writes **no** move-slot delta, so unlike `mov` + there is nothing for `move_applied` to count; `167862c` counted one + anyway, and `resolved_region` then subtracted a distance the chain + never held. Every such widget's hit box sat short of its drawing by + its last step, with the drawing correct -- nothing on screen to say + so. `Span` reaches this on the **first frame** of any tree containing + a `Rect` (the `.background(rect(..))` idiom, list row tints), because + it measures each child at the full region and then places it. Pinned + by `a_size_independent_widget_moved_by_its_parent_has_the_hit_box_it_is_drawn_at`, + the sibling of `a_panned_widgets_own_hit_box_moves_exactly_once` on the + branch that fix had no reason to touch. + +3. **Selection across blocks is sound; its rebuild path had no test** + (commit `155d899`). `SelKey = (RowKey, u32)` orders lexicographically, + which is reading order at both levels, so `begin`/`extend`/`locate` + and the range queries carry over unchanged; `selected_text` joining + with a blank line is right for blocks as well as rows, since that is + how markdown separates them. The gap was the tail rebuilt under the + **same key with fewer blocks** -- the dropped blocks keep pointing at + widgets `replace_back`'s drop frees, and `Selection::begin` resolves + every registered handle on an ordinary press, so the next tap anywhere + panics. `e1030d6`'s unconditional `unregister` is correct and now has + `a_tail_rebuilt_with_fewer_blocks_leaves_none_of_them_in_selection`, + confirmed to fail (3 blocks still registered, expected 1) without it. + `Selection::registered_blocks` is the test-only accessor that lets it + assert the contract rather than only that nothing panicked. + +4. **The three new `debug_assert!`s are whole-set, not one member.** + `Len::fold_dp`'s is in `draw_inner` after *every* `Widget::draw`, so + it governs the set by construction; `Pad` and `Span` were checked and + already fold through `apply_rest`, and `Sized`/`MaxSize` are the two + that reported a caller-written `Len` raw. `own_mask`'s reuse lives + inside `Painter::set_mask` itself, whose only caller is + `widget/mask.rs`. `move_applied` has exactly two writers, `mov` and + `reposition` (now one, after finding 2), and `resolved_region` is the + only reader -- `window_region` goes through it. + +5. **The O(last block) claim now holds for parley, by counter** + (commit `c3cfc67`). `take_counters` gained a fourth number, text + shapes, bumped in `Painter::render_text` -- which `TextView::render` + only reaches on a cache miss, so it counts shapes and not requests. A + draw counter cannot stand in for it either way. Measured: **one delta + into a 100-paragraph reply shapes exactly 1 text layout, the same as + into a one-paragraph reply.** + +6. **The composer bar's grey background *is* drawn** -- IRIS_TODO.md's + "still open, and pre-existing" note is stale and has been corrected. + Measured by decoding the screencap rather than eyeballing it: the bar + is `rgb(41,40,49)` (the declared `40,40,46` after sRGB rounding), + **full width, y2245..y2365** on the 1080x2424 AVD, with the field at + `31,2277..1048,2329` and the 63px nav strip below. Whatever the note + saw, Task A's `MaxSize`/`own_mask` fixes closed it. + +**Checks run**: `cargo fmt --all --check` clean in both workspaces; +`cargo clippy --workspace --all-targets` warning-free (only the +pre-existing future-incompat note about `wgpu`/`naga`/`winit`); +`cargo test` 81 (iris) + 13 (iris-core) + 20 (transcript-ui) + 123 +(client-core), all passing. One bench run on this checkout's AVD with the +assertions live, debug x86_64 `force-gles`, no abort and nothing in +logcat: **stream: 298 frames over 21.0s, late 287 (96.3%), p50 52.8ms, +p90 108.1ms, p99 137.3ms, worst 148.9ms** -- reproducing the "after" +column above. + - [x] **Merge the `DragGesture` work** -- done 2026-09-06 (merge commit `f802de9`, `git merge --no-ff worktree-agent-a754368325fa06839`,