RUST.md: bring it up to date, and say it must be kept that way

Adds a "Keep this file current as you work" section at the top saying what
it is for: this file is the handoff, so writing results into it as they
arrive is what lets a session that has filled its context be cleared
instead of carrying the conversation or re-deriving what was measured. It
asks for the dead ends too, since those are what stop the next session
spending an afternoon somewhere already ruled out.

Adds a "Where things stand" block, because the next agent's first question
is which box is next and the answer was previously spread across the list:
E0, E1, I0a, I0b and I1 done, I2 next with E2 able to run in parallel,
client-core not started, and the two emulator-tools changes made outside
this repo.

Corrects what had gone stale: the next-agent steps still said to start at
E0; the iris section still described a fourteen-gate cosmic-text tree and
called the text stack an open question; and the weight section still spoke
of E1 as something that would happen. It now carries the numbers instead --
43s and 2.1 GB against 1m46s and 1.5 GB for iris, and 181 MB debug against
11 MB release for the Masonry demo. Adds the rule about bounding heavy runs
with a kill timer scoped to the pid, which cost a wrong conclusion here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Opus 5 committed 2026-09-04 19:32:41 -04:00
1 parent 1a97d0ef5c
commit 43743ba171
1 file changed
+93 -25
+93 -25
View File
@@ -14,8 +14,50 @@ this clone is where things get tried before anything is committed to
**in-house framework to be built up** for this, with Masonry as the
yardstick it is measured against.
Decisions get a date and a reason here, the way `PLAN.md` does. Nothing in
this file has been tried yet unless a section says it has.
Decisions get a date and a reason here, the way `PLAN.md` does. A section
describes something that has been tried only where it says so, with a date.
## Keep this file current as you work
**This file is the handoff, and it is meant to let a session be cleared.**
Write each result into it *as you get it*, not at the end: the box ticked
or the reason it could not be, the measurement with its number, the
decision with its date and what it rejected, and anything that cost time to
find out. Then a session that has filled its context can be cleared and the
next one can pick up from this file alone, which is much cheaper than
carrying a long conversation or re-deriving what was already measured.
Two things that follow. Write for somebody who was not here — name the
command, the file and the number rather than "the fix" or "the earlier
run". And write the failures and the dead ends too: "Venus is blocked by
the emulator, not by Mesa" and "the present mode was not the cause" are
worth as much as the successes, because they are what stops the next
session spending an afternoon on them again.
## Where things stand (2026-09-04)
- **Done**: E0 (toolchain), E1 (Masonry on android-view, which found the
keyboard gap), I0a, I0b (iris builds on a pinned nightly and runs), I1
(parley + glyph atlas).
- **Next**: **I2** — iris on android-view. E1 says the first thing to
answer there is why the editor gets keystrokes but no autocorrect or
suggestions, since that is the constraint the framework decision turns
on. **E2** (a transcript in Masonry) can go in parallel in another
session.
- **Not started**: `client-core`, which is item 1 of the recommendation
below and does not depend on the framework choice. Nothing has been
built for it, and it is not one of the numbered boxes — worth picking up
in a session that wants work independent of the emulator.
- **The app itself is untouched.** Everything so far is in `iris/` and in
the rigs; nothing under `app/` or `server/` has changed.
- **Changed outside this repo**, both in `emulator-tools` and both pushed:
`avd_serial` now validates its cache by asking the device its AVD name
rather than by checking the serial is still attached (a recycled port
silently pointed this checkout at another session's emulator), and
`EMU_GPU=software` was added as an opt-in that keeps a run off the host
GPU and gives the guest a software Vulkan device. The default is
unchanged, because `-gpu host` was measured and the Compose benchmarks
depend on it.
## What has to be reproduced
@@ -317,7 +359,8 @@ Desktop runs on winit. Vello needs a compute-capable GPU or falls back to
[cat16/iris](https://github.com/cat16/iris), read 2026-09-04 from the one
public commit (2026-01-31, "portfolio copy"; ~8,700 lines in `core`,
`macro` and the crate itself). Retained-mode widgets stored outside the
render tree, `wgpu` 28 directly, `winit` 0.30, `cosmic-text` 0.16, a
render tree, `wgpu` 28 directly, `winit` 0.30, `cosmic-text` 0.16 (parley
since I1), a
relative-anchor-plus-offset layout with `rest()` and `rel()` lengths, a
postfix builder API (`rect(..).radius(30).on(CursorSense::click(), ..)
.sized(..).align(..)`), events handled where the widget is declared, and
@@ -325,10 +368,17 @@ a single-threaded context passed explicitly — all of which reads like this
codebase's own rules. There is text editing (`widget/text/edit.rs`),
images, masks, spans and stacks; the TODO names text resizing as
per-frame slow and scaling as unsolved. It requires **nightly** (fourteen
`#![feature]` gates, among them `const_trait_impl`, `unboxed_closures`,
`portable_simd`, `associated_type_defaults`). Desktop only; no Android
surface, no IME, no accessibility tree, no virtualised list, no rich-text
selection.
`#![feature]` gates as vendored, among them `const_trait_impl`,
`unboxed_closures`, `portable_simd`, `associated_type_defaults`; eleven
after I0b and I1 — see those steps for the current list). Desktop only; no
Android surface, no IME, no accessibility tree, no virtualised list, no
rich-text selection.
**That list is the work, and some of it is done.** As of 2026-09-04 it
builds on a pinned nightly, runs on this machine's GPU, has parley and a
glyph atlas, and `iris-core` cross-compiles to Android. What it still
lacks from the list above is the Android surface, the IME bridge, the
accessibility tree and the virtualised list — I2, I3 and I4.
**iris is not a candidate to be tested as it stands. It is the in-house
library** (Iris, 2026-09-04): "essentially a good start to a rewrite from
@@ -340,16 +390,16 @@ it needs are the same ones Masonry gets from android-view, Parley and
AccessKit, and there is no reason iris cannot sit on those same
foundations rather than reinvent them — the surface, the keyboard bridge
and the accessibility tree are platform plumbing, not a framework's
identity. Whether the text stack stays cosmic-text or moves to Parley is
the first real design decision in that work (see I1 below).
identity. The text stack was the first real design decision in that work,
and it is settled: **Parley, with a glyph atlas** (I1, 2026-09-04).
Two things to carry into that work honestly. Nightly is the opposite of
"holds up long term": a build that breaks on a toolchain update, on the
machine Dev Updater builds on, unattended. Pin a dated nightly in
`rust-toolchain.toml` immediately, and keep a list of which `#![feature]`
gates are load-bearing so they can be retired as they stabilise or are
designed around. And a one-person framework carries every gap itself,
which is what Iris said she is willing to do.
machine Dev Updater builds on, unattended. **Done in I0b**
`iris/rust-toolchain.toml` pins `nightly-2026-09-03` — and the gate list
lives with I0b and I1, to be retired as they stabilise or are designed
around; it is down from fourteen to eleven. And a one-person framework
carries every gap itself, which is what Iris said she is willing to do.
"From scratch" therefore means iris, not a fourth thing. Masonry stays in
the plan as the **yardstick and the fallback**: building its demo and its
@@ -377,10 +427,18 @@ uses is to optimise dependencies while leaving the app crate at `opt-level
[profile.dev.package."*"]
opt-level = 2
E1 measures this rather than remembering it: cold and incremental build
time, APK size, resident memory at rest and while streaming, and the
frame cost of one 800-event page — for the Masonry demo as shipped, then
with the profile above. Vello proper needs compute shaders and carries a
**Measured 2026-09-04, and it is not the widget layer.** iris's own
graph (wgpu + winit + cosmic-text at the time) built cold in **43s** with
a 2.1 GB `target/`, and **1m46s** with a 1.5 GB `target/` under the
profile above — so the knob costs build time and saves disk here, and
plain debug was never the problem. Masonry's graph is the one with Vello,
Parley, Fontique and Skrifa in it, and E1 gives the number that matters
for it: **`libmain.so` is 181 MB in debug and 11 MB in release.** That
size is also a correctness issue rather than only a weight one — a debug
build labels its Vulkan objects, and the emulator's driver segfaults in
`SetDebugUtilsObjectNameEXT` when it does. Runtime cost of the profile
knob is still unmeasured; resident memory and the frame cost of an
800-event page want E2. Vello proper needs compute shaders and carries a
large shader set; `vello_hybrid` is lighter and Masonry can now render
through either (or Vello CPU) via its `imaging` abstraction, so "keep it
light" has a knob inside the same stack.
@@ -737,18 +795,28 @@ re-derived:
2. Work on the **`rustify`** branch of this clone (`ai-app-2`), not on
`main` and not in `ai-app`. Nothing on this branch is production until
Iris says so. Commit and push as you go.
3. Take the next unchecked box above, in order: E0 first, then E1, then
the iris track from I0. E-steps and I-steps can proceed in parallel in
separate sessions once E1 has proved android-view on this emulator.
3. Take the next unchecked box above, in order. E1 has proved android-view
on this emulator, so the E-steps and the I-steps can now proceed in
parallel in separate sessions; see "Where things stand" at the top for
which is next.
4. Every step ends with its measurement written into this file beside the
box, and the box ticked or the reason it could not be written in its
place. A step that is blocked says by what, not "later".
place. A step that is blocked says by what, not "later". Write it as you
go rather than at the end — see "Keep this file current as you work".
5. Run the existing rigs rather than inventing new ones: `ui-sandbox.sh`
for a server with fixtures, `transcript-bench.sh` for the scroll
baseline, `ui-trace` for anything positional, `emu up` for the
emulator. The Vulkan section below says how to get a Vulkan path in the
emulator when a `wgpu` backend needs one.
6. Decisions belong here with a date and what was rejected, the way
emulator, and `iris/run-headless.sh EXAMPLE --shot PNG` for an iris
example on this displayless machine. The Vulkan section below says how
to get a Vulkan path in the emulator when a `wgpu` backend needs one.
6. **Bound anything heavy at the moment you start it.** An emulator or a
long build gets a deadline — `timeout`, or a watchdog scoped to the pid
you just started — rather than a plan to stop it later. Scope it to
that pid: a watchdog written as `sleep N; emu down` fired into a later
experiment here and made a working Vulkan build look like a crash. And
stop the emulator when the work needing it is done rather than between
tasks.
7. Decisions belong here with a date and what was rejected, the way
`PLAN.md` does it. Do not put design into commit messages alone.
### Vulkan in the emulator (measured 2026-09-04)