Seed app/data/operatii-etichetate.json regenerat cu subagenti Haiku pe TOATE cele 17181 operatii distincte (ordine frecventa, 100%), inlocuind seed-ul Groq (3758). Validare Haiku vs Groq pe 157 op etichetate: la dezacorduri Haiku corect ~22/30, Groq ~0. Haiku prinde gunoiul ratat de Groq (ITP, chirie anvelope, nume piese fara actiune): NUL 2200 (12.8%) vs ~7.6% Groq; adaptare electronica OE-7 (nu OE-5), placute frana uzura OE-1 (nu OE-F avarie). US-001..006: prefiltru NUL determinist, etichetator offline, generator seed, seeder mapping_suggestions (in init_db, gated seed_operatii_enabled), embeddings indexeaza corpus etichetat, enrich NUL+kNN. Distributie seed: OE-1 80.1%, NUL 12.8%, OE-2 3.5%, restul rar (OE-4/3/7/8/R/I/5, AITLV, R-ODO). config: seed_operatii_enabled=True + embeddings_enabled=True implicit (SILVER populat + sugestii semantice; ambele suggestion-only, dezactivabile prin env). Suita: 1387 passed, 1 deselected (live). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
25 KiB
PRD 5.18 — Corpus k-NN din exemple reale etichetate (mapare operatii service)
Stare: aprobat + revizuit /autoplan (2026-06-28; intrebari deschise rezolvate de user — vezi §5 Decizii; cerinte user D4/D5 + 10 constatari Eng incorporate — vezi GSTACK REVIEW REPORT la final)
Proces:
docs/ROADMAP.md§5. Contract RAR:docs/api-rar-contract.md. Construieste peste infrastructura 5.14 (straturi GOLD/SILVER/embeddings,app/embeddings.py,app/shared_store.py,mapping_suggestions). NU re-deschide deciziile 5.14 (#11-#19); le foloseste.
0. Context si motivatie (de ce acest PRD)
5.14 a livrat embeddings in-proces, dar corpusul indexat = cele 18 denumiri RAR generice
din nomenclator (nume_prestatie -> cod_prestatie). O operatie reala ("inlocuit lubrifiant
la propulsor") se potriveste semantic slab cu etichete generice scurte ("INTRETINERE",
"REPARATIE"). In plus, stratul SILVER (mapping_suggestions) e populat DOAR in teste —
in productie e gol, deci nu produce nicio sugestie (LLM-ul nu e chemat la runtime).
Acest PRD muta corpusul de la cele 18 categorii la operatiile reale etichetate (k-NN peste exemple): o operatie noua se potriveste semantic cu o operatie deja vazuta si MOSTENESTE codul ei.
Masuratori care justifica directia (vezi memorie test-precizie-knn-embeddings, rulat 2026-06-28):
- k-NN peste exemple etichetate: 94.3% acord cu LLM pe operatii distincte (baseline "mereu OE-1" = 86.2%).
- Acoperire IEFTINA: pe volumul real total (155.195 aparitii, 17.181 operatii distincte): 148 operatii = 50% volum, 1.380 = 80%, 4.368 = 90%, 9.422 = 95%.
- Punct slab masurat: NUL recall 64% (ITP/discount/plata scapa ca OE-1) -> de aici pre-filtrul (US-001).
- Etichetarea offline cu Qwen3-4B local (LM Studio, GPU RX 6600M) + prompt procedural in 3 pasi: 91% pe batch greu, 20/20 pe batch de validare, ambele NUL prinse. Debit ~1.5-2h pentru ~13.5k operatii.
1. Obiectiv
Inlocuieste corpusul embeddings (18 categorii generice) cu corpusul de operatii reale etichetate (exemplu -> cod RAR), populat dintr-un seed comis in repo, plus un pre-filtru determinist pentru non-operatii (NUL). Rezultat: sugestii de mapare semnificativ mai precise in editor, fara LLM la runtime.
Pasul 1 (bootstrap offline, fundatia intregului PRD) = etichetare cu LLM via LM Studio local. Tot restul (seeder, corpus embeddings, enrich) consuma artefactul produs aici. Pasul are doua garantii non-negociabile:
- LM Studio = backend implicit aprobat pentru rularea v1 (Qwen3-4B local, GPU RX 6600M,
json_schemastrict —json_objecte respins de LM Studio). Groq/OpenRouter raman fallback-uri interschimbabile, dar NU sunt calea aprobata pentru bootstrap-ul v1 (vezi D4). - Dedup INAINTE de orice apel LLM. Cele 4 fisiere (
docs/operatii-service/*.csv) contin 19.456 randuri brute -> 17.181 operatii distincte dupanormalize_for_match(gain de doar 254 fata de dedup exact-string, pentru ca datele sunt deja majuscule, fara diacritice —normalize_for_matchcolapseaza spatii + scoate diacritice, NU scoate punctuatie). Din cele 17.181, 3.662 sunt deja etichetate (in spatiu normalizat) inlabels-groq-partial.json. Trimitem la LLM EXACT cele 13.519 operatii distincte ne-etichetate, niciodata un duplicat normalizat, o cheie normalizata vida sau o operatie deja etichetata (vezi D5). Economie: 31% mai putine apeluri vs randuri brute. (Castigul real al pipeline-ului nu e atat normalizarea — 254 chei — cat reuse-ul etichetelor existente + agregarea frecventei; motivul principal pentru spatiul normalizat e consistenta end-to-end cu cheia DB/k-NN, vezi F1/F3 din review.)
2. Non-Goals (anti scope-creep)
- NU auto-send peste GOLD propriu. Toate sursele (k-NN, exact, NUL pre-filtru) raman SUGGESTION-ONLY,
niciodata in
resolve_prestatii/load_mapping(invariant #13, #11 din 5.14). Singura cale sprequeuedramaneoperations_mapping(GOLD propriu confirmat de om). - NU LLM la runtime. Etichetarea LLM se face O SINGURA DATA, offline; runtime = doar embeddings + exact + reguli.
- NU validare temporala / re-etichetare automata. Seedul e static; reimprospatarea e un re-run manual al tool-ului.
- NU schimbare UI majora. Editorul (
_mapari.html) consuma dejasugestie_principala; doar sursa se schimba. (Un badge optional de sursa = US-007, jos.) - NU eshantion etichetat de om in acest PRD (doar mentionat la Riscuri ca recomandare — Decision #19).
3. Stories atomice
Fiecare story = cea mai mica unitate care lasa sistemul functional. Refoloseste
mapping_suggestions(SILVER) ca tabela-corpus (are deja:denumire_normalizata,cod_prestatie,is_nul,source,confidence) — populata acum si in productie, nu doar in teste.
US-001: Pre-filtru determinist non-operatii (NUL)
Ca operator vreau ca gunoiul evident (ITP, plata, discount, nr. inmatriculare, tractare) sa fie marcat NUL inainte de k-NN pentru ca masuratoarea arata recall NUL doar 64% (scapa ca OE-1).
- Depinde de: —
- Fisiere:
app/mapping.py(functie nouaprefiltru_nul(denumire) -> bool),tests/test_prefiltru_nul.py(~2 fisiere) - Test intai (RED):
tests/test_prefiltru_nul.py—test_itp_e_nul,test_plata_discount_nul,test_nr_inmatriculare_nul,test_operatie_reala_nu_e_nul - Acceptance criteria:
- Reguli text/regex deterministe (ITP, ACHITAT/PLATA, DISCOUNT/REDUCERE, NR INMATRICULARE + pattern placuta, TRACTARE, TAXA)
prefiltru_nul("13 X ITP")/("DISCOUNT FIDELITATE 10%")-> True;("INLOCUIT PLACUTE FRANA")-> False- Zero fals-pozitiv pe un set de 20 operatii reale (din
docs/operatii-service) python3 -m pytest tests/test_prefiltru_nul.py -qverde
- Verificare E2E: — (pur backend, acoperit de teste)
US-002: Etichetator offline multi-backend cu prompt procedural
Ca dezvoltator vreau un tool care eticheteaza operatii->coduri RAR via LM Studio local / Groq /
OpenRouter, cu prompt procedural in 3 pasi si json_schema strict pentru ca LM Studio respinge
json_object si promptul nou ridica precizia (91% vs 80%).
- Depinde de: —
- Fisiere:
tools/mapare-llm/eticheteaza.py(NOU, backend-uri interschimbabile),tests/test_eticheteaza_tool.py(mock HTTP) (~2 fisiere) - Test intai (RED):
tests/test_eticheteaza_tool.py—test_construieste_prompt_3pasi,test_parseaza_json_schema,test_backend_selectabil_env,test_scrub_pii_inainte_de_request - Acceptance criteria:
- Backend selectabil prin env (
ETICHETARE_BACKEND=lmstudio|groq|openrouter, endpoint+model configurabile); default =lmstudio(backend-ul aprobat pentru bootstrap v1, D4). Groq/OpenRouter = fallback. response_format=json_schemastrict cu envelope complet{"type":"json_schema","json_schema":{"name":...,"strict":true,"schema":{...}}}(NU{"type":"json_object"}caor_common.py:57/label_common.py:24);cod= enum peste cele 19ALL_LABELS(18 + NUL), cod invalid/lipsa ->?(F8 din review). Etichetatorul nou NU reutilizeaza request-ul vechi, doar promptul/codurile/scrub-ul.- Dezactiveaza explicit "thinking"-ul Qwen3 (
/no_thinksau reasoning off) — altfel modelul emite<think>si umfla tokeni/latenta sub structured output strict (F8). - Garda de truncare: daca raspunsul are mai putine iteme decat batch-ul sau JSON invalid -> log + marcheaza
?pe pozitiile lipsa, NU le ascunde tacit (la batch 40 + prompt 3 pasi,n_ctx=4096e stramt — F8). - Promptul = procedura 3 pasi + ancore (mapare parte caroserie->OE-C etc.), versionat in fisier
- Scrub PII (nr. inmatriculare, VIN) inainte de orice request (refoloseste
or_common.scrub, #3) - Setari conservatoare documentate in tool (batch 32-40,
n_parallel=1,n_ctx=4096) — vezi Riscuri python3 -m pytest tests/test_eticheteaza_tool.py -qverde (fara retea reala)
- Backend selectabil prin env (
- Verificare E2E: rulare manuala 1 batch pe LM Studio local (
http://<tailscale>:1234), confirmare JSON valid
US-003: Generare seed etichetat in faze pe frecventa
Ca dezvoltator vreau sa generez un fisier seed operatii-etichetate.json (operatie->cod) pornind de la
operatiile existente + cele deja etichetate, in ordinea frecventei pentru ca 1.380 operatii prind 80% din volum.
- Depinde de: US-002
- Fisiere:
tools/mapare-llm/genereaza_seed.py(NOU),app/data/operatii-etichetate.json(artefact comis),tests/test_genereaza_seed.py(~3 fisiere) - Test intai (RED):
tests/test_genereaza_seed.py—test_dedup_normalizat,test_zero_duplicate_trimis_la_llm,test_rerun_zero_apeluri_llm,test_reuse_conflict_determinist,test_skip_cheie_normalizata_vida,test_reuse_in_spatiu_normalizat,test_ordine_pe_frecventa,test_format_seed_valid - Pipeline dedup (ordinea e obligatorie, INAINTE de orice apel LLM):
- Agrega cele 4 CSV-uri -> pentru fiecare rand
(denumire, NR). Parseaza NR tolerant (skip rand pe NR ne-numeric, nu zero-weight — F9). cheie = normalize_for_match(denumire)— ACEEASI functie ca DB/k-NN (app/mapping.py:40), NU.strip()exact. Arunca randurile cucheie == ""(gunoi gen"..."," ") inainte de dedup — altfel se bat pe slotul UNIQUE gol (F6).- Dedup pe cheie: un singur reprezentant per cheie,
freq = suma NRpe toate aparitiile/fisierele. - Construieste harta
cheie_normalizata -> cod(NU doar un set) din TOATE sursele de etichete deja existente:labels-groq-partial.json(cheiat pe text BRUT) PLUS seedul comis anterioroperatii-etichetate.json(cheiat normalizat). Reuse + scaderea se fac in spatiu normalizat. Rezolvare conflict determinista cand acelasicheieare coduri diferite pe variante raw (masurat: 1 azi —CURATAT CATALIZATOROE-2 vs OE-1): castiga varianta cufreq(suma NR) maxima, tie-break pecodsortat (F3). de_etichetat = {cheie in corpus} - {cheie in harta etichete}. Lista (distincta, ne-etichetata, sortata desc pe freq) = SINGURUL input catre LLM.
- Agrega cele 4 CSV-uri -> pentru fiecare rand
- Acceptance criteria:
test_zero_duplicate_trimis_la_llm(within-run): backend LLM mock care inregistreaza fiecare denumire primita; input cu duplicate intentionate (spatii/case + cross-file) -> mock-ul nu vede NICIODATA doua chei normalizate egale, nicio cheie deja etichetata, nicio cheie vida.test_rerun_zero_apeluri_llm(cross-run, criteriul real de idempotenta, F2/F7): ruleaza tool-ul de doua ori cu acelasi input; a doua rulare consuma seedul comis ca cache -> 0 apeluri LLM, seed identic byte-cu-byte.test_reuse_conflict_determinist(F3/F7): doua variante raw ale aceleiasi chei cu coduri diferite -> codul ales e determinist (freq-max, tie-break cod).- Dedup pe
normalize_for_match(colapseaza spatii + diacritice, NU punctuatie; gain real ~254 chei vs exact-string — valoarea principala e consistenta cu cheia DB/k-NN, nu volumul); NU reutilizaor_common.corpus_by_freq()ca atare (dedup exact-string). - Eticheteaza DOAR ce lipseste, in ordine descrescatoare de frecventa, cu
--target-volum 0.9(oprire la prag) sau--all - Seed format
[{denumire, denumire_normalizata, cod, is_nul, source, confidence}], UTF-8, comis in repo;denumire_normalizataunica + ne-vida in seed (oglindeste UNIQUE dinmapping_suggestions;test_format_seed_validasserta non-empty) python3 -m pytest tests/test_genereaza_seed.py -qverde
- Verificare E2E: rulare
--target-volum 0.5pe date reale -> ~150 etichete noi, fisier valid; log-ul tool-ului raporteaza explicit "{brute} randuri -> {distincte} dupa normalizare -> {de_etichetat} trimise la LLM"
US-004: Seeder corpus etichetat in DB (mapping_suggestions)
Ca sistem vreau sa incarc seedul etichetat in mapping_suggestions la init (INSERT OR IGNORE)
pentru ca SILVER e gol in productie si trebuie populat ca sa dea sugestii exact-match + corpus k-NN.
- Depinde de: US-003
- Fisiere:
app/operatii_seed.py(NOU, dupa modelulnomenclator_seed.py),app/db.py(apel la init),tests/test_operatii_seed.py(~3 fisiere) - Test intai (RED):
tests/test_operatii_seed.py—test_seed_populeaza_mapping_suggestions,test_insert_or_ignore_nu_clobber_uman,test_is_nul_din_seed,test_idempotent_la_reinit - Acceptance criteria:
- La
init_db, daca seedul exista si tabela permite, INSERT OR IGNORE randurile (idempotenta re-seed: nu dubla / nu clobber un rand seedat sau de embedding deja prezent). NB (F10): confirmarile UMANE stau inshared_mappings(record_human_validation), NU inmapping_suggestions— deci INSERT OR IGNORE pastreaza TACIT codul LLM vechi la re-seed; daca vrei refresh pe coduri LLM invechite, e decizie explicita upsert-vs-ignore (v1 = ignore) is_nul=1->cod_prestatie=NULL(respecta CHECK-ul existent);source='llm_seed',confidencedin seed- Idempotent: a doua initializare nu dubleaza si nu modifica randuri existente
python3 -m pytest tests/test_operatii_seed.py -qverde
- La
- Verificare E2E: pornire app pe DB gol ->
SELECT count(*) FROM mapping_suggestions> 0
US-005: Embeddings indexeaza corpusul etichetat (nu nomenclatorul)
Ca sistem vreau ca ensure_embeddings_corpus sa indexeze operatiile etichetate (denumire->cod, cu is_nul)
pentru ca k-NN peste exemple reale e net mai precis decat peste 18 categorii generice.
- Depinde de: US-004
- Fisiere:
app/mapping.py(ensure_embeddings_corpusschimba sursa),app/embeddings.py(suggest_nearestintoarce siis_nul),tests/test_embeddings_corpus_etichetat.py(~3 fisiere) - Test intai (RED):
tests/test_embeddings_corpus_etichetat.py—test_corpus_din_mapping_suggestions,test_suggest_nearest_intoarce_is_nul,test_semnatura_corpus_pe_seed,test_degradare_gratioasa_pastrata - Acceptance criteria:
- Corpusul =
mapping_suggestions(denumire_normalizata -> cod, is_nul), NUnomenclator_rar - Simetrie corpus/query (F1, HIGH): corpusul e text
denumire_normalizata; decienrich_suggestionstrebuie sa interoghezesuggest_nearest(normalize_for_match(denumire), ...), NUdenumirebrut. Altfel corpus normalizat vs query brut degradeaza cosine si NU e configul sub care s-a masurat 94.3%.test_query_normalizat_ca_si_corpusulo asserta. suggest_nearestintoarce[{cod, is_nul, similaritate}]; un vecin NUL -> semnal de supresie, nu cod- Re-index doar la schimbarea semnaturii corpusului (cache pastrat, #16b degradare gratioasa neschimbata)
- Gated pe
AUTOPASS_EMBEDDINGS_ENABLED(acum default True — vezi 5.14 CLOSE); off in teste (conftest) python3 -m pytest tests/test_embeddings_corpus_etichetat.py -qverde
- Corpusul =
- Verificare E2E: cu flag on + seed incarcat,
suggest_nearest("schimbat uleiul motor")-> cod revizie/intretinere real
US-006: enrich_suggestions = pre-filtru NUL + k-NN pe corpus etichetat
Ca operator vreau ca editorul sa imbine pre-filtrul NUL, exact-match si k-NN semantic in ordinea de precedenta corecta pentru ca vreau sugestia cea mai buna fara junk.
- Depinde de: US-001, US-005
- Fisiere:
app/mapping.py(enrich_suggestions),tests/test_enrich_corpus_etichetat.py(~2 fisiere) - Test intai (RED):
tests/test_enrich_corpus_etichetat.py—test_prefiltru_nul_supreseaza_inainte_de_knn,test_precedenta_gold_exact_embedding,test_prag_similaritate,test_abtinere_sub_prag - Acceptance criteria:
- Ordine: pre-filtru NUL -> daca NUL, fara sugestie de cod (marcat non-operatie); altfel GOLD partajat > exact (SILVER) > k-NN embeddings
- k-NN sub
EMB_MIN_SIMILARITATE-> abtinere (embedding=None), nu sugestie incerta - Vecin k-NN cu
is_nul=1-> tratat ca supresie, nu cod (consecventa cu pre-filtrul) - Invariant #13 pastrat: nimic din asta nu intra in
resolve_prestatii/load_mapping(test de regresie) python3 -m pytest tests/test_enrich_corpus_etichetat.py -qverde + suita 5.14 (test_mapare_integrare_l14.py) ramane verde
- Verificare E2E: browser HTMX pe
/_fragments/mapari— operatie parafraza primeste cod corect pre-selectat din k-NN
US-007 (optional): Badge sursa sugestie in editor
Ca operator vreau sa vad de unde vine sugestia (confirmat de om / exemplu similar / non-operatie) pentru ca acum nu pot distinge sursa si nu stiu cata incredere sa am.
- Depinde de: US-006
- Fisiere:
app/web/templates/_mapari.html,tests/test_web_badge_sursa.py(~2 fisiere) - Test intai (RED):
tests/test_web_badge_sursa.py—test_badge_gold,test_badge_embedding,test_badge_nul - Acceptance criteria:
- Chip mic langa sugestie: "confirmat" (gold), "similar" (embedding/silver), "non-operatie" (NUL)
- Fara sursa -> fara chip; nu rupe layoutul 5.15/5.16
python3 -m pytest tests/test_web_badge_sursa.py -qverde
- Verificare E2E: browser — chip vizibil si corect colorat pe randul de mapare
4. Riscuri
- Calitate etichetare model local (Qwen3-4B Q4) < model mare (Groq 70b). Masurat: bun pe cap (frecvent, clar), mai slab pe coada rara/ambigua (ADAS calibrare, chei, "doar nume piesa"). Mitigare: pre-filtru NUL (US-001) + optiunea unui al doilea pas de verificare cloud DOAR pe esantionul cu cod rar/incert.
- Hardware GPU-box instabil sub sarcina (shutdown observat 2026-06-29). La config-ul rulant erau ~4GB VRAM
liberi -> cauza probabil termica/alimentare, NU memorie. Mitigare OBLIGATORIE pentru pasul de etichetare:
n_parallel=1,n_ctx=4096, batch 32-40, monitorizare temperatura GPU. NU mari batch/context fara headroom termic. - Ground-truth = eticheta LLM, nu om. 94.3% e ACORD cu LLM, nu acuratete reala; LLM impinge 86% in OE-1
(posibil prea agresiv). Recomandare (Decision #19): inainte de a creste increderea/orice auto-send, ruleaza
heldout_eval.pycu un esantion etichetat de OM. Ramane in afara scope-ului acestui PRD, dar e poarta pentru orice 5.x viitor de auto-send. mapping_suggestionspopulat schimba comportamentul testelor care presupuneau SILVER gol. Mitigare: seederul ruleaza doar daca seedul exista; conftest poate dezactiva seedul in testele care nu-l vor (ca la embeddings).- Coada lunga ramane needs_mapping. Chiar la 90% volum acoperit, 76% din operatiile DISTINCTE raman neetichetate (frecventa 1). Asteptare corecta: bootstrap-ul reduce mult volumul, dar editorul uman ramane necesar pe coada.
- (F1, review) Simetrie corpus/query la embeddings. Corpusul k-NN devine text NORMALIZAT (
denumire_normalizata), deci query-ul TREBUIE normalizat la fel inainte de embedding (US-005 AC). Daca raman asimetrice (corpus normalizat, query brut), similaritatea scade si nu mai e configul masurat (94.3%). Risc de regresie tacuta — acoperit de test in US-005. - (F2, review) Idempotenta cross-run a etichetarii. Etichetele noi produse de o rulare trebuie sa devina cache pentru
urmatoarea (seedul comis = sursa de etichete, nu doar
labels-groq-partial.json), altfel re-run-ul re-trimite tot la LLM. Acoperit detest_rerun_zero_apeluri_llm(US-003).
5. Decizii (intrebari deschise rezolvate la aprobare, 2026-06-28)
Erau intrebari deschise; rezolvate de user la poarta de aprobare PRD. Devin constrangeri de executie.
- D1 — Tinta de acoperire la etichetare: 90% din volum (
--target-volum 0.9, ~4.368 operatii distincte). Restul (coada lunga, 76% din operatiile distincte dar doar ~10% din volum) ramane pe editorul uman. US-003 implementeaza exact acest default;--allramane disponibil dar NU e calea aprobata pentru v1. - D2 — Verificare cloud pe esantionul incert: NU in acest PRD. Toate sursele sunt suggestion-only (blast
radius mic: o sugestie gresita = omul alege altceva in editor). Pre-filtrul NUL (US-001) acopera punctul slab
masurat. Codurile rare/avarii grave sunt volum mic; un pas de verificare cloud adauga un backend in plus pentru
castig marginal. Se reia DOAR daca esantionul uman (Decision #19, vezi Riscuri) arata ca erorile pe coduri rare
sunt o problema reala.
source/confidencedin seed raman in DB pentru o eventuala flag-uire ulterioara. - D3 — Pastram exact-match (SILVER) separat de k-NN. Exact-match (
lookup_suggestionpe text normalizat) = instant, 100% pe text identic; k-NN = generalizare semantica pentru texte nevazute. Precedenta confirmata: GOLD partajat > exact (SILVER) > k-NN embedding (US-006). k-NN NU inlocuieste exact-match. - D4 — Bootstrap-ul v1 ruleaza pe LM Studio local (Qwen3-4B,
json_schemastrict), nu pe Groq/OpenRouter. Motiv: zero cost per-token, date pe hardware propriu (PII service local), masurat 91% pe batch greu + 20/20 validare. Groq/OpenRouter raman in tool ca fallback interschimbabil (US-002), dar nu sunt calea aprobata pentru v1. Cerinta user, 2026-06-28. - D5 — Dedup pe
normalize_for_matchINAINTE de orice apel LLM, cu reuse in spatiu normalizat. Nu se trimite la LLM niciun duplicat normalizat si nicio operatie deja etichetata. Garantat detest_zero_duplicate_trimis_la_llm(within-run) +test_rerun_zero_apeluri_llm(cross-run, idempotenta) — US-003. Motiv: ~31% randuri redundante (19.456 brute -> 13.519 de etichetat: cross-file + variatii spatii + reuse labels existente); fara dedup-ul corect platim apeluri LLM inutile si riscam etichete inconsistente pe acelasi text logic. Cerinta user, 2026-06-28.
6. Valuri de executie (graful de dependente)
PASUL 1 — BOOTSTRAP ETICHETE OFFLINE (LM Studio LLM) — fundatia, ruleaza prima:
Val 1: [US-002] [US-001] ← US-002 (etichetator LM Studio) = pasul 1; US-001 (pre-filtru NUL) paralel, fisiere disjuncte
Val 2: [US-003] ← deblocat de US-002: dedup normalizat -> trimite la LLM -> seed comis
PASUL 2 — CONSUM SEED (fara LLM):
Val 3: [US-004] ← deblocat de US-003 (owns schema/seed loader)
Val 4: [US-005] ← deblocat de US-004
Val 5: [US-006] ← deblocat de US-001 + US-005
Val 6: [US-007] (optional) ← deblocat de US-006
Raport VERIFY
Completat de subagentul verificator (context curat) in faza VERIFY — vezi ROADMAP §5.6. PASS/FAIL per criteriu, cu dovezi (output pytest citat, E2E pe RAR test). Lipseste pana la VERIFY.
GSTACK REVIEW REPORT (/autoplan — Eng focus, 2026-06-28)
Scope review: Eng (CEO premise gate + Eng dual-voice). Design/DX sarite (UI = doar badge optional US-007, tool intern mono-dezvoltator). Voce Eng: subagent-only — Codex a lovit limita de utilizare (degradare conform matricei).
Premise confirmate (poarta umana): (1) k-NN peste exemple reale > 18 categorii generice (94.3% vs 86.2% masurat); (2) etichetare LLM o singura data, offline, zero LLM la runtime; (3) SILVER populat in productie din seed comis; (4) pre-filtru NUL necesar (recall 64%); (5) LM Studio Qwen3-4B = calitate acceptabila pt bootstrap (91% batch greu / 20/20 validare).
Cerinte user incorporate: D4 (LM Studio = backend default v1), D5 (dedup pe normalize_for_match + reuse normalizat, INAINTE de LLM).
Decision Audit Trail
| # | Faza | Decizie | Clasif. | Principiu | Rationament |
|---|---|---|---|---|---|
| 1 | CEO | Restructurare valuri: Pasul 1 = bootstrap LM Studio (US-002->US-003) | Mecanic | P1 | Cerinta user explicita; reflecta dependenta reala |
| 2 | Eng | F1: query embedding normalizat ca si corpusul (US-005 AC + test) | Mecanic | P5 | Corectitudine; altfel 94.3% nereproductibil. Blast radius (US-005) |
| 3 | Eng | F2: seed comis = cache de etichete cross-run (US-003 pipeline + test_rerun_zero_apeluri_llm) |
Mecanic | P1 | Criteriul "0 apel LLM la re-run" altfel nesatisfiabil |
| 4 | Eng | F3: harta normalizat->cod cu tie-break determinist (freq-max) | Mecanic | P5 | 1 conflict real azi (CURATAT CATALIZATOR); altfel cod nedeterminist |
| 5 | Eng | F4/F5: corectie cifre (17.181 distinct, 13.519 de etichetat, 31%) + claim "fara punctuatie" | Mecanic | P5 | Cifre verificate cu normalize_for_match real |
| 6 | Eng | F6: arunca cheie normalizata vida inainte de dedup | Mecanic | P1 | Coliziune pe slot UNIQUE gol |
| 7 | Eng | F7: teste two-run + conflict adaugate | Mecanic | P1 | Testul single-run nu acopera idempotenta/determinismul |
| 8 | Eng | F8: envelope json_schema strict + enum cod + dezactivare thinking Qwen3 + garda truncare | Mecanic | P1 | Realism integrare LM Studio (cerinta user #1) |
| 9 | Eng | F9: parsare NR toleranta (skip, nu zero-weight) | Mecanic | P3 | Date curate azi; ieftina robustete |
| 10 | Eng | F10: re-justificare INSERT OR IGNORE (confirmari umane = shared_mappings) | Mecanic | P5 | Evita inducerea in eroare a unui mentainer |
Zero decizii de gust (taste) si zero user-challenge: toate constatarile au intarit directia user, nu au contrazis-o.