fix(maria): acoperirea se judeca pe ce a intrebat omul acum, si pe radacina cuvantului

Doua reparatii pe poarta de acoperire, amandoua masurate pe setul de calibrare
extins (31 de cazuri, de la 26).

**Termenii distinctivi se comparau pe cuvantul intreg.** Documentatia si clientul
nu folosesc aceleasi forme: documentul scrie „token" si „tokenuri", omul scrie
„tokenul"; documentul „Generare", omul „generez". Trei continuari legitime din
cinci escaladau desi chunk-ul cu raspunsul era chiar in context. Comparatia se
face acum pe primele 5 litere; codurile raman intregi (ORA-01722 si ORA-01720 au
aceleasi cinci).

**Interogarea avea doua roluri amestecate.** Pe un fir, regasirea are nevoie de
ancora („da, ma blocheaza" singur nu gaseste nimic), dar acoperirea nu: judecata
pe ancora, ea cere sa apara in documente si salutul, si numele firmei, si luna,
deci raportul scade la fiecare replica si firul lung escaladeaza degeaba.
`rank.assess` primeste `dovada` — mesajul nou, plus OCR-ul capturii lui; cand
acesta n-are termeni proprii, se cade inapoi pe interogarea intreaga.

Setul de calibrare: 31/31 cu reparatia, 30/31 fara.

Ce NU s-a facut, desi era propus in handover: lista de formule de politete in
`rare_terms`. Masuratoarea nu o justifica — cu potrivirea pe radacina, cazurile cu
ancora politicoasa trec si fara ea, iar intr-una din configuratii facea rau.
Cauza reala nu era politetea din ancora, ci morfologia.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
This commit is contained in:
Claude Agent
2026-09-01 19:57:49 +00:00
parent 89145d437e
commit 653f5cbba9
6 changed files with 184 additions and 20 deletions

View File

@@ -45,6 +45,45 @@ def test_rare_terms_prinde_codurile_si_ignora_cuvintele_comune():
assert "ora-01722" in rare
def test_assess_gaseste_termenul_la_alta_forma_gramaticala():
# Documentul scrie „token"/„tokenuri", omul scrie „tokenul". Comparat pe cuvantul
# intreg, singurul cuvant care conteaza nu se gaseste si intrebarea escaladeaza.
bm = rank.Bm25(DOCS)
covered, motiv = rank.assess("imi zice ca tokenul a expirat", 0.64, DOCS[1:2], bm)
assert covered
assert "tokenul" in motiv
def test_assess_codurile_se_compara_intregi_nu_pe_radacina():
# „ora-01722" si „ora-01720" au aceleasi cinci litere de la inceput.
bm = rank.Bm25(DOCS)
covered, _ = rank.assess("eroarea ORA-01720", 0.64, DOCS[:1], bm)
assert not covered
def test_assess_dovada_judeca_mesajul_nou_nu_ancora():
# Continuare pe un fir: ancora e salutul plus reclamatia vaga, mesajul nou e
# chiar intrebarea. Fara dovada separata, „buna/august" (care nu apar nicaieri)
# trag raportul sub prag si escaladeaza degeaba.
bm = rank.Bm25(DOCS)
ancora = "Buna ziua . Am o problema pe luna august la firma AUTO SULEA . Ma ajutati?"
query = f"{ancora}\ntokenul a expirat"
fara, _ = rank.assess(query, 0.64, DOCS[1:2], bm)
cu, motiv = rank.assess(query, 0.64, DOCS[1:2], bm, dovada="tokenul a expirat")
assert not fara
assert cu and "expirat" in motiv
def test_assess_continuare_scurta_cade_inapoi_pe_interogarea_intreaga():
# „da, ma blocheaza complet" n-are termeni distinctivi proprii. Judecata singura
# ar escalada orice continuare scurta — exact regresia pentru care exista ancora.
bm = rank.Bm25(DOCS)
query = "token efactura expirat\nda"
covered, _ = rank.assess(query, 0.64, DOCS[1:2], bm, dovada="da")
fara, _ = rank.assess(query, 0.64, DOCS[1:2], bm)
assert covered is fara is True
def test_rank_urca_chunkul_confirmat_de_ambele_metode():
# cosinusul favorizeaza documentul 3, dar lexical se potriveste documentul 0;
# documentul 0 e sustinut de amandoua (cosinus decent + BM25 mare) si iese primul