Finding-header rendert te groot: geen inhoud-bewuste auto-fit (kan op ~50%) #1282

Closed
opened 2026-08-05 19:02:04 +00:00 by brenno · 2 comments
Owner

Symptoom

Een finding-slide met ocideck_finding_role: header rendert de inhoud véél te groot.
De kop met alle informatie (titel, Scope object, CVSS 4.0-vector, CWE-link, Test,
Retest, en de secties Description / Confirmation / Possible impact / Recommendation)
past ruimschoots op ~50% van de huidige grootte en zou dan prima leesbaar én compleet
zijn. Nu is de tekst onnodig groot.

Reproductie (Proefpresentatie.md, slide 29 "F-01 · Slim kattenluik met
ingebakken sleutel"): open de header-slide in preview/presenteren.

Oorzaak (bestand:regel) — hypothese (a): geen auto-fit

De tekstgroottes zijn vast en w-relatief × één constante — er is geen krimpstap
die naar de inhoud meet:

  • lib/widgets/slides/previews/finding_preview.dart:12
    const double _findingFontScale = 0.84; (de enige globale knop).
  • Elke fontgrootte is w * <fractie> * _findingFontScale, hard: kop w*0.038 (:159),
    scope w*0.024 (:182), CVSS-score w*0.052 (:258), badges w*0.024 (:438),
    body w*0.024 (:504), sectiekop w*0.03 (:505).
  • De enige schaling is de gedeelde scaffold:
    lib/widgets/slides/previews/preview_scaffold.dart:88
    FittedBox(fit: BoxFit.scaleDown, alignment: topLeft). scaleDown krimpt alleen,
    vergroot nooit
    .
  • Paginering (lib/services/finding_pagination.dart)
    bestaat juist om die scaleDown te vermíjden door te splitsen; de vloer
    _minSinglePageScale = 0.70 (:158) houdt een finding enkel-pagina zolang hij ≥0,70
    breedte rendert, anders splitsen.

Gevolg: de gerenderde grootte is in de praktijk de vaste natuurlijke grootte, en
die is voor een dichte pentest-header ~2× te groot. Precies de meet-en-schaal-stap die
de gebruiker wil (naar ~0,5, mét bovengrens) ontbreekt. Bullets hébben die stap wél
(bulletsSlideFitScale,
lib/services/slide_layout_metrics.dart:370,
met maxScale-bovengrens); findings kregen hem nooit.

Wat "50%" is: geen fout gezette constante — de krimpstap ontbreekt.
_findingFontScale = 0.84 staat ~2× te hoog voor een dichte header (zou rond ~0,42 =
0,84×~0,5 goed lezen). Erger: de vloer _minSinglePageScale = 0.70 maakt ~50% zelfs
onbereikbaar — ook het vangnet (scaleDown) is via paginering op 0,70 begrensd.

Waarom het niét het kostenmodel (#1198) is

Hypothese (b) — het pagineringskostenmodel onderschat de renderhoogte — is een andere
bug en wijst de verkeerde kant op. Het onderschatten zit in de body/sectie-kost
(_charsPerLine = 47 :149, _bodyCost :161, _linesPerSlide = 23 :58).
Onderschatten → te veel op één pagina → pagina hoger dan de dia → scaleDown krimpt
richting de 0,70-vloer → kleiner/smaller, het tegenovergestelde van "te groot".
Belangrijk bewijs: de header-kost is aan een echte render gepind
(test/finding_header_cost_test.dart), maar de
body-kost is door géén enkele echte-render-test gepind — de pagineringstests toetsen
alleen paginatellingen/sectieverdeling. Dat is exact de "schatting die stil wegrot"-situatie.

Voorgestelde oplossing

Geef de header een echte gemeten auto-fit mét bovengrens, naar het bullets-model:

  1. Nieuwe top-level functie (bv. findingHeaderFitScale(...) in
    slide_layout_metrics.dart, náást bulletsSlideFitScale:370) die de pagina-inhoud
    (header-card + de secties van díe pagina) met TextPainter tegen de beschikbare
    dia-hoogte/breedte meet en een schaal in (0, maxScale] teruggeeft (maxScale =
    bovengrens, zodat een schaarse header niet opblaast).
  2. Toepassen in _FindingPreview: vermenigvuldig de vaste groottes met die schaal
    (_findingFontScale * fitScale). Let op: fitScaleOverride bestaat al op
    SlidePreviewWidget (slide_preview.dart:472)
    maar wordt niet aan _FindingPreview doorgegeven (:945) en _PreviewScaffold
    negeert het (hardcoded scaleDown) — dus of die keten uitbreiden, of de schaal binnen
    _FindingPreview berekenen.
  3. Meet op de gepagineerde inhoud (na firstRenderPageSpec/expandFindingsForRender),
    niet op de rauwe slide, zodat een finding die legitiem over 2 dia's gaat blijft
    splitsen en niet stil wordt afgekapt. Verlaag je de vloer _minSinglePageScale, dan
    moet je de gekoppelde body-begroting (_linesPerSlide/_charsPerLine)
    mee-herijken, anders verschuift stil hoeveel findings pagineren.
  4. Anker de body-kost (#1198) op dezelfde echte meting, zodat model en render niet meer
    uiteenlopen.

Kleinste veilige vorm: paginering behouden voor écht lange findings, maar de
auto-fit/lagere vloer laten toe dat een louter-dichte header op ~0,5 op één dia krimpt
i.p.v. te groot te blijven.

Regressietest (eerst rood)

Sjabloon: test/finding_header_cost_test.dart
rendert SlidePreviewWidget op vast oppervlak en meet een keyed subtree met
tester.getSize. Nieuw:

  • Render de dichte F-01-header (volledige meta + 4 secties); meet de werkelijke
    gerenderde hoogte (via finding-header-card-key / de content-hoogte in de FittedBox,
    zoals renderWidthFraction in
    test/finding_preview_test.dart:242).
  • Voeg de ontbrekende bovengrens toe: inhoud past binnen de dia (onderkant ≤
    dia-onderkant) én rendert op ~doelschaal (bv. schaal ≤ ~0,55 / frac in een band),
    niet alleen > 0.70 (de bestaande test toetst enkel de ondergrens). Met de huidige
    vaste 0,84 faalt dit = eerst-rood; na de auto-fit groen.
  • Pin óók de body/sectie-kost tegen een echte render (nu alleen de header gepind), zodat
    _charsPerLine/_linesPerSlide niet stil wegrotten.
  • Behoud een "paginering-niet-gebroken"-test: lange finding blijft >1 pagina en verliest
    geen sectie (finding_pagination_test.dart:79 dekt de sectiestroom al).
  • Ronde afsluiten met visuele controle (skill beeldkeuring).

Geraakte poorten / ketens

  • Klasseplafond (≤150 regels/methode) + top-level helper: zet de fit-functie
    top-level in dezelfde library (zoals bulletsSlideFitScale), niet als methode op
    _FindingPreview.
  • File-size ratchet (≤1000 → part): finding_preview.dart 509 regels,
    finding_pagination.dart 365 — ruimte genoeg; slide_layout_metrics.dart checken.
  • Dekkingspoort: nieuwe functie/branches moeten in een test voorkomen.
  • l10n: pure layout → geen zichtbare tekst → geen 31 vertalingen; alléén bij een
    nieuw label/tooltip make add-l10n.
  • Calibratie-poorten schuiven mee: finding_header_cost_test.dart en de
    paginatellingen in finding_pagination_test.dart zijn de ijkpunten en worden bij
    herijking van de begroting rood — in dezelfde PR bijwerken.

Open vragen voor de bouwer

  • Richting bevestigen op de echte render (beeldkeuring): staat de demo-F-01 op volle
    natuurlijke grootte (niet-overlopende pagina) of oogt hij tegen de 0,70-vloer juist
    krap? Dat bepaalt of pure schaalverlaging volstaat of dat de begroting mee moet.
  • Scope: alleen header-rol? _FindingPreview bedient header én continuation;
    detail/evidence routeren óók naar _FindingPreview (slide_preview.dart:945 sleutelt
    op SlideType.finding, niet op rol). Continuation-kop is al half zo groot
    (finding_preview.dart:116) — waarschijnlijk oké, maar detail/evidence nalopen.
  • Zusterslides met hetzelfde patroon: findingsSummary, scopeMatrix, checklist,
    controlStatus, signOff gebruiken óók _PreviewScaffold + vaste groottes en zitten
    niet in de dichtheids/overflow-dekking van de kwaliteitsanalyzer. Overweeg of de fix
    breder moet (mogelijk aparte bevinding).
  • Productkeuze: "hele finding op één dia op ~50%" (dan wordt paginering voor typische
    findings bijna overbodig) versus "paginering behouden, alleen niet meer te groot". De
    opdracht zegt paginering niet breken — leg dit bij de product-owner neer.
## Symptoom Een finding-slide met `ocideck_finding_role: header` rendert de inhoud véél te groot. De kop met alle informatie (titel, Scope object, CVSS 4.0-vector, CWE-link, Test, Retest, en de secties Description / Confirmation / Possible impact / Recommendation) past ruimschoots op ~50% van de huidige grootte en zou dan prima leesbaar én compleet zijn. Nu is de tekst onnodig groot. **Reproductie** (`Proefpresentatie.md`, slide 29 "F-01 · Slim kattenluik met ingebakken sleutel"): open de header-slide in preview/presenteren. ## Oorzaak (bestand:regel) — hypothese (a): geen auto-fit De tekstgroottes zijn vast en `w`-relatief × één constante — er is **geen** krimpstap die naar de inhoud meet: - [lib/widgets/slides/previews/finding_preview.dart:12](lib/widgets/slides/previews/finding_preview.dart) — `const double _findingFontScale = 0.84;` (de enige globale knop). - Elke fontgrootte is `w * <fractie> * _findingFontScale`, hard: kop `w*0.038` (`:159`), scope `w*0.024` (`:182`), CVSS-score `w*0.052` (`:258`), badges `w*0.024` (`:438`), body `w*0.024` (`:504`), sectiekop `w*0.03` (`:505`). - De enige schaling is de gedeelde scaffold: [lib/widgets/slides/previews/preview_scaffold.dart:88](lib/widgets/slides/previews/preview_scaffold.dart) → `FittedBox(fit: BoxFit.scaleDown, alignment: topLeft)`. `scaleDown` **krimpt alleen, vergroot nooit**. - Paginering ([lib/services/finding_pagination.dart](lib/services/finding_pagination.dart)) bestaat juist om die scaleDown te vermíjden door te splitsen; de vloer `_minSinglePageScale = 0.70` (`:158`) houdt een finding enkel-pagina zolang hij ≥0,70 breedte rendert, anders splitsen. **Gevolg:** de gerenderde grootte is in de praktijk de vaste natuurlijke grootte, en die is voor een dichte pentest-header ~2× te groot. Precies de meet-en-schaal-stap die de gebruiker wil (naar ~0,5, mét bovengrens) ontbreekt. Bullets hébben die stap wél (`bulletsSlideFitScale`, [lib/services/slide_layout_metrics.dart:370](lib/services/slide_layout_metrics.dart), met `maxScale`-bovengrens); findings kregen hem nooit. **Wat "50%" is:** geen fout gezette constante — de **krimpstap ontbreekt**. `_findingFontScale = 0.84` staat ~2× te hoog voor een dichte header (zou rond ~0,42 = 0,84×~0,5 goed lezen). Erger: de vloer `_minSinglePageScale = 0.70` maakt ~50% zelfs **onbereikbaar** — ook het vangnet (scaleDown) is via paginering op 0,70 begrensd. ## Waarom het niét het kostenmodel (#1198) is Hypothese (b) — het pagineringskostenmodel onderschat de renderhoogte — is een **andere** bug en wijst de verkeerde kant op. Het onderschatten zit in de **body/sectie**-kost (`_charsPerLine = 47` `:149`, `_bodyCost` `:161`, `_linesPerSlide = 23` `:58`). Onderschatten → te veel op één pagina → pagina hoger dan de dia → scaleDown krimpt richting de 0,70-vloer → **kleiner/smaller**, het tegenovergestelde van "te groot". Belangrijk bewijs: de **header**-kost is aan een echte render gepind ([test/finding_header_cost_test.dart](test/finding_header_cost_test.dart)), maar de **body**-kost is door géén enkele echte-render-test gepind — de pagineringstests toetsen alleen paginatellingen/sectieverdeling. Dat is exact de "schatting die stil wegrot"-situatie. ## Voorgestelde oplossing Geef de header een echte gemeten auto-fit mét bovengrens, naar het bullets-model: 1. Nieuwe **top-level** functie (bv. `findingHeaderFitScale(...)` in `slide_layout_metrics.dart`, náást `bulletsSlideFitScale:370`) die de pagina-inhoud (header-card + de secties van díe pagina) met `TextPainter` tegen de beschikbare dia-hoogte/breedte meet en een schaal in `(0, maxScale]` teruggeeft (`maxScale` = bovengrens, zodat een schaarse header niet opblaast). 2. Toepassen in `_FindingPreview`: vermenigvuldig de vaste groottes met die schaal (`_findingFontScale * fitScale`). Let op: `fitScaleOverride` bestaat al op `SlidePreviewWidget` ([slide_preview.dart:472](lib/widgets/slides/slide_preview.dart)) maar wordt **niet** aan `_FindingPreview` doorgegeven (`:945`) en `_PreviewScaffold` negeert het (hardcoded scaleDown) — dus of die keten uitbreiden, of de schaal binnen `_FindingPreview` berekenen. 3. Meet op de **gepagineerde** inhoud (na `firstRenderPageSpec`/`expandFindingsForRender`), niet op de rauwe slide, zodat een finding die legitiem over 2 dia's gaat blijft splitsen en niet stil wordt afgekapt. Verlaag je de vloer `_minSinglePageScale`, dan **moet** je de gekoppelde body-begroting (`_linesPerSlide`/`_charsPerLine`) mee-herijken, anders verschuift stil hoeveel findings pagineren. 4. Anker de body-kost (#1198) op dezelfde echte meting, zodat model en render niet meer uiteenlopen. Kleinste veilige vorm: paginering behouden voor écht lange findings, maar de auto-fit/lagere vloer laten toe dat een louter-dichte header op ~0,5 op één dia krimpt i.p.v. te groot te blijven. ## Regressietest (eerst rood) Sjabloon: [test/finding_header_cost_test.dart](test/finding_header_cost_test.dart) rendert `SlidePreviewWidget` op vast oppervlak en meet een keyed subtree met `tester.getSize`. Nieuw: - Render de dichte F-01-header (volledige meta + 4 secties); meet de werkelijke gerenderde hoogte (via `finding-header-card`-key / de content-hoogte in de `FittedBox`, zoals `renderWidthFraction` in [test/finding_preview_test.dart:242](test/finding_preview_test.dart)). - Voeg de **ontbrekende bovengrens** toe: inhoud past binnen de dia (onderkant ≤ dia-onderkant) **én** rendert op ~doelschaal (bv. schaal ≤ ~0,55 / frac in een band), niet alleen `> 0.70` (de bestaande test toetst enkel de ondergrens). Met de huidige vaste 0,84 faalt dit = eerst-rood; na de auto-fit groen. - Pin óók de body/sectie-kost tegen een echte render (nu alleen de header gepind), zodat `_charsPerLine`/`_linesPerSlide` niet stil wegrotten. - Behoud een "paginering-niet-gebroken"-test: lange finding blijft >1 pagina en verliest geen sectie (`finding_pagination_test.dart:79` dekt de sectiestroom al). - Ronde afsluiten met visuele controle (skill `beeldkeuring`). ## Geraakte poorten / ketens - **Klasseplafond (≤150 regels/methode) + top-level helper:** zet de fit-functie top-level in dezelfde library (zoals `bulletsSlideFitScale`), niet als methode op `_FindingPreview`. - **File-size ratchet (≤1000 → `part`):** `finding_preview.dart` 509 regels, `finding_pagination.dart` 365 — ruimte genoeg; `slide_layout_metrics.dart` checken. - **Dekkingspoort:** nieuwe functie/branches moeten in een test voorkomen. - **l10n:** pure layout → geen zichtbare tekst → geen 31 vertalingen; alléén bij een nieuw label/tooltip `make add-l10n`. - **Calibratie-poorten schuiven mee:** `finding_header_cost_test.dart` en de paginatellingen in `finding_pagination_test.dart` zijn de ijkpunten en worden bij herijking van de begroting rood — in dezelfde PR bijwerken. ## Open vragen voor de bouwer - **Richting bevestigen op de echte render** (beeldkeuring): staat de demo-F-01 op volle natuurlijke grootte (niet-overlopende pagina) of oogt hij tegen de 0,70-vloer juist krap? Dat bepaalt of pure schaalverlaging volstaat of dat de begroting mee moet. - **Scope: alleen header-rol?** `_FindingPreview` bedient header én continuation; detail/evidence routeren óók naar `_FindingPreview` (`slide_preview.dart:945` sleutelt op `SlideType.finding`, niet op rol). Continuation-kop is al half zo groot (`finding_preview.dart:116`) — waarschijnlijk oké, maar detail/evidence nalopen. - **Zusterslides met hetzelfde patroon:** `findingsSummary`, `scopeMatrix`, `checklist`, `controlStatus`, `signOff` gebruiken óók `_PreviewScaffold` + vaste groottes en zitten niet in de dichtheids/overflow-dekking van de kwaliteitsanalyzer. Overweeg of de fix breder moet (mogelijk aparte bevinding). - **Productkeuze:** "hele finding op één dia op ~50%" (dan wordt paginering voor typische findings bijna overbodig) versus "paginering behouden, alleen niet meer te groot". De opdracht zegt paginering niet breken — leg dit bij de product-owner neer.
Author
Owner

Opgepakt. Tak: fix/1282-finding-header-autofit. Reikwijdte: inhoud-bewuste auto-fit met bovengrens voor de finding-header (finding_preview.dart + een top-level fit-helper in slide_layout_metrics.dart), paginering behouden. NB: #1163 zette al de vaste _findingFontScale=0.84 op main; dit maakt het inhoud-afhankelijk. Body-kostenmodel blijft #1198.

Opgepakt. Tak: fix/1282-finding-header-autofit. Reikwijdte: inhoud-bewuste auto-fit met bovengrens voor de finding-header (finding_preview.dart + een top-level fit-helper in slide_layout_metrics.dart), paginering behouden. NB: #1163 zette al de vaste _findingFontScale=0.84 op main; dit maakt het inhoud-afhankelijk. Body-kostenmodel blijft #1198.
Author
Owner

Opgelost op main (squash van PR #1288). Inhoud-bewuste auto-fit findingHeaderFitScale (nieuw bestand lib/services/finding_header_metrics.dart) meet de gepagineerde header-inhoud en krimpt de vaste 0.84-schaal tot hij past, met bovengrens; paginering intact (#1147/#1198 groen). Eerst-rood geverifieerd; beeldkeuring: past, heel en leesbaar op scherm-oppervlakken + donker thema. NB voor de bouwlus: de agent strandde en de recovery vergde twee poort-fixes (file-split onder de 1000-regelgrens + SOURCE_MAP-registratie van het nieuwe bestand).

Opgelost op main (squash van PR #1288). Inhoud-bewuste auto-fit findingHeaderFitScale (nieuw bestand lib/services/finding_header_metrics.dart) meet de gepagineerde header-inhoud en krimpt de vaste 0.84-schaal tot hij past, met bovengrens; paginering intact (#1147/#1198 groen). Eerst-rood geverifieerd; beeldkeuring: past, heel en leesbaar op scherm-oppervlakken + donker thema. NB voor de bouwlus: de agent strandde en de recovery vergde twee poort-fixes (file-split onder de 1000-regelgrens + SOURCE_MAP-registratie van het nieuwe bestand).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#1282
No description provided.