11 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 has been reviewed six times ("very close now"); the sixth
is answered in 444a2cd and a seventh has not arrived. Check for one before doing anything
else:
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
Check the newest submitted_at rather than assuming the first result is
current. My replies are ordinary issue comments on the same PR and say what
each change was for.
Agree a design before sending another variation of it. The owner stopped
the fourth round with "we should probably agree on the design here rather
than you keep submitting variations that I review". When a review comes back
about the shape of something rather than a defect in it, put the options and a
recommendation in front of her and implement what she picks. She chose the
per-image bind group for textures on 2026-09-13; the alternatives were
packing images into arrays like atlas pages, and a bindless binding_array
(ruled out by Android support).
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, head444a2cd, twelve commits on top of0f6a28b. Reviewed six times, all answered. - #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 four rounds of review turned it into a rework of how primitives are drawn. Worth knowing before reading a 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. - A primitive registers itself by being drawn. The type carries its own
WGSL and
PrimitiveRegistrykeys ids byTypeId, so the kind comes from the type and there are noRECT/GLYPH/TEXTUREconstants. Nothing is seeded, so an id depends on what a ui drew first and a ui pays only for what it uses. - 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. - The shared group is what every pipeline gets: window, masks, the glyph
atlas array, and the one sampler. A mask texture would go here too. A
primitive that samples an image of its own declares
Primitive::TEXTURE, which gives it an image bind group, a draw call per instance, and the slot recorded at write time; no other pipeline mentions textures at all. shader.wgslbecameshader/prelude.wgslplus one file per primitive, because one module cannot declare two types at the same binding. The prelude carries only what every primitive uses -- window, masks, vertex shader,masked()-- and its header records the group 0 binding numbers; the atlas and sampler are declared by the shaders that read them.- A texture handle is drawn like anything else.
Painter::primitivetakesimpl PrimitiveLike: a primitive, or something that yields one and does what else drawing it needs -- a&TextureHandleretains its share on the way through. The blanket impl and the one for&TextureHandledo not collide, becausePrimitiveis ours and no crate can add the overlapping impl. - Order within a layer means nothing, and the widgets do not rely on it:
Stackgives each child its own layer andTextEditdraws its view in a child layer above the selection rectangles. Verified with a ui that registers glyph before rect.
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.