diff --git a/docs/IRIS_EXTRACTION_HANDOFF.md b/docs/IRIS_EXTRACTION_HANDOFF.md index dc4c0d6..7ddfc0e 100644 --- a/docs/IRIS_EXTRACTION_HANDOFF.md +++ b/docs/IRIS_EXTRACTION_HANDOFF.md @@ -5,9 +5,9 @@ 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: +**Pull request #11 has been reviewed four times; the fourth is answered in +`29d390d` and the fifth has not arrived.** Check for one before doing anything +else: ```sh TOKEN=$(cat ~/.config/gitea/token) @@ -19,10 +19,18 @@ 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. +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 @@ -31,8 +39,8 @@ say what each change was for. - 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. + head `29d390d`, nine commits on top of `0f6a28b`. Reviewed four times, all + answered. - **#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. @@ -40,31 +48,36 @@ say what each change was for. ## 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: +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.** `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. +- **A primitive registers itself by being drawn.** The type carries its own + WGSL and `PrimitiveRegistry` keys ids by `TypeId`, so the kind comes from the + type and there are no `RECT`/`GLYPH`/`TEXTURE` constants. Built-ins are + seeded up front only so first-draw order cannot shuffle them. - **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. +- **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.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. + carries the window, masks, atlas, sampler, vertex shader and `masked()`, and + is the one place binding numbers are written down. +- **Order within a layer means nothing** and nothing claims otherwise -- but + the widgets do rely on it today, since a `Text` over a `Rect` in one layer + only works because glyph registers after rect. Open question, raised on the + PR: text may need a layer of its own. ## Standing instructions from the owner