Current as of PR #11's fourth review, which is deliberately unread: the first instruction is to fetch it. Records what #11 became over three rounds of review, since that shape is what the new review is about, and where the headless rig actually lives, since a rendering claim cannot be verified without it. Drops the finished detail -- PR #10's contents, the source-history archaeology that has been consumed -- and points at the machine-wide pre-submit-review gate rather than restating it.
9.7 KiB
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:
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/<id>/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,mainat0f6a28b(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 intoiris/iris:main. - #11
split/11-texture-bindings, worktree/home/bob/repos/iris-pr11, head7b318e3, eight commits on top of0f6a28b. Reviewed four times; the fourth is unread. - #12
split/12-pointer-routing, worktree/home/bob/repos/iris-pr12, head028521b. 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-2is onrustify, 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.
GlyphAtlasowns its page images and emits dirty rectangles;GpuPagesowns the array texture they upload to.Texturesholds standalone images only. - Every primitive is a registration.
PrimitiveRegistry::register::<P>takes the primitive's WGSL and what it samples, and returns aPrimitiveKind<P>. 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.
InstanceListcarries 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.wgslbecameshader/prelude.wgslplus 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 andmasked().- 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
aibranch 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, branchrustify.iris/is a submodule pinned at32f6ad8, the complete extracted snapshot, and.gitmodulespoints 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
mainandorigin/archive/full-extractionboth name32f6ad8, the target snapshot.history/fullnames the source-history resulta615bcd. - 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/mainin its own worktree:
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
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.confandrig-inputlive 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
cd <iris-worktree>
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:
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 <ms> down|move|up <x> <y> 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.mdand 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
mainai-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 theiris-pr*worktrees once. Sources and git state were untouched. Tell peers before changing shared machine tooling, and expect a cold rebuild sometimes.