an.bench.golden#
The golden gate: committed frames, compared on decoded pixels.
Family B of the panel. Everything else in an.bench measures a property
of one render; this compares today’s render against a picture a human looked at
and blessed, so it is the only part that can catch a change nobody predicted.
Four decisions here that are easy to get wrong in a way that still looks like it works:
**The criterion is sha256 of the decoded RGB array, never the file bytes.**
Chromium 1187 -> 1223 changed 144 of 144 PNG files and zero pixels. A
file-byte gate goes red on the first Playwright bump for a reason that has
nothing to do with animation quality — and, worse, trains people to re-bless
without looking.
The path keys on the Chromium build ALONE — no platform, no arch. Measured across arm64 macOS, x86-64 Linux and arm64 Linux, across two different SwiftShader JIT backends: zero differing pixels and zero differing PNG bytes. Carrying the platform would force one committed copy per platform for no information. What the convention keeps is its real benefit: a Playwright bump becomes a new path requiring a deliberate re-bless, not a red test with no explanation.
Three different absences get three different gates. “This scene declares no
golden frames”, “goldens exist but not for this Chromium build” and “the
Chromium build could not be determined at all” are three different facts, and a
reader who cannot tell them apart cannot act on any of them. The last one
matters most: an.bench.environment.probe_browser() never raises, it
returns {"error": ...} — so without a distinct gate an un-probeable browser
reads exactly like a scene nobody has blessed yet.
A comparison against a golden written in the same run is a tautology, so a
--bless run records family B as gated rather than as a pass. The row would
otherwise carry a perfect score that no code could ever have failed.
Module Attributes
Per-scene, per-build bless record, committed beside the frames. |
|
How many golden frames a scene must declare. |
|
Gate names. |
|
Gate names that appear in rows written BEFORE this module existed, and what they meant. |
Functions
|
Write one scene's golden frames and its bless record. |
|
The Chromium build from an environment record, or |
|
Compare today's render against the committed goldens for one scene. |
|
The frame a pinned time names, snapped to the nearest one. |
|
The filename stem for a frame, zero-padded so a directory listing sorts. |
|
Where the renderer left the PNG for one resolved frame. |
|
Every committed golden PNG for one scene and build, in sorted order. |
|
The committed bless record, or |
|
Where one scene's bless record for one Chromium build lives. |
|
|
|
Map each pinned time onto |
Classes
|
One pinned golden frame, resolved against the render that just happened. |
Exceptions
A bless was refused, or a committed golden is unusable. |
- an.bench.golden.BLESS_MANIFEST_TEMPLATE: str = 'bless-chromium{chromium_build}.json'#
Per-scene, per-build bless record, committed beside the frames. Per build rather than per scene: a Playwright bump adds a new set of frames under new names, and the old set stays valid for anyone still on the old build.
- class an.bench.golden.FrameRef(key, time, index, shot_id, local_index)[source]#
Bases:
objectOne pinned golden frame, resolved against the render that just happened.
- an.bench.golden.GATE_UNDECLARED: str = 'golden_frames_undeclared'#
Gate names. Literals rather than an enum because they are written into the ledger and read back by
an bench --comparefrom rows written by older registries, so their spelling is a wire format.
- exception an.bench.golden.GoldenError[source]#
Bases:
RuntimeErrorA bless was refused, or a committed golden is unusable.
- an.bench.golden.REQUIRED_GOLDEN_FRAMES: int = 2#
How many golden frames a scene must declare. Two, because one frame tests a single instant and cannot notice a scene that renders its first frame correctly and then stops.
- an.bench.golden.RETIRED_GATES: dict[str, str] = {'golden_absent': 'golden_absent_for_chromium_build'}#
Gate names that appear in rows written BEFORE this module existed, and what they meant.
an bench --compare(an#40) reads old rows as fact, so the one place a reader has to look is here rather than in a commit message. The an#36 row carried a singlegolden_absentfor both family-B keys, at a time when the corpus had no goldens for ANY build — which is this module’sGATE_ABSENT, not itsGATE_UNDECLARED(the fixtures did declare no times, but the gate was not distinguishing the two).
- an.bench.golden.bless_scene(capture, *, times, chromium_build, reason, git, scene_contract_sha256, golden_note='', root=None)[source]#
Write one scene’s golden frames and its bless record. Refuses, loudly.
Every refusal here is a case where writing the file would produce a gate that cannot fail:
no reason — a re-bless with no recorded reason is the same failure as a silently widened threshold, which is the named failure mode this whole wave exists to prevent;
fewer than two frames — one frame cannot notice a scene that renders its first instant correctly and then stops;
a pixel-identical pair — measured on
promote_demo: frame 0 and theduration/2frame differ by exactly zero pixels, so the obvious choice blesses one picture twice and the second golden tests nothing;an unknown Chromium build — the path keys on it, so without it the frames would be written under a name no future run could look up.
- Return type:
- an.bench.golden.chromium_build_of(environment)[source]#
The Chromium build from an environment record, or
Noneif unknown.probe_browsernever raises — it reports anerrorkey — so “we could not ask the browser” arrives here as a missing field rather than as an exception, and must not be confused with “nobody has blessed this scene”.
- an.bench.golden.compare_scene(capture, *, times, chromium_build, root=None)[source]#
Compare today’s render against the committed goldens for one scene.
Returns a dict with
statein{"measured", "gated", "unavailable"}, the reduced numbers the ledger carries, and a per-frame record for provenance. The reduction is worst frame wins:identicalis the conjunction andmin_ssim_win8is the minimum, because a maximum or a mean lets one clean frame hide a broken one, and this metric’s own name is “the worst small window”.- Return type:
- an.bench.golden.frame_index_for(time, *, fps, n_frames)[source]#
The frame a pinned time names, snapped to the nearest one.
int(time * fps)is the trap:0.25 * 24is5.999999999999999in binary floating point, so the obvious spelling silently picks frame 5.- Return type:
>>> frame_index_for(0.25, fps=24, n_frames=12) 6 >>> frame_index_for(0.0, fps=24, n_frames=12) 0
- an.bench.golden.frame_key(index)[source]#
The filename stem for a frame, zero-padded so a directory listing sorts.
Keyed on the frame index, not the pinned time: the index is what names the picture. A change to
fpsmoves the index, which changes the path, which makes the golden absent and therefore gated — loud, and pointing at the right cause.- Return type:
>>> frame_key(7) 'f0007'
- an.bench.golden.frame_png_path(capture, ref)[source]#
Where the renderer left the PNG for one resolved frame.
- Return type:
- an.bench.golden.iter_committed(scene, chromium_build, *, root=None)[source]#
Every committed golden PNG for one scene and build, in sorted order.
- an.bench.golden.load_manifest(scene, chromium_build, *, root=None)[source]#
The committed bless record, or
Nonewhen this scene has never been blessed.
- an.bench.golden.manifest_path(scene, chromium_build, *, root=None)[source]#
Where one scene’s bless record for one Chromium build lives.
- Return type:
- an.bench.golden.pixels_sha256(rgb)[source]#
sha256over the decoded pixels — shape and dtype included.Never over file bytes, for the reason in the module docstring. And never over the raw buffer alone either:
tobytes()carries no shape, so a 320x240 frame and a 240x320 one holding the same bytes hash identically, and issue #38’s literal “the criterion issha256(decoded RGB array)” would report PASS on a transposed frame. Both orientations are live in this corpus.an.bench.metrics.golden_comparison()catches it separately via itsshape_mismatchbranch; this makes the digest agree with the gate rather than quietly disagreeing with it.- Return type:
>>> import numpy as np >>> a = np.arange(24, dtype=np.uint8) >>> pixels_sha256(a.reshape(2, 4, 3)) == pixels_sha256(a.reshape(4, 2, 3)) False
- an.bench.golden.resolve_frames(capture, times)[source]#
Map each pinned time onto
(global index, shot, index within that shot).Indices run over the scene’s concatenated timeline — what the delivered mp4 shows — so a pinned time can land in the second shot, which is exactly what
multi_shot’s second golden does.