Write down what the Image family taught, where the next lane will look

The section on what a headless FFI test can and cannot pin was written before
anything CPU-side was bound, so it had no example of the one shape that beats
store-and-return: scalars in and struct fields out, with nothing for a
permuted layout to cancel against.

It also did not say that MeasureText answers 0 without a window, which is the
assumption this lane started with and had to measure its way out of. Two
lanes have now guessed the same thing.
This commit is contained in:
Joseph Ferano 2026-09-11 19:47:08 +07:00
parent 05676f3181
commit cb11fdf272

26
NEXT.md
View File

@ -295,10 +295,36 @@ turned out to check nothing.
computes four numbers from four different field pairs, and the point/rect
predicates turn the wrong way when width and height are exchanged.
- **Scalars in, fields out is the strongest shape there is**, and the Image
family is where it was finally available. `GenImageColor(4, 2, colour)` is
handed two integers and answers with a struct reading 4, 2, 1, 7 — four
distinct values in four adjacent `i32` slots, with no input struct for a
permutation to cancel against. That pins `Image` completely, including that
`data` is present and first; `Texture2D` could never be pinned that way
because nothing without a GPU reads its width, height or mipmaps at all.
- **A non-square image is an axis discriminator.** `GetImageColor` indexes
`y*width + x`, so on a 4-wide, 2-tall image `(3,0)` exists and its transpose
does not: exchange the wrapper's `x` and `y` and the read goes out of bounds
and answers transparent black. `ImageFlipHorizontal` against
`ImageFlipVertical` says the same thing twice more.
- **A file is external ground truth**, so `ExportImage` then `LoadImage` is not
the symmetric round trip the rest of the package has to avoid — stb's encoder
and decoder agree with each other, not with Flan's field order. Verified
red by the `x`/`y` permutation above.
The rule that falls out: make raylib **compute** something whose answer differs
per axis, then verify the test can fail by permuting the fields and watching it
go red. A case not verified that way is decoration.
One correction to an assumption that has now cost two lanes a guess:
**`MeasureText` is not headless material.** It measures with the default font,
`LoadFontDefault` is not exported, and nothing but `InitWindow` loads it — so
with no window it answers 0 for every string. Measured against
`libraylib.so.550`, not reasoned about. `GetFrameTime`, `GetTime` and
`GetScreenWidth`/`Height` are all 0 headless for the same kind of reason. All
five are bound, and all five are exercised by running `sand.flan` and looking,
which is the whole of what can be claimed for them.
## Packages
`lib/load.ml` resolves `(import rl "vendor:raylib")` before the checker runs.