fix(preview): een dia-preview op een ontaarde breedte viel om (#714, foutklasse) #784

Merged
brenno merged 2 commits from fix/preview-nulbreedte-clamp into main 2026-07-23 23:06:13 +00:00
Owner

Nasleep van #714: bij het aflopen van dezelfde foutklasse bleek die ook in de
previews te zitten — daar mét een reproductie. Dit repareert de twee oorzaken
die ik kon aantonen; de rest staat als #782.

Twee oorzaken, allebei ontaarde invoer

1. clamp met een layout-constraint als bovengrens.

final availW = (outerW - padding.horizontal).clamp(1.0, outerW);

In een LayoutBuilder ís de bovengrens de constraint. Zakt die onder 1,0, dan
staat de bovengrens onder de ondergrens en gooit clamp
Invalid argument(s): 1.0 — letterlijk de melding uit #714, andere plek. Twee
zusterregels in hetzelfde bestand droegen hetzelfde patroon.

2. Een deling die NaN oplevert. bulletScaleCap deelt w door
bulletSize, en die is nul zodra de breedte nul is (alle corpsgroottes zijn een
fractie van w). 0 / 0 is NaN, die NaN reist door de fit-bisectie tot in een
TextStyle, en gaat daar af als fontSize >= 0 is not true — een melding die
nergens naar de deling wijst.

De tweede kwam pas boven toen de eerste weg was; zo werken deze lagen.

Waarom dit ertoe doet

Flutter meet een widget vaker dan hij hem tekent. Een inklappend paneel, een
rij zonder resterende ruimte, een animatie die bij nul begint — geen van die
drie is bijzonder, en alle drie leveren ze precies deze constraint.

Wat dit níét is

Een gebruikerspad hiernaartoe is niet aangetoond. Het venster heeft op
desktop een ondergrens van 1000×650 (minimumWindowSize) en de panelen hebben
hun eigen vloer (_minSlideRailWidth = 210). Dit is dus hardening met een
reproductie, geen gerapporteerde storing. De reden om het tóch te doen: de
volgende animatie of nieuwe layout breekt die aanname stilzwijgend, en de
melding wijst dan nergens naar de oorzaak — precies wat #714 was.

De toets

preview_degenerate_width_test scheidt "past niet" van "valt om". Een
overloop van een paar pixels is bij deze breedtes de juiste uitkomst — twee
kolommen passen niet in één pixel — en blijft toegestaan; een ArgumentError of
een gefaalde assertie niet. Zonder dat onderscheid zou de toets iets eisen wat de
layout niet kan leveren.

Rood gezien, per reparatie apart: de clamp terugzetten maakt 5 toetsen rood,
de NaN-guard weghalen 3.

Wat er níét in zit

Drie van de zes omvallende slidetypes hebben een ándere oorzaak — checklist en
scopeMatrix (een LinearProgressIndicator-assertie), timeline
(Infinity or NaN toInt) en cockpit (meerdere uitzonderingen). Die meenemen
zou van deze bugfix drie ongerelateerde wijzigingen maken; ze staan met
reproductiemethode in #782.

Ratchet

De methodelengte viel (153 van 150): _bulletsContent stond op main al op 148,
dus twee regels speling. Niet de uitleg ingekort en niet de basislijn opgehoogd —
de berekening staat nu als eigen functie naast _bulletsSlideShell, waar ze
inhoudelijk ook thuishoort.

Poort

make check groen (exit 0, 86,2% dekking), check-secrets en sast schoon.
Geen nieuwe l10n.d('…')-string, geen afhankelijkheidswijziging, geen zichtbare
tekst geraakt.

Refs #714. Zie #782 voor de rest.

Nasleep van #714: bij het aflopen van dezelfde foutklasse bleek die ook in de previews te zitten — daar mét een reproductie. Dit repareert de twee oorzaken die ik kon aantonen; de rest staat als #782. ## Twee oorzaken, allebei ontaarde invoer **1. `clamp` met een layout-constraint als bovengrens.** ```dart final availW = (outerW - padding.horizontal).clamp(1.0, outerW); ``` In een `LayoutBuilder` ís de bovengrens de constraint. Zakt die onder 1,0, dan staat de bovengrens onder de ondergrens en gooit `clamp` `Invalid argument(s): 1.0` — letterlijk de melding uit #714, andere plek. Twee zusterregels in hetzelfde bestand droegen hetzelfde patroon. **2. Een deling die NaN oplevert.** `bulletScaleCap` deelt `w` door `bulletSize`, en die is nul zodra de breedte nul is (alle corpsgroottes zijn een fractie van `w`). `0 / 0` is NaN, die NaN reist door de fit-bisectie tot in een `TextStyle`, en gaat daar af als `fontSize >= 0 is not true` — een melding die nergens naar de deling wijst. De tweede kwam pas boven toen de eerste weg was; zo werken deze lagen. ## Waarom dit ertoe doet Flutter **meet** een widget vaker dan hij hem tekent. Een inklappend paneel, een rij zonder resterende ruimte, een animatie die bij nul begint — geen van die drie is bijzonder, en alle drie leveren ze precies deze constraint. ## Wat dit níét is **Een gebruikerspad hiernaartoe is niet aangetoond.** Het venster heeft op desktop een ondergrens van 1000×650 (`minimumWindowSize`) en de panelen hebben hun eigen vloer (`_minSlideRailWidth = 210`). Dit is dus hardening met een reproductie, geen gerapporteerde storing. De reden om het tóch te doen: de volgende animatie of nieuwe layout breekt die aanname stilzwijgend, en de melding wijst dan nergens naar de oorzaak — precies wat #714 was. ## De toets `preview_degenerate_width_test` scheidt **"past niet"** van **"valt om"**. Een overloop van een paar pixels is bij deze breedtes de juiste uitkomst — twee kolommen passen niet in één pixel — en blijft toegestaan; een `ArgumentError` of een gefaalde assertie niet. Zonder dat onderscheid zou de toets iets eisen wat de layout niet kan leveren. **Rood gezien, per reparatie apart:** de clamp terugzetten maakt 5 toetsen rood, de NaN-guard weghalen 3. ## Wat er níét in zit Drie van de zes omvallende slidetypes hebben een ándere oorzaak — `checklist` en `scopeMatrix` (een `LinearProgressIndicator`-assertie), `timeline` (`Infinity or NaN toInt`) en `cockpit` (meerdere uitzonderingen). Die meenemen zou van deze bugfix drie ongerelateerde wijzigingen maken; ze staan met reproductiemethode in **#782**. ## Ratchet De methodelengte viel (153 van 150): `_bulletsContent` stond op main al op 148, dus twee regels speling. Niet de uitleg ingekort en niet de basislijn opgehoogd — de berekening staat nu als eigen functie naast `_bulletsSlideShell`, waar ze inhoudelijk ook thuishoort. ## Poort `make check` groen (exit 0, 86,2% dekking), `check-secrets` en `sast` schoon. Geen nieuwe `l10n.d('…')`-string, geen afhankelijkheidswijziging, geen zichtbare tekst geraakt. Refs #714. Zie #782 voor de rest.
Bij het aflopen van de clamp-foutklasse uit #714 bleek dezelfde fout in
de previews te zitten, en daar mét een reproductie.

**Twee oorzaken, allebei van ontaarde invoer.**

`(outerW - padding).clamp(1.0, outerW)` in `_bulletsSlideShell`: de
bovengrens is hier een layout-constraint, en zodra die onder 1,0 zakt
gooit clamp `Invalid argument(s): 1.0` — letterlijk de melding uit #714,
andere plek. Twee zusterregels in hetzelfde bestand hadden hetzelfde
patroon.

`bulletScaleCap` deelt door `bulletSize`, en die is nul wanneer de
breedte nul is (alle corpsgroottes zijn een fractie van w). `0 / 0` is
NaN, die NaN reist door de fit-bisectie tot in een TextStyle, en gaat
daar af als 'fontSize >= 0 is not true' — een melding die nergens naar
de deling wijst.

**Waarom dit ertoe doet:** Flutter meet een widget vaker dan hij hem
tekent. Een inklappend paneel, een rij zonder resterende ruimte of een
animatie die bij nul begint levert precies deze constraint.

**Wat dit niet is:** een gerapporteerde storing. Een gebruikerspad naar
deze breedte is in de huidige app niet aangetoond — het venster heeft
een ondergrens van 1000x650 en de panelen hebben hun eigen vloer. Dit is
hardening met een reproductie.

De toets scheidt 'past niet' van 'valt om': een overloop van een paar
pixels is bij deze breedtes de juiste uitkomst en blijft toegestaan, een
ArgumentError of gefaalde assertie niet. Rood gezien: de clamp terugzetten
maakt 5 toetsen rood, de NaN-guard weghalen 3.
refactor(preview): de breedte naast de voortgangsgrafiek als eigen functie
Some checks failed
ci / gate (pull_request) Failing after 1h31m49s
6a0b0bf47e
De methodelengte-ratchet viel (153 van 150). _bulletsContent stond op
main al op 148, dus twee regels speling — het commentaar bij de
reparatie paste er niet meer bij.

Niet de uitleg ingekort en niet de basislijn opgehoogd: de berekening
staat nu als top-level functie naast _bulletsSlideShell, waar hij ook
inhoudelijk thuishoort — het is dezelfde valkuil, twee keer.
brenno merged commit 90a37cd34b into main 2026-07-23 23:06:13 +00:00
Sign in to join this conversation.
No description provided.