fix: laat redactie de ingestelde landenpakketten volgen #529

Merged
brenno merged 2 commits from fix/redactie-regios into main 2026-07-22 10:39:48 +00:00
Owner

Summary

PrivacyProjection._project built its own PrivacyScanner without regions:, falling back to defaultPrivacyRegions, while privacy_provider.dart passed the configured set. Turn a country pack off and you got black boxes over values OciWacht never reported — so the quality panel no longer predicted what the export would contain, which is exactly what the user reads it for.

Closes #512

Direction of the bug

Over-redaction, not a leak: allPrivacyRegions == defaultPrivacyRegions today, so only "pack turned off" is reachable. Worth saying plainly — this was a trust and consistency defect, not an exposure.

Wider than the issue described

The issue named _project. Two more scanners were built the same way and would have kept the disagreement alive, just moved:

  • redaction_manifest_service.dart:130 — the manifest of what was redacted. This is the sharpest one: an entry for a block that is not in the export sends the recipient looking for a redaction that does not exist, undermining the very trust the manifest exists to establish.
  • app_shell_main_layout.dart:811 — the export-gate summary.

All five forAudience call sites now pass settings.privacyRegions.

Two deliberate boundaries

The default stays defaultPrivacyRegions, not const {}. A caller who forgets must redact more, not less. Fail-closed, matching the reasoning already written on _project.

forExternalProcessing deliberately takes no regions parameter. Someone switching off the Dutch pack because it fires too often in their deck is making a statement about their own quality panel and their own export — not granting permission to send a BSN to a third party's model. Same reasoning the file already applies to disposition: stricter, because data that leaves the device cannot be recalled. The decision is pinned by a test with the reasoning attached, so a future regions: there has to argue its case first.

Verification

test/privacy_region_projection_parity_test.dart, red first (the parameter did not exist). Four assertions, two of them calibration: without checking that the scanner does report the BSN with the pack on and does not with it off, the real assertion could sit green because detection itself broke. A fourth pins that the universal layer — IBAN, e-mail, passport — keeps redacting under regions: {}, so this fix cannot become a leak.

Gates

make check green (86.2%). make check-secrets / make sast still red for the pre-existing reasons in #522 and #521.

Principles

Touches the privacy boundary, which is the one place where getting it wrong is not recoverable. Weighed and recorded above: the fix moves towards what the user was told, the two asymmetries (fail-closed default, stricter external route) are deliberate, and the universal rules were explicitly re-tested rather than assumed.

## Summary `PrivacyProjection._project` built its own `PrivacyScanner` **without** `regions:`, falling back to `defaultPrivacyRegions`, while `privacy_provider.dart` passed the configured set. Turn a country pack off and you got black boxes over values OciWacht never reported — so the quality panel no longer predicted what the export would contain, which is exactly what the user reads it for. Closes #512 ## Direction of the bug Over-redaction, not a leak: `allPrivacyRegions == defaultPrivacyRegions` today, so only "pack turned off" is reachable. Worth saying plainly — this was a trust and consistency defect, not an exposure. ## Wider than the issue described The issue named `_project`. Two more scanners were built the same way and would have kept the disagreement alive, just moved: - `redaction_manifest_service.dart:130` — the manifest of what was redacted. This is the sharpest one: an entry for a block that is not in the export sends the recipient looking for a redaction that does not exist, undermining the very trust the manifest exists to establish. - `app_shell_main_layout.dart:811` — the export-gate summary. All five `forAudience` call sites now pass `settings.privacyRegions`. ## Two deliberate boundaries **The default stays `defaultPrivacyRegions`, not `const {}`.** A caller who forgets must redact *more*, not less. Fail-closed, matching the reasoning already written on `_project`. **`forExternalProcessing` deliberately takes no `regions` parameter.** Someone switching off the Dutch pack because it fires too often in their deck is making a statement about their own quality panel and their own export — not granting permission to send a BSN to a third party's model. Same reasoning the file already applies to disposition: stricter, because data that leaves the device cannot be recalled. The decision is pinned by a test with the reasoning attached, so a future `regions:` there has to argue its case first. ## Verification `test/privacy_region_projection_parity_test.dart`, red first (the parameter did not exist). Four assertions, two of them calibration: without checking that the scanner *does* report the BSN with the pack on and *does not* with it off, the real assertion could sit green because detection itself broke. A fourth pins that the universal layer — IBAN, e-mail, passport — keeps redacting under `regions: {}`, so this fix cannot become a leak. ## Gates `make check` green (86.2%). `make check-secrets` / `make sast` still red for the pre-existing reasons in #522 and #521. ## Principles Touches the privacy boundary, which is the one place where getting it wrong is not recoverable. Weighed and recorded above: the fix moves *towards* what the user was told, the two asymmetries (fail-closed default, stricter external route) are deliberate, and the universal rules were explicitly re-tested rather than assumed.
Dezelfde vorm als privacy_scan_redact_parity_test, één laag hoger: daar
liepen de velden uiteen tussen scannen en redigeren, hier de regels.

Vier assertions, waarvan twee ijkpunten: zonder de controle dat de scanner
het BSN mét het pakket wél en zónder het pakket níet meldt, kan de
eigenlijke test groen staan doordat de detectie zelf stuk is.

Staat bewust rood: forAudience kent nog geen regions-parameter.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fix(privacy): laat redactie de ingestelde landenpakketten volgen
Some checks failed
CI / Gate (Linux) · Format · Analyze · Coverage (pull_request) Has been cancelled
CI / Test (macos-latest) (pull_request) Has been cancelled
CI / Test (windows-latest) (pull_request) Has been cancelled
CI / Web hardening (pull_request) Has been cancelled
CI / Docs links (pull_request) Has been cancelled
CI / Supply-chain (Trivy · advisory) (pull_request) Has been cancelled
CI / Gate (Linux) · Format · Analyze · Coverage (push) Has been cancelled
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Web hardening (push) Has been cancelled
CI / Docs links (push) Has been cancelled
CI / Supply-chain (Trivy · advisory) (push) Has been cancelled
562913f881
PrivacyProjection._project bouwde zijn eigen scanner zonder regions en
viel terug op defaultPrivacyRegions, terwijl privacy_provider de
ingestelde pakketten wél doorgaf. Wie een land uitzette kreeg zwarte
blokken over waarden die nooit gemeld waren: het kwaliteitspaneel
voorspelde niet meer wat er in de export zou staan.

Doorgegeven langs de hele keten — projectie, redactiemanifest en de
exportsamenvatting. Het manifest is daarbij het scherpst: een entry voor
een blok dat niet in de export staat laat de ontvanger zoeken naar een
redactie die er niet is, en ondermijnt precies het vertrouwen dat het
manifest hoort te vestigen.

Twee bewuste grenzen. De standaardwaarde blijft defaultPrivacyRegions en
niet const {}: een aanroeper die dit vergeet moet méér redigeren, niet
minder. En forExternalProcessing neemt bewust géén regions — dat iemand
het nl-pakket uitzet omdat het in zijn deck te vaak aanslaat, is een
uitspraak over zijn eigen paneel, niet om een BSN naar een model van een
derde te sturen. Die keuze staat nu ook als test vastgepind.

Closes #512

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
brenno merged commit 195bfd6ca2 into main 2026-07-22 10:39:48 +00:00
brenno deleted branch fix/redactie-regios 2026-07-22 10:39:48 +00:00
Sign in to join this conversation.
No description provided.