De kop en de kop-/voetband van een document worden op contrast getoetst #1616

Merged
brenno merged 3 commits from claude/wonderful-spence-190527 into main 2026-08-20 16:46:14 +00:00
Owner

De stijlinstelling waarschuwt bij te weinig contrast, maar de reeks in SlideQualityAnalyzer somde alleen kleuren op die op een dia voorkomen: tekst, titel, tabeltekst, tabelkop, broncode en accent. De twee paren die alléén op een blad bestaan stonden er niet in:

  • documentHeadingColor tegen slideBackgroundColor — de kopkleur van een document (toegevoegd in de tak feat/documentkopkleur);
  • documentBandTextColor tegen effectiveDocumentBandBackgroundColor — de tekst van de kop- en voetband.

Daardoor kon iemand een documentstijl zetten waarvan de kop of de band onleesbaar is zonder dat de kwaliteitspoort of de instellingendialoog iets zei — terwijl élke dia-kleur wél gecontroleerd werd. Dit is de achtste route uit de memory contrast-escape-routes, en dezelfde as als de zesde (#1290, de ondertitel op 0,72 dekking): niet een kleur die je in de code opschrijft, maar een gerenderd paar dat de opsomming vergat.

Welke drempel, en waarom

De kop: grote tekst (3,0). Een # rendert op 27 beeldpunten, ruim boven de WCAG-grens. Diepere niveaus zakken naar de body-maat, maar dit ene veld is de kleur die alle niveaus delen — een strengere drempel zou een leesbare h1 afkeuren omwille van een h5 die je zelden ziet.

De band: gewone tekst (de volle drempel). document_page_chrome.dart zet kop-, voettekst en paginanummer op 12 beeldpunten, 9 in de compacte weergave.

Alleen wat de auteur zelf zette

Beide toetsen kijken uitsluitend naar een kleur die niet null is. Laat de auteur ze leeg, dan valt het documentvlak terug op textColor, accentColor en slideBackgroundColor — precies de paren die 'Thema bodytekst' en 'Thema accent' al meten, en op een stríktere drempel. Een tweede en derde melding over datzelfde paar zou alleen ruis zijn in het paneel. Een test houdt dat vast: een onleesbare textColor levert één melding, niet drie.

De waarschuwing landt bij het juiste veld

Beide velden gaan nu door _themeColorAnchor en _colorWithContrastWarning, zoals de gedeelde kleuren. Daarbij hoort een _documentOnlyThemeFields naast de bestaande lijst voor dia-kleuren: zonder die lijst opende een sprong vanuit het kwaliteitspaneel het algemene vlak, waar het veld niet staat, en leek de melding nergens heen te wijzen.

Eén analyse voor het hele documentvlak, niet één per veld — zowel de kopkleur als de bandtekst vraagt ernaar en dit vlak tekent ze allebei; elk veld zijn eigen analyse laten starten zou hem bij élke kleurbewerking dubbel laten draaien.

Meegeleverde refactor

De reeks verhuist naar een top-level _checkThemeContrast naast _addSlidePairIssue. Ze hangt aan het thema en niet aan de staat van de analyzer, en anders tripte het klasseplafond. Het plafond zakt van 1125 naar 1040 (de klasse meet 1037).

Toetsen

Nieuw test/document_contrast_test.dart (8 toetsen) plus drie in theme_profile_contrast_warning_test.dart en twee in settings_dialog_profile_test.dart.

Rood geproefd tegen de onherstelde code, met sabotage-in-plaats (geen git checkout over ongecommit werk): 4 van de 8 analyzer-toetsen vallen om zodra de twee if-takken uitstaan, en alle vier de dialoogtoetsen vallen om zodra _colorWithContrastWarning en _documentOnlyThemeFields zijn uitgeschakeld. De negatieve toetsen — geërfde kleuren melden niets dubbel — blijven in beide standen groen; dat is juist hun punt.

De grijstinten liggen bewust om de drempels heen (#999999 = 2,85:1 en #8C8C8C = 3,36:1 op wit), en een aparte toets pint die opzet vast. Zo is per geval aantoonbaar wélk paar de bindende beperking is, in plaats van bijvangst van een profiel dat toch al zou waarschuwen.

l10n

Twee nieuwe labels — 'Thema documentkop' en 'Thema documentband' — via make add-l10n in alle 31 niet-Nederlandse talen. make l10n-check groen.

Poorten

make check groen na de rebase op de huidige main: 10.238 tests, dekking 87,2%, per-bestand-vloer 0. make check-secrets (gitleaks over 3.272 commits + trufflehog over werkboom én historie): geen bevindingen. make sast (semgrep, 4 Dart-regels over 1.147 bestanden): 0 findings. DAST (ZAP) niet gedraaid — deze wijziging raakt het geserveerde weboppervlak niet.

Bewaker: overgeslagen, met reden. Geen bestandsformaat, geen opslag, geen afhankelijkheid, geen uitgaand verkeer. De wijziging raakt wél een gedocumenteerde belofte — de contrasttabel in de gebruikershandleiding — maar alleen door een bestaande WCAG-AA-claim waar te maken op een vlak waar hij stil niet gold. Een toegankelijkheidsgarantie laten kloppen met wat de code doet, is niet het soort belofte dat een weging vraagt.

Wat ik vond maar niet heb gebouwd

De band tekent links met linkColor: accentColor (document_page_chrome.dart:80), en de accentlijn onder de kopband staat op diezelfde bandachtergrond. accentColor tegen effectiveDocumentBandBackgroundColor is dus een derde ongemeten paar van dezelfde familie — echt, maar smal: het treedt alleen op bij een kop- of voettekst met een Markdown-link. Een derde label kost opnieuw 31 vertalingen, en deze PR was op twee paren afgebakend. Los op te pakken.

Niet met eigen ogen nagekeken. Er is geen visuele ronde gedaan: deze wijziging voegt een melding toe aan bestaande, al beproefde bedrading (_colorWithContrastWarning tekent al de waarschuwing onder zes andere kleuren) en verandert niets aan hoe een document of dia rendert. De widgettoetsen openen het echte dialoogvenster op het documentvlak en lezen de waarschuwingstekst en de ratio terug.

De stijlinstelling waarschuwt bij te weinig contrast, maar de reeks in `SlideQualityAnalyzer` somde alleen kleuren op die op een **dia** voorkomen: tekst, titel, tabeltekst, tabelkop, broncode en accent. De twee paren die alléén op een **blad** bestaan stonden er niet in: - `documentHeadingColor` tegen `slideBackgroundColor` — de kopkleur van een document (toegevoegd in de tak feat/documentkopkleur); - `documentBandTextColor` tegen `effectiveDocumentBandBackgroundColor` — de tekst van de kop- en voetband. Daardoor kon iemand een documentstijl zetten waarvan de kop of de band onleesbaar is zonder dat de kwaliteitspoort of de instellingendialoog iets zei — terwijl élke dia-kleur wél gecontroleerd werd. Dit is de achtste route uit de memory `contrast-escape-routes`, en dezelfde as als de zesde (#1290, de ondertitel op 0,72 dekking): niet een kleur die je in de *code* opschrijft, maar een gerenderd paar dat de opsomming vergat. ## Welke drempel, en waarom **De kop: grote tekst (3,0).** Een `#` rendert op 27 beeldpunten, ruim boven de WCAG-grens. Diepere niveaus zakken naar de body-maat, maar dit ene veld is de kleur die *alle* niveaus delen — een strengere drempel zou een leesbare h1 afkeuren omwille van een h5 die je zelden ziet. **De band: gewone tekst (de volle drempel).** `document_page_chrome.dart` zet kop-, voettekst en paginanummer op 12 beeldpunten, 9 in de compacte weergave. ## Alleen wat de auteur zelf zette Beide toetsen kijken uitsluitend naar een kleur die niet `null` is. Laat de auteur ze leeg, dan valt het documentvlak terug op `textColor`, `accentColor` en `slideBackgroundColor` — precies de paren die 'Thema bodytekst' en 'Thema accent' al meten, en op een *stríktere* drempel. Een tweede en derde melding over datzelfde paar zou alleen ruis zijn in het paneel. Een test houdt dat vast: een onleesbare `textColor` levert één melding, niet drie. ## De waarschuwing landt bij het juiste veld Beide velden gaan nu door `_themeColorAnchor` en `_colorWithContrastWarning`, zoals de gedeelde kleuren. Daarbij hoort een `_documentOnlyThemeFields` naast de bestaande lijst voor dia-kleuren: zonder die lijst opende een sprong vanuit het kwaliteitspaneel het *algemene* vlak, waar het veld niet staat, en leek de melding nergens heen te wijzen. Eén analyse voor het hele documentvlak, niet één per veld — zowel de kopkleur als de bandtekst vraagt ernaar en dit vlak tekent ze allebei; elk veld zijn eigen analyse laten starten zou hem bij élke kleurbewerking dubbel laten draaien. ## Meegeleverde refactor De reeks verhuist naar een top-level `_checkThemeContrast` naast `_addSlidePairIssue`. Ze hangt aan het thema en niet aan de staat van de analyzer, en anders tripte het klasseplafond. Het plafond zakt van 1125 naar 1040 (de klasse meet 1037). ## Toetsen Nieuw `test/document_contrast_test.dart` (8 toetsen) plus drie in `theme_profile_contrast_warning_test.dart` en twee in `settings_dialog_profile_test.dart`. **Rood geproefd tegen de onherstelde code**, met sabotage-in-plaats (geen `git checkout` over ongecommit werk): 4 van de 8 analyzer-toetsen vallen om zodra de twee `if`-takken uitstaan, en alle vier de dialoogtoetsen vallen om zodra `_colorWithContrastWarning` en `_documentOnlyThemeFields` zijn uitgeschakeld. De negatieve toetsen — geërfde kleuren melden niets dubbel — blijven in beide standen groen; dat is juist hun punt. De grijstinten liggen bewust om de drempels heen (`#999999` = 2,85:1 en `#8C8C8C` = 3,36:1 op wit), en een aparte toets pint die opzet vast. Zo is per geval aantoonbaar wélk paar de bindende beperking is, in plaats van bijvangst van een profiel dat toch al zou waarschuwen. ## l10n Twee nieuwe labels — 'Thema documentkop' en 'Thema documentband' — via `make add-l10n` in alle 31 niet-Nederlandse talen. `make l10n-check` groen. ## Poorten `make check` groen na de rebase op de huidige main: 10.238 tests, dekking 87,2%, per-bestand-vloer 0. `make check-secrets` (gitleaks over 3.272 commits + trufflehog over werkboom én historie): geen bevindingen. `make sast` (semgrep, 4 Dart-regels over 1.147 bestanden): 0 findings. **DAST (ZAP) niet gedraaid** — deze wijziging raakt het geserveerde weboppervlak niet. **Bewaker: overgeslagen, met reden.** Geen bestandsformaat, geen opslag, geen afhankelijkheid, geen uitgaand verkeer. De wijziging raakt wél een gedocumenteerde belofte — de contrasttabel in de gebruikershandleiding — maar alleen door een bestaande WCAG-AA-claim waar te maken op een vlak waar hij stil niet gold. Een toegankelijkheidsgarantie laten kloppen met wat de code doet, is niet het soort belofte dat een weging vraagt. ## Wat ik vond maar niet heb gebouwd De band tekent links met `linkColor: accentColor` ([`document_page_chrome.dart:80`](https://pawprint.vigilis.online/LibreKAT/Ocideck/src/branch/main/lib/widgets/document_page_chrome.dart#L80)), en de accentlijn onder de kopband staat op diezelfde bandachtergrond. `accentColor` tegen `effectiveDocumentBandBackgroundColor` is dus een **derde** ongemeten paar van dezelfde familie — echt, maar smal: het treedt alleen op bij een kop- of voettekst met een Markdown-link. Een derde label kost opnieuw 31 vertalingen, en deze PR was op twee paren afgebakend. Los op te pakken. **Niet met eigen ogen nagekeken.** Er is geen visuele ronde gedaan: deze wijziging voegt een melding toe aan bestaande, al beproefde bedrading (`_colorWithContrastWarning` tekent al de waarschuwing onder zes andere kleuren) en verandert niets aan hoe een document of dia rendert. De widgettoetsen openen het echte dialoogvenster op het documentvlak en lezen de waarschuwingstekst en de ratio terug.
De thema-contrastreeks somde op wat op een *dia* voorkomt: tekst, titel,
tabeltekst, tabelkop, broncode, accent. De twee paren die alléén op een
blad bestaan stonden er niet in — de kopkleur van een document tegen het
papier, en de tekst van de kop- en voetband tegen die band. Wie zo'n
kleur onleesbaar zette kreeg dus niets te horen, terwijl élke dia-kleur
wél gemeten werd.

De kop krijgt de WCAG-drempel voor grote tekst: een `#` rendert op 27
beeldpunten, ruim boven de grens. Diepere niveaus zakken naar de
body-maat, maar dit ene veld is de kleur die álle niveaus delen — een
strengere drempel zou een leesbare h1 afkeuren om een h5 die je zelden
ziet. De band krijgt de volle drempel: hij zet zijn tekst op twaalf
beeldpunten, negen in de compacte weergave.

Beide tellen alleen wanneer de auteur de kleur zélf zette. Laat hij ze
leeg, dan valt het documentvlak terug op `textColor`, `accentColor` en
`slideBackgroundColor` — precies de paren die 'Thema bodytekst' en
'Thema accent' al meten, en op een stríktere drempel. Een tweede melding
over datzelfde paar zou alleen ruis zijn in het paneel, en de test houdt
dat vast: één melding, geen drie.

De reeks verhuist naar een top-level functie naast `_addSlidePairIssue`.
Ze hangt aan het thema en niet aan de staat van de analyzer, en anders
tripte het klasseplafond. Het plafond gaat daarmee van 1125 naar 1040.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
De stijlinstelling toont onder een kleur een waarschuwing zodra de
analyzer haar zou afkeuren. De twee kleuren van het documentvlak hingen
buiten die bedrading: geen streepje eronder, en een sprong vanuit het
kwaliteitspaneel opende het algemene vlak, waar het veld niet staat — de
melding leek dan nergens heen te wijzen.

Allebei nu in `_themeColorAnchor` en `_colorWithContrastWarning`, met een
`_documentOnlyThemeFields` naast de bestaande lijst voor dia-kleuren.

Eén analyse voor het hele vlak, niet één per veld. Zowel de kopkleur als
de bandtekst vraagt ernaar en dit vlak tekent ze allebei; elk veld zijn
eigen analyse laten starten zou hem bij élke kleurbewerking dubbel laten
draaien.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
docs(kwaliteit): de twee documentparen staan in de gids en de bronkaart
All checks were successful
scans / scans (pull_request) Successful in 3m35s
static-gate / static-gate (pull_request) Successful in 7m28s
e3c23386c5
De contrasttabel in de gebruikershandleiding somde de gemeten paren op
en miste dus dezelfde twee; de zin over de inline waarschuwing beloofde
haar bovendien alleen "voor een presentatie".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
brenno merged commit 122e67a753 into main 2026-08-20 16:46:14 +00:00
Sign in to join this conversation.
No description provided.