# Eval-set for the retrieval quality gate (module 5, phase 3, plan §6.2, # kb/phases/kb-m5-faza3.md). Transcribed 1:1 from the pilot baseline, # kb/phases/kb-m5-eval-retrieval-pilot.md (read-only source -- this file is the versioned # copy the plan asked for, so the set stops living only in a session transcript). # # kind: # hit -- pilot found a correct top-1 match (dist < 0.45) # grey_zone -- pilot landed in the 0.45-0.55 band (on-topic, imprecise) # negative_control -- pilot correctly found nothing (dist > 0.55) # negative_control_borderline -- pilot correctly found nothing, but close to the 0.55 edge # # expected_envelope is null for both negative-control kinds: there is no document these # queries should match, by design. queries: - id: "1" text: "polisa ubezpieczeniowa PZU warunki odpowiedzialności" kind: hit expected_envelope: "paperless:14" baseline_top1_dist: 0.3418 note: > Pilot top-1 = paperless:14 (OWU PZU Auto); ujawnił duplikat paperless:14 ≡ paperless:74 (flagowany excluded_reason='duplicate' w kroku 1 fazy 3). - id: "2" text: "faktura za usługi telekomunikacyjne kwota do zapłaty" kind: hit expected_envelope: "paperless:192" baseline_top1_dist: 0.3447 note: > Pilot top-1 = paperless:192 (faktura P4); poz. 3/5 w pilocie był chunk z OCR-śmieciem (kody kreskowe) -- powinien wypaść po excluded_reason='ocr_junk' z kroku 1. - id: "3" text: "zasady punktacji FLL Challenge robot game (PL)" kind: grey_zone expected_envelope: "paperless:5" baseline_top1_dist: 0.4154 note: > Pilot: szara strefa -- rodzina dokumentów OK, sedno (zasady punktacji) nie trafione precyzyjnie. Kandydat na poprawę: czy pre-filtr po streszczeniu podnosi trafność? - id: "4" text: "FLL robot game mission scoring points table (EN)" kind: hit expected_envelope: "paperless:5" baseline_top1_dist: 0.4114 note: > Cross-lingual (EN zapytanie) trafia lepiej niż PL (zapytanie 3); poz. 2+ w pilocie = paperless:119 (scoresheet, mojibake) -- mojibake nie jest śmieciem, niesie sygnał. - id: "5" text: "innovation project scoring" kind: hit expected_envelope: "paperless:3" baseline_top1_dist: 0.3869 note: "Najlepszy wynik pilota: top-5 spójnie z jednego właściwego dokumentu (arkusz ocen IP)." - id: "N" text: "przepis na sernik z rodzynkami" kind: negative_control expected_envelope: null baseline_top1_dist: 0.6210 note: "Poprawny brak w pilocie; separacja od trafień wyraźna." # --- historia kontrolki borderline: N2 "piaskownica plastikowa" (WYCOFANA 2026-08-06) --- # Nie kasować: to zapis decyzji, nie komentarz do kodu. Rolę kontrolki borderline przejmuje # N3 poniżej, a samo zapytanie o piaskownicę żyje dalej jako pozytywne M5 w `mail_queries`. # # Pilot (kb-m5-eval-retrieval-pilot.md): kind negative_control_borderline, baseline_top1_dist # 0.5533, no_answer_threshold 0.50. Poprawnie na granicy "brak" -- semantycznie sąsiednie # dokumenty wspólnoty mieszkaniowej, nie odpowiedź na zapytanie. # 2026-07-23 (faza mailowa, bramka po Etapie A): po dolaniu chunków mailowych top-1 = # newsletter szkoły narciarskiej (Rossignol, rozmiary nart 155-181 cm, dist 0.5298) -- # zweryfikowana treść pokazała kolizję semantyczną krótkich, liczbowych tekstów w # przestrzeni wektorowej, NIE realny mail o piaskownicy; korpus mailowy Etapu A takiego # trafienia nie zawierał (próbne zapytanie "piaskownica plac zabaw wspólnota" dało wtedy # dist 0.5585, miss -- odrzucone jako wpis mail_queries, ówczesne "M5"). Próg obniżono # wtedy z 0.55 do 0.50 właśnie z powodu tej znanej kolizji, żeby bramka nie płonęła co # uruchomienie na nie-problemie. # 2026-08-06 (zamknięcie Etapu B, pełny korpus mailowy w HNSW) -- ZWROT AKCJI: kontrolka # unieważniona przez wzrost korpusu, w dwóch niezależnych miejscach naraz: # a) "piaskownica plastikowa" spadła do 0.4924 (flat i hybrid, cascade 0.5533) na mail # przedszkolny "Materiały plastyczne" -- znowu kolizja leksykalna (plastikowa / # plastyczne), ale tym razem PONIŻEJ progu 0.50, więc kryterium 3 FAIL przy PASS # kryteriów 1/2/4 -- czyli bramka płonęła dokładnie na tym, przed czym próg miał # chronić; # b) odrzucone w Etapie A "piaskownica plac zabaw wspólnota" ma dziś realne odpowiedzi: # maile administracji wspólnoty (holc.waw.pl, 2023) "WM Targowa 2A - zabawy na terenie # wspólnoty" (dist 0.4562) i "WM Targowa 2A - wymiana piasku" (dist 0.4597, # envelope 6ab218df-ef21-dc78-d589-34f69a97aae6@holc.waw.pl). # Wniosek: to NIE regresja retrievalu -- korpus urósł o treść, której w Etapie A nie było, # a kontrolka negatywna z definicji traci ważność w chwili, gdy odpowiedź na nią wpada do # korpusu. Stąd przekwalifikowanie na pozytywne M5 zamiast łatania progu w dół. # --- dobór następcy (kandydaci sprawdzeni na żywym kb-query 2026-08-06, --gate-n 10) --- # Wymóg: temat sąsiadujący z korpusem (żeby kontrolka była borderline, nie oczywista), ale # bez odpowiednika w Paperless ANI w mailach, dist > 0.50 we WSZYSTKICH torach. # Uwaga metodologiczna z tego doboru: korpus mailowy jest po Etapie B znacznie szerszy niż # "wspólnota / przedszkole / FLL / polisy / telco / narty" -- zawiera też archiwum zawodowe, # newslettery, oferty pracy, Allegro, rezerwacje hoteli, PIT, najem, judo. Odrzucone jako # kontrolki, bo korpus MA na nie realną odpowiedź (dist w nawiasie = min po torach): # kominiarski/wentylacja (0.4277, paperless:105), hotel nad morzem (0.4166), PIT-37 (0.3994), # judo dla dzieci (0.3469), najem mieszkania (0.3699), prawo jazdy kat. B (0.3606), # opony zimowe (0.4098), gwarancja AGD (0.4498), karta rowerowa (0.4340). # Kandydaci, którzy przeszli (flat / cascade / hybrid): # A. "sterylizacja kota cennik kliniki weterynaryjnej" 0.5257 / 0.5799 / 0.5257 <- AKTYWNY # B. "karta wędkarska pozwolenie na połów ryb" 0.5203 / 0.5223 / 0.5203 # (odrzucony: cascade tylko 0.0223 nad progiem -- za ciasno na trwałą bramkę) # C. "pasieka ul pszczeli zbiór miodu" 0.5985 / 0.6318 / 0.5985 # (odrzucony jako aktywny: za łatwy, powiela rolę N "przepis na sernik"; trzymany jako # zapasowy, gdyby korpus kiedyś unieważnił A tak jak unieważnił N2) - id: "N3" text: "sterylizacja kota cennik kliniki weterynaryjnej" kind: negative_control_borderline expected_envelope: null baseline_top1_dist: 0.5257 no_answer_threshold: 0.50 note: > Następca N2 (2026-08-06, patrz historia powyżej). Temat celowo sąsiedni wobec korpusu -- usługa domowa z językiem cennika/rozliczenia, czyli rejestr, w którym korpus jest gęsty -- ale zwierząt domowych nie ma w nim ani w Paperless, ani w mailach. Baseline zmierzony na żywym kb-query (192.168.31.5:8230, --transport http, --gate-n 10), nie w pilocie: flat 0.5257 / cascade 0.5799 / hybrid 0.5257. Top-1 we flat/hybrid to newsletter zakupowy z ofertami -- brak realnej odpowiedzi, czyli kontrolka działa. Próg 0.50 przeniesiony z N2 bez zmiany (margines ~0.026 nad progiem; przy kolejnym dużym doładowaniu korpusu należy go zweryfikować, a nie obniżać próg -- lekcja z N2). # Faza mailowa (kb/phases/kb-m5-faza-mailowa.md, §8, Krok 5) -- bramka jakościowa dla # treści mailowej wprowadzonej w Etapie A (ostatnie 12 miesięcy, plan §7 Krok 4). Wypełniona # przez operatora 2026-07-23 (5 zapytań "wiem że to mam w mailach z ostatniego roku"; M5 # odrzucone wtedy po weryfikacji, patrz historia N2 powyżej -- i PRZYWRÓCONE 2026-08-06 po # Etapie B, gdy odpowiedź na nie realnie znalazła się w korpusie). expected_envelope jest null # dla M1-M4 -- operator dostarczył treść zapytania, nie surowy Message-ID; kind: mail_hit ma # inną semantykę hit@3 niż `queries:` powyżej: hit iff top-3 hybrid zawiera wynik z gałęzi # mailowej (envelope.source w summaryless_sources, dziś gmail) z dist < 0.45 # (retrieval_eval.py::mail_hit_at_3) -- identity-match na expected_envelope nie ma tu # zastosowania, bo dla M1-M4 nie ma czego dopasować. # # WYJĄTEK (2026-08-06): M5 ma znane, zweryfikowane curl-em expected_envelope. Uwaga przy # czytaniu raportu -- retrieval_eval.py::summarize_query_result dla kind: mail_hit NIE używa # expected_envelope (idzie ścieżką mail_hit_at_3, source-match), więc ten identyfikator ma # dziś wartość wyłącznie dokumentacyjną/audytową: mówi, który mail uznaliśmy za poprawną # odpowiedź, ale bramka go nie sprawdza. Jeśli kiedyś ma być egzekwowany, to zmiana w # retrieval_eval.py (np. identity-match gdy expected_envelope != null), nie w tym pliku. # # Format wpisu (identyczny co do pól z `queries:` powyżej, minus baseline_top1_dist -- nie było # pilota mailowego przed tą bramką): # - id: "M1" # text: "..." # kind: mail_hit # expected_envelope: "" # note: "..." mail_queries: - id: "M1" text: "szkolenie narciarskie zegrze termin" kind: mail_hit expected_envelope: null note: "Wątek listy klubowej (lasery-zegrze) — celowo na granicy filtra newsletterowego." - id: "M2" text: "faktura Play kwota do zapłaty telefon" kind: mail_hit expected_envelope: null note: "Faktury operatora przychodzą mailem co miesiąc." - id: "M3" text: "wznowienie polisy OC składka samochód" kind: mail_hit expected_envelope: null note: "Korespondencja ubezpieczeniowa — cross-source z dokumentami OWU." - id: "M4" text: "rejestracja drużyny FLL zgłoszenie sezon" kind: mail_hit expected_envelope: null note: "Wątki organizacyjne FLL 25-26." - id: "M5" text: "wymiana piasku w piaskownicy na placu zabaw wspólnoty" kind: mail_hit expected_envelope: "6ab218df-ef21-dc78-d589-34f69a97aae6@holc.waw.pl" note: > Dawna kontrolka negatywna N2, przekwalifikowana 2026-08-06 po Etapie B (pełna historia w komentarzu w `queries:` powyżej). Odpowiedź: mail administracji wspólnoty "WM Targowa 2A - wymiana piasku" (k.szrajner@holc.waw.pl, 2023-06-16, wymiana piasku w piaskownicy na placu zabaw osiedla 19.06). Sformułowanie to naturalniejsza wariacja operatorskiego "piaskownica plac zabaw wspólnota": samo "piaskownica plac zabaw wspólnota" daje dziś top-1 0.4562 / top-2 0.4597 -- oba NAD progiem HIT_THRESHOLD 0.45, więc mail_hit_at_3 liczyłoby to jako miss mimo poprawnych i zweryfikowanych trafień w top-2. Wariant z "wymianą piasku" trafia expected_envelope na pozycji 1 z dist 0.2858 (flat i hybrid), z zapasem wobec progu. To zarazem jedyne mail_query z niepustym expected_envelope -- patrz WYJĄTEK w komentarzu nagłówkowym tej sekcji (bramka go nie egzekwuje).