Record the renders and the counters for the frame-as-length step

Step 3 is done: against #18 the render set is byte-identical but for two
pixels of antialiasing in random and one padded block in text moving a
pixel, and a live resize of random matches a cold render at that size
exactly. The cost table is re-measured at adbedaf, where the fuzzer's own
Branch was found pinning the window and hiding what the change costs.
This commit is contained in:
iris-ai committed 2026-09-19 00:35:42 -04:00
1 parent 36ce66554b
commit 150245071f
2 files changed
+83 -35

No files matched your search

+29 -1
View File
@@ -75,13 +75,21 @@ after the step lands.
- **The clipping debug assert compared the reported size with the frame**
rather than with the box it is a claim about.
Two rig changes came out of it, both kept:
Three rig changes came out of it, all kept:
- The shrinker prints the *shrunk* tree's divergence rather than the grown
tree's, and the divergence now lists, for the failing widget and every
ancestor, warm and cold `frame`, `ask`, `box` and `size`. Reading that
table is what found the box-arm defect; reconstructing a 20-widget plan by
hand would not have.
- The fuzzer's `Branch` states the range it branched on rather than pinning
the window it read the measurement against (`adbedaf`). It is the only
widget in the fixture that reads a length in pixels and chooses a subtree
from it, so with a pin every one of them redrew on every resize: seed 1's
resize was 131 widget draws and seed 13's 828, against 44 and nothing once
it says the range. That is a fixture that cannot tell a change that reuses
well from one that does not, and it looked exactly like a regression in
the change being measured.
- A `size-resize` case: a size change and *then* a resize. Every other case
changes something and compares at once or resizes first, so an answer kept
as a fraction of the wrong length agreed at the window it was made at and
@@ -93,6 +101,26 @@ generated, the 400-seed depth-5 shrinker over all sixteen cases, the
1000-seed depth-6 oracle, and the 2000-seed depth-4 scan over all sixteen
cases.
What the renders showed, at 1920x1200 against `e44dea3` (#18), with the
examples identical in both checkouts and Vulkan confirmed (the example asks
for `Backends::PRIMARY` and would have aborted on the GL fallback):
- `minimal` and `tabs` are byte-identical, and so is `tabs` after the
reference replay -- which changes 94% of the screen, so it is a real
comparison and not two pictures of nothing.
- `random` differs in two pixels, each by one grey level: glyph
antialiasing, nothing deleted.
- `text` differs only in its third block, the `rel(0.5)` padded paragraph in
a row: the block is the same width (945 px) and wraps the same lines, and
sits one pixel further right. Its box is 948 px, so the drawing is centred
with a 1.5 px remainder and the two expressions round that half-pixel the
other way. The first two blocks, which have no declared width, are
identical -- padding coming off the frame does not move a text that wraps
at the box it was given.
- A live resize of `random` to 900x1200 is byte-identical to a cold render
at 900x1200, which is the warm/cold rule checked in pixels rather than in
regions.
One thing is unexplained and worth knowing about: seed 30 at depth 5
(`shuffle-all-but-first`) failed once, with a span keeping an answer of
`1 rel` for an axis whose frame had become `78 px`, and then stopped failing