perf(privacy): memoiseer de gezichtsscan per afbeelding #911

Merged
brenno merged 1 commit from fix/beeldscan-memo into main 2026-07-27 09:02:47 +00:00
Owner

Wat & waarom

Typen in een titel — en in elk ander tekstveld — werd op een deck vol beeld, zoals de proefpresentatie, onwerkbaar traag. Oorzaak: imagePrivacyRawIssuesProvider hangt aan het hele deck en draaide dus bij élke toetsaanslag opnieuw. Zonder memoisatie herlas en her-detecteerde hij dán álle deck-afbeeldingen, en countFaces (decode + YuNet op drie schalen) is een synchrone OpenCV-aanroep op de UI-thread. Elke toets startte een verse volledige scan; die stapelden op.

De tekst-privacyscan (memoizedDeckScan) en de kwaliteitsanalyse waren hier al tegen gehard met per-dia-memoisatie; alleen de gezichtsscan miste dat — terwijl het bestand zelf schrijft dat deze scan "niet in het pad hoort dat bij elke toetsaanslag draait".

Fix

Memoiseer de gezichtsscan per afbeelding op pad + mtime + grootte — dezelfde sleutel die averageImageColor al voor de contrastscan gebruikt. Een titel typen raakt geen afbeelding, dus alle scans zijn cache-treffers en de UI blijft vrij. Een gewijzigd bestand mist de sleutel en wordt opnieuw gescand: geen verouderde privacyuitslag. Valt er geen echt bestand te statten (relatief pad, web, test met neppe ImageService), dan scant hij ongecachet verder — gedrag identiek aan vóór de memo.

De scanner zit bewust níét in de sleutel: de detector is een vast ONNX-model met een const drempel, dus het getelde aantal hangt uitsluitend van de beeldpunten af.

Test

test/image_face_scan_memo_test.dart bewaakt beide kanten:

  • een titelwijziging herscant de afbeelding niet (memo-treffer);
  • een overschreven bestand wordt wél opnieuw gescand (geen stale privacyuitslag).

Poorten

  • make check: groen (hele testsuite, dekkingsvloer én per-bestand-vloer).
  • make check-secrets (gitleaks + trufflehog, werkboom + historie): schoon.
  • make sast (semgrep, 3 Dart-regels): 0 findings.
  • DAST/ZAP: niet gedraaid (niet geïnstalleerd) en hier niet van toepassing — er is geen web- of geserveerd oppervlak geraakt.

Bewaker

Overgeslagen, expliciet: raakt geen bestandsformaat, opslag, afhankelijkheid, uitgaand verkeer of publieke belofte. Puur interne caching; het detectiegedrag is ongewijzigd, en de regressietest borgt dat.

🤖 Generated with Claude Code

## Wat & waarom Typen in een titel — en in elk ander tekstveld — werd op een deck vol beeld, zoals de proefpresentatie, onwerkbaar traag. Oorzaak: `imagePrivacyRawIssuesProvider` hangt aan het hele deck en draaide dus bij élke toetsaanslag opnieuw. Zonder memoisatie herlas en her-detecteerde hij dán álle deck-afbeeldingen, en `countFaces` (decode + YuNet op drie schalen) is een synchrone OpenCV-aanroep op de UI-thread. Elke toets startte een verse volledige scan; die stapelden op. De tekst-privacyscan (`memoizedDeckScan`) en de kwaliteitsanalyse waren hier al tegen gehard met per-dia-memoisatie; alleen de gezichtsscan miste dat — terwijl het bestand zelf schrijft dat deze scan "niet in het pad hoort dat bij elke toetsaanslag draait". ## Fix Memoiseer de gezichtsscan per afbeelding op **pad + mtime + grootte** — dezelfde sleutel die `averageImageColor` al voor de contrastscan gebruikt. Een titel typen raakt geen afbeelding, dus alle scans zijn cache-treffers en de UI blijft vrij. Een gewijzigd bestand mist de sleutel en wordt opnieuw gescand: geen verouderde privacyuitslag. Valt er geen echt bestand te statten (relatief pad, web, test met neppe `ImageService`), dan scant hij ongecachet verder — gedrag identiek aan vóór de memo. De scanner zit bewust níét in de sleutel: de detector is een vast ONNX-model met een const drempel, dus het getelde aantal hangt uitsluitend van de beeldpunten af. ## Test `test/image_face_scan_memo_test.dart` bewaakt beide kanten: - een titelwijziging herscant de afbeelding niet (memo-treffer); - een overschreven bestand wordt wél opnieuw gescand (geen stale privacyuitslag). ## Poorten - `make check`: groen (hele testsuite, dekkingsvloer én per-bestand-vloer). - `make check-secrets` (gitleaks + trufflehog, werkboom + historie): schoon. - `make sast` (semgrep, 3 Dart-regels): 0 findings. - DAST/ZAP: niet gedraaid (niet geïnstalleerd) en hier niet van toepassing — er is geen web- of geserveerd oppervlak geraakt. ## Bewaker Overgeslagen, expliciet: raakt geen bestandsformaat, opslag, afhankelijkheid, uitgaand verkeer of publieke belofte. Puur interne caching; het detectiegedrag is ongewijzigd, en de regressietest borgt dat. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
perf(privacy): memoiseer de gezichtsscan per afbeelding
All checks were successful
scans / scans (pull_request) Successful in 3m31s
e35694dda4
De beeldprivacyscan (imagePrivacyRawIssuesProvider) hangt aan het hele
deck en draaide dus bij élke toetsaanslag opnieuw: hij herlas en
her-detecteerde álle deck-afbeeldingen, en countFaces is een synchrone
OpenCV-aanroep (decode + YuNet op drie schalen) op de UI-thread. Op een
deck vol beeld — zoals de proefpresentatie — werd typen daardoor
onwerkbaar traag.

Memoiseer de scan per afbeelding op pad + mtime + grootte, dezelfde
sleutel die averageImageColor al voor de contrastscan gebruikt. Een
titel typen raakt geen afbeelding, dus alle scans zijn cache-treffers en
de UI blijft vrij. Een gewijzigd bestand mist de sleutel en wordt
opnieuw gescand, dus er ontstaat geen verouderde privacyuitslag — een
regressietest bewaakt beide kanten.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brenno merged commit 77b6024b94 into main 2026-07-27 09:02:47 +00:00
Sign in to join this conversation.
No description provided.