# Iris extraction handoff Operational handoff for pulling Iris out of ai-app into a standalone framework. Not a decisions log; delete it when the extraction is done. ## Read this first **Pull request #11 was reviewed on 2026-09-13 and the review has not been read.** The session that got it was asked to write this document and stop rather than spend context on it. So the first thing to do is read it: ```sh TOKEN=$(cat ~/.config/gitea/token) curl -s -H "Authorization: token $TOKEN" \ https://git.arirex.me/api/v1/repos/iris/iris/pulls/11/reviews curl -s -H "Authorization: token $TOKEN" \ https://git.arirex.me/api/v1/repos/iris/iris/pulls/11/reviews//comments curl -s -H "Authorization: token $TOKEN" \ https://git.arirex.me/api/v1/repos/iris/iris/issues/11/comments ``` Three rounds of review had already landed on #11 before this one, so check the newest `submitted_at` rather than assuming the first result is current. My replies to the earlier rounds are ordinary issue comments on the same PR and say what each change was for. ## Stop point - Canonical Iris: `git@git.arirex.me:iris/iris.git`, `main` at `0f6a28b` (the squash merge of #10). - Agent fork: `git@git.arirex.me:iris-ai/iris.git`. The bot cannot push canonical; work in the fork and open PRs into `iris/iris:main`. - **#11** `split/11-texture-bindings`, worktree `/home/bob/repos/iris-pr11`, head `7b318e3`, eight commits on top of `0f6a28b`. Reviewed four times; the fourth is unread. - **#12** `split/12-pointer-routing`, worktree `/home/bob/repos/iris-pr12`, head `028521b`. A scroll falling through a hovered button. Not reviewed as of the last check. Independent of #11 and can merge in either order. - `/home/bob/repos/ai-app-2` is on `rustify`, worktree clean. ## What #11 became It started as "draw the glyph atlas as an array texture" and the review turned it into a rework of how primitives are drawn. Worth knowing before reading the new review, because the earlier rounds are what produced this shape: - **Atlas pages are their own thing.** `GlyphAtlas` owns its page images and emits dirty rectangles; `GpuPages` owns the array texture they upload to. `Textures` holds standalone images only. - **Every primitive is a registration.** `PrimitiveRegistry::register::

` takes the primitive's WGSL and what it samples, and returns a `PrimitiveKind

