Skip to content

fix: word-boundary voor alle keys + memory-validator + placeholder-collapse#4

Open
Treason8579 wants to merge 1 commit into
mainfrom
fix/word-boundary-en-memory-hygiene
Open

fix: word-boundary voor alle keys + memory-validator + placeholder-collapse#4
Treason8579 wants to merge 1 commit into
mainfrom
fix/word-boundary-en-memory-hygiene

Conversation

@Treason8579

Copy link
Copy Markdown
Contributor

Samenvatting

Drie structurele bugs opgelost die de output van de anonimizer onleesbaar maakten op realistische testdata.

1. Word-boundary voor alle keys (replacer.py)

Voorheen kregen alleen keys ≤4 tekens `\b`-wrapping. Daardoor matchte `beveiliging` overal als substring binnen `informatiebeveiliging`, en `Leiden` binnen `begeleiden`. Nu krijgt elke key die begint én eindigt op een woord-karakter de boundary — lengte is niet langer beslissend.

2. Dubbele lidwoorden collapsen (replacer.py)

Memory-vervangingen die zelf een lidwoord bevatten (`CISO → de Chief Information Security Officer`) produceerden `de de Chief Information Security Officer` als de brontekst al een lidwoord had. Post-processing stap collapst `de de / het het / een een` → één lidwoord, case-insensitive, met behoud van de oorspronkelijke hoofdletter.

3. Placeholder-lijsten collapsen (replacer.py)

`VOORBEELDGEMEENTE, VOORBEELDGEMEENTE, VOORBEELDGEMEENTE en VOORBEELDGEMEENTE` werd produced wanneer meerdere gemeentenamen op een rij stonden — informatieverlies zonder meerwaarde. Post-processing collapst 2+ opeenvolgende `VOORBEELDGEMEENTE`-tokens (komma/`en`/`of` gescheiden) naar `de betrokken gemeenten`.

4. Memory-validator (memory.py)

Nieuwe `valideer_entry()` weigert drie soorten rotzooi bij `remember()`:

  • No-ops: origineel == vervanging (case-insensitive).
  • Mojibake: U+FFFD of dubbele-UTF8-markers in tekst of vervanging.
  • Blocklist-nouns: losse generieke lowercase-nouns (`beveiliging`, `directeur`, `griffie`, `college`, `directie`, `receptie`, `medewerker`, ...). Deze veroorzaken substring-cascades zelfs met `\b`.

Bestaande entries (update-pad) blijven ongemoeid om niet per ongeluk historische keuzes te wissen. `anonimizer.py` toont nu een waarschuwing met reden wanneer een entry is afgewezen.

5. Detector-prompt (detector.py)

Expliciet: geen no-op suggesties; generieke functietitels mét lidwoord (`de directeur`), interne artikelverwijzingen (`artikel 3.7`) en publieke normen (NEN/NTA/ISO) moeten blijven staan.

Tests

  • `tests/test_replacer.py`: 7 nieuwe tests (word-boundary voor lange keys, dubbele lidwoorden, placeholder-lijsten).
  • `tests/test_memory.py`: 13 nieuwe tests (validator + remember-skip gedrag).
  • Totaal: 110 → 116 tests, alle groen.

Impact op een realistische testset (6 docs, ~150 kB tekst)

Probleem Voor Na
`informatiede beveiligingsafdeling`-achtige substring-bugs ~40 0
`begeVOORBEELDGEMEENTEde` (Leiden als substring van begeleiden) 1+ 0
Dubbele lidwoorden (`de de CISO`) 15+ 0
No-ops die in memory belandden 9 0
`VOORBEELDGEMEENTE, VOORBEELDGEMEENTE, …` frequent 0

Test plan

  • `python -m pytest` lokaal groen (116/116)
  • Handmatige re-run op realistische testset (6 gemeentelijke beleidsdocumenten) toont geen van de bovenstaande regressies
  • Review door maintainer

…llapse

replacer.py:
- Word-boundary (\b) wordt nu toegepast op elke key die begint én eindigt
  op een woord-karakter, ongeacht lengte. Voorheen alleen bij keys ≤4
  tekens — daardoor matchte 'beveiliging' overal binnen
  'informatiebeveiliging' en 'Leiden' binnen 'begeleiden'.
- Post-processing: 'de de X' / 'het het X' / 'een een X' collapst naar
  één lidwoord. Fixt dubbele lidwoorden als memory-vervanging al een
  lidwoord bevat ('de CISO') en de brontekst er ook een heeft.
- Post-processing: lijsten van 2+ identieke VOORBEELDGEMEENTE-tokens
  (komma, 'en', 'of' gescheiden) collapsen naar 'de betrokken gemeenten'.

memory.py:
- Nieuwe valideer_entry(): weigert no-ops (origineel == vervanging),
  mojibake (U+FFFD en dubbele-UTF8-markers), en losse generieke
  lowercase-nouns uit BLOCKLIST_GENERIEKE_NOUNS (beveiliging, directeur,
  griffie, college, etc.).
- remember() roept validator aan voor nieuwe entries; bestaande entries
  (update-pad) worden ongemoeid gelaten.

anonimizer.py:
- Toont waarschuwing wanneer een LLM-bevestigde entry wordt afgewezen
  door de memory-validator, met reden.

detector.py (prompt):
- Expliciet: geen no-op suggesties. Als vervanging == origineel,
  detecteer niet.
- Expliciet: generieke functietitels mét lidwoord ('de directeur'),
  interne artikelverwijzingen, en publieke normen (NEN/NTA/ISO) laten
  staan.

Tests: 110 → 116 (7 nieuwe replacer-tests, 13 nieuwe memory-tests).
Alle 116 groen.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant