v1.14.0: refactor OV-filter naar driestapsmodel — één regel i.p.v. drie uitzonderingstakken
- _filter_passes: 'zwak-alleen in samenvatting' en 'sterk+zwak uitsluitend in samenvatting' reduceren tot één regel: zonder enig titel-signaal (familie-hit, whitelist-term of storingszin) mag de score geen zwak woord bevatten. Equivalentie bewezen over de volledige beslissing-ruimte (420 configuraties). - Nieuwe dienststoring-context 'vervoerswoord rijdt/rijden niet' (gedeeld patroon): sterk titel-signaal (+2) en familie (2) — 'sprinters rijden niet tussen Utrecht en Amsterdam', 'metro rijdt niet tussen Rotterdam en Schiedam' passeren nu; bus/tram/metro/sprinter zelf blijven zwak/medium. - Overlappende regexes opgeruimd: busbaan/bushokje uit de halte-familie. - Blacklist 29 -> 2 woorden: restant (stationsstraat, stationair, stationcar, stationeren ...) was inert sinds de woordgrens-familie; vastgelegd in tests. - validate_filter.py: 56 -> 90 regressie-cases + invariant 4 (whitelist-term in familie, blacklist-term door familie gematcht). - _filter_summary/beleidsdocumentatie geactualiseerd.
This commit is contained in:
parent
1346cbb549
commit
91d0c3d7fe
3 changed files with 215 additions and 141 deletions
|
|
@ -25,8 +25,9 @@ WANT_ASSIGN = {
|
|||
"MATCH_FILTER_FAMILIES", "MATCH_FILTER_THRESHOLD", "MATCH_FILTER_BLACKLIST",
|
||||
"MATCH_FILTER_WHITELIST", "_compiled_match_families",
|
||||
"_WHITELIST_RE", "_WHITELIST_PHRASES",
|
||||
"_DISRUPTION_RE_SRC", "_DISRUPTION_RE",
|
||||
}
|
||||
WANT_METHODS = {"_fam_hits", "_filter_passes", "_filter_text", "_whitelist_hit"}
|
||||
WANT_METHODS = {"_fam_hits", "_filter_passes", "_filter_text", "_whitelist_hit", "_disruption_hit"}
|
||||
|
||||
nodes = []
|
||||
for n in tree.body:
|
||||
|
|
@ -116,6 +117,16 @@ for p, w in FAMILIES:
|
|||
check(w in (1, 2), f"familie {p[:40]!r} heeft geldig gewicht {w} (max-2-stelsel)")
|
||||
check(len(COMPILED) == len(FAMILIES), "alle families compileren")
|
||||
|
||||
# --- Invariant 4 (refactor 2026-09-13): sterke-signaal-garantie + geen dode
|
||||
# blacklist. Elke whitelist-term moet óók in een familie zitten (anders telt een
|
||||
# whitelist-titel niet als sterk signaal 2+2) en elke zwartgelijste term moet door
|
||||
# minstens één familie worden gematcht (anders is de blacklist-regel dood gewicht).
|
||||
print("== invariant 4: whitelist-term in familie; blacklist-term door familie gematcht ==")
|
||||
for w in sorted(ns["MATCH_FILTER_WHITELIST"]):
|
||||
check(any(p.search(w) for p, _ in COMPILED), f"whitelist-term {w!r} zit ook in een familie")
|
||||
for w in sorted(ns["MATCH_FILTER_BLACKLIST"]):
|
||||
check(any(p.search(w) for p, _ in COMPILED), f"blacklist-term {w!r} wordt door een familie gematcht")
|
||||
|
||||
# --- Regressie: gedrag van _filter_passes op bekende cases (precision-first)
|
||||
GOLDEN = [
|
||||
# (titel, samenvatting, verwacht_door)
|
||||
|
|
@ -225,6 +236,46 @@ GOLDEN = [
|
|||
# twee VERSCHILLENDE termen blijven samen tellen (geen over-merge).
|
||||
("Busbaan wordt afgesloten voor het doorgaande verkeer", "De omleiding duurt tot het voorjaar.", True),
|
||||
("Bus rijdt om, busbaan is afgesloten", "De bussen rijden via de wijk.", True), # bus(1) + busbaan(2) = 3
|
||||
# refactor 2026-09-13 — positieve gevallen die de dienststoring-context én
|
||||
# sterke signalen vastleggen (prompt "Starke OV-signalen").
|
||||
("NS meldt storing: sprinters rijden niet", "De storing wordt verholpen.", True), # ns-titel + 'sprinters rijden niet'-context
|
||||
("Metro rijdt niet tussen Rotterdam en Schiedam", "De metro's stoppen na de storing.", True), # 'metro rijdt niet'-context (2) + metro(2)
|
||||
("Buslijn 12 vervalt tijdelijk", "De vervanging rijdt via de wijk.", True), # buslijn(2) + vervoer(1)
|
||||
("Werkzaamheden aan perron", "Het perron wordt nieuwe maand opgeknapt.", True), # perron-titel-anker (2+2)
|
||||
("Nieuwe bushalte geopend", "De halte ligt aan de rand van de wijk.", True), # bushalte-whitelist (2+2)
|
||||
("Sprinters rijden niet tussen Utrecht en Amsterdam", "De oorzaak is nog onbekend.", True), # dienststoring-context(2) + sprinter(1) = 3 — prompt: echte sprinter-context
|
||||
("Stoptreinen rijden niet naar Den Haag vanwege een storing", "De NS zet bussen in.", True), # 'stoptreinen rijden niet'(2) + trein(1) + ns(2)
|
||||
# refactor 2026-09-13 — negatieve gevallen (prompt): ambigue woorden en
|
||||
# straatnamen mogen niet zelfstandig voldoende zijn.
|
||||
("Nieuwe woning bij station", "", False), # woning naast station: station(1) < 3
|
||||
("Restaurant opent nieuwe vestiging", "Het restaurant ligt tegenover het station waar dagelijks veel reizigers komen.", False), # station+reizigers als bijzin — titel zegt niets over OV
|
||||
("Stationstraat krijgt nieuwe woningen", "", False), # straatnaam-inert (oudere blacklist-entries verwijderd, refactor 2026-09-13)
|
||||
("Werkzaamheden aan de stationsweg", "", False),
|
||||
("Het stationsplein wordt heringericht voor de markt", "", False),
|
||||
("De auto stond stationair te draaien", "", False),
|
||||
("Nieuwe stationwagen van het merk", "", False),
|
||||
("Stationcar uit de jaren zestig", "", False),
|
||||
("De Metro publiceert vandaag een interview", "De krant verschijnt wekelijks.", False), # krant 'De Metro': metro(2) alleen
|
||||
("Tram is een populaire naam voor het café", "", False), # café 'De Tram': tram(2) alleen
|
||||
("Schoolbus betrokken bij ongeval", "De kinderen werden opgevangen.", False), # schoolbus: 0 OV-hits
|
||||
("Bus en station tijdelijk gesloten voor het feest", "", False), # bus(1)+station(1) = 2 — geen auto-pass
|
||||
("Wijkbewoners klagen over het station en de bussen", "De gemeente komt langs.", False), # station(1)+bussen(1)=2 — bus+station is geen auto-pass
|
||||
("Passagiers klagen over de incheckbalie", "De balie opende te laat.", False), # passagiers(1)+inchecken(1) = 2
|
||||
("Gemeente verhuist naar het stationsgebouw", "Het station en het stationsgebied worden vernieuwd.", False), # semantische stapel: station-varianten tellen niet als 4 signalen — alleen station(1) in samenvatting
|
||||
# combinaties (prompt): twee onafhankelijke context-signalen zijn genoeg,
|
||||
# tenzij de context niet-OV is (bovenstaande negatieve cases).
|
||||
("Bus en tram krijgen in december een nieuwe dienstregeling", "", True), # bus(1)+dienstregeling(1)+tram(2) = 4 — echte OV-context van bus+dienstregeling
|
||||
("Tram krijgt nieuwe dienstregeling", "De wijziging geldt vanaf december.", True), # tram(2)+dienstregeling(1) = 3
|
||||
("De halte wordt verplaatst voor de bus", "De nieuwe halte komt bij de rotonde.", True), # halte(2)+bus(1) = 3
|
||||
("Metro rijdt niet vanwege een storing", "Er is onbekend wanneer het rijden hervat.", True), # metro(2)+storing(1) = 3 (prompt: metro+storing)
|
||||
("Trein rijdt niet meer op de spoorlijn naar Den Bosch", "Werkzaamheden duren tot maart.", True), # trein(1)+spoorlijn(2) = 3 (prompt: trein+spoorlijn)
|
||||
("Sprinters rijden niet; NS zet bussen in", "", True), # sprinter(1)+rijden-niet(2)+ns(2) (prompt: sprinter+NS)
|
||||
("De trams rijden niet door een storing", "Er zijn vervangende bussen ingezet.", True), # trams(2)+rijden-niet(2) (prompt: tram-storing)
|
||||
("Tramverkeer stilgelegd na aanrijding", "", True), # tramverkeer-whitelist (prompt: tram-storing)
|
||||
("ProRail meldt wisselstoring op traject Utrecht", "Het treinverkeer ligt stil.", True), # prorail-whitelist + treinverkeer(2)
|
||||
("Treinstoring tussen Den Haag en Leiden", "Reizigers moeten rekening houden met vertraging.", True), # treinstoring-whitelist (prompt: treinstoring)
|
||||
("Treinvertraging op het spoor bij Utrecht", "", True), # treinvertraging-whitelist (prompt: echte treinvertraging)
|
||||
("NS past de dienstregeling aan", "Door werkzaamheden rijden er minder treinen.", True), # prompt-voorbeeld: ns + treinen
|
||||
]
|
||||
print(f"== regressie: {len(GOLDEN)} cases (precision-first) ==")
|
||||
for t, s, want in GOLDEN:
|
||||
|
|
|
|||
Loading…
Reference in a new issue