From 1f168b2f54b3a09c435cd4217d1a136db02e7a92 Mon Sep 17 00:00:00 2001 From: Eddy de Vink Date: Fri, 11 Sep 2026 07:49:05 +0200 Subject: [PATCH] v1.9.6: pendelbus/shuttlebus naar zwak + zwak-alleen moet titel-anker hebben MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aanleiding: Omroep Brabant-golfbericht (Solheim Cup Cromvoirt, 11-09-2026) kwam door het filter. 'pendelbus' stond op de whitelist (evenementpendel vanaf station Den Bosch), en 'station'+'bus'+'pendelbus' in de samenvatting was samen al drempel 3. - pendelbus/shuttlebus: whitelist + medium -> zwak (1), één familie (synoniemen tellen niet als twee onafhankelijke signalen). - _filter_passes: bij uitsluitend zwakke hits moet minstens één zwak woord in de TITEL staan; zwakke woorden alleen in de samenvatting zijn geen bewijs. - validate_filter.py: invariant 1 uitgebreid + 3 regressiecases (golfbericht, zwak-alleen samenvatting, positieve controle met titel-anker). - _filter_summary()/docstrings gelijkgetrokken met de werkelijke gewichten. --- buzzrss/bot.py | 74 ++++++++++++++++++++++++++++++---------------- maubot.yaml | 2 +- validate_filter.py | 10 +++++++ 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/buzzrss/bot.py b/buzzrss/bot.py index 7fc981e..051630e 100644 --- a/buzzrss/bot.py +++ b/buzzrss/bot.py @@ -56,9 +56,12 @@ rss_change_level = EventType.find("xyz.maubot.rss", t_class=EventType.Class.STAT # Gewicht 2 (medium): één woord in de titel volstaat; in de samenvatting moet er # een tweede OV-woord bijkomen. # Gewicht 1 (zwak/dubbelzinnig: los "bus", "breng", "overweg", "overwegen", "sein", -# "kaartje", "opwaarderen", "rails"): moet met een ander OV-woord combineren (een -# tweede, andere familie — dezelfde zwakke familie in titel én samenvatting telt -# niet als combinatie). Weert zo "VW-bus"/"schoolbus", "weer op de rails", het +# "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 @@ -101,7 +104,15 @@ rss_change_level = EventType.find("xyz.maubot.rss", t_class=EventType.Class.STAT # 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. +# opwaarderen, rails, dienstregeling, chipkaart, ontsporen, +# pendelbus/shuttlebus (evenement-/hotel-/parkeerpendel; +# synoniemen -> bewust één familie, anders tellen twee +# synoniemen als twee onafhankelijke signalen). +# 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 +# de samenvatting zijn anders samen al 3 punten +# ("station" + "pendelbus" + "bus" in een golfverslag). # 3. BLACKLIST -> gematchte woorden zonder OV-waarde (stationsstraat, # stationair, stationcar, ...); blokkeren de familie niet. # @@ -128,13 +139,14 @@ MATCH_FILTER_FAMILIES: list[tuple[str, int]] = [ # medium (2) (r"\btrams?\b", 2), (r"\bmetro(?:'?s)?\b", 2), - (r"\b(?:openbaar vervoer|lightrail|pendelbus|shuttlebus|halte|bushokje|busbaan)\w*\b", 2), + (r"\b(?:openbaar vervoer|lightrail|halte|bushokje|busbaan)\w*\b", 2), (r"\b(?:ov-chipkaart|ovpay|ov-pay|studentenreisproduct)\w*\b", 2), (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 # zwak (1) — dubbelzinnig, moet combineren (r"(?= drempel. Sterke families (gewicht 3) halen de drempel al met één woord in titel óf - samenvatting. Medium (2) in de titel ook; in de samenvatting moet een tweede - OV-woord bijkomen. Zwakke woorden (losse 'bus', 'breng', 'overweg', 'overwegen', - 'sein', 'opwaarderen', 'kaartje', 'rails') moeten combineren met een ander - OV-woord; dezelfde zwakke familie in titel én samenvatting is géén combinatie. - 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' en figuratief 'weer op de rails'. - Bewust doorgelaten: krant 'De Metro'/café 'De Tram' (medium), film-'treinramp' - en atleet-'sprinter' (sterk).""" + samenvatting. Medium (2) in de titel ook; in de samenvatting moet er een + tweede OV-woord bijkomen. + 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. 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: één onmiskenbare OV-term (titel óf samenvatting) laat altijd door. if RSSBot._whitelist_hit(title) or RSSBot._whitelist_hit(summary): return True @@ -396,9 +411,13 @@ class RSSBot(Plugin): score = 2 * sum(w for _, w in t_hits) + sum(w for _, w in s_hits) if score < MATCH_FILTER_THRESHOLD: return False - # Alleen zwakke families? Dan moet een tweede (verschillende) familie meetellen. - if max(w for _, w in t_hits + s_hits) == 1 and len({i for i, _ in t_hits + s_hits}) < 2: - return False + if max(w for _, w in t_hits + s_hits) == 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({i for i, _ in t_hits + s_hits}) < 2: + return False return True @staticmethod @@ -406,17 +425,20 @@ class RSSBot(Plugin): """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, seinstoring, perron), " - "station(s), bushalte/buslijn/bushokje/busstation, intercity/sprinter/streekvervoer/veerdienst/buurtbus, 'lijn 12'\n" - "- Medium (2): tram, metro, openbaar vervoer/dienstregeling/inchecken, halte, bushokje, busbaan, vervoerder, reiziger, " - "ov-chipkaart/ovpay/reisproduct, ov-staking, pont\n" - "- Zwak (1): losse 'bus' (niet ná een koppelteken), 'trein', 'breng', 'overweg', 'overwegen', 'sein', 'kaartje', 'opwaarderen', 'rails' — moet combineren met een ander OV-woord\n\n" + "- Sterk (3): vervoerders (NS, Arriva, ProRail, Qbuzz, ...), spoorinfra (spoorlijn, spoorwegovergang, perron, spoorstoring), " + "trein-/metro-/busstation, 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, ov-chipkaart/ovpay, ov-staking, conducteur\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):** één onmiskenbare OV-term in titel óf samenvatting is genoeg " "(NS, ProRail, Nederlandse Spoorwegen, spoorstoring, perron, bushalte, metrostation, conducteur, " - "ov-chipkaart, ovpay, openbaar vervoer, dienstregeling, ...)\n\n" + "ov-chipkaart, ovpay, openbaar vervoer, ...)\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: `2×(titel-score) + 1×(samenvatting-score) ≥ 3`" + "Doorlaten: `2×(titel-score) + 1×(samenvatting-score) ≥ 3`; bij uitsluitend zwakke woorden tellen alleen " + "≥2 verschillende families én een zwak woord in de titel" ) async def _send( diff --git a/maubot.yaml b/maubot.yaml index 5509c9b..c528086 100644 --- a/maubot.yaml +++ b/maubot.yaml @@ -1,5 +1,5 @@ id: nl.eddydevink.rss -version: 1.9.5 +version: 1.9.6 modules: - buzzrss main_class: RSSBot diff --git a/validate_filter.py b/validate_filter.py index b10f9ab..1db6557 100755 --- a/validate_filter.py +++ b/validate_filter.py @@ -77,6 +77,7 @@ AMBIGUOUS = [ "inchecken", "uitchecken", "sein", "overweg", "overwegen", "breng", "kaartje", "opwaarderen", "rails", "dienstregeling", "chipkaart", "reisproduct", "vervoersbewijs", "vervoerbewijs", + "pendelbus", "shuttlebus", "ontspor", "ontspoor", "ontspoord", "ontspoorde", "ontsporing", ] print(f"== invariant 1: {len(AMBIGUOUS)} dubbelzinnige woorden -> alleen zwak (1), nooit whitelist ==") @@ -123,7 +124,16 @@ GOLDEN = [ ("Fietser gewond op de Stationsstraat", "Het slachtoffer is naar het ziekenhuis gebracht.", False), ("Kunstenaar maakt kaartje voor het museum", "", False), ("Benzineprijs stijgt opnieuw", "De pomp wordt duurder door de olieprijs.", False), + # geweerd — zwakke woorden alléén in de samenvatting (geen titel-anker). + # Echt geval: Omroep Brabant, Solheim Cup-golfverslag (11-09-2026) — 'pendelbus' + # stond op de whitelist en 'station'+'pendelbus'+'bus' in de samenvatting was + # samen score 3. + ("Golf-fans uit de hele wereld naar Cromvoirt: 'Beter dan sterrenrestaurant'", + "Op het station in Den Bosch stapte de oud-prof in de pendelbus naar Bernardus Golf. " + "In de bus bleek ze zeker niet de enige Amerikaanse.", False), + ("Toernooi trekt duizenden bezoekers", "Vanaf het station rijden pendelbussen en extra bussen.", False), # door — echte OV-berichten + ("Trein vertraagd, reizigers pakken de bus", "De storing duurde een uur.", True), ("Station Amersfoort krijgt nieuwe perrons", "De NS laat de perrons vernieuwen.", True), ("Trein ontspoorde bij Weesp", "De spoorlijn was uren dicht.", True), ("Bushalte aan de Markt wordt verplaatst", "De halte gaat 200 meter opschuiven.", True),