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:
1 parent
1a97d0ef5c
commit
43743ba171
1 file changed
+93
-25
@@ -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
|
**in-house framework to be built up** for this, with Masonry as the
|
||||||
yardstick it is measured against.
|
yardstick it is measured against.
|
||||||
|
|
||||||
Decisions get a date and a reason here, the way `PLAN.md` does. Nothing in
|
Decisions get a date and a reason here, the way `PLAN.md` does. A section
|
||||||
this file has been tried yet unless a section says it has.
|
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
|
## 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
|
[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`,
|
public commit (2026-01-31, "portfolio copy"; ~8,700 lines in `core`,
|
||||||
`macro` and the crate itself). Retained-mode widgets stored outside the
|
`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
|
relative-anchor-plus-offset layout with `rest()` and `rel()` lengths, a
|
||||||
postfix builder API (`rect(..).radius(30).on(CursorSense::click(), ..)
|
postfix builder API (`rect(..).radius(30).on(CursorSense::click(), ..)
|
||||||
.sized(..).align(..)`), events handled where the widget is declared, and
|
.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`),
|
codebase's own rules. There is text editing (`widget/text/edit.rs`),
|
||||||
images, masks, spans and stacks; the TODO names text resizing as
|
images, masks, spans and stacks; the TODO names text resizing as
|
||||||
per-frame slow and scaling as unsolved. It requires **nightly** (fourteen
|
per-frame slow and scaling as unsolved. It requires **nightly** (fourteen
|
||||||
`#![feature]` gates, among them `const_trait_impl`, `unboxed_closures`,
|
`#![feature]` gates as vendored, among them `const_trait_impl`,
|
||||||
`portable_simd`, `associated_type_defaults`). Desktop only; no Android
|
`unboxed_closures`, `portable_simd`, `associated_type_defaults`; eleven
|
||||||
surface, no IME, no accessibility tree, no virtualised list, no rich-text
|
after I0b and I1 — see those steps for the current list). Desktop only; no
|
||||||
selection.
|
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
|
**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
|
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
|
AccessKit, and there is no reason iris cannot sit on those same
|
||||||
foundations rather than reinvent them — the surface, the keyboard bridge
|
foundations rather than reinvent them — the surface, the keyboard bridge
|
||||||
and the accessibility tree are platform plumbing, not a framework's
|
and the accessibility tree are platform plumbing, not a framework's
|
||||||
identity. Whether the text stack stays cosmic-text or moves to Parley is
|
identity. The text stack was the first real design decision in that work,
|
||||||
the first real design decision in that work (see I1 below).
|
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
|
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
|
"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
|
machine Dev Updater builds on, unattended. **Done in I0b** —
|
||||||
`rust-toolchain.toml` immediately, and keep a list of which `#![feature]`
|
`iris/rust-toolchain.toml` pins `nightly-2026-09-03` — and the gate list
|
||||||
gates are load-bearing so they can be retired as they stabilise or are
|
lives with I0b and I1, to be retired as they stabilise or are designed
|
||||||
designed around. And a one-person framework carries every gap itself,
|
around; it is down from fourteen to eleven. And a one-person framework
|
||||||
which is what Iris said she is willing to do.
|
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
|
"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
|
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."*"]
|
[profile.dev.package."*"]
|
||||||
opt-level = 2
|
opt-level = 2
|
||||||
|
|
||||||
E1 measures this rather than remembering it: cold and incremental build
|
**Measured 2026-09-04, and it is not the widget layer.** iris's own
|
||||||
time, APK size, resident memory at rest and while streaming, and the
|
graph (wgpu + winit + cosmic-text at the time) built cold in **43s** with
|
||||||
frame cost of one 800-event page — for the Masonry demo as shipped, then
|
a 2.1 GB `target/`, and **1m46s** with a 1.5 GB `target/` under the
|
||||||
with the profile above. Vello proper needs compute shaders and carries a
|
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
|
large shader set; `vello_hybrid` is lighter and Masonry can now render
|
||||||
through either (or Vello CPU) via its `imaging` abstraction, so "keep it
|
through either (or Vello CPU) via its `imaging` abstraction, so "keep it
|
||||||
light" has a knob inside the same stack.
|
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
|
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
|
`main` and not in `ai-app`. Nothing on this branch is production until
|
||||||
Iris says so. Commit and push as you go.
|
Iris says so. Commit and push as you go.
|
||||||
3. Take the next unchecked box above, in order: E0 first, then E1, then
|
3. Take the next unchecked box above, in order. E1 has proved android-view
|
||||||
the iris track from I0. E-steps and I-steps can proceed in parallel in
|
on this emulator, so the E-steps and the I-steps can now proceed in
|
||||||
separate sessions once E1 has proved android-view on this emulator.
|
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
|
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
|
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`
|
5. Run the existing rigs rather than inventing new ones: `ui-sandbox.sh`
|
||||||
for a server with fixtures, `transcript-bench.sh` for the scroll
|
for a server with fixtures, `transcript-bench.sh` for the scroll
|
||||||
baseline, `ui-trace` for anything positional, `emu up` for the
|
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, and `iris/run-headless.sh EXAMPLE --shot PNG` for an iris
|
||||||
emulator when a `wgpu` backend needs one.
|
example on this displayless machine. The Vulkan section below says how
|
||||||
6. Decisions belong here with a date and what was rejected, the way
|
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.
|
`PLAN.md` does it. Do not put design into commit messages alone.
|
||||||
|
|
||||||
### Vulkan in the emulator (measured 2026-09-04)
|
### Vulkan in the emulator (measured 2026-09-04)
|
||||||
|
|||||||
Reference in new issue
Block a user