v1.12.0: max-2-stelsel — enkele familie-hit kan nooit solo doorlaten
- Gewicht-3-tier vervallen: alle families wegen max 2; drempel blijft 3,
dus elke echte OV-bericht combineert met een tweede signaal (besluit
2026-09-12, gevalideerd op 205 productie-artikelen).
- 'hermes' uit vervoerders + whitelist -> eigen zwakke familie (achternaam
Ton Hermes, Margraten false positive 2026-09-12).
- Whitelist geen auto-pass meer: titel-hit = +2 titel-anker (onmiskenbare
termen behouden hun recall; samenvatting blijft inert).
- Completheids-audit (2026-09-12): +20 termen/frasen —
sterk: spoorsector, spoorbeheerder, spoornet, spoorvervoerder,
treinvertraging/hinder/uitval/verstoring, ertms, teso, rangeer/rangeren,
ice-<stad>/ice-trein, maaslijn/nedersaksenlijn/kamperlijn, ns international,
deutsche bahn, european sleeper, italo, nightjet;
zwak: busongeluk, busvervoer, spoor, staking, passagier(+reizigers),
vervoer, vervoersbedrijf, vervoerregio, ritten, bovenleiding, abonnement.
- validate_filter.py: invariant gewicht in {1,2}, 46 dubbelzinnige + 39
onmiskenbare termen, 52 regressie-cases groen.
This commit is contained in:
parent
4adfff5b2a
commit
7997d7572a
3 changed files with 223 additions and 145 deletions
328
buzzrss/bot.py
328
buzzrss/bot.py
|
|
@ -57,21 +57,21 @@ rss_change_level = EventType.find("xyz.maubot.rss", t_class=EventType.Class.STAT
|
|||
# of het woord in beide velden = één signaal — 'busstation' 60× weegt 1×, besluit
|
||||
# 2026-09-11). Drempel (3): doorlaten als de som van de unieke familie-gewichten
|
||||
# >= MATCH_FILTER_THRESHOLD (titel weegt niet extra).
|
||||
# Gewicht 3 (sterk, onmiskenbaar OV): één woord in titel óf samenvatting volstaat.
|
||||
# Gewicht 2 (medium): moet combineren met een andere OV-familie; één medium-hit,
|
||||
# in titel óf samenvatting, haalt de drempel niet.
|
||||
# Gewicht 1 (zwak/dubbelzinnig: los "bus", "breng", "overweg", "overwegen", "sein",
|
||||
# "kaartje", "opwaarderen", "rails", "pendelbus"): moet met een ander OV-woord
|
||||
# combineren (een tweede, andere familie — dezelfde zwakke familie in titel én
|
||||
# samenvatting telt niet als combinatie) EN minstens één zwak woord moet in de
|
||||
# TITEL staan: een combinatie van alleen zwakke woorden in de samenvatting is
|
||||
# geen bewijs (het golfbericht met "station" + "pendelbus" + "bus" in de
|
||||
# samenvatting is geen OV-nieuws). Weert zo "VW-bus"/"schoolbus", "weer op de rails", het
|
||||
# werkwoord "brengen" ("hoe breng je ... in beeld"), het idioom "goed met elkaar
|
||||
# overweg kunnen", het werkwoord "overwegen" ("gratieverlening overwegen"), het
|
||||
# werkwoord "opwaarderen" ("een wijk opwaarderen") en brandweerjargon
|
||||
# ("sein brandmeester"), zonder eenduidige bushalte/overweg/NS/trein-berichten
|
||||
# te raken.
|
||||
# MAX-GEWICHT 2 — besluit 2026-09-12: een enkele FAMILIE-hit kan nooit solo
|
||||
# doorlaten (2 < 3); écht OV-nieuws combineert in de praktijk altijd met een
|
||||
# tweede signaal (gevalideerd op 205 productie-artikelen; zie beleidsblok).
|
||||
# Gewicht 2 (onmiskenbaar OV: merken, sectorjargon, samenstellingen als bushalte/
|
||||
# spoorlijn/veerboot — de vroegere 'sterk(3)' én 'medium(2)' zijn hierin
|
||||
# opgegaan, want beide moeten nu combineren).
|
||||
# Gewicht 1 (zwak/dubbelzinnig): moet met een andere OV-familie combineren
|
||||
# (een tweede, andere familie — dezelfde zwakke familie in titel én samenvatting
|
||||
# telt niet als combinatie) EN minstens één zwak woord moet in de TITEL staan:
|
||||
# een combinatie van alleen zwakke woorden in de samenvatting is geen bewijs
|
||||
# (het golfbericht met "station" + "pendelbus" + "bus" in de samenvatting is
|
||||
# geen OV-nieuws). Weert zo "VW-bus"/"schoolbus", "weer op de rails", het
|
||||
# werkwoord "brengen", het idioom "goed met elkaar overweg kunnen", het werkwoord
|
||||
# "overwegen", het werkwoord "opwaarderen" en brandweerjargon ("sein brandmeester"),
|
||||
# zonder eenduidige bushalte/overweg/NS/trein-berichten te raken.
|
||||
# Inflectie: families matchen met \w* aan het eind, zodat meervoud en vervoeging
|
||||
# meegenomen worden ("spoorlijnen", "seinstoringen", "ontspoorde", "chipkaarten").
|
||||
# Een koppelteken vóór een match is géén OV-signaal: "VW-bus" en "radio-station"
|
||||
|
|
@ -80,61 +80,69 @@ rss_change_level = EventType.find("xyz.maubot.rss", t_class=EventType.Class.STAT
|
|||
# straatnamen rond stations — "de Stationsstraat afsluiten voor een festival"
|
||||
# is geen OV-nieuws). Zwartgelijste woorden leveren geen score op, maar
|
||||
# blokkeren de familie niet: een écht "station"-woord ernaast scoort gewoon.
|
||||
# Bewust geaccepteerde botsingen: krant "De Metro"/café "De Tram" (medium).
|
||||
# 'spoorbrug' is MEDIUM (niet sterk/whitelist): een brug is vaak louter locatie
|
||||
# ('bij de spoorbrug tussen Liempde en Boxtel', Stuifmail 2026-09-12) — één
|
||||
# spoorbrug-hit in de samenvatting is geen OV-nieuws; écht spoorbrug-nieuws
|
||||
# combineert met trein/spoor/verkeer en haalt de drempel alsnog (besluit 2026-09-12).
|
||||
# Losse algemene woorden zijn zwak (moeten combineren met een andere familie):
|
||||
# "trein", "sprinter" (atleet), "vervoerder" (logistiek), "reiziger",
|
||||
# "inchecken"/"uitchecken" (Schiphol/hotel), "station(s)" (omroepen), "bus",
|
||||
# "sein" (brandweer), "overweg", "breng", "kaartje", "opwaarderen", "rails".
|
||||
# Bewust geaccepteerde botsingen: krant "De Metro"/café "De Tram" (gewicht 2,
|
||||
# moet combineren). 'spoorbrug' weegt 2: een brug is vaak louter locatie
|
||||
# ('bij de spoorbrug tussen Liempde en Boxtel', Stuifmail 2026-09-12) — écht
|
||||
# spoorbrug-nieuws combineert met trein/spoor/verkeer (besluit 2026-09-12).
|
||||
# Naam-botsingen die bewust zijn afgezwakt (2026-09-12): 'hermes' (vervoerder
|
||||
# Hermes vs. achternaam Ton Hermes — Margraten-false positive), 'breng'
|
||||
# (vervoerder vs. werkwoord 'brengen'), 'spoor' (figuurlijk 'op het spoor van').
|
||||
# Losse algemene woorden zijn zwak (moeten combineren): "trein", "sprinter"
|
||||
# (atleet), "vervoerder" (logistiek), "reiziger"/"passagier" (vliegen),
|
||||
# "inchecken"/"uitchecken" (Schiphol/hotel), "station(s)" (omroepen), "bus",
|
||||
# "sein" (brandweer), "overweg", "breng", "kaartje", "opwaarderen", "rails",
|
||||
# "staking" (alle sectoren), "vervoer" (vracht/auto), "abonnement", "ritten".
|
||||
# Multi-woord-frasen en merknamen (ice-berlijn, deutsche bahn, european sleeper,
|
||||
# ns international, teso, italo, nightjet, maaslijn) zijn onmiskenbaar OV en
|
||||
# wegen 2; een los 'ice' is NIET toevoegbaar (case-insensitive botsing met 'ijs',
|
||||
# besluit 2026-09-12).
|
||||
# =====================================================================
|
||||
# FILTERCLASSIFICATIE-BELEID (bij elke aanpassing aan het filter volgen)
|
||||
# =====================================================================
|
||||
# Doel: precisie boven recall. Liever een OV-bericht te veel gefilterd dan
|
||||
# een niet-OV-bericht te veel doorgelaten (gebruikersbesluit, 2026-09-10).
|
||||
#
|
||||
# Drie lagen, elk met een eigen regel:
|
||||
# 1. WHITELIST -> ALTIJD door BIJ EEN HIT IN DE TITEL. Alleen termen die
|
||||
# in élke context OV betekenen (merken: NS/ProRail/Arriva; onmiskenbaar jargon:
|
||||
# spoorstoring, perron, bushalte, conducteur, ovpay; multi-woord termen).
|
||||
# REGEL: twijfel je of de term ook buiten het OV kan voorkomen -> NIET hier.
|
||||
# NIET: station-samenstellingen (busstation/metrostation) — een bericht over
|
||||
# een pand 'naast het busstation' is geen OV-nieuws (besluit 2026-09-11);
|
||||
# die wegen mee via de gewogen families (medium).
|
||||
# Een whitelist-term ALLEEN in de SAMENVATTING laat NIET onvoorwaardelijk
|
||||
# door: een bijzin als 'de zakelijke bezoeker is ook nodig voor het openbaar
|
||||
# vervoer' in een economiebericht is geen OV-nieuws (besluit 2026-09-12).
|
||||
# Zo'n hit scoort via de gewogen families (dezelfde termen staan daar ook in).
|
||||
# 2. GEWOGEN FAMILIES -> score = som van unieke OV-families over het hele artikel
|
||||
# (titel + samenvatting; per familie 1× per artikel — herhaling of beide velden
|
||||
# tellen niet dubbel, besluit 2026-09-11) >= drempel (3).
|
||||
# - sterk (3): onmiskenbaar OV-jargon/merken/samenvoegingen (spoorlijn,
|
||||
# bushalte, busverkeer, intercity, lijn 12, ...).
|
||||
# - medium (2): onmiskenbaar OV maar iets algemener (tram, metro, halte,
|
||||
# pont, ovpay, openbaar vervoer, trein-/bus-/metrostation).
|
||||
# Moet COMBINEREN met een andere OV-familie: één medium-hit,
|
||||
# in titel óf samenvatting, is onvoldoende — de titel weegt
|
||||
# niet extra ('restaurant naast busstation' in de titel is
|
||||
# geen OV-bericht, besluit 2026-09-11).
|
||||
# EXTRA (besluit 2026-09-12): een medium + zwak-combinatie
|
||||
# UITSLUITEND in de samenvatting (geen enkele hit in de
|
||||
# titel) is geen OV-bewijs — 'openbaar vervoer' + 'zakelijke
|
||||
# reizigers' in een economiebericht telt dan toch op tot de
|
||||
# drempel. Sterke (3) families blijven in de samenvatting
|
||||
# gewoon tellen.
|
||||
# Lagen, elk met een eigen regel (MAX-2-stelsel, besluit 2026-09-12):
|
||||
# 1. WHITELIST -> termen die in élke context OV betekenen (merken:
|
||||
# NS/ProRail/Arriva; onmiskenbaar jargon: spoorstoring, perron, bushalte,
|
||||
# conducteur, ovpay; multi-woord-frasen: nederlandse spoorwegen, openbaar
|
||||
# vervoer, ice-berlijn ...). Een whitelist-hit in de TITEL telt +2 (geen
|
||||
# auto-pass meer). Omdat elke whitelist-term óók in een familie zit, is dat
|
||||
# effectief het oude titel-anker voor onmiskenbare termen — 'Reactie
|
||||
# Nederlandse Spoorwegen' blijft daardoor door. REGEL: twijfel je of de term
|
||||
# ook buiten het OV kan voorkomen -> NIET hier, maar zwak (eigen familie).
|
||||
# Een whitelist-term ALLEEN in de SAMENVATTING blijft inert: een bijzin als
|
||||
# 'de zakelijke bezoeker is ook nodig voor het openbaar vervoer' in een
|
||||
# economiebericht is geen OV-nieuws (besluit 2026-09-12); zo'n hit scoort
|
||||
# alleen via de overeenkomstige familie.
|
||||
# 2. GEWOGEN FAMILIES -> score = som van unieke OV-families over het hele
|
||||
# artikel (titel + samenvatting; per familie 1× per artikel — herhaling of
|
||||
# beide velden tellen niet dubbel, besluit 2026-09-11) >= drempel (3).
|
||||
# - sterk (2): onmiskenbaar OV-jargon/merken/samenvoegingen (spoorlijn,
|
||||
# bushalte, busverkeer, intercity, veerboot, ertms,
|
||||
# rangeer..., ice-frasen, ...). Eén hit (titel óf samenvatting)
|
||||
# is onvoldoende: moet combineren (2 + 1 = 3). De vroegere
|
||||
# 'één sterk woord volstaat'-regel is vervallen — 'hermes'
|
||||
# als achternaam passeerde zo op één vervoerder-hit
|
||||
# (Margraten, 2026-09-12).
|
||||
# EXTRA (besluit 2026-09-12): een sterk/medium + zwak-
|
||||
# combinatie UITSLUITEND in de samenvatting (geen enkele hit
|
||||
# in de titel én geen whitelist-term in de titel) is geen
|
||||
# OV-bewijs — 'openbaar vervoer' + 'zakelijke reizigers' in
|
||||
# een economiebericht telt anders op tot de drempel.
|
||||
# - zwak (1): DUBBELZINNIGHEID. Woorden die (ook) buiten het OV
|
||||
# voorkomen. REGEL: elk dubbelzinnig woord krijgt een EIGEN
|
||||
# familie (niet samengevoegd), zodat twee verschillende
|
||||
# zwakke woorden wél als combinatie tellen, maar één enkel
|
||||
# woord nooit de doorslag kan geven. Bekende dubbelzinnige:
|
||||
# trein, bus, station(s), sprinter, reiziger, vervoerder,
|
||||
# inchecken/uitchecken, sein, overweg, breng, kaartje,
|
||||
# opwaarderen, rails, dienstregeling, chipkaart, ontsporen,
|
||||
# pendelbus/shuttlebus (evenement-/hotel-/parkeerpendel;
|
||||
# synoniemen -> bewust één familie, anders tellen twee
|
||||
# synoniemen als twee onafhankelijke signalen).
|
||||
# trein, bus, station(s), sprinter, reiziger/passagier,
|
||||
# vervoerder, inchecken/uitchecken, sein, overweg, breng,
|
||||
# kaartje, opwaarderen, rails, dienstregeling, chipkaart,
|
||||
# ontsporen, pendelbus/shuttlebus (evenement-/hotel-/
|
||||
# parkeerpendel; synoniemen -> bewust één familie),
|
||||
# busongeluk/busvervoer (touringcar/schoolbus), staking,
|
||||
# vervoer, vervoersbedrijf, vervoerregio, ritten,
|
||||
# bovenleiding (industrie), abonnement, hermes, spoor.
|
||||
# EXTRA REGEL voor zwak-alleen: staat er uitsluitend zwak
|
||||
# bewijs in de SAMENVATTING (geen enkele zwakke hit in de
|
||||
# titel), dan niet doorlaten. Twee/meer zwakke woorden in
|
||||
|
|
@ -143,27 +151,38 @@ rss_change_level = EventType.find("xyz.maubot.rss", t_class=EventType.Class.STAT
|
|||
# 3. BLACKLIST -> gematchte woorden zonder OV-waarde (stationsstraat,
|
||||
# stationair, stationcar, ...); blokkeren de familie niet.
|
||||
#
|
||||
# BEOORDELEN VAN EEN NIEUW WOORD:
|
||||
# BEOORDELEN VAN EEN NIEUW WOORD (incl. COMPLETEHEIDS-AUDIT, 2026-09-12):
|
||||
# a) Kan het ook buiten het OV voorkomen? ja -> zwak (1), eigen familie.
|
||||
# b) Is het een samenvoeging/merk die alleen OV kan betekenen? -> sterk (3)
|
||||
# of whitelist.
|
||||
# b) Is het een samenvoeging/merk die alleen OV kan betekenen? -> sterk (2)
|
||||
# of whitelist (frasen die in élke context OV betekenen).
|
||||
# c) Bij twijfel: zwak (1). Conservatief = precision-first.
|
||||
# d) Ter controle: leg nieuwe woordkandidaten voor aan minimaal één extra
|
||||
# taalmodel (de audit op 2026-09-10 gebruikte 3 modellen; enige stem
|
||||
# 'TWIJFEL'/'NIET-OV' => behandelen als dubbelzinnig).
|
||||
# e) COMPLETEHEID (besluit 2026-09-12): check bij elke filterwijziging óók of
|
||||
# de families compleet zijn — draai de OV-gap-scan over de afgewezen
|
||||
# artikelen van OV-specialist-feeds (SpoorPro/Treinreiziger/Mobiliteit),
|
||||
# classificeer nieuwe kandidaten via stap a-d en vul aan. De audit van
|
||||
# 2026-09-12 leverde o.a. spoorsector, spoorbeheerder, spoornet,
|
||||
# spoorvervoerder, treinvertraging/uitval, ertms, teso, rangeer, ice-frasen,
|
||||
# maaslijn, ns international, deutsche bahn, european sleeper, italo,
|
||||
# nightjet (sterk) en 11 zwakke woorden op.
|
||||
# =====================================================================
|
||||
MATCH_FILTER_FAMILIES: list[tuple[str, int]] = [
|
||||
# sterk (3)
|
||||
(r"\b(?:ns|arriva|qbuzz|connexxion|cxx|transdev|keolis|ret|gvb|ebs|htm|syntus|u-ov|allgo|flixbus|blauwnet|r-net|valleilijn|waterbus|eurostar|thalys|randstadrail|gvu|prorail|hermes|rrreis|qliner|ov)\b", 3), # vervoerders ('Breng' staat in de zwakke groep: botst met het werkwoord "brengen")
|
||||
(r"\b(?:spoorweg|spoorba(?:an|nen)|spoorlijn|spoorverkeer|spoorwegovergang|spoorstoring|perron|seinstoring|wisselstoring|spoorstaking)\w*\b", 3), # spoorinfra; let op de klinkerwisseling: 'ontsporing' (open lettergreep, één o) vs 'ontspoord'/'ontspoorde' (dicht, dubbel o) — vandaar beide stammen. Géén 'spoorbrug': die is medium (vaak locatie-referentie, besluit 2026-09-12)
|
||||
(r"\b(?:treinstation|treinstations|metrostation|metrostations|busstation|busstations)\b", 2), # station-samenstellingen: onmiskenbaar OV, maar MEDIUM — één station-woord náást een ander onderwerp ('pand naast busstation', besluit 2026-09-11) is geen OV-bericht; in de samenvatting moet een tweede OV-woord bijkomen
|
||||
# sterk (2) — onmiskenbaar OV, maar één hit is onvoldoende (max-2-stelsel,
|
||||
# besluit 2026-09-12): elke echte OV-bericht combineert met een tweede signaal.
|
||||
(r"\b(?:ns|arriva|qbuzz|connexxion|cxx|transdev|keolis|ret|gvb|ebs|htm|syntus|u-ov|allgo|flixbus|blauwnet|r-net|valleilijn|waterbus|eurostar|thalys|randstadrail|gvu|prorail|rrreis|qliner|ov|teso|deutsche bahn|european sleeper|ns international|italo|nightjet)\b", 2), # vervoerders; 'hermes' is zwak (achternaam-botsing, Margraten 2026-09-12), 'Breng' ook (werkwoord "brengen"); internationale vervoerders: teso (veer), deutsche bahn/european sleeper/italo/nightjet/ns international (audit 2026-09-12)
|
||||
(r"\b(?:spoorweg|spoorba(?:an|nen)|spoorlijn|spoorverkeer|spoorwegovergang|spoorstoring|perron|seinstoring|wisselstoring|spoorstaking|spoorsector|spoorbeheerder|spoornet|spoorvervoerder|ertms)\w*\b", 2), # spoorinfra; let op de klinkerwisseling: 'ontsporing' (open lettergreep, één o) vs 'ontspoord'/'ontspoorde' (dicht, dubbel o) — vandaar beide stammen. Géén 'spoorbrug': die is 2 maar vaak louter locatie (besluit 2026-09-12). Uitbreiding 2026-09-12 (completheids-audit): spoorsector, spoorbeheerder, spoornet, spoorvervoerder, ertms
|
||||
(r"\b(?:treinstation|treinstations|metrostation|metrostations|busstation|busstations)\b", 2), # station-samenstellingen: onmiskenbaar OV, maar één station-woord náást een ander onderwerp ('pand naast busstation', besluit 2026-09-11) is geen OV-bericht; in de samenvatting moet een tweede OV-woord bijkomen
|
||||
(r"(?<![\w-])\bstations?\b", 1), # los 'station(s)' is ZWAK: ook tv-/radio-/regionale omroepstations ('de lokale stations'), moet combineren met een andere OV-familie
|
||||
(r"\b(?:bus|tram|metro)-?(?:halte|haltes|lijn|lijnen|verkeer|net|staking|ba(?:an|nen)|hok(?:je|jes)|chauffeur)\w*\b", 3), # voertuig-samenstelling (bushalte/buslijn/bushokje/busbanen/…); géén 'station': *station-samenstellingen zitten in de station-familie, anders telde 'busstation' dubbel mee (via 'bus' én 'station') — fix 2026-09-11
|
||||
(r"\b(?:treinstoring|treinverkeer|treinstaking|treinongeval|treinbotsing|treinongeluk)\w*\b", 3), # trein-jargon-samenstellingen: onmiskenbaar OV
|
||||
(r"\b(?:bus|tram|metro)-?(?:halte|haltes|lijn|lijnen|verkeer|net|staking|ba(?:an|nen)|hok(?:je|jes)|chauffeur)\w*\b", 2), # voertuig-samenstelling (bushalte/buslijn/bushokje/busbanen/buschauffeur/…); géén 'station': *station-samenstellingen zitten in de station-familie, anders telde 'busstation' dubbel mee — fix 2026-09-11. Géén 'ongeluk'/'vervoer': die zijn bewust zwak (busongeluk = ook touringcar, busvervoer = ook bedrijfsvervoer, audit 2026-09-12)
|
||||
(r"\b(?:treinstoring|treinverkeer|treinstaking|treinongeval|treinbotsing|treinongeluk|treinvertraging|treinhinder|treinuitval|treinverstoring)\w*\b", 2), # trein-jargon-samenstellingen: onmiskenbaar OV; uitgebreid met vertraging/hinder/uitval/verstoring (audit 2026-09-12)
|
||||
(r"\b\w*trein\w*\b", 1), # losse 'trein' en algemene samenstellingen (stoptrein, goederentrein, treinverkeer al in bovenstaande familie) — ZWAK: 'de trein naar mijn nieuwe huis' is geen OV-jargon, moet combineren met een andere familie
|
||||
(r"\b(?:intercity|streekvervoer|stadsvervoer|veerdienst|veerboot|veerboten|veerpont|voetveer|veerverbinding|buurtbus|belbus)\w*\b", 3), # treintypes, vervoerssectoren en veren ('sprinter' staat in de zwakke groep: atleet-botsing)
|
||||
(r"\blijn\s?\d{1,3}\b", 3), # 'lijn 12' — vervoerslijn met nummer
|
||||
# medium (2)
|
||||
(r"\b(?:intercity|streekvervoer|stadsvervoer|veerdienst|veerboot|veerboten|veerpont|voetveer|veerverbinding|buurtbus|belbus|maaslijn|nedersaksenlijn|kamperlijn)\w*\b", 2), # treintypes, vervoerssectoren, veren en lijnnamen ('sprinter' staat in de zwakke groep: atleet-botsing); maaslijn/nedersaksenlijn/kamperlijn via audit 2026-09-12
|
||||
(r"\blijn\s?\d{1,3}\b", 2), # 'lijn 12' — vervoerslijn met nummer
|
||||
(r"(?:\brangeer\w*|\brangeren\w*)\b", 2), # rangeren/rangerend/rangeerterrein/rangeerbedrijf: onmiskenbaar spoorjargon (audit 2026-09-12; stam 'rangeren' = ranger+en, 'rangeerterrein' = rangeer+...)
|
||||
(r"\bice[\s\-–—]*(?:berlijn|hamburg|brussel|bremen|parijs|frankfurt|keulen|amsterdam|bazel|milaan|kopenhagen|zurich|zürich|duitsland|international)\b|\bice-trein\w*\b", 2), # ICE-frasen: onmiskenbaar trein; los 'ice' is NIET toevoegbaar (case-insensitive botsing met 'ijs', besluit 2026-09-12)
|
||||
# onmiskenbaar OV maar iets algemener (2, moet ook combineren)
|
||||
(r"\btrams?\b", 2),
|
||||
(r"\bmetro(?:'?s)?\b", 2),
|
||||
(r"\b(?:openbaar vervoer|lightrail|halte|bushokje|busbaan)\w*\b", 2),
|
||||
|
|
@ -171,14 +190,14 @@ MATCH_FILTER_FAMILIES: list[tuple[str, int]] = [
|
|||
(r"\b(?:ov-staking|conducteursstaking)\w*\b", 2),
|
||||
(r"\bconduct(?:eur|eurs)\b", 2), # trein-/buspersoneel: onmiskenbaar OV-jargon
|
||||
(r"\b(?:pont|ponten)\b", 2), # waterbus/veerdienst
|
||||
(r"\bspoorbrug(?:gen)?\b", 2), # spoorinfra, maar MEDIUM: vaak locatie-referentie, geen OV-nieuws ('bij de spoorbrug', Stuifmail 2026-09-12); moet combineren — zelfde regel als station-samenstellingen (besluit 2026-09-11)
|
||||
(r"\bspoorbrug(?:gen)?\b", 2), # spoorinfra, maar vaak locatie-referentie ('bij de spoorbrug', Stuifmail 2026-09-12); moet combineren — zelfde regel als station-samenstellingen
|
||||
# zwak (1) — dubbelzinnig, moet combineren
|
||||
(r"(?<!-)\bbus(?:sen)?\b", 1), # ná een koppelteken geen OV: 'VW-bus', 'school-bus'
|
||||
(r"\b(?:pendelbus|shuttlebus)\w*\b", 1), # evenement-/hotel-/parkeerpendel ('pendelbus naar de golfbaan') is geen OV; synoniemen bewust in één familie
|
||||
(r"\b(?:inchecken|uitchecken)\w*\b", 1), # ook op luchthavens/hotels — geen OV-jargon, moet combineren
|
||||
(r"\bsprinters?\b", 1), # ook atleet ('sprinter verpulvert record') — aparte familie, moet combineren
|
||||
(r"\bvervoerders?\b", 1), # ook logistiek ('vrachtvervoerder') — aparte familie, moet combineren
|
||||
(r"\breizigers?\b", 1), # ook algemeen ('zakenreizigers vliegen') — aparte familie, moet combineren
|
||||
(r"\b(?:reizigers?|passagiers?)\b", 1), # ook 'zakenreizigers vliegen' / vliegtuigpassagiers — synoniemen bewust één familie (audit 2026-09-12)
|
||||
(r"\bdienstregeling\w*\b", 1), # dubbelzinnig (modelaudit) — meestal OV, maar moet combineren
|
||||
(r"\bchipkaart(?:en)?\b", 1), # dubbelzinnig (bankpas/algemeen) — aparte familie
|
||||
(r"\breisproduct(?:en)?\b", 1), # dubbelzinnig — aparte familie
|
||||
|
|
@ -191,9 +210,24 @@ MATCH_FILTER_FAMILIES: list[tuple[str, int]] = [
|
|||
(r"\bkaart(?:je|jes)\b", 1),
|
||||
(r"\bopwaarderen\b", 1), # ov-chipkaart opladen vs werkwoord "een wijk/park opwaarderen"
|
||||
(r"\brails\b", 1),
|
||||
(r"\bbusongeluk(?:ken)?\b", 1), # audit 2026-09-12: ook touringcar/schoolbus; combineert met buschauffeur/bus → door (busongeluk Zwitserland)
|
||||
(r"\bbusvervoer\b", 1), # audit 2026-09-12: ook touringcar-/bedrijfsvervoer
|
||||
(r"\bspoor\b", 1), # figuurlijk 'op het spoor van de daders', 'het spoor bijster'; écht spoornieuws combineert met spoorlijn/trein/perron
|
||||
(r"\bstaking(?:en)?\b", 1), # arbeidsstaking in alle sectoren; 'spoorstaking'/'busstaking'/'ov-staking' zitten in de sterke families (besluit 2026-09-12)
|
||||
(r"\bvervoer\b", 1), # ook vracht-/autovervoer; 'openbaar vervoer' zit in de sterke familie; samenstellingen (streekvervoer e.d.) matchen hier niet (geen \b)
|
||||
(r"\bvervoersbedrijf(?:ven)?\b", 1), # ook goederen-/taxibedrijf (audit 2026-09-12)
|
||||
(r"\bvervoerregio'?s?\b", 1), # OV-autoriteit ('Vervoerregio Amsterdam'), maar audit: ook algemener vervoersgebied
|
||||
(r"\britten\b", 1), # ook fiets-/taxiritten (audit 2026-09-12)
|
||||
(r"\bbovenleiding(?:en)?\b", 1), # audit 2026-09-12: ook water/gas/elektra-bovenleiding; spoor-combinatie (spoorlijn/ertms) haalt de drempel
|
||||
(r"\babonnement(?:en)?\b", 1), # gym/museum/telefoon (audit 2026-09-12)
|
||||
(r"\bhermes\b", 1), # vervoerder Hermes vs. achternaam (Ton Hermes, stichting Adoptie Graven Margraten, 2026-09-12)
|
||||
]
|
||||
|
||||
# Drempel voor doorlaten (score = 2×titel + 1×samenvatting).
|
||||
# Drempel voor doorlaten: som van unieke familie-gewichten >= 3. Max-2-stelsel
|
||||
# (besluit 2026-09-12): geen enkele familie weegt meer dan 2, dus een enkele hit
|
||||
# kan nooit solo doorlaten; een whitelist-term in de titel telt +2 (zie
|
||||
# _filter_passes). De oude '2×titel + 1×samenvatting'-rekensom is vervallen
|
||||
# (2026-09-11: de titel weegt niet extra).
|
||||
MATCH_FILTER_THRESHOLD = 3
|
||||
|
||||
# Woorden die een familie wél matcht maar die geen OV-waarde hebben. Een hit dat
|
||||
|
|
@ -216,34 +250,38 @@ MATCH_FILTER_BLACKLIST: frozenset[str] = frozenset({
|
|||
"stationnement", "stationering",
|
||||
})
|
||||
|
||||
# MATCH_FILTER_WHITELIST: termen die een bericht per definitie OV maken. Eén enkele
|
||||
# hit in de TITEL laat ALTIJD door (geen familiescore nodig) — dit is het expliciete
|
||||
# "onmiskenbaar OV"-signaal, zodat we voor deze termen niet op de gewogen
|
||||
# heuristiek hoeven te leunen. Vergelijking is case-insensitive, dus ook 'nederlandse
|
||||
# spoorwegen', 'prorail' en 'NS' in all-caps titels tellen mee.
|
||||
# Een whitelist-hit ALLEEN in de samenvatting is géén onvoorwaardelijk signaal
|
||||
# (besluit 2026-09-12: 'openbaar vervoer' als bijzin in een economiebericht is geen
|
||||
# OV-nieuws); die term scoort dan via de gewogen families — voor whitelist-termen
|
||||
# die geen eigen familie hebben (bv. 'treinstel': alleen zwak via \w*trein\w*) is
|
||||
# een samenvatting-alleen hit dus zwak.
|
||||
# Termen MOETEN in elke context OV betekenen. Niet hierop (algemeen/dubbelzinnig):
|
||||
# los 'trein', 'bus', 'metro', 'tram', 'station', 'lijn', 'ov', 'reiziger',
|
||||
# 'vervoerder', 'sprinter',
|
||||
# 'inchecken' (Schiphol/hotel), 'sein' (brandweerjargon), 'overweg', 'treinramp'
|
||||
# (films) — die blijven in de gewogen families.
|
||||
# MATCH_FILTER_WHITELIST: termen die een bericht per definitie OV maken. Sinds
|
||||
# besluit 2026-09-12 is dit geen auto-pass meer: een whitelist-hit in de TITEL
|
||||
# telt +2 (één onmiskenbare term 2, nog een signaal nodig voor de drempel 3), en
|
||||
# in de SAMENVATTING helemaal niet (die scoort via de overeenkomstige familie —
|
||||
# een whitelist-term zit altijd óók in een familie). Zie _filter_passes.
|
||||
# "Onmiskenbaar" = in élke context OV: merken (NS/ProRail/Arriva), onmiskenbaar
|
||||
# jargon (spoorstoring, perron, bushalte, conducteur, ovpay), multi-woord-frasen
|
||||
# (nederlandse spoorwegen, openbaar vervoer, ice-berlijn ...).
|
||||
# Regel: twijfel je of de term ook buiten het OV kan voorkomen -> NIET hier, maar
|
||||
# zwak (eigen familie). Daarom 'hermes' hieruit (achternaam, besluit 2026-09-12).
|
||||
# 'treinstel'/'veerdienst'/'buurtbus'/'lijn 12' staan hier alleen als TITEL-anker
|
||||
# (= het oude effect van één onmiskenbare term in de titel, nu via +2) — in de
|
||||
# samenvatting wegen ze als familie (2/1). Vergelijking is case-insensitive.
|
||||
MATCH_FILTER_WHITELIST: frozenset[str] = frozenset({
|
||||
# Vervoerders en OV-merken (incl. multi-woord termen)
|
||||
"nederlandse spoorwegen", "ns", "prorail", "randstadrail", "arriva", "qbuzz",
|
||||
"connexxion", "transdev", "keolis", "ret", "gvb", "htm", "ebs", "syntus",
|
||||
"u-ov", "allgo", "blauwnet", "r-net", "valleilijn", "hermes", "rrreis",
|
||||
"u-ov", "allgo", "blauwnet", "r-net", "valleilijn", "rrreis",
|
||||
"qliner", "flixbus", "eurostar", "thalys", "gvu", "ovpay",
|
||||
"deutsche bahn", "european sleeper", "ns international", "italo", "nightjet",
|
||||
"teso", "ice-berlijn",
|
||||
# Spoorinfra-jargon (samenvoegingen, onmiskenbaar OV)
|
||||
"spoorstoring", "spoorverkeer", "spoorwegovergang", "spoorlijn", "spoorbaan",
|
||||
"spoorstaking", "perron", "wisselstoring", "seinstoring", "treinstoring", "treinverkeer",
|
||||
"treinstaking", "treinongeval", "treinbotsing", "treinstel",
|
||||
"spoorstaking", "spoorsector", "spoorbeheerder", "spoornet", "spoorvervoerder",
|
||||
"ertms", "perron", "wisselstoring", "seinstoring", "treinstoring", "treinverkeer",
|
||||
"treinstaking", "treinongeval", "treinbotsing", "treinstel", "treinvertraging",
|
||||
"treinhinder", "treinuitval", "treinverstoring", "maaslijn", "nedersaksenlijn",
|
||||
"kamperlijn",
|
||||
# Bus/tram/metro-jargon
|
||||
"bushalte", "bushaltes", "busbaan", "buslijn", "busnet",
|
||||
"busstaking", "tramhalte", "tramlijn", "tramnet", "tramverkeer",
|
||||
"busstaking", "buurtbus", "veerdienst", "lijn 12",
|
||||
"tramhalte", "tramlijn", "tramnet", "tramverkeer",
|
||||
"metrolijn", "metroverkeer",
|
||||
# Tarief/vervoerder-jargon
|
||||
"ov-chipkaart", "ov-staking", "lightrail",
|
||||
|
|
@ -420,54 +458,63 @@ class RSSBot(Plugin):
|
|||
|
||||
@staticmethod
|
||||
def _filter_passes(title: str, summary: str) -> bool:
|
||||
"""Gewogen familiescore: elke OV-familie telt 1× per artikel (titel + samenvatting
|
||||
samen; herhaling of beide velden = één signaal). Doorlaten bij som >= drempel.
|
||||
(titel weegt NIET extra — één medium-hit, 'restaurant naast busstation',
|
||||
is geen OV-bewijs; besluit 2026-09-11).
|
||||
"""Gewogen familiescore (max-2-stelsel, besluit 2026-09-12): elke OV-familie
|
||||
telt 1× per artikel (titel + samenvatting samen; herhaling of beide velden =
|
||||
één signaal). Doorlaten bij som >= drempel (3). Geen enkele familie weegt
|
||||
meer dan 2, dus een enkele familie-hit kan nooit solo doorlaten — 'hermes'
|
||||
als achternaam passeerde vroeger op één vervoerder-hit van 3 (Margraten,
|
||||
2026-09-12); écht OV-nieuws combineert in de praktijk altijd met een tweede
|
||||
signaal (gevalideerd op 205 productie-artikelen).
|
||||
|
||||
Whitelist-termen (onmiskenbaar OV in élke context) tellen in de TITEL +2 —
|
||||
géén auto-pass meer; omdat elke whitelist-term óók in een familie zit, is
|
||||
dat effectief het behouden titel-anker ('Reactie Nederlandse Spoorwegen',
|
||||
'Werkzaamheden aan perron', 'Buurtbus rijdt niet meer' blijven door). Een
|
||||
whitelist-term ALLEEN in de samenvatting is geen OV-bewijs (besluit
|
||||
2026-09-12: 'openbaar vervoer' als bijzin in een economiebericht) en scoort
|
||||
alleen via de overeenkomstige familie.
|
||||
|
||||
Sterke families (gewicht 3) halen de drempel al met één woord in titel óf
|
||||
samenvatting. Medium (2) moet combineren met een andere OV-familie.
|
||||
Zwakke woorden (losse 'bus', 'breng', 'overweg', 'overwegen', 'sein',
|
||||
'opwaarderen', 'kaartje', 'rails', 'pendelbus') moeten combineren met een
|
||||
ander OV-woord én minstens één zwak woord moet in de titel staan; dezelfde
|
||||
zwakke familie in titel én samenvatting is géén combinatie. Whitelist-termen
|
||||
(NS, perron, bushalte, openbaar vervoer, ...) laten alleen onvoorwaardelijk
|
||||
door BIJ EEN HIT IN DE TITEL; in de samenvatting wegen ze mee als gewogen
|
||||
familie. Een medium + zwak-combinatie UITSLUITEND in de samenvatting (geen
|
||||
enkele hit in de titel) is geen OV-bewijs ('openbaar vervoer' + 'zakelijke
|
||||
reizigers' in een economiebericht, besluit 2026-09-12). Weert oa
|
||||
'VW-bus' (bus matcht niet ná een koppelteken), 'schoolbus', 'bussen rijden
|
||||
om' in een woningbrand-lead, het werkwoord 'brengen', het idioom 'goed met
|
||||
elkaar overweg kunnen', 'een wijk opwaarderen', brandweerjargon
|
||||
'sein brandmeester', figuratief 'weer op de rails' en een golfverslag
|
||||
waarin de samenvatting 'station' + 'pendelbus' + 'bus' noemt.
|
||||
Bewust doorgelaten: krant 'De Metro'/café 'De Tram' (medium) en atleet-
|
||||
'sprinter' in combinatie met ander OV-woord."""
|
||||
# Whitelist: een onmiskenbare OV-term in de TITEL laat altijd door (het
|
||||
# artikel kondigt het onderwerp aan: 'NS verlengt noodregeling'). Een
|
||||
# whitelist-term ALLEEN in de samenvatting is geen OV-bewijs ('openbaar
|
||||
# vervoer' als bijzin in een economiebericht, besluit 2026-09-12) en
|
||||
# scoort via de gewogen families hieronder.
|
||||
if RSSBot._whitelist_hit(title):
|
||||
return True
|
||||
'opwaarderen', 'kaartje', 'rails', 'pendelbus', 'spoor', 'staking',
|
||||
'vervoer', 'busongeluk', ...) moeten combineren met een ander OV-woord én
|
||||
minstens één zwak woord moet in de titel staan (of een whitelist-term in de
|
||||
titel); dezelfde zwakke familie in titel én samenvatting is géén combinatie.
|
||||
Een sterk (2) + zwak-combinatie UITSLUITEND in de samenvatting (geen
|
||||
familie-hit én geen whitelist-term in de titel) is geen OV-bewijs
|
||||
('openbaar vervoer' + 'zakelijke reizigers' in een economiebericht, besluit
|
||||
2026-09-12). Weert oa 'VW-bus' (bus matcht niet ná een koppelteken),
|
||||
'schoolbus', 'bussen rijden om' in een woningbrand-lead, het werkwoord
|
||||
'brengen', het idioom 'goed met elkaar overweg kunnen', 'een wijk
|
||||
opwaarderen', brandweerjargon 'sein brandmeester', figuratief 'weer op de
|
||||
rails', een golfverslag waarin de samenvatting 'station' + 'pendelbus' +
|
||||
'bus' noemt, en het Margraten-bericht met 'Ton Hermes' als achternaam.
|
||||
Bewust doorgelaten: krant 'De Metro'/café 'De Tram' (2, combineert) en
|
||||
atleet-'sprinter' in combinatie met ander OV-woord."""
|
||||
t_hits = RSSBot._fam_hits(title)
|
||||
s_hits = RSSBot._fam_hits(summary)
|
||||
# Eén familie telt 1× per ARTIKEL (titel én samenvatting samen): 'busstation'
|
||||
# in beide velden, of 60× in de tekst, blijft één signaal (besluit 2026-09-11).
|
||||
combined = dict(t_hits + s_hits)
|
||||
score = sum(combined.values())
|
||||
whitelist_title = RSSBot._whitelist_hit(title)
|
||||
if whitelist_title:
|
||||
# Whitelist-term in de titel = +2 (geen auto-pass, max-2-stelsel
|
||||
# 2026-09-12): houdt het titel-anker voor onmiskenbare termen, maar
|
||||
# een enkele whitelist-hit laat nooit meer solo door.
|
||||
score += 2
|
||||
if score < MATCH_FILTER_THRESHOLD:
|
||||
return False
|
||||
if max(combined.values()) == 1:
|
||||
if max(combined.values(), default=0) == 1:
|
||||
# Alleen zwakke families: dan moeten ≥2 verschillende families meetellen
|
||||
# én minstens één zwak woord moet in de TITEL staan. Zwakke woorden in
|
||||
# de samenvatting alleen zijn geen bewijs ('station' + 'pendelbus' +
|
||||
# 'bus' in een golfverslag telt anders op tot de drempel).
|
||||
if not t_hits or len(combined) < 2:
|
||||
# én een titel-anker (familie-hit óf whitelist-term in de titel).
|
||||
# Zwakke woorden in de samenvatting alleen zijn geen bewijs
|
||||
# ('station' + 'pendelbus' + 'bus' in een golfverslag telt anders op
|
||||
# tot de drempel).
|
||||
if not whitelist_title and (not t_hits or len(combined) < 2):
|
||||
return False
|
||||
elif not t_hits and 1 in combined.values():
|
||||
# Medium + zwak uitsluitend in de samenvatting, niets in de titel: geen
|
||||
# OV-bewijs. 'openbaar vervoer' + 'zakelijke reizigers' in een
|
||||
elif not t_hits and not whitelist_title and 1 in combined.values():
|
||||
# Sterk (2) + zwak uitsluitend in de samenvatting, niets in de titel:
|
||||
# geen OV-bewijs. 'openbaar vervoer' + 'zakelijke reizigers' in een
|
||||
# economiebericht telt anders op tot de drempel (besluit 2026-09-12).
|
||||
return False
|
||||
return True
|
||||
|
|
@ -476,20 +523,21 @@ class RSSBot(Plugin):
|
|||
def _filter_summary() -> str:
|
||||
"""Mensvriendelijke weergave van het vaste gewogen match-filter."""
|
||||
return (
|
||||
"**OV-matchfilter (vast in code, gewogen families):**\n"
|
||||
"- Sterk (3): vervoerders (NS, Arriva, ProRail, Qbuzz, ...), spoorinfra (spoorlijn, spoorwegovergang, perron, spoorstoring), "
|
||||
"samenstellingen als bushalte/buslijn/bushokje/busbaan/busverkeer, treinstoring/treinverkeer/treinstaking, "
|
||||
"intercity/streekvervoer/veerdienst/buurtbus/belbus, 'lijn 12'\n"
|
||||
"- Medium (2): tram, metro, openbaar vervoer, lightrail, halte, pont, spoorbrug, ov-chipkaart/ovpay, ov-staking, conducteur, "
|
||||
"trein-/bus-/metrostation — één medium-hit volstaat niet, moet combineren met een andere OV-familie; "
|
||||
"medium + zwak uitsluitend in de samenvatting (geen hit in de titel) telt niet\n"
|
||||
"**OV-matchfilter (vast in code, gewogen families, max-2):**\n"
|
||||
"- Sterk (2): vervoerders (NS, Arriva, ProRail, Qbuzz, Deutsche Bahn, TESO, ...), spoorinfra (spoorlijn, spoorstoring, perron, spoorsector, ertms), "
|
||||
"samenstellingen als bushalte/buslijn/buschauffeur, treinstoring/treinverkeer/treinvertraging, "
|
||||
"intercity/streekvervoer/veerdienst/buurtbus/belbus, 'lijn 12', ICE-frasen, rangeer... — één hit volstaat NIET: "
|
||||
"moet combineren (max-2-stelsel, besluit 2026-09-12)\n"
|
||||
"- Middel (2): tram, metro, openbaar vervoer, lightrail, halte, pont, spoorbrug, ov-chipkaart/ovpay, ov-staking, conducteur, "
|
||||
"trein-/bus-/metrostation — zelfde regel: moet combineren met een andere OV-familie; "
|
||||
"sterk/middel + zwak uitsluitend in de samenvatting (geen hit in de titel) telt niet\n"
|
||||
"- Zwak (1): losse 'bus' (niet ná een koppelteken), 'pendelbus'/'shuttlebus', 'trein', 'station(s)', 'breng', 'overweg', 'overwegen', "
|
||||
"'sein', 'kaartje', 'opwaarderen', 'rails', 'inchecken'/'uitchecken', 'dienstregeling', 'chipkaart', 'reisproduct', 'vervoersbewijs', "
|
||||
"'ontsporen', 'reiziger', 'vervoerder', 'sprinter' — moet combineren met een ander OV-woord, met minstens één zwak woord in de titel\n\n"
|
||||
"**Whitelist (altijd door bij een hit in de TITEL):** een onmisbare OV-term in de titel is genoeg "
|
||||
"'ontsporen', 'reiziger'/'passagier', 'vervoerder', 'sprinter', 'spoor', 'staking', 'vervoer', 'busongeluk', ... — moet combineren met een ander OV-woord, met minstens één zwak woord in de titel\n\n"
|
||||
"**Whitelist (+2 bij een hit in de TITEL, geen auto-pass):** onmiskenbare OV-termen "
|
||||
"(NS, ProRail, Nederlandse Spoorwegen, spoorstoring, perron, bushalte, conducteur, "
|
||||
"ov-chipkaart, ovpay, openbaar vervoer, ...); in de samenvatting alleen weegt zo'n term mee "
|
||||
"als gewogen familie (medium/sterk)\n\n"
|
||||
"ov-chipkaart, ovpay, openbaar vervoer, Deutsche Bahn, ICE Berlijn, ...); in de samenvatting alleen weegt zo'n term mee "
|
||||
"als gewogen familie\n\n"
|
||||
"Uitgesloten (blacklist): woorden die wél matchen maar geen OV-waarde hebben, "
|
||||
"o.a. straatnamen rond stations ('stationsstraat', 'stationsweg', ...) en niet-OV-vormen als 'stationcar' en 'stationair'\n\n"
|
||||
"Doorlaten: som van unieke OV-families ≥ 3 — één familie telt 1× per artikel "
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
id: nl.eddydevink.rss
|
||||
version: 1.11.0
|
||||
version: 1.12.0
|
||||
modules:
|
||||
- buzzrss
|
||||
main_class: RSSBot
|
||||
|
|
|
|||
|
|
@ -73,12 +73,16 @@ def check(cond: bool, msg: str):
|
|||
# --- Invariant 1: dubbelzinnige woorden mogen nooit sterk/medium of whitelist zijn
|
||||
AMBIGUOUS = [
|
||||
"trein", "bus", "station", "stations", "sprinter", "sprinters",
|
||||
"reiziger", "reizigers", "vervoerder", "vervoerders",
|
||||
"reiziger", "reizigers", "passagier", "passagiers", "vervoerder", "vervoerders",
|
||||
"inchecken", "uitchecken", "sein", "overweg", "overwegen", "breng",
|
||||
"kaartje", "opwaarderen", "rails", "dienstregeling", "chipkaart",
|
||||
"reisproduct", "vervoersbewijs", "vervoerbewijs",
|
||||
"pendelbus", "shuttlebus",
|
||||
"ontspor", "ontspoor", "ontspoord", "ontspoorde", "ontsporing",
|
||||
# audit 2026-09-12 (max-2-stelsel + completheids-audit)
|
||||
"hermes", "spoor", "staking", "stakingen", "vervoer", "vervoersbedrijf",
|
||||
"vervoerregio", "ritten", "bovenleiding", "abonnement",
|
||||
"busongeluk", "busongelukken", "busvervoer",
|
||||
]
|
||||
print(f"== invariant 1: {len(AMBIGUOUS)} dubbelzinnige woorden -> alleen zwak (1), nooit whitelist ==")
|
||||
for w in AMBIGUOUS:
|
||||
|
|
@ -93,6 +97,12 @@ UNAMBIGUOUS = [
|
|||
"conducteur", "ovpay", "ns", "prorail",
|
||||
"treinstoring", "halte", "openbaar vervoer", "intercity", "buurtbus",
|
||||
"veerdienst", "lijn 12", "ov-chipkaart", "spoorbrug",
|
||||
# audit 2026-09-12 (completheids-audit, max-2-stelsel)
|
||||
"spoorsector", "spoorbeheerder", "spoornet", "spoorvervoerder",
|
||||
"treinvertraging", "treinhinder", "treinuitval", "treinverstoring",
|
||||
"ertms", "teso", "rangeerterrein", "rangeren", "ice-berlijn",
|
||||
"maaslijn", "nedersaksenlijn", "kamperlijn",
|
||||
"ns international", "deutsche bahn", "european sleeper", "italo", "nightjet",
|
||||
]
|
||||
print(f"== invariant 2: {len(UNAMBIGUOUS)} onmiskenbare OV-termen -> sterk/medium of whitelist ==")
|
||||
for w in UNAMBIGUOUS:
|
||||
|
|
@ -100,10 +110,10 @@ for w in UNAMBIGUOUS:
|
|||
check(whitelisted(w) or any(g >= 2 for g in gew),
|
||||
f"{w!r} heeft whitelist of gewicht >= 2 (gewichten {sorted(gew)})")
|
||||
|
||||
# --- Invariant 3: patronen compileren en gewichten geldig
|
||||
print("== invariant 3: alle 24+ families compileren, gewicht in {1,2,3} ==")
|
||||
# --- Invariant 3: patronen compileren en gewichten geldig (max-2, besluit 2026-09-12)
|
||||
print("== invariant 3: alle families compileren, gewicht in {1,2} ==")
|
||||
for p, w in FAMILIES:
|
||||
check(w in (1, 2, 3), f"familie {p[:40]!r} heeft geldig gewicht {w}")
|
||||
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")
|
||||
|
||||
# --- Regressie: gedrag van _filter_passes op bekende cases (precision-first)
|
||||
|
|
@ -183,6 +193,26 @@ GOLDEN = [
|
|||
("Lijn 12 rijdt vanaf maandag een andere route", "De route gaat via het centrum.", True),
|
||||
("Werkzaamheden aan perron", "Het perron wordt volgende maand opgeknapt.", True),
|
||||
("Reactie Nederlandse Spoorwegen", "De Nederlandse Spoorwegen zeggen meer in te zetten op punctualiteit.", True),
|
||||
# max-2-stelsel (besluit 2026-09-12): geproduceerd op 205 productie-artikelen
|
||||
# + LLM-audit. Geen enkele familie weegt meer dan 2 → één hit kan nooit solo
|
||||
# doorlaten; whitelist-term in de titel telt +2 (titel-anker).
|
||||
("Veel animo voor 'adopteren' graf op Amerikaanse begraafplaats Margraten",
|
||||
"…'Het voelde echt alsof je in de rij stond voor festivaltickets'… 'Ik ben bang dat mensen met de slaapzak voor de laptop gaan liggen', zei Ton Hermes eerder.", False),
|
||||
# ^ echte false positive 2026-09-12: 'hermes' (achternaam) scoorde vroeger 3 via de vervoerdersfamilie
|
||||
("TESO onderzoekt komst derde veerboot tussen Texel en Den Oever",
|
||||
"Veerdienst TESO onderzoekt of het haalbaar is om een derde veerboot in te zetten tussen Oudeschild en Den Oever.", True), # teso(2) + veerboot(2) = 4
|
||||
("Vrouw buschauffeur Rob zwaar aangeslagen na dodelijk ongeval",
|
||||
"Bij het dodelijke busongeluk in Zwitserland zat de politicus achter het stuur.", True), # buschauffeur(2) + busongeluk(1) = 3
|
||||
("Vakbonden noemen stakingsdag in het OV 'een geslaagde dag'",
|
||||
"Gisteren was de landelijke stakingsdag in het OV; medewerkers legden in de spoorsector 24 uur het werk neer.", True), # ov(2) + staking(1) + spoorsector(2)
|
||||
("Dodental veerbootbrand Filipijnen loopt verder op", "Zeker 76 mensen kwamen om bij de brand op de veerboot.", False), # één veerboot-hit (2) = geen NL-OV
|
||||
("ICE Berlijn voegt na Hamburg vanaf december ook stop in Bremen toe",
|
||||
"De ICE Berlijn gaat vanaf december via Bremen en Hamburg Hauptbahnhof naar Berlijn rijden. Dat meldt NS International.", True), # ice-berlijn(2) + ns(2) = 4
|
||||
("Laatste noot voor vernielde stationspiano Eindhoven",
|
||||
"De piano in het station was jarenlang een begrip reizigers produceerden er filmpjes.", False), # cultuurstukje; 'station'/'reizigers' zwak-alleen zonder titel-anker
|
||||
("Meerdere doden na busongeluk in Zwitserland", "Het busongeluk gebeurde naast de snelweg bij een afrit.", False), # busongeluk(1) alleen = zwak-alleen
|
||||
("Antwerpen ontvangt eerste ICE", "De eerste ICE van Deutsche Bahn rijdt vanaf volgende maand naar Antwerpen.", False), # bewust geweerd: 'ice van' is NIET opgenomen (ijs-botsing); deutsche bahn(2) alleen < 3 — was vóór de wijziging óók al geweerd
|
||||
("NS verlengt noodregeling tot volgend jaar", "De vervoerder kampt met personeelstekorten.", True), # ns(2) + vervoerder(1) = 3
|
||||
]
|
||||
print(f"== regressie: {len(GOLDEN)} cases (precision-first) ==")
|
||||
for t, s, want in GOLDEN:
|
||||
|
|
|
|||
Loading…
Reference in a new issue