`. Its list, free list, buffers, bind group layout and pipeline all follow from that. Rect, glyph and texture are registered the same way at startup, so a caller registering their own primitive with their own shader takes the identical path. That is deliberate — the owner wants custom user shaders later. - **Nothing dispatches dynamically.** Push, free, renumber, upload and draw are identical for every primitive; only the entry size and the pipeline differ, and those are data. `InstanceList` carries a runtime stride and its data as bytes. Measured: 0.2ns per write over a statically typed list, against 1.6ns for a trait object. - **`shader.wgsl` became `shader/prelude.wgsl` plus one file per primitive**, because one module cannot declare two types at the same binding. The prelude carries the window, masks, sampled texture, vertex shader and `masked()`. - **Within a layer, types draw in registration order** — rect under glyph under texture. Order within a layer was never meaningful (freeing an instance swaps another into its place), and layers are the compositing mechanism. ## Standing instructions from the owner - Pull Iris out even if the Rust application switchover is not accepted. No app, session, transcript, setup or server concepts in Iris; the dependency runs one way from `app/` to Iris. - **Small, coherent PRs.** The original extraction PR was too large to review. A slice may be redone rather than transplanted, and need not remove every old feature. Independent PRs may be open at once so work continues during review. - Do not recreate an `ai` branch in canonical Iris; the fork is the boundary. - **Never rewrite a pushed branch.** Follow review with additive commits. - Respond to each review finding with a fix or a concise explanation. Do not add a ceremonial comment when the changed code already answers it. ## The review gate `~/.claude/MACHINE.md` now carries a machine-wide rule, and the procedure is the installed **`pre-submit-review`** skill. It is not optional and not project-specific: build clean, review the code, review the comments separately once the code has settled, then verify the claim by running it. The fixes a review produces are themselves unreviewed code, so the passes repeat until a round finds nothing. Running it on #11 found four defects that format, clippy, tests and five headless renders had all passed — including one hidden *by* the tests passing, where an image alone in a layer failed GPU validation because every other case happened to have a rectangle in the same layer leaving a bind group set. That is the shape to hunt for. `audit.sh` in the skill directory prints every comment line a branch adds against a base ref, for an explicit verdict each. The owner's standing complaint is verbose agent comments; the default verdict is delete. ## Repository topology ### ai-app checkout - `/home/bob/repos/ai-app-2`, `origin = git@git.arirex.me:iris/ai-app.git`, branch `rustify`. - `iris/` is a submodule pinned at `32f6ad8`, the complete extracted snapshot, and `.gitmodules` points at the **bot fork**, not canonical Iris. - Do not change either casually: ai-app needs the complete snapshot while canonical Iris is only partly caught up. Reconcile when canonical contains what ai-app needs, or when the owner accepts a temporarily non-building pin. ### standalone Iris checkout - `/home/bob/repos/iris`, `origin` = fork, `upstream` = canonical. - Fork `main` and `origin/archive/full-extraction` both name `32f6ad8`, the target snapshot. `history/full` names the source-history result `a615bcd`. - **Do not reset, overwrite or force-push fork `main`**: it is both the target reference and the commit ai-app pins. - Start each new branch from current `upstream/main` in its own worktree: ```sh cd /home/bob/repos/iris && git fetch upstream git worktree add -b split/13-name /home/bob/repos/iris-pr13 upstream/main ``` The other `/home/bob/repos/iris-pr*` worktrees hold merged branches. They are readable references; do not build new work on them. ## Merged so far | PR | On canonical `main` | | --- | --- | | #2 | Build on the current nightly (`4275314`) | | #3 | Request a frame after resize (`936fbdd`) | | #4 | Decouple `iris-core` from winit (`465e430`) | | #5 | Use vsync by default (`ec2b5d4`) | | #6 | Notify winit before presenting (`db9b0f2`) | | #7 | Keep unsafe reference helpers internal (`0191f20`) | | #8 | Initialize the window uniform from the surface (`6e271e8`) | | #9 | Preserve primitive-count recursion (`b90c855`) | | #10 | Text layout and rendering on Parley (`0f6a28b`) | URLs are `https://git.arirex.me/iris/iris/pulls/{number}`. ## Choosing the next slice ```sh cd /home/bob/repos/iris && git fetch upstream git diff --stat upstream/main..archive/full-extraction ``` The archive is a reference, not a patch to apply. Recreate a change on top of canonical `main`, leave app-specific behaviour out, and verify it independently. Pick disjoint path sets when two PRs are open, and branch each from the latest `upstream/main` rather than stacking. Still in the target and not yet claimed: - Widget draw size and measurement cleanup (source commit `6671194`). - Retained span, scrolling and layout placement. - Retained paints, selection, overlays and shared UI runtime state. - Generic desktop/Android framework hosts and reusable example/APK tooling. - Application-owned fonts and application-named font families. - Shared resource-handle bookkeeping and replaceable glyph-atlas buckets. - Positioned text overflow and cluster-safe ellipsis. - **The headless rig** — `scripts/run-headless.sh`, `headless.conf` and `rig-input` live in ai-app's iris submodule and not in canonical Iris. Everything below depends on running them from there; extracting them is a slice of its own. ## Verifying a framework slice ```sh cd cargo fmt --all --check cargo clippy --all-targets -- -D warnings cargo test ``` `--workspace` when the slice crosses workspace crates. A rendering claim needs a real run, which on this machine means the headless rig in ai-app's submodule: ```sh cd /home/bob/repos/ai-app-2/iris ./scripts/run-headless.sh tabs --dir /home/bob/repos/iris-prNN \ --shot /tmp/out.png --seconds 3 ./scripts/run-headless.sh tabs --dir ... --replay /tmp/taps.touch --shot ... ``` A `.touch` file is ` down|move|up ` in the output's own pixels; the script replays it through a virtual pointer. The `tabs` example's five tabs sit at x = 192, 576, 960, 1344 and 1728 on a 1920x1200 output. Read the `this-machine-graphics` skill before trusting any of it — the Vulkan device here comes and goes, and everything silently falls back to software when it does. ## Cautions - Read `/home/bob/repos/ai-app-2/AGENTS.md` and the machine-wide rules first. - Keep Iris generic: session drivers, transcripts, setup and server concepts, app icons and product fonts stay in ai-app. Android and desktop code is Iris work only when it is a generic host or platform integration. - Preserve the dirty-worktree rule. All worktrees were clean at handoff; anything found later may be the owner's or another agent's. - Do not delete the archived snapshot or the fork `main` ai-app pins. - A complete target branch is not permission to recreate the giant PR. - Another agent was freeing disk on this VM and removed `target/` from the `iris-pr*` worktrees once. Sources and git state were untouched. Tell peers before changing shared machine tooling, and expect a cold rebuild sometimes.