tests/golden/thresholds.json · 46f81ba, 2026-08-19
Was misst ein Diff-Schwellenwert eigentlich?
Ein Schwellenwert beantwortet eine einzige Frage — wie viel Unterschied bedeutsam ist — und diese Frage lässt sich nicht beantworten, solange du nicht weißt, wie viel Unterschied auftaucht, wenn sich gar nichts geändert hat. Der Großteil der veröffentlichten Ratschläge überspringt diesen Schritt komplett. Fang unter einem Prozent an, heißt es dort, und justiere nach, wenn die Suite unruhig wird.
Gegen Fehlschläge zu justieren optimiert auf eine grüne Suite, und das ist das Einzige, worauf ein Schwellenwert niemals optimiert werden darf. Dieses Repository hat da angefangen, wo alle anfangen: mit nach Augenmaß gewählten Zahlen. Seine Config hat das in der Datei selbst zugegeben — die Canvas-Zahlen waren als PROVISIONAL markiert, Platzhalter, bis ein Lauf von Referenz gegen Referenz auf derselben Maschine das echte Grundrauschen festlegt.
Dieser Lauf fand noch am selben Abend statt, in Commit b5175ae, und er hat jede Zahl in der Datei bewegt. Und zwar in die Richtung, mit der fast niemand rechnet — die Messung hat die Suite strenger gemacht, nicht lockerer, und sie hat ein Gate komplett gestrichen.
| Schwellenwert | Geschätzt, 46f81ba | Gemessen, b5175ae |
|---|---|---|
| pixel.default.maxDiffRatio | 0.001 | 0.0001 |
| pixel.byViewport.mobile-390 | 0.002 | 0.0005, weiterhin provisorisch |
| pixel.byViewport.tablet-768 | keine Zeile | 0.0005, weiterhin provisorisch |
| ssim.page.meanMin | 0.995 | 0.999 |
| ssim.page.worstMin | 0.9 | 0.95 |
| ssim.canvas.meanMin | 0.98 | null, Gate disqualifiziert |
| ssim.canvas.worstMin | 0.85 | null, Gate disqualifiziert |
| observation listenerTotal | keine Toleranzzeile | maxDelta 24 |
tools/golden/noise-floor.mjs:75-93
Wie misst man ein Grundrauschen?
Das Tool hat genau einen Zweck, und der steht in seiner ersten Zeile: messen, wie sehr das Instrument sich selbst widerspricht. Es serviert einen einzigen Build, nimmt die Referenz zweimal über dasselbe Capture-Skript auf, das auch die echte Suite benutzt, und vergleicht Lauf A mit Lauf B. Was dabei herauskommt, ist Rauschen, denn zwischen den beiden hat sich nichts geändert.
Der Vergleich ist bewusst dünn — zwei Zahlen pro Bildpaar, kein Diff-Bild, keine Deutung. pixelmatch liefert die Anzahl der Pixel, die einen Farbgrenzwert überschritten haben, und ein eigenes SSIM mit einem Fenster von acht Pixeln und einer Schrittweite von vier liefert den perzeptuellen Blick. Sowohl der Mittelwert als auch das schlechteste Fenster werden behalten, denn eine Shader-Regression ist meist lokal, und ein Mittelwert von 0.99 kann eine kaputte Ecke verstecken.
Drei Populationen kommen heraus, und sie werden nie vermischt: strukturelle Screenshots, rohe Canvas-Aufnahmen und Beobachtungsdrift — jedes Nicht-Pixel-Feld des Digests pro Checkpoint, das sich zwischen zwei Läufen derselben Seite unterschied. Perzentile werden als min, p50, p95 und max über jede sortierte Menge berichtet.
function comparePair(a, b) {
if (a.width !== b.width || a.height !== b.height) return { ok: false, reason: 'size-mismatch' }
const total = a.width * a.height
// Hier ist kein Diff-Bild erwünscht — nur die Anzahl. pixelmatch akzeptiert
// genau für diesen Fall einen undefinierten Ausgabepuffer.
const changed = pixelmatch(a.data, b.data, undefined, a.width, a.height, {
threshold: 0.1,
includeAA: false,
})
const score = ssim(a, b, { windowSize: 8, stride: 4 })
return {
ok: true,
diffRatio: changed / total,
changedPixels: changed,
totalPixels: total,
ssimMean: score.mean,
ssimWorst: score.worst,
}
}
Es kostet exakt das Doppelte einer Aufnahme in einem Viewport, und ein Viewport sind hier sechs bis neun Minuten Echtzeit, die Messung ist also eher eine Viertelstunde als umsonst. Ihre Ausgabe wird ins Repository eingecheckt, mit der Begründung, dass sie Beweismaterial ist — und klein.
noise-floor.json · 2026-08-19 · n=19 and n=89
Worüber waren sich zwei identische Läufe uneinig?
Dieselbe Maschine, derselbe Browser, dieselbe URL, zwei Läufe der Golden-Master-Startseite bei 1440 × 900, gestempelt auf 2026-08-19T19:33:49.368Z unter Node v22.23.1. Neunzehn strukturelle Screenshots und neunundachtzig rohe Canvas-Aufnahmen kamen von jeder Seite zurück.
Die strukturelle Population war sich über rein gar nichts uneinig: Pixel-Diff-Verhältnis min 0, p50 0, p95 0, max 0, wobei achtzehn der neunzehn Paare byte-identisch waren und das neunzehnte eine Marquee ist, die mit Absicht live aufgenommen wird, weil kontinuierliche Bewegung genau das Verhalten ist, das hier geprüft wird. Die Canvas-Population war sich über fast alles uneinig: p95 0.025829475308641974, max 0.8112244897959183, ein SSIM-Mittelwert, der auf 0.0181484156493548 fällt, und ein schlechtestes Fenster bei -0.886465409531798.
Dieser negative Wert ist ein echter Messwert und kein Fehler. SSIM läuft von -1 bis 1, so wie Wang, Bovik, Sheikh und Simoncelli es 2004 definiert haben, und der Unit-Test dieses Repositorys nagelt das fest, indem er zusichert, dass ein invertiertes Bild unter null liegt. Eine Metrik, die legitim negativ werden kann, sagt dir, dass die beiden Fenster strukturell antikorreliert sind — und genau so sieht ein Canvas aus, das in zwei zusammenhanglosen Momenten erwischt wurde.
- 0 strukturelles Pixel-Diff-Verhältnis min, p50, p95 und max, über 19 Screenshot-Paare
- 81% Canvas-Pixel mit Unterschied das Maximum über 89 rohe Canvas-Paare
- 0.018148 schlechtester Canvas-SSIM-Mittelwert das geschätzte Gate hatte 0.98 verlangt
- 447 vs. 431 listenerTotal, ein Checkpoint das einzige Nicht-Pixel-Feld, das sich bewegt hat
Der letzte Wert ist der Grund, das hier über Screenshots hinaus laufen zu lassen. listenerTotal las im einen Lauf 447 und im anderen 431 am eingeschwungenen Hero, ein Drift von 16, während rootFontSizePx, documentHeight und globalsLeaked über beide Läufe und über alle 21 Checkpoints einer späteren Matrix exakt gleich blieben. Die Zusicherung wurde von exakt auf tolerant heruntergestuft, mit einem maxDelta von 24 — über den beobachteten 16 und unter allem, was sich als Listener-Leck lesen ließe — und die anderen blieben exakt, weil die Messung sagte, dass sie es können.
Dieselbe Disziplin — miss die Bedingung, bevor du der Zahl traust — hat die veröffentlichte Barrierefreiheitszahl dieser Seite hervorgebracht, wo eine unkontrollierte Bedingung die Anzahl um etwa das 140-Fache aufblähte.
thresholds.json ssim.canvas · enforced false
Wenn kein Schwellenwert über dem Grundrauschen liegt, blockiere das Gate
Das geschätzte Canvas-Gate verlangte einen SSIM-Mittelwert von mindestens 0.98. Das gemessene Grundrauschen liegt bei 0.018148. Zwischen diesen beiden Zahlen gibt es keinen Schwellenwert, und kein Nachjustieren hätte einen gefunden: Eine Suite, die mit 0.98 ausgeliefert wird, wäre bei jedem Lauf durchgefallen, wäre durch Lockern repariert worden und hätte am Ende nichts über die riskanteste Fläche der Seite bewiesen.
Das Gate wurde also nicht gelockert, es wurde disqualifiziert. enforced false, meanMin null, worstMin null und ein Status-String, der die Bedingung benennt, statt mit den Schultern zu zucken: BLOCKED, needs deterministic time control on the scene side. Der Comparator hält sich im Code daran und nicht nur in der Prosa — er berechnet das SSIM bei jedem Lauf, notiert den Mittelwert, das schlechteste Fenster und dessen Koordinaten und gibt trotzdem ok zurück.
Der echte Lauf über beide Targets bestätigt das Urteil von der anderen Seite. Über die 306 Canvas-SSIM-Zeilen, die die beiden Builds vergleichen, hat der Mittelwert einen Median von 0.7284514638837428 und das schlechteste Fenster einen Median von -0.20839572391449632. Ein Gate, dessen medianes schlechtestes Fenster zwischen zwei für korrekt gehaltenen Builds negativ ist, kann eine Regression nicht von Rauschen trennen.
- PASS
- Der Vergleich hat stattgefunden und der Checkpoint war sich einig. Im eingecheckten Lauf kommen 120 von 132 Checkpoints mit einem Verhältnis von exakt 0.000000 zurück.
- FAIL
- Der Vergleich hat stattgefunden und der Unterschied lag über dem, was das gemessene Grundrauschen erlaubt. Der eine Fehlschlag in diesem Lauf ist eine veraltete Ledger-Zeile, kein Pixel.
- BLOCKED
- Der Vergleich hat nicht stattgefunden — das Instrument konnte das Motiv nicht stillhalten, oder kein Schwellenwert liegt über seinem Rauschen. Wird getrennt gezählt, nie in die Bestanden-Zahl eingerechnet.
- informational
- Die Zahl wird bei jedem Lauf berechnet und notiert und bringt den Build nie zum Scheitern. Sie ist der Beleg, der es später rechtfertigen wird, das Gate einzuschalten.
BLOCKED ist nur dann vertretbar, wenn es eine benannte Bedingung zum Entsperren mitbringt, und hier ist diese Bedingung eingetroffen. Die eigene WebGL-Szene des Rebuilds bietet einen Test-Hook, der exakt ein Frame zu einem expliziten Zeitpunkt rendert, und damit wurde derselbe Inhalt Byte für Byte gate-fähig: Ein festgepinntes Frame wird jetzt über zwei unabhängige Seitenaufrufe hinweg als identisch zugesichert. Die Parität gegen das Legacy bleibt bauartbedingt eine menschliche Sichtprüfung anhand aufgenommener Standbilder, weil sich das Legacy nicht auf ein Frame festpinnen lässt.
Determinismus einzufordern hat außerdem zwei Defekte gefunden, die ein Blick auf das Bild nicht gefunden hätte. Ein Composite-Pass hat ein eingeschwungenes Frame über einen nicht geleerten Puffer geblendet, entdeckt daran, dass Frames, die bei 1,5 Sekunden und bei 9 Sekunden festgepinnt waren, byte-identisch zurückkamen — eine festgepinnte Zeit, die nichts ändert, ist ein Uniform, das keinen Shader erreicht. Diese Null-Differenz war der Bug, und ein Comparator, der nur auf zu viel Veränderung getrimmt ist, hätte Grün gemeldet.
Ein Canvas auf ein Frame festzupinnen ist genau die Fähigkeit, die ein Canvas braucht, um eine Reduced-Motion-Anfrage ehrlich zu beantworten — was WebGL und Rive prefers-reduced-motion schulden.
sha256 d8ca0518 · 5,851 B · one colour
Ein Grundrauschen von null kann heißen, dass der Objektivdeckel drauf ist
Die strukturelle Zeile dieser Messung liest sich viermal als 0, und die Thresholds-Datei zitiert sie als achtzehn von neunzehn Checkpoints byte-identisch über zwei Läufe. Beide Aussagen stimmen exakt. Wer die eingecheckten Screenshots dekodiert, sieht, worüber sie stimmen.
Die Referenz-Startseite bei initial-load ist 1440 × 900, 5.851 Byte und eine Farbe: 1.296.000 Pixel in #ff00ff. Genauso hero-settled, und hero-pointer-corner, und otot-section, und footer, und zwölf weitere. Sechzehn Checkpoints, an sechzehn verschiedenen Scroll-Positionen von y 0 bis y 17809, teilen sich einen einzigen sha256.
Das ist die dokumentierte Mask-Regel, die exakt wie spezifiziert arbeitet. Die Referenzseite trägt zwei Canvas-Flächen über den vollen Viewport, und vor jeder Aufnahme wird ein fixiertes Magenta-Overlay auf das Viewport-Rechteck jedes Canvas gepinnt, ganz oben in der Stapelreihenfolge — nie in das Canvas selbst gezeichnet, denn es über einen 2D-Kontext zu füllen zerstört seinen Inhalt und würde eine WebGL-Fläche komplett ruinieren. Zwei Canvas über den vollen Viewport ergeben an jeder Scroll-Position ein Overlay über den vollen Viewport.
| Checkpoint | Canvas-Regel | Verschiedene Farben |
|---|---|---|
| initial-load | mask | 1 |
| hero-settled | mask | 1 |
| vierzehn weitere, gleicher sha256 | mask | 1 |
| marquee | capture, live | 797 |
| menu-open | hide | 14.060 |
| menu-closed-again | hide | 14.080 |
Der Befund ist nur deshalb auffindbar, weil das Instrument aufschreibt, wo es absichtlich nicht hingeschaut hat. Jeder Screenshot-Datensatz trägt die Rechtecke, die er ausgeschlossen hat, und das Architekturdokument nennt dieses Feld als eines von zwei Dingen, die man lesen muss, bevor man irgendeinem Pixel-Ergebnis traut. Nichts im Repository ist falsch; die Stichprobe hinter einem Satz ist nur kleiner, als der Satz nahelegt.
Die zwei Checkpoints, die tatsächlich Seiten-Pixel tragen, tragen sie durch einen Zufall der Regel. menu-open und menu-closed-again verstecken ihre Canvas-Flächen, statt sie zu maskieren, weil das Canvas des Menüs in einem Container sitzt, der noch transformiert wird, während das Mask-Rechteck berechnet wird — ein fixiertes Overlay würde also danebenrutschen. Beide waren über den A- und den B-Lauf byte-identisch, und beide sind es fünf Tage später auch in einem unabhängigen Lauf über die volle Matrix noch — das ist echter Beleg, und deshalb ist die verschärfte 0.0001 richtig. Sie ruht auf zwei Bildern, und die Datei sagt achtzehn von neunzehn.
Und es ist kein Einzelfall. Dekodiert man jeden strukturellen Screenshot, der in den beiden Voll-Matrix-Manifesten genannt wird, sind 108 von 126 beim Golden Master und 114 von 132 beim Rebuild zu 100 Prozent einfarbig, über alle sechs Viewports, auf beiden Targets. Die billigste Prüfung, die es hier gibt, ist ein Einzeiler: Dekodiere eine Baseline und zähle ihre verschiedenen RGB-Werte, bevor du einer Null traust.
menu-open vs menu-closed-again · 3 of 6
Der zweite Weg, auf dem ein grüner Checkpoint über nichts sein kann
Ein Grundrauschen sagt dir, was dein Instrument auflösen kann. Es kann dir nicht sagen, ob der Checkpoint überhaupt auf irgendetwas gerichtet war, und diese beiden Fehlschläge sehen in der Zusammenfassungszeile identisch aus.
Bei drei der sechs Viewports — breakpoint-991, tablet-768 und mobile-390 — haben der Screenshot namens menu-open und der Screenshot namens menu-closed-again denselben sha256, auf beiden Targets. Der Klick, der das Menü öffnet, ist als erfolgreich vermerkt, failedInteractions steht überall auf 0, und der Pixel-Vergleich besteht in beide Richtungen mit Verhältnis 0, weil beide Targets gleichermaßen leer sind. Die Parität zwischen den beiden Builds bleibt wirklich gewahrt. Der Checkpoint, dessen erklärter Zweck ist zu beweisen, dass der Schließweg keine Reste hinterlässt, beweist auf der Hälfte der Matrix nichts.
Der Beobachtungsdatensatz enthält die Antwort, und sie ist auf zwei benachbarte Felder verteilt, von denen eines sehr viel einladender zu lesen ist als das andere.
- interactions
- Ein Klick auf den Hamburger, ok true, dann ein Warten von 1200 ms, ok true. Der Digest meldet failedInteractions 0 bei jedem Viewport auf beiden Targets.
- navGroups.opacity
- 1 — was sich liest, als wäre das Menü offen, und es ist das Feld, das jeder beim Debuggen zuerst prüfen würde.
- navGroups.rect
- x 0, y 0, width 0, height 0. Das Element hat keine Box. Bei desktop-1440 misst derselbe Knoten 128,794 mal 60 bei x 16,656, mit einer Scale-Transform von 1,2.
- pixel
- Verhältnis 0 gegen das andere Target, bequem unter dem gemessenen Grundrauschen. Der Vergleich ist statistisch solide, korrekt konfiguriert — und über nichts.
Die allgemeine Regel hat zwei Hälften, und kein Schwellenwert kann sie zusammenführen. Miss, wie sehr das Instrument sich selbst widerspricht, und sichere getrennt davon zu, dass jeder Checkpoint den Zustand erreicht hat, den sein Name behauptet — ein sichtbares Element, eine Box ungleich null, ein Digest-Feld, das sich zwischen dem Vorher und dem Nachher wirklich bewegt hat. Die erste Hälfte ist Rechnen über Bildern. Die zweite ist eine völlig andere Zusicherung, und sie ist die, die eine Suite davon abhält, ihr eigenes leeres Blatt zu benoten.
tests/.golden-diff/report.json · 2026-08-24
Zähle die Vergleiche, die nicht stattgefunden haben
Der eingecheckte Lauf über beide Targets liest 132 verglichen, 132 bestanden. Er liest außerdem 162 Canvas-Vergleiche, die nie stattgefunden haben, und der Comparator druckt diese Zahl mit Absicht direkt neben die Bestanden-Zahl: Ein Lauf, der 132 von 132 sagt und dabei still hundert ungemachte Vergleiche zurückhält, hat die Form eines hergestellten Bestehens.
Die größte Kategorie ist ein Crop-Artefakt — also die Seite, die sich mit sich selbst einig ist, während der Screenshot-Cropper es nicht ist. Ein Element von 13,328125 CSS-Pixeln Breite kam auf der einen Seite zu 15 mal 14 zugeschnitten zurück und auf der anderen zu 14 mal 15, weil der Element-Screenshot das Element zuerst in den sichtbaren Bereich scrollt und sich der Subpixel-Ursprung darunter verschiebt. Die Lösung ist keine Toleranz: Die CSS-Box wird gegatet und erzwungen, 468 von 468 Box-Prüfungen bestehen, während die PNG-Größe als informational notiert wird — die Box entscheidet die Seite, den Zuschnitt entscheidet der Cropper, und nur das Erste ist eine Aussage über den Build.
Die anderen beiden Kategorien sind billiger zu erklären und weit teurer im Lauf. 192 von 792 Versuchen, ein Canvas aufzunehmen, fanden überhaupt keine Box zum Fotografieren. 66 Versuche liefen nach jeweils 30 Sekunden in einen Timeout, jeder einzelne davon an einem einzigen Canvas — dem Seitenübergang der Referenz, der bei keinem seiner 66 Versuche stillhielt. Das sind mindestens 1.980 Sekunden eines Matrix-Laufs von 2.620,6 Sekunden: drei Viertel der Echtzeit damit verbracht, auf das Fotografieren von etwas zu warten, das sich nicht fotografieren ließ.
Die eigene Matrix des Rebuilds, mit 132 Checkpoints etwas größer, war in 4,82 Minuten fertig, gegen 43,68 bei der Referenz. Fast der gesamte Unterschied geht auf ein einziges Canvas zurück, das sich nicht auf ein Frame festpinnen lässt — und das ist zugleich ein Performance-Fakt und ein Instrumenten-Fakt: Das, was deine Suite nicht fotografieren kann, ist auch das, womit sie ihren Nachmittag verbringt.
Echtzeit ist ein eigenes Messproblem, und die Scroll-Schicht dieser Seite hat dieselbe Behandlung bekommen — Lenis gegen natives Scrolling, gemessen statt behauptet.
pixelmatch 7.2.0 · checked 2026-08-26
Was setzen die Thresholds von pixelmatch und Playwright eigentlich?
Die halbe Verwirrung um Schwellenwerte kommt daher, dass das Wort zwei verschiedene Zahlen benennt. In pixelmatch — der Bibliothek unter diesem Vergleich und dem Modell, dem Playwrights eigene Screenshot-Zusicherung folgt — ist threshold ein Farbabstands-Grenzwert pro Pixel und keine Toleranz pro Bild. In Version 7.2.0, der hier gepinnten, wird threshold 0.1 zu einem maximalen quadrierten YIQ-Abstand von 35215 × 0.1 × 0.1 = 352.15, gegen einen maximal möglichen Wert von 35215. Die Funktion gibt dann die Anzahl der Pixel zurück, die ihn überschritten haben.
Die Toleranz pro Bild ist eine eigene Zahl, und sie ist die, die dir ein Grundrauschen nennt. Playwright macht die Trennung sichtbar und lässt die eine Hälfte leer: threshold liegt standardmäßig bei 0.2, während maxDiffPixels und maxDiffPixelRatio überhaupt keinen Standard haben — ab Werk lässt also ein einziges hinreichend abweichendes Pixel die Zusicherung scheitern. Vitest liefert ebenfalls keine Standardtoleranz und sagt das auch offen, mit der Empfehlung, ein Verhältnis aus der Größe des Screenshots zu berechnen statt einer festen Anzahl.
Noch etwas, das das Wort verbirgt: Die Metrik darunter ist über Versionen hinweg nicht stabil. pixelmatch hat auf seinem main-Branch den YIQ-Abstand durch die OKLab-HyAB-Metrik ersetzt, threshold 0.1 ist über die Zeit also keine feste Größe. Und includeAA liest sich rückwärts zu seinem Namen — false, der Standard und die Einstellung dieses Repositorys, bedeutet, dass die Antialiasing-Erkennung an ist und AA-Pixel nicht als Unterschiede zählen.
| Tool | Grenzwert pro Pixel | Toleranz pro Bild |
|---|---|---|
| pixelmatch 7.2.0, dieses Repository | threshold 0.1, YIQ quadriert | maxDiffRatio 0.0001, gemessen |
| pixelmatch, main-Branch | threshold, OKLab HyAB | keine, es gibt eine Anzahl zurück |
| Playwright toHaveScreenshot | threshold 0.2, YIQ | standardmäßig nicht gesetzt |
| Vitest Browser-Mode | nicht zugänglich | kein Standard, ein Verhältnis empfohlen |
Keiner dieser Standardwerte weiß irgendetwas über deine Seite, und genau darum misst man die eigene. Playwright und Vitest sagen dir beide, Baselines in der Umgebung neu zu erzeugen, in der du sie vergleichen wirst, und jede oben zitierte Zahl stammt von einer Maschine, einem Chromium-Build, headless, ohne Determinismus-Flags bei der Aufnahme — kein font-render-hinting, kein erzwungener Device-Scale. Die Toleranz von 0.0001 wird in der Datei als Spielraum für Font-Rasterisierung über Maschinen hinweg beschrieben, also als Spielraum für einen Fall, den dieses Repository noch nicht gemessen hat.
noise-floor.json · one commit, never re-run
Wie du einen Schwellenwert ohne Raten setzt
Das Verfahren ist kurz, und das meiste daran ist Buchhaltung. Tragfähig wird es dadurch, dass die Ausgabe neben den Zahlen eingecheckt wird, die sie begründet — ihr Alter steht damit in einem git log statt in irgendjemandes Gedächtnis.
- Einen Build servieren, zweimal aufnehmen Zwischen den beiden Läufen darf sich nichts unterscheiden außer dem Moment, in dem sie passiert sind. Nimm dasselbe Capture-Tool, das auch die echte Suite benutzt, statt eines vereinfachten Ersatzes, sonst hast du ein anderes Instrument gemessen.
- A gegen B diffen, über alles, was du zusicherst Anzahl pro Pixel, eine perzeptuelle Metrik mit behaltenem schlechtestem Fenster zusätzlich zum Mittelwert, und jedes Nicht-Pixel-Feld, das dein Digest festhält. listenerTotal hat sich hier um 16 bewegt; documentHeight hat sich gar nicht bewegt.
- Jeden Schwellenwert über sein eigenes p95 setzen Mit einem Spielraum, den du bewusst wählst, und mit der Messung als Kommentar neben der Zahl. Ein Schwellenwert, den niemand zurückverfolgen kann, ist ein Schwellenwert, den jeder lockern kann.
- Wo nichts über dem Rauschen liegt, das Gate blockieren Notiere die Zahlen, lass den Build nie daran scheitern und benenne die konkrete Änderung, die es entsperren würde. Ein blockiertes Gate mit einem Weg zurück ist ehrlich; ein gelockertes ist Dekoration.
- Die Messung einchecken, datiert und klein Als Text, im Repository, neben den Schwellenwerten, die sie hervorgebracht hat. Nur so merkt der nächste Leser, dass sie veraltet ist, statt ihr zu vertrauen.
- Prüfen, ob das Instrument das Motiv gesehen hat Dekodiere eine Baseline und zähle ihre verschiedenen RGB-Werte. Eine Farbe heißt, du hast die Maske fotografiert. Lies danach, was dein Tooling über die ausgeschlossenen Regionen festhält.
- Zusichern, dass jeder Checkpoint seinen Namen eingelöst hat Ein sichtbares Element, eine Box ungleich null, ein Digest-Feld, das sich zwischen dem Vorher und dem Nachher geändert hat. Kein Schwellenwert impliziert irgendetwas davon, und eine grüne Suite ohne das benotet leeres Papier.
Zwei Vorbehalte, die dieses Repository an sich selbst vorführt, beide in seiner eigenen Config sichtbar. Zwei seiner sechs Viewports, beide mit deviceScaleFactor 2, haben nie ein gemessenes Grundrauschen bekommen, und ihre Schwellenwerte tragen das Eingeständnis genau dort, wo der nächste Leser darauf stößt: noch nicht gemessen, provisorisch. Das Architekturdokument nennt die Konsequenz ohne Weichzeichner — ein Bestehen oder ein Scheitern bei diesen zwei Viewports beweist nichts über das Instrument, und kein Kandidat sollte darauf abgenommen werden.
Und das Grundrauschen selbst hat genau einen Commit. Es wurde am 2026-08-19 erhoben und nie wiederholt, während sich das gemessene Szenario seither zweimal geändert hat und von 19 auf 21 Checkpoints gewachsen ist. Ein Grundrauschen ist verderblich, es zerfällt, sobald sich die Seite, der Browser oder die Maschine bewegt, und der einzige Grund, warum überhaupt jemand sagen kann, wie alt dieses hier ist, ist eine kleine datierte Datei in der Versionsverwaltung, direkt neben den Zahlen, die sie hervorgebracht hat.
Dasselbe Argument hat auf dieser Seite eine typografische Zahl entschieden, wo ein Verhältnis, das alle nachplappern, ersetzt wurde durch eine aus den Umrissen berechnete Zeilenhöhen-Untergrenze.
Instrumentenarbeit wie diese gehört dazu, wie die Seiten hier gebaut werden, beschrieben in den vier Disziplinen.