Files
feuerwerk/todo-notes/done/flaky-pixel-art-filter.md
T
root 75be133374 Make the smooth-filter check unable to cover for the hard one
The pixel-art check falls over sporadically, and its follow-up hid it. That one only
asked whether some pixel across the border is blended – but in the failing case the
`nearest` reading is already blurred, so the `linear` one is too, and the check passed
while saying nothing about whether the switch had any effect at all.

It now also demands that the picture actually changed against the `nearest` reading:
the summed colour distance over the five sample points must exceed 150. Measured on the
readings recorded in the note, a working switch drifts 425 and a hung one 0 – and 30
even if every channel were off by two, so the threshold is not brittle against noise.
Exact equality was the first draft and would have gone green on a single wobbling bit.

Both checks now carry `__gm.textureFilter(file)` in their message, so a failure says by
itself whether the model never switched, the switch missed the GPU sampler, or the
pixels were measured wrong.

The cause of the sporadic failure is still unknown; four hypotheses are measured and
ruled out in the note, which is filed with that stated plainly.
2026-09-09 15:55:28 +02:00

3.6 KiB

Der E2E-Check pixel-art filtering keeps the border between two quadrants hard faellt sporadisch um — am 2026-09-09 zweimal in vier Laeufen, jeweils ohne dass eine Aenderung Texturen beruehrt haette.

  • gruen: ["#e63c3c","#e63c3c","#3cc85a","#3cc85a","#3cc85a"] — harte Kante, nearest greift
  • rot: ["#c65641","#a67047","#868a4c","#66a552","#3cc85a"] — weicher Verlauf, also linear

Erledigt: der Folge-Check deckt nichts mehr zu

Der zweite Check (switching the filter back to smooth …) verglich nur soft.some(c => !pure(c)) und meldete damit auch dann gruen, wenn beide Filter denselben Verlauf zeigten — ein haengender Wechsel liess genau einen Check fallen, der zweite verdeckte ihn.

Er verlangt jetzt zusaetzlich, dass sich das Bild gegenueber nearest messbar geaendert hat (Summe der Farbabstaende ueber die fuenf Punkte > 150). An den oben aufgezeichneten Reihen gerechnet: echter Wechsel 425, haengender 0 — und 30 selbst dann, wenn jeder Kanal um zwei danebenlaege. Beide Checks legen ausserdem __gm.textureFilter(datei) in ihren Fehlertext.

Das Messgeraet

__gm.textureFilter(datei) liest beides: was das Modell will (scaleMode) und was der Treiber tatsaechlich weiss (gl.getTexParameter an der hochgeladenen Textur). Ein FAIL beantwortet damit von selbst, was bisher Deutungssache war:

Messung Bedeutung
scaleMode linear, Bild weich das Modell hat nie umgeschaltet
scaleMode nearest, gpu linear der Wechsel erreichte den Sampler nicht — Produktfehler
beide nearest, Bild trotzdem weich der Test misst falsch

Es bindet die Source ueber renderer.texture.bindSource statt per rohem bindTexture — sonst verfaelscht die Messung Pixis Vorstellung davon, was gebunden ist, und stiftet selbst Flakiness.

Offen: die Ursache

Vier Hypothesen sind gemessen und widerlegt — nicht erneut probieren:

Hypothese Messung Ergebnis
Der Wechsel erreicht den GPU-Sampler nicht 30 Wechsel, Modell und gl.getTexParameter gelesen 60/60 einig
Der Vorlauf der elf Module hinterlaesst etwas 15 Runden nach echtem Vorlauf alle gruen
Verlorener GPU-Prozess (Chrome meldete exit_code=34) Kontext gezielt verloren und wiederhergestellt nearest ueberlebt beides, auch mit Redraw
Genau ein Wechsel auf frischer Seite, wie im Test 12 Runden, je neuer Seed und Seitenaufbau alle gruen

Dass in ueber 60 gezielten Versuchen nichts faellt, waehrend der echte Lauf in ein bis zwei von vier Laeufen umfaellt, ist der eigentliche Widerspruch.

Naechste Spur bleibt die Umgebung: Chrome meldet beim Start auf der Windows-Maschine GPU process exited unexpectedly: exit_code=34. Wie oft das passiert, ist allerdings unbekannt — harness.mjs gibt die Browser-stderr nur bei einer Exception oder bei RUN DIED aus, in gruenen Laeufen also nie. Solange das so ist, laesst sich gar nicht messen, ob der Absturz mit dem Fehlschlag korreliert. Wer hier weitermacht, protokolliert die stderr zuerst bei jedem Lauf.

Die Sonden dazu waren Wegwerfware und sind geloescht. Wer weitermacht, baut sie neu — beide waren duenn: die eine fuhr den echten Modul-Vorlauf und danach eine Messschleife aus Filterwechsel + __gm.textureFilter, die andere erzwang ueber WEBGL_lose_context einen Kontextverlust und mass danach dasselbe.

Warum diese Notiz trotz offener Ursache in done/ liegt

Abgelegt am 2026-09-09 auf Anweisung. Erledigt ist der Testmangel, den die Notiz beschrieb, plus das Messgeraet — die Ursache der Sporadik nicht. Faellt der Check wieder um, ist das hier der Stand: vier widerlegte Hypothesen und die einzige offene Spur (stderr zuerst protokollieren).