diff --git a/base-config.yaml b/base-config.yaml index c45ac42..af5b956 100644 --- a/base-config.yaml +++ b/base-config.yaml @@ -28,7 +28,7 @@ exclude_paywalled: true # 0 = uit. title_dedup_days: 30 # OV-matchfilter: VAST in code (gewogen families + blacklist), niet via config te wijzigen. -# Doorlaten als titelscore + samenvattingscore >= 3 (titel weegt niet extra). Zie de families en de +# Doorlaten als som van unieke OV-families >= 3; één familie telt 1× per artikel (titel + samenvatting; herhaling of beide velden = 1 signaal). Zie de families en de # blacklist in buzzrss/bot.py (MATCH_FILTER_FAMILIES / MATCH_FILTER_BLACKLIST). # `!rss set-filter` en `!rss filter` tonen alleen de huidige (vaste) filter. # Users who can bypass room permission checks diff --git a/buzzrss/bot.py b/buzzrss/bot.py index 651b6eb..8dae00b 100644 --- a/buzzrss/bot.py +++ b/buzzrss/bot.py @@ -50,10 +50,10 @@ rss_change_level = EventType.find("xyz.maubot.rss", t_class=EventType.Class.STAT # Gewogen OV-trefwoord-families voor het match-filter. Elke tuple = (regex, gewicht). -# Per familie wordt 1× geteld per tekst (niet per cluster/herhaling). Drempel (3): -# doorlaten als titelscore + samenvattingscore >= MATCH_FILTER_THRESHOLD -# (titel weegt NIET extra — besluit 2026-09-11: 'restaurant naast busstation' -# als enige medium-hit in de titel is geen OV-bericht). +# Per familie wordt 1× geteld per ARTIKEL (titel én samenvatting samen; herhaling +# 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. @@ -96,7 +96,9 @@ rss_change_level = EventType.find("xyz.maubot.rss", t_class=EventType.Class.STAT # 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). -# 2. GEWOGEN FAMILIES -> score = titel + samenvatting >= drempel (3). +# 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, @@ -395,9 +397,10 @@ class RSSBot(Plugin): @staticmethod def _filter_passes(title: str, summary: str) -> bool: - """Gewogen familiescore: doorlaten bij titelscore + samenvattingscore >= drempel - (titel weegt NIET extra — één medium-hit in de titel, 'restaurant naast - busstation', is geen OV-bewijs; besluit 2026-09-11). + """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). Sterke families (gewicht 3) halen de drempel al met één woord in titel óf samenvatting. Medium (2) moet combineren met een andere OV-familie. @@ -417,15 +420,18 @@ class RSSBot(Plugin): return True t_hits = RSSBot._fam_hits(title) s_hits = RSSBot._fam_hits(summary) - score = sum(w for _, w in t_hits) + sum(w for _, w in s_hits) + # 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()) if score < MATCH_FILTER_THRESHOLD: return False - if max(w for _, w in t_hits + s_hits) == 1: + if max(combined.values()) == 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: + if not t_hits or len(combined) < 2: return False return True @@ -447,7 +453,8 @@ class RSSBot(Plugin): "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: `titel-score + samenvatting-score ≥ 3` (titel weegt niet extra); " + "Doorlaten: som van unieke OV-families ≥ 3 — één familie telt 1× per artikel " + "(titel + samenvatting samen; herhaling of beide velden = één signaal); " "bij uitsluitend zwakke woorden tellen alleen " "≥2 verschillende families én een zwak woord in de titel" ) diff --git a/maubot.yaml b/maubot.yaml index eecf6e1..c8802e0 100644 --- a/maubot.yaml +++ b/maubot.yaml @@ -1,5 +1,5 @@ id: nl.eddydevink.rss -version: 1.9.8 +version: 1.9.9 modules: - buzzrss main_class: RSSBot diff --git a/validate_filter.py b/validate_filter.py index d4aef85..450e62d 100755 --- a/validate_filter.py +++ b/validate_filter.py @@ -145,10 +145,10 @@ GOLDEN = [ ("Restaurant weg, pand staat te verloederen: 'Doorn in het oog'", "De gemeente Midden-Delfland wil het leegstaande horecapand naast busstation Maasland " "Viaduct kopen. Het gebouw staat al jaren leeg en maakt een vervallen indruk.", False), - ("Pand naast busstation wordt gesloopt", "Het leegstaande pand naast het busstation gaat plat.", True), # busstation in titel ÉN samenvatting: 2+2=4 — twee velden tellen mee + ("Pand naast busstation wordt gesloopt", "Het leegstaande pand naast het busstation gaat plat.", False), # één familie in titel ÉN samenvatting = één signaal: 2 < 3 (besluit 2026-09-11) ("Nieuwe fietsenstalling bij busstation", "", False), # besluit 2026-09-11: één medium-hit in de titel is onvoldoende (titel weegt 1×, was 2×) ("Restaurant naast busstation wil uitbreiden", "De eigenaar wil uitbreiden naar het naastgelegen pand.", False), # zelfde regel, letterlijk gebruikersvoorbeeld - ("Busstation wordt verbouwd", "Het busstation krijgt andere perrons.", True), # busstation in titel én samenvatting: 4 + ("Busstation wordt verbouwd", "De verbouwing duurt tot het voorjaar.", False), # herhaling/één woord = 1 signaal: 2 < 3 ('busstation' 60× weegt ook 1×) ("Metro rijdt niet", "De halte is tijdelijk gesloten.", True), # medium-combinatie over twee families: metro(2)+halte(2)=4 # busstation mag niet dubbel meetellen via 'bus' én 'station' (was 2×3=6→nu 1×2) ("Metrostation Centraal tijdelijk gesloten", "De metro's rijden niet.", True),