Files
rar-autopass/docs/ROADMAP.md
Claude Agent 705ad030fe feat(embeddings): cache persistent de vectori in SQLite + warmup in fundal
Vectorii corpusului k-NN persista in tabela embedding_cache (PK model+text_hash,
blob float32 LE); la warmup se vectorizeaza doar textele lipsa din cache, deci
restartul cu corpus neschimbat nu mai plateste ~1-2 min de embed (embed=0).

- app/embedding_cache.py: serializare array('f'), load/save/purge chunk 500 cu
  BEGIN/COMMIT explicit (conexiuni autocommit), validare dimensiune la scriere
  si citire, orchestrare sync_corpus_vectors cu embed_fn injectat
- index_corpus(vectors=): vectori precalculati cu validare aliniere; mismatch
  -> fallback embed complet
- ensure_embeddings_corpus: warmup in thread la startup (block=True), calea de
  request ne-blocanta (acquire non-blocking pe lock; warmup in curs -> return
  imediat); purjare orfane + modele vechi doar dupa indexare reusita
- log warmup: cache=N embed=M in Xs
- 31 teste noi (cold/warm/incremental, model schimbat, concurenta, ranking
  exact, echivalenta float32); suita completa 1596 passed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 21:57:49 +00:00

59 KiB
Raw Blame History

AutoPass — Roadmap & Proces de Dezvoltare

Sursa unica de progres + procesul de lucru. O sesiune noua are nevoie doar de promptul: "Citeste docs/ROADMAP.md si continua roadmap-ul [optional: livrabila X.Y]." Sesiunea isi detecteaza singura faza (§5.7), planifica SAU executa, verifica si inchide — cu doua porti umane: aprobarea PRD-ului si confirmarea commit-ului.

Contractul RAR (sursa de adevar de contract) = docs/api-rar-contract.md. Acolo unde un plan difera de contract, contractul are dreptate.

Status fara emoji (preferinta proiect): TODO neinceput · WIP in lucru · DONE gata · BLOCAT blocat de o dependenta · AMANAT deferat/taiat cu motiv.


1. Context

Gateway central care declara prestatiile de service-auto la RAR AUTOPASS (Legea 142/2023, OM 210/2024), portat din clasa Visual FoxPro RarAutoPass (ROAAUTO). Stack: Python/FastAPI + SQLite (WAL) + httpx + Jinja2/HTMX. Un container (API) + un proces separat (worker).

Doua canale de intrare, ambele LIVE pe endpoint-ul de test RAR:

  • Treapta 1 — canal API (POST /v1/prezentari) pentru ROAAUTO / soft propriu.
  • Treapta 2 — import xlsx/csv + mapare coloane + UI web (HTMX) pentru service-uri non-ROA.

2. Arhitectura (rezumat)

  Canal API (ROAAUTO)  ─┐
  Upload web (xlsx/csv) ─┴─▶ Gateway FastAPI ─▶ validare → mapare op→cod → enqueue (PII criptat)
                                  │
                                  ▼
                             WORKER (proces separat): claim atomic → login RAR → postPrezentare → retry
                                  │
  Dashboard (Jinja2+HTMX) ◀───────┴── monitorizare live RAR + coada + editor mapari + audit CSV

Reguli de contract (detalii in docs/api-rar-contract.md): FINALIZATA e terminal la RAR (fara anulare/corectie prin API); idempotency = hash de continut server-side; JWT TTL = 30h.


3. Stadiu Implementare (dashboard)

Singurul loc din document care se modifica pe parcurs. Detaliile NU intra aici — stau in PRD-uri (docs/prd/prd-X.Y-*.md), linkate in coloana Detalii. La fiecare livrabila terminata: schimba statusul + data + linkul PRD si actualizeaza "Ultima actualizare".

Ultima actualizare: 2026-07-06 — 5.21 CACHE PERSISTENT EMBEDDINGS IN SQLITE — LIVRAT (PRD: prd-5.21; executie echipa de agenti Sonnet: cache-core T1+T2, wiring T3+T5, tests T4+T6, reviewer adversarial). Vectorii corpusului k-NN (17.181 exemple SILVER) persista in tabela noua embedding_cache (PK (model, text_hash), blob float32 LE 384, array('f') end-to-end); la warmup se vectorizeaza DOAR miss-urile (hash sha256 pe denumire_normalizata din lista FILTRATA, identica cu ce intra in index_corpus), restarturile cu corpus neschimbat = embed=0. Modul nou app/embedding_cache.py (fara dependinte noi): sync_corpus_vectors(conn, model, texts, embed_fn) hash->load->embed(miss)->save; scrieri/stergeri in chunk-uri de 500 cu BEGIN/COMMIT EXPLICIT (conexiunile sunt autocommit — conn.commit() e no-op); validare dimensiune la scriere SI citire (blob corupt = miss re-vectorizat); purjare orfane + modele vechi DOAR dupa indexare reusita; toate erorile SQLite -> log.warning + fallback embed complet (degradare gratioasa, nimic propagat). EmbeddingEngine.index_corpus(vectors=) valideaza alinierea len(vectors)==len(items) + absenta None (mismatch -> fallback embed complet). Secventa protejata de _embeddings_lock (mapping.py); pe calea de request (block=False) acquire NE-blocant — daca warmup-ul tine lock-ul, return imediat (fix MAJOR din review: altfel primul request in fereastra de cold start ingheta ~1-2 min). Log observabilitate: embeddings: warmup ok cache=N embed=M in Xs (eticheta corpus reindexat pe calea de request). Semnatura corpusului (_corpus_signature_silver) = mecanism de decizie NESCHIMBAT; worker-ul nu atinge cache-ul. Review adversarial: 1 MAJOR + 2 MINOR + 1 NIT, toate reparate. Suita completa: 1596 passed, 1 skipped (+31 teste noi: 15/15 cai din diagrama de acoperire, toate cu AUTOPASS_EMBEDDINGS_ENABLED=1 explicit, backend mock). Crestere DB ~26-30MB acceptata; deferate in TODOS.md: CLI embcache, precompute la build, graceful reload, numpy la >50k randuri. De verificat pe instanta reala (US-006): doua restarturi ./start.sh, al doilea cu embed=0 si sugestia "similaritate" in <30s.

2026-07-06 — HARDENING 80/20 LIVRAT + PUSH (main la 63b6cbc; plan /autoplan main-hardening-8020-plan-20260703.md, audit securitate 2026-07-03, inainte de expunerea publica autopass.romfast.ro). P0: compose fail-safe — :? obligatoriu pe AUTOPASS_REQUIRE_API_KEY/AUTOPASS_WORKER_SEND_ENABLED/AUTOPASS_RAR_ENV (split-brain api-prod/worker-test eliminat; post-5.20 variabila e doar ancora de fallback, nu tinta trimiterilor), FORWARDED_ALLOW_IPS="*" ca rate-limit-ul sa vada IP-ul real dupa Traefik (invariante in comentariu: api fara ports: pe host, Traefik fara forwardedHeaders.insecure), AUTOPASS_SESSION_SECRET obligatoriu + SESSION_HTTPS_ONLY default true; invarianta E1 fail-fast la boot (validate_prod_invariants): prod fara cheie API sau session secret -> RuntimeError cu mesaj actionabil. P0-4 backup criptat SQLite: tools/backup_db.sh (snapshot online stdlib + gpg AES256 + retentie + rclone optional), tools/restore_check.sh (integrity_check pe restore), docs/backup.md; trigger dur: configurat INAINTE de prima declaratie reala prod. P1: headers de securitate in-app (SecurityHeadersMiddleware, HSTS doar pe https) + body-cap global 10MB (BodyCapMiddleware ASGI pur, 413 inainte de parserul multipart/JSON; verificarea per-endpoint ramane strat 2) + imagine Docker non-root (uid 10001, HOME=/home/app pt fastembed, chown /data INAINTE de VOLUME, loguri pe /data/logs, port 8010 aliniat EXPOSE/CMD; migrare one-off volum existent: docker compose run --rm --user root api chown -R app:app /data). P2: print-uri cu email in stdout eliminate (signup + notify degradat din app/email.py -> log_event fara PII) + fix crestere monotona chei ratelimit._hits. Executie multi-agent (4 agenti implementare pe fisiere disjuncte + review dedicat: 0 constatari blocante, 3 nit-uri acceptate). Suita completa: 1557 passed, 1 skipped (3 rulari independente). Post-deploy HOUR-1 (Dokploy): seteaza env-urile obligatorii INAINTE de redeploy (:? pica pornirea), creeaza cheia API + tier pro/trial pe contul propriu (altfel 403 PLAN_FARA_API), ruleaza migrarea chown, seteaza passphrase-ul de backup.

2026-06-18 — 3.4 LIVRAT (interfata web ergonomica: tab-uri + wizard + microcopy). US-001 modul pur app/web/labels.py (stari tehnice→text uman + clasa CSS; test parametrizat din CHECK-ul schema.sql iese rosu la stare nemapata). US-002 bara status /_fragments/status + _status.html (etichete umane, defalcare blocate pe motiv, poll 15s, scoped pe cont). US-003 shell 6 tab-uri (Acasa·Import·Coada·Mapari·Cont·Nomenclator) cu deep-link ?tab=, panou activ randat server-side, fragmente inactive lazy pe click, ARIA real (tablist/tab/tabpanel + aria-selected + navigare cu sageti). US-004 stepper import 4 pasi (PUR vizual, hx-target="#import-section" + csrf pastrate). US-005 Acasa onboarding checklist auto-bifat (are_creds/are_trimiteri) + colaps cand totul gata + empty states prietenoase Coada/Mapari. VERIFY lead-driven (TestClient ACs + 434 pytest pass; E2E browser/RAR LIVE neprobat in sesiune — recomandata probare manuala --send). Fix izolare teste (reset ratelimit._hits in fixturi, 429 la rulare subset). /code-review high: regasit avertisment "cont in asteptare de activare" (regresie din scoaterea /_fragments/banner) re-introdus in bara status + culori hardcodate→variabile paleta. 434 teste pass. Backend trimitere neatins. PRD: prd-3.4. Urmeaza Etapa 4 (4.1 mapare AI/MCP).

3.3b LIVRAT (self-service cheie/creds + admin web + email). US-007 rute web proprii pentru rotire cheie + setare creds RAR scoped pe sesiune (C13, nu endpointul API). US-010 rol admin (users.is_admin) + require_adminAdminRequired→403 + CLI tools/account.py set-admin + bootstrap automat (primul cont care se inregistreaza = admin, citit in BEGIN IMMEDIATE anti-race). US-011 panou /admin (conturi in asteptare/active, activare/dezactivare cu CSRF + PRG, contul dev id=1 protejat) + link "Panou admin" pe dashboard doar pentru admini + buton logout. US-012 app/email.py notify_signup best-effort DEGRADAT fara SMTP (no-op + log, prinde orice exceptie, nu blocheaza signup) + config smtp_*. Fix migrare defensiva users.is_admin/email_verified in _migrate (gap prins de VERIFY r1, ca C1 pe accounts.active). 2 runde VERIFY context curat (r2 PASS, sweep securitate toate rutele noi sub require_login/require_admin + CSRF, scoped sesiune). /code-review high: TOCTOU bootstrap mutat in tranzactie + _render_admin extras (anti-duplicare + N+1). 393 teste pass. Urmeaza Etapa 4 (4.1 mapare AI/MCP). Deferat din 3.1 (P3): rename/set-cui, --if-not-exists. SMTP real = follow-up pe US-012.

3.3a LIVRAT (self-onboarding web core: app/users.py parole scrypt cu eticheta de parametri onorata la verify; SessionMiddleware same_site=strict + app/web/session.py guard require_loginLoginRequired; CSRF per-sesiune enforce in prod inclusiv pe login/signup + rate-limit signup & login in-proces; signup active=0 tranzactie atomica + cheie-o-data + log SIGNUP; login/logout; dashboard & import multi-tenant scoped pe sesiune cu regula NULL→cont 1 — toate rutele web care ating date sensibile sub require_login + scope; gate worker claim_one LEFT JOIN ... COALESCE(active,1)=1. 2 runde VERIFY context curat — runda 1 a prins un leak cross-account pe /_fragments/mapari, reparat; runda 2 PASS. /code-review high a prins 3 findings, reparate. 361 teste pass). Urmeaza 3.3b (self-service cheie/creds + admin web + email). Deferat din 3.1 (P3): rename/set-cui, --if-not-exists.

Etapa 1 — Canal API ROAAUTO (Treapta 1)

# Livrabila Status Data Detalii
1.1 Gateway complet: validare + mapare + coada + worker + reconciliere + dashboard DONE 2026-06-15 E2E LIVE prin gateway: POST /v1/prezentari → worker → FINALIZATA la RAR test (idPrezentare=68516). Cod app/, 279 teste.

Etapa 2 — Import xlsx/csv + UI web (Treapta 2)

# Livrabila Status Data Detalii
2.1 Parser xlsx/csv 2-treceri + staging criptat (POST /v1/import) DONE 2026-06 app/import_parse.py; encoding RO, delimiter sniff, coercion, robustete sheet/merged/footer
2.2 Creds RAR durabile per-cont + worker re-login fallback DONE 2026-06 accounts.rar_creds_enc, gate purjare worker
2.3 batch_id scope reresolve_account (inchide R1 bulk-send) DONE 2026-06 app/mapping.py
2.4 Mapare coloane + semnatura + detectie drift + fuzzy DONE 2026-06 app/api/v1/import_router.py
2.5 Preview 6 stari + canonicalize partajat + gate HARD + atestare DONE 2026-06 duplicate_in_file, already_sent, needs_review, import_attestations, TOCTOU ON CONFLICT
2.6 UI web upload HTMX (drop → mapare → preview → confirma) DONE 2026-06 app/web/templates/_upload.html, _mapcoloane.html, _preview_import.html
2.7 Export randuri esuate CSV + job purjare purge_after + E2E DONE 2026-06 export_failed_rows, tests/test_import_e2e.py

Etapa 3 — Multi-cont / self-onboarding (URMATORUL FOCUS)

# Livrabila Status Data Detalii
3.1 Creare cont nou (CLI dedicat) DONE 2026-06-17 CLI tools/account.py (create/list[--pending]/activate/deactivate, --with-key atomic) + accounts.active + index unic CUI + app/accounts.py. 20 teste noi. PRD: prd-3.1
3.2 Filtrare pe cont a GET-urilor de listare DONE 2026-06-17 scope cheie pe /v1/prezentari(/{id}), /v1/mapari(/pending), /v1/audit/export (NULL→cont 1); nomenclator global; 404 cross-account identic (B3) + allowlist campuri detaliu (B4) + helper account_scope_clause (B2) + index (B5). 14 teste noi, 313 pass. PRD: prd-3.2
3.3a Self-onboarding web (core) DONE 2026-06-17 users (scrypt) + sesiune (SessionMiddleware, same_site=strict) + CSRF (enforce prod, inclusiv login/signup) + rate-limit signup/login + signup/login/logout + dashboard & import scoped pe sesiune (NULL→1, anti-leak C6) + gate worker active=0 (COALESCE). 2 runde VERIFY (leak /_fragments/mapari prins+reparat) + code-review (csrf erori, scrypt_params, login rate-limit). 361 teste. PRD: prd-3.3
3.3b Self-service cheie/creds + admin web + email DONE 2026-06-18 US-007 (rute web proprii /cont/roteste-cheie+/cont/rar-creds scoped sesiune, C13), US-010 (rol admin is_admin + require_admin→403 + CLI set-admin + bootstrap primul cont=admin), US-011 (/admin activare/dezactivare cu CSRF+PRG, link doar pt admini + logout), US-012 (app/email.py notify best-effort degradat fara SMTP + log SIGNUP). Fix migrare defensiva users.is_admin/email_verified. 2 runde VERIFY context curat (r1 a prins migrarea lipsa, reparat; r2 PASS) + /code-review high (TOCTOU bootstrap admin mutat in tranzactie + extras _render_admin anti-duplicare/N+1). 393 teste. PRD: prd-3.3
3.4 Interfata web ergonomica (tab-uri + wizard + microcopy uman) DONE 2026-06-18 Dashboard reorganizat in 6 tab-uri (Acasa·Import·Coada·Mapari·Cont·Nomenclator) cu deep-link ?tab= + panou activ server-side + lazy pe rest; bara status cu etichete umane (app/web/labels.py) + defalcare blocate; import ca stepper 4 pasi (PUR vizual); Acasa onboarding auto-bifat + empty states. Backend trimitere neatins. 434 teste. PRD: prd-3.4
3.5 Dashboard compact: import pe prima pagina, status cu bife, Trimiteri lizibile, Mapari complete DONE 2026-06-19 11 stories (4 valuri), 3 review-uri de plan facute. Acasa=ecran de import (scoate tab Import); bara status compacta font normal + bife accesibile (auto-send/RAR) + data dd.mm.yyyy hh24:mi:ss; "Coada"→"Trimiteri" cu coloane RO + detalii comanda din payload_json (helper partajat payload_view.py) + detaliu la click in panou dedicat; filtrare Trimiteri (US-009); corectie inline needs_data cu re-enqueue + detectie coliziune idempotency (US-010); badge contoare pe tab-uri (US-011); "Mapari" 3 sectiuni (de rezolvat / op salvate cu re-rezolvare auto / formate coloane), "Cont"=doar cheie+creds; feedback needs_data la import. Backend trimitere neatins. PRD: prd-3.5
3.6 Editare celule in preview + Acasa unificata (Trimiteri inline, upload slim, Mapari tabelar, comutator coada) DONE 2026-06-22 7 stories (3 valuri), 2 echipe in paralel (TeamCreate) pe fisiere disjuncte + US-007 secvential. US-003/004 tab "Trimiteri" eliminat→sectiune "Trimiterile tale" sub upload pe Acasa; upload bara slim (hero la first-run); ?tab=coada+/_fragments/coada→Acasa; poll gated visibilityState. US-001 import_rows.override_json (Approach B, Fernet, _migrate defensiv) aplicat ULTIMUL in _resolve_row_for_preview+commit_import (mutatie pura; completeaza si coloane ABSENTE din fisier); ruta .../rand/{i}/editeaza scoped JOIN→404, guard committed→409, empty=clear. US-002 buton Editeaza pe rand, swap pe <tr>+OOB contoare (nu pe sectiune), form propriu (confirm dezactivat la editare), mutual-exclusion, reuse grila _trimitere_detaliu.html. US-005/006 Mapari/formate tabelar (.tablewrap, H4 auto_send stocat). US-007 bifa auto-send→comutator pe COADA ("Pune automat in coada"/"Tine pentru verificare"), scoped operatie, name=auto_send pastrat (zero backend). 523 teste pass. VERIFY E2E browser + LIVE RAR test: import fara coloana data→editare completeaza data (override)→commit→worker login RAR test→postPrezentare→sent idPrezentare=68696 (confirmat in finalizate RAR). 3 bug-uri JS prinse la E2E (invizibile la TestClient) reparate: htmx useTemplateFragments (raspuns <tr>+OOB parsat in context tabel→swapError), re-activare confirm-btn deferita pe tick, n-hint actualizat. /code-review high (2026-06-22): 1 bug real reparat — decriptarea override_json era in afara try/except-ului care protejeaza raw_json in ambele cai de preview (import_router.preview_import + routes._web_compute_preview); la rotatie cheie Fernet / token corupt raw_json degrada gratios la {} dar override_json arunca 500 pe tot batch-ul — acum protejat identic. Notat ca cleanup viitor (nereparat, disciplina backend-neatins): _override_of + blocul canonicalize-dupa-override duplicate in 3-4 locuri (preview/commit API vs web). Backend trimitere (worker/masina stari/idempotenta/mapare) NEATINS. PRD: prd-3.6

Etapa 5 — Ergonomie & Integrare (FOCUS CURENT)

Directie noua (2026-06-22, decizie utilizator): produsul e functional, dar greu de adoptat de service-urile care vin din Visual FoxPro / soft propriu. Prioritatea trece pe usurinta de integrare + ergonomie, peste Etapa 4 (vezi nota de mai jos). Propunere fundamentata cu lentila DX gstack (/devex-review) pe codul real: lipseste suprafata de onboarding API self-service, exemplele de cod, puntea VFP, dry-run-ul si tema light.

# Livrabila Status Data Detalii
5.1 Hub de integrare (pagina /integrare autentificata): exemple cod multi-limbaj (curl/Python/PHP/C#/Node) + retetar Visual FoxPro (POST via MSXML2.ServerXMLHTTP + upload CSV) + export OpenAPI/Postman + buton "Testeaza conexiunea" DONE 2026-06-22 4 stories (2 valuri, 2 echipe paralel + restore dupa clobber de merge). US-001 GET /v1/ping readiness (account_id/mediu/autentificat_cu_cheie/are_creds_rar/ts) + GET /v1/integrare/postman.json (v2.1.0, allowlist 3 rute). US-002 integrare_examples.py pur (7 limbaje × 2 canale, drift-test is_required()). US-003 tab "Integrare" IA pe 2 niveluri (limbaj→canal, VFP cu dialecte MSXML2/WinHttp), copy din <pre><code>, empty-state CTA, export .cardlink, doar tokens. US-004 POST /integrare/test-cheie (account_for_key direct, scoped sesiune, no-echo). VERIFY: 568 teste + E2E browser (Playwright: VFP 3 niveluri comuta, htmx test-cheie → fragment eroare, 0 erori consola) + enqueue live; live RAR neprobat (lipsa creds key). /code-review high: 4 bug-uri reale reparate (C#/VFP snippet JSON multi-linie nevalid, Node node:buffer fara FormData, script ne-scoped acumuland listeneri). Backend trimitere NEATINS. PRD: prd-5.1
5.2 Endpoint dry-run POST /v1/prezentari/valideaza — valideaza payload + mapare, intoarce erorile reale FARA enqueue DONE 2026-06-22 1 story (US-001), un worker TDD. Helper pur partajat classify_prezentare (mapping.py) folosit de AMBELE rute → garanteaza ca dry-run-ul da acelasi verdict ca trimiterea reala (invariant de corectitudine, nu doar DRY); create_prezentari refactorizat pe el (comportament identic, test_api.py verde). Ruta read-only: {results:[{index,valid,status_estimat,erori,nemapate,prestatii_rezolvate}]}, rar_credentials optional+ignorat, zero scriere DB, scope prin resolve_account_id. Doar validare+mapare (FARA idempotency/duplicat — decizie user; idempotency.py neatins) + hub /integrare amanat. VERIFY context curat PASS (577 teste; E2E API: queued/needs_data/needs_mapping + COUNT(*)=0 dupa dry-run, fara leak creds; regresia de aur POST /v1/prezentari→queued verde; live RAR neprobat — lipsa AUTOPASS_CREDS_KEY/creds test, endpoint read-only nu atinge worker/coada). /code-review high: 0 findings. PRD: prd-5.2
5.3 Light/Dark mode — toggle in header, persistat (localStorage); CSS deja pe variabile :root DONE 2026-06-22 3 stories (US-001 paleta light + US-003 fix suprafete fragmente; US-002 comutator+persistenta+anti-FOUC), un worker TDD secvential (toate ating templates). Tema light = bloc [data-theme="light"] care suprascrie variabilele :root (dark NESCHIMBAT la octet, default pastrat); fundalurile de stare hardcodate (#241a1a/#201c0f/#16241c) convertite la color-mix(... 12%, var(--card)) in base.html + 7 fragmente _*.html. Comutator soare/luna in header (aria-label, >=36px), pe toate paginile (login/signup/dashboard/admin). Default OS-aware (prefers-color-scheme, fallback dark); persistenta localStorage DOAR la click (init doar sincronizeaza iconita → OS-aware ramane viu pana la comutare explicita); script anti-FOUC in <head> inainte de <style> (data-theme sincron pre-paint). Zero backend. VERIFY 2 runde context curat: r1 FAIL (literali dark hardcodati in 7 fragmente HTMX → text invizibil in light; testul scana doar base.html, verde vacuu) → fix US-003 (color-mix in fragmente + test care scaneaza _*.html de pe disc); r2 PASS (E2E browser: banner light rgb(246,234,225)/text rgb(26,29,36) ~13:1, toggle instant+persista+anti-FOUC, dark neschimbat). /code-review high: 1 finding real reparat (light --ok green-600 ~3.3:1 ca text pe alb → green-700 #15803d ~5.0:1, trece AA). Backend trimitere NEATINS. PRD: prd-5.3
5.5 Uniformizare/standardizare UI/UX: tabele la grila Trimiteri (Mapari compact + toggle Auto/Manual + Ajutor; Nomenclator), meniu hamburger (Cont/Integrare/Nomenclator/Admin/logout) cu tab-bar redus la Acasa+Mapari, sterge Ajutor de pe Acasa, panou admin cu selectie+bulk (Activeaza/Blocheaza/Arhiveaza/Sterge) pe model nou de stare cont DONE 2026-06-23 9 stories, 3 valuri. UI pur (reskin+reasezare) cu O SINGURA exceptie backend: accounts.status (pending/active/blocked/archived/deleted, migrare defensiva, gate worker claim_one pastrand active=1 ⇔ status='active'). Macro autosend rescris compact pastrand semantica de prezenta auto_send (zero backend). Stergere = SOFT: tombstone, dar PII (creds RAR + chei API + CUI) purjate IMEDIAT la stergere (GDPR/L.142), nu prin retentie. VERIFY 671 teste pass (+40); E2E browser Playwright a prins 2 bug-uri invizibile la TestClient (bara bulk display:flex inline invingea [hidden]; arhivate cadeau sub "in asteptare" → grupare pe status). /code-review high: 2 bug-uri reale reparate (soft delete pastra creds+CUI fara purjare → purjare PII la stergere; apostrof in nume rupea confirm() inline kebab) + cleanup _lifecycle_route. Debt acceptat: /admin/deactivate+set_active pastrate legacy (test CLI). Backend trimitere neatins (exceptie: gate cont). Commit 1fbd894. Design: 5.5-uniformizare-ui. PRD: prd-5.5
5.4 Erori pe 3 niveluri (problema + cauza + fix) pe API si UI DONE 2026-06-22 Catalog central pur app/errors.py (24 coduri, eroare(){field,cod,problema,cauza,fix,message}, ridica pe cod necunoscut) ca SINGURA sursa de adevar, consumat de API+UI+worker (acelasi invariant anti-divergenta ca 5.2). 8 stories, 5 valuri. Tot ADITIV (decizie user): field/message/error pastrate la octet, adaugam 3 niveluri + cod stabil; rar_error stocat = SUPERSET (chei vechi intacte → labels.py nu se rupe intre valuri, zero migrare). Scope = fluxul de declarare (validare continut, RAR 400/401, import, mapare op→cod); login/signup/CSRF NEATINSE. US-001 catalog; US-002 validation.py (cod+3n, byte-compat); US-003 mapping.py+/valideaza (needs_mapping/auto_send superset, nemapate 3n); US-004 worker RAR 400→RAR_VALIDARE (field_errors passthrough) + 401→RAR_CREDS_INVALIDE (clasificare transient neschimbata, fara echo creds); US-005 import_router detalii superset; US-006 labels.parse_erori (degradeaza gratios, lectia 3.6) + macro _eroare.html (progresiv: lista compacta, 3n complete in detaliu/preview; AA light+dark, accent≠rosu); US-007 upload/mapcoloane web prin macro; US-008 contract documentat. VERIFY context curat PASS (628 teste; byte-compat+superset verificate direct; E2E API /valideaza 3 niveluri + regresia de aur queued; E2E web fragmente upload+detaliu; live RAR FINALIZATA neprobat — lipsa creds key, endpoint-urile/UI noi nu ating trimiterea). /code-review high: 2 bug-uri reale reparate in labels.pymotiv_uman nu avea ramura pentru dict-ul 3-niveluri (401 creds → text garbled "field: None; cod:..." in coloana Motiv) + parse_erori intorcea element gol pe {}/[{}] (cutie de eroare goala); cleanup notat ca viitor (dublare parse_erori/motiv_uman, enrichment COD_NEMAPAT pe 2 straturi, upload handlers copy-paste cross-channel routes.py/import_router, json.loads mort in ramura COLOANE_FORMAT_JSON). 631 teste. Backend trimitere (worker masina stari/idempotenta/mapping-rezolvare) si schema NEATINSE. PRD: prd-5.4
5.6 Observabilitate & jurnal aplicatie + lifecycle trimiteri blocate: jurnal structurat de evenimente (tabela app_events + log text) cu vizualizator in dashboard, handler global 500→eroare 3 niveluri + request_id, audit cereri API + login RAR + ciclu trimiteri (worker), redactare PII/creds, retentie/purjare; plus stergere/re-pune in coada randuri blocate (UI+API), dedup care nu mai e blocat de un rand error, purjare randuri blocate, banner "Necesita atentia ta" actionabil (link + identificare rand) APROBAT 2026-06-23 Nascut din incidentul 500 (client VFP). HOTFIX deja livrat in afara procesului (US-000): cheie Fernet valida in .env + crypto.validate_creds_key() fail-fast in main.lifespan + mesaj error corectat in labels.py; confirmat live POST→200, send RAR test→idPrezentare=68818. 14 stories ramase: observabilitate US-001..008, lifecycle US-009..013, banner US-014. Decizii §5 rezolvate cu user: retentie jurnal 90z (AUTOPASS_LOG_RETENTION_DAYS) + RotatingFileHandler; tipuri evenimente extensibile; jurnal non-admin scoped pe cont (admin vede tot); la resubmit doar error se re-activeaza (needs_* raman deduped); retentie randuri blocate 30z (AUTOPASS_BLOCKED_RETENTION_DAYS); stergere UI cu confirmare simpla + bulk pe lista. NEIMPLEMENTAT inca (doar hotfix-ul e in cod). PRD: prd-5.6
5.8 UX tabel trimiteri (detaliu inline, fara scroll, cod RAR sub operatie) + reguli mapare pe text (substring, per cont) DONE 2026-06-24 11 stories (4 valuri) livrate TDD, executate de echipa de workeri (lead orchestreaza). Reguli text US-001..004 (tabela operation_text_rules per cont; resolve_prestatii cu param aditiv text_rules + precedenta stricta cod-direct>mapare-exacta>regula-text>nemapat; threading pe TOATE cele 6 callsite-uri + valid_codes + seam classify_prezentare; UI sectiune Mapari cu „contine"/empty state). UX tabel US-005..008 (cod_rar in payload_view; eticheta_scurta separata; tabel fara scroll orizontal scopat .tabel-trimiteri + responsive carduri <768px; detaliu INLINE ca rand-sibling expandabil cu chevron+fundal+a11y+pauza poll 15s via htmx:beforeRequest). Expansiuni Val 4 US-009..011 (preview pre-salvare cati nemapate potriveste; telemetrie text_rule_hit in app_events pe TOATE caile inclusiv corectie+import web; avertizare overlap neblocanta). VERIFY context curat: 814 passed, 1 skipped (live opt-in); E2E functional TestClient (browser pixel-level neprobat — sandbox + /login; live RAR neprobat — lipsa creds). /code-review high: 1 bug critic real reparat — regula text cu auto_send=0 (DEFAULT, decizia CEO de siguranta) trecea randul pe queued (trimis automat la RAR) in loc sa-l TINA needs_mapping pentru review: has_no_auto_send inspecta doar operations_mapping, nu si regula text care a rezolvat itemul; VERIFY initial ratase cazul. Reparat TDD (mapping.py: _rezolva_din_reguli_text intoarce auto_send; resolve_prestatii marcheaza regula_fara_autosend + curata adnotari stale — repara si o telemetrie falsa latenta; has_no_auto_send prinde flagul). Backend trimitere (worker/masina stari/idempotenta/contract RAR) + schema-send NEATINSE (schema = pur aditiv: tabela noua). PRD: prd-5.8
5.7 Raspuns API onest la blocaje (erori/nemapate/motiv pe orice status != queued) + mapare inline din panoul de detaliu trimitere DONE 2026-06-23 Raportat din client VFP: POST /v1/prezentari raspundea submission_id+status fara motiv pe randuri blocate (erori doar pe on_unmapped_error=True) → needs_data/needs_mapping parea succes. 3 stories TDD. US-001 (backend API): SubmissionResult += nemapate+motiv (ADITIV), create_prezentari populeaza erori/nemapate/motiv pe enqueue + respins + reactivare via helperele _rezultat_enqueue/_rezultat_respins/_motiv_clasificare; on_unmapped_error=True pastreaza erori=COD_NEMAPAT (compat). US-002 (web): ruta POST /trimitere/{id}/mapeaza (reuse EXACT save_mapping+reresolve_account, scoped sesiune 404 + CSRF, re-rezolva pe batch_id-ul randului) + _nemapate_pentru_submission + context in _detaliu_ctx. US-003 (UI): sectiune "Mapeaza codul operatiei" in _trimitere_detaliu.html (selector cod RAR cu sugestie fuzzy preselectata >=60, ui.autosend_toggle), doar pe operatii nemapate reale. /code-review high: 2 buguri reale reparate (reactivarea omitea erori/nemapate/motiv; dublu load_nomenclator), restul infirmate. pytest -q 765 passed, 0 failed (+1 skipped live). Live RAR --send PROBAT (2026-06-23): mapare inline in browser → queued → worker → sent idPrezentare=68827 (confirmat independent in finalizate RAR + jurnal app_events); automatizat ca test live opt-in tests/test_live_rar.py (skip implicit; AUTOPASS_LIVE_RAR=1 + creds test → reproduce tot lantul, idPrezentare=68828). Backend trimitere (worker/masina stari/idempotenta) si schema NEATINSE. PRD: prd-5.7
5.10 UX trimiteri (pill filtre + paginare numerotata + VIN sub nr + editare op RAR + op service in detaliu + eroare simpla) + Mapari in meniu hamburger (pagina consolidata + butoane icon/dirty) + branding ROMFAST (header by ROMFAST + paleta azur + IBM Plex + selector tema ciclic Light/Dark/Petrol/Auto) DONE 2026-06-25 14 stories TDD prin echipa (lead orchestreaza, 3 teammates Sonnet pe valuri cu fisiere disjuncte; routes.py + base.html serializate). US-001 _iso_date_prefix (garda+comparatie, fix filtrare data cu ora). US-002 chei distincte op_service_cod/denumire in payload_view (conventie goala ""). US-003 pill-uri <button> aria-pressed (needs_mapping --warn, needs_data/error --err; dropdown status + lista ID-uri eliminate). US-004 paginare numerotata 25/pag (total ramificat: SQL COUNT fara filtru Python / fetch-all+slice cu filtru; clamp page; poll pastreaza pagina via OOB f-page; pager ascuns la pages<=1). US-005 VIN block-level sub nr. US-006+US-006b editare cod RAR cu validare nomenclator + injectare in prestatii[0] + canonicalize + build_key (cheie idempotency noua) + check coliziune — pe needs_data/needs_mapping via /corecteaza, pe error via /repune (error→queued); read-only pe sent/sending/queued. US-007 op service distinct in detaliu (editabil+read-only). US-008 card eroare 3-niveluri doar pe read-only + rezumat top-of-form pt erori fara camp. US-009 Mapari in #cont-menu cu badge + scoatere tab-bar/role=tablist orfan/JS sageti. US-010 pagina Mapari consolidata (ordine De rezolvat/salvate/reguli text/formate; ajutor+empty-text scoase). US-011 butoane icon SVG .icon-btn mereu vizibile + dirty-state pe change (fara kebab/emoji). US-012(+012b) header grid centrat + env badge in grila + logo ROMFAST in header: initial wordmark text, apoi (decizie user) PNG-ul real /static/romfast_logo.png (.brand-logo ~28px, fundal transparent, lizibil pe toate temele). US-013 paleta azur ROMFAST (#2E74D6 dark/#1F66C9 light) + IBM Plex Sans/Mono self-host woff2 (subseturi reale fontsource v5.0.8, latin+latin-ext, font-display:swap). US-014 selector tema ciclic Light→Dark→Petrol→Auto + anti-FOUC extins atomic la 4 stari + fallback legacy + aria-label curenta+urmatoarea/aria-live. VERIFY context curat PASS (toate 14 stories, dovezi in cod). /code-review high: 1 finding material reparat TDD (US-006b — error lipsea din editarea op RAR, cerut de AC) + 4 minore notate ca debt (comparatie data bruta sigura prin UI; dublu load_nomenclator cand nomenclator gol; vehicul uppercased in linkuri pager cosmetic; duplicare cale validare+idempotency intre post_corectie/post_repune). Regresie 896 passed, 1 skipped, 0 failed. E2E browser NEPROBAT (sandbox fara browser interactiv) — recomandat la deploy (./start.sh test both --send + browser pe /). Backend trimitere (worker/masina stari/idempotenta/mapping) + schema NEATINSE (UI/UX pur + fix filtrare). Design: DESIGN.md. PRD: prd-5.10
5.11 Import compact + preview in format Trimiteri + navigatie + simplificare auto_send (dogfooding baza goala) DONE 2026-06-26 8 stories TDD prin echipa de teammates Sonnet (lead orchestreaza, NU scrie cod; 6 runde pe valuri cu fisiere disjuncte; base.html/routes.py/_coada.html/_status.html serializate ca fisiere fierbinti). US-001 scoate hold-ul auto_send din mapare: has_no_auto_sendreturn False (NEUTRALIZAT, simbol pastrat — importat in routes.py+import_router.py; stergerea ar da ImportError la boot), ramura AUTO_SEND_OPRIT scoasa din classify, cod rezolvat→queued, needs_mapping doar pt cod RAR nerezolvat; coloane DB raman (default 1, ne-citite); teste vechi rescrise; canal API auto_send=0→queued (R1 acceptat constient: rastoarna default-ul de siguranta CEO). US-002 scoate bifa auto_send din UI (macro golit, 0 reziduuri in 3 sabloane). US-003 preview pas 3 = format Trimiteri (STARI_PREVIEW+nota_umana_preview in labels.py — fara KeyError pe stari preview, fara repr Python in Note; view-model prez din payload_view; .tabel-trimiteri+col-*+data-eticheta+editor tr.preview-edit care scapa grila fixa). US-004 rand filtre ca referinta (quick-pills data STANGA+Custom / cautare / pills stare DREAPTA; reset=accent, categorie=culoarea ei; hover color-mix; :focus-visible pastrat). US-005 nav Trimiteri+Mapari sub contoare pe toate paginile (_status.html+stub dashboard.html, tab_activ explicit pastrat la self-refresh, badge sursa unica, logo+titlu link /, hamburger Trimiteri-first). US-006 import = <details open=are_trimiteri> nativ (colapsat la returning, deschis la first-run, fara toggle JS). US-007 post-commit reveal: web_confirma_import→OOB _coada (#trimiteri-section)+OOB _status (#status-bar)+header HX-Trigger: trimiteriChanged, mesaj onest. US-008 auto-refresh dupa actiuni (poller→reincarcaTrimiteri() pastrand filtru+pagina; nudge "Date noi" eliminat). VERIFY context curat PASS (8/8 stories cu dovezi cod+teste+randare runtime — verificatorul a pornit aplicatia reala si a inspectat HTML-ul). /code-review high (8 unghiuri prin subagenti): 3 buguri reale reparate TDD — (1) #status-bar pierdea tab-ul activ la self-refresh (_status.html hx-get fara ?tab=→nav marca gresit Trimiteri pe ?tab=mapari), (2) pill Custom lasa valori stale→interval inversat silentios, (3) nota_umana_preview afisa flag inaintea "Cod RAR lipsa" pe needs_mapping; debt acceptat notat (dublu-fetch idempotent la commit; etichete in 3 locuri; import mort has_no_auto_send). Regresie 934 passed, 1 skipped, 0 failed; smoke boot OK. E2E browser click-through complet + live RAR FINALIZATA NEPROBATE (mediu fara browser interactiv/creds web) — backend trimitere (worker/masina stari/idempotenta/build_key/contract RAR) si schema NEATINSE (non-goals respectate). PRD: prd-5.11.
5.13 Responsive compact (mobil/tableta) + sistem de butoane (.act/.btn-* desktop text / mobil iconita Lucide 44px) + stepper compact + design.md (sursa de adevar design) DONE 2026-06-27 Nascut din dogfooding (screenshot-uri urate pe ecrane mici) + eng/CEO/design review (autoplan). Decizie premisa user: listele actionabile = O COLOANA pana la 1024px (reverseaza grila 2/rand). Wave 0 BLOCANT: refacut cele 2 teste responsive fragile (fereastra fixa [idx:idx+5000] -> ancora pe SENTINEL CSS + slice la </style>), cauza probabila a revert-ului anterior. Wave 1: FIX P0 break vertical (min-width:120px eliminat -> card stivuit), sistem butoane .btn-secondary/.btn-ghost/.btn-danger/.btn-sm + .act/.act-save/.act-del + macro act_btn (aria-label invariant) + icon() Lucide, stepper .stepper-track/.stepper-collapsed, cardificare <=1024px (zero repeat(2), versiune ascunsa mobil, sticky-bar compacta. Wave 2: _stepper.html rescris, _mapari.html icon-btn->act_btn (4 butoane), _submissions.html guard „Eroare/Eroare" pill-only + linie meta actualizat. Wave 3: test_web_mapari_actiuni.py -> .act (superseda 5.10) + 5 teste responsive noi + fix test_web_import_stepper.py (facut->is-done). VERIFY context curat: 992 passed, 1 deselected (live) + E2E browser Playwright 390/820/1280 (mobil fara break vertical, tableta o coloana, desktop tabel neschimbat, wizard slim pe o linie). Bulk-select declarat desktop-only by design (checkbox ascuns mobil). Backend trimitere + schema NEATINSE (pur CSS + markup: 6 template-uri + design.md + 2 teste). Debt: timp relativ ramane absolut; SVG inline (sprite = optimizare viitoare). PRD: prd-5.13
5.12 Editare unificata in modal (preview = acelasi formular ca Trimiteri, scoate editarea inline rupta + eroarea htmx htmx-internal-data) + calendar <input type=date> pe data prestatiei + cont cu companie/email/CUI obligatorii (accounts.email + gate activare) + mapare cu antet+prima inregistrare + un singur Salveaza pe operatii + preview compact fara coloana „Verificat?" + responsive tableta/mobil (header fara suprapuneri) TODO Nascut din dogfooding first-run E2E (Playwright pe exemple/prezentari_test.csv, 2026-06-26): reprodus modul de editare inline colapsat pe verticala (tr.preview-edit in table-layout:fixed) + TypeError htmx-internal-data la Anuleaza; data prestatie doar text; toate conturile cu cui=NULL + conturi CLI/teste fara email; mapare coloane fara cap de tabel/valori; N butoane Salveaza pe operatii; coloana „Verificat?" neclara; pe tableta/mobil header-ul se suprapune (grila desktop fara breakpoint 7681024). 8 stories (3 valuri). Decizii user (AskUserQuestion 2026-06-26): calendar = <input type=date> nativ; email canonic pe accounts (model A); coloana „Verificat?" scoasa (gate needs_review mutat in modal). Backend trimitere NEATINS; singura schema = accounts.email (migrare defensiva). PRD: prd-5.12
5.15 Propagare design landing in aplicatie + dashboard editare (teme aditive, componente slim, dashboard contoare + strip sanatate, lista slim, form editare slim cu chips prestatii multi-cod, obs editabil, bulk-fix, salvare mapare din chip, account-scope pe GET-urile de listare, analytics device-mix) DONE 2026-06-28 12 stories, verify-pass, prin agent team (lead orchestreaza, teammates Sonnet, TDD per story, base.html+routes.py serializate ca fisiere fierbinti). US-004 lista slim (trimitere-slim), US-006 prestatii multi-cod (form.getlist pozitional), US-007 form editare slim + chips + obs, US-009 salvare mapare din chip, US-011 account-scope pe fragmentele de listare (404-before-leak pe id strain), US-012 analytics device-mix fara PII. CLOSE (/code-review high -> reparare TDD 2026-06-28): 8 buguri reale reparate — (1) HIGH modalul nu se deschidea pe randul slim (base.html verifica doar trimitere-row, nu trimitere-slim, in click+keyboard handler); (2) HIGH /repune trunchia prestatii (itera enumerate(codes)=1 select -> pierdea prestatii[1:] -> declaratie incompleta la RAR ireversibil; fix: iterare peste existing, codes pozitional); (3) HIGH picker chips GOL pe re-render dupa eroare validare/coliziune (_detaliu_ctx fara conn/account_id -> nomenclator_rar=[]; fix pe toate 4 ramurile post_corectie); (4) MED obs re-derivat dupa stergere explicita (_merge_override pop pe obs -> derive-on-empty il reinvia; fix: pastreaza obs='' explicit); (5) MED mapare salvata fara denumire poluă GOLD partajat cu cod_op_service ca cheie (fix: helper _record_gold_validation care sare scrierea cand denumire lipseste/==cod_op_service, aplicat la toate 4 callsite-urile); (6) MED typo nome_prestatie->nume_prestatie in select /repune; (7) MED bucketare timp +3 hours fix gresita iarna (RO=UTC+2 EET; fix: SQLite localtime DST-aware + TZ=Europe/Bucharest in Docker/compose + tzdata); cleanup: hoist load_* din bucla bulk-fix, import re la top. Regresie 1256 passed, 1 deselected (live). E2E browser real OPEN (Playwright indisponibil in sandbox). PRD: prd-5.15
5.14 Mapare LLM distilata: etichetator offline (OpenRouter NVIDIA) + temporal holdout + shared store GOLD partajat cross-account (suggestion-only) + SILVER LLM + embeddings in-proces (fastembed/ONNX) + held-out eval + integrare Layer 2/3 in editor DONE 2026-06-28 6 stories (S1-S6), verify-pass, in paralel cu 5.15 pe acelasi branch (piese disjuncte de fisier rulate paralel; integrarea L14-S6 in editor venita DUPA 5.15, suggestion-only, fara a atinge designul, D9). Auto-send DOAR GOLD propriu; SILVER/GOLD-partajat/embeddings = sugestie, niciodata auto-send (#11/#13, resolve_prestatii/load_mapping nu citesc tabelele de sugestii). Gate holdout = SLABA (validare temporala imposibila — CSV fara timestamp; non-blocant). CLOSE (/code-review high 2026-06-28): bug embeddings „mort dar scump" reparat — enrich_suggestions apela is_available() neconditionat -> lazy-load model ~230MB sincron in thread-ul de cerere desi corpus gol (index_corpus nu era wired) -> zero beneficiu. Decizie user CLOSE: WIRE embeddings functional (PRD #15: embeddings in v1): ensure_embeddings_corpus(conn) construieste corpus din nomenclator, gated pe AUTOPASS_EMBEDDINGS_ENABLED (default OFF -> /mapari instant + teste rapide; ON -> lazy-load la prima cerere, re-index pe semnatura nomenclator); enrich_suggestions ramane query ieftin cu garda has_corpus(). Corectata marimea modelului in PRD/cod: ~50MB (estimare gresita) -> ~230MB real masurat (paraphrase-multilingual-MiniLM-L12-v2 ONNX quantizat). Regresie 1256 passed. PRD: prd-5.14
5.16 Tipografie uniforma (system-ui, scoate IBM Plex self-hostat) + scala tipografica uniforma + rebrand antet/login profesional + bug-fix formular editare (4 bug-uri reale) + E2E TODO PRD draft + autoplan (CEO/Design/Eng; DX skip — UI operator) rulat 2026-06-28, single-voice (Codex la plafon de utilizare pana 2026-07-18). User Challenge #1 REZOLVAT = system-ui (decizia user; challenge respins, Approach A/IBM Plex picat; risc randare per-OS + design slop #11 „system-ui ca font primar" = ACCEPTAT CONSTIENT). Cele 4 bug-uri confirmate in cod: US-007 (base.html hasAttribute la buton cu copii -> click pe text nu inchide), US-006 (post_corectie nu citeste chips_add_cod_flat -> save no-op), US-004 (picker plat doar cod vs op-mode cod+denumire), US-005 (add_extra lipseste din post_form_chips). Pre-ship (Eng issues_open, 0 critical gaps): test E1 (grep literale IBM Plex ramase fara fallback) + E3 (by-index op corecta). Audit trail + GSTACK REVIEW REPORT scrise in PRD; niciun commit. PRD: prd-5.16
5.17 Tipuri de cont (free/standard/pro/premium, sursa unica app/plans.py) + trial Pro 30 zile automat la creare + enforcement DUR (volum 60/luna Gratuit pe ambele canale + gate API Pro+) + downgrade lazy la expirare + alocare manuala admin (CLI set-tier). Fara billing self-service (non-goal) TODO PRD draft + autoplan (CEO/Design/Eng/DX) rulat 2026-06-28, single-voice (Codex la plafon pana 2026-07-18). User Challenge REZOLVAT = enforcement DUR direct de la deploy (decizia user); CRITICAL GAP „migrare conturi legacy" = MOOT (fara conturi legacy, pre-productie/in teste). Feature-flag AUTOPASS_ENFORCE_PLANS = OPTIONAL (kill-switch de operare, nu blocant). 3 taste decisions rezolvate cu user (toate pe recomandare): limita 60 = constanta config tunabila (sursa unica); banner one-time la trecerea trial->Gratuit; valideaza dry-run ramane permis pe orice plan. Limita Gratuit scade 100->60/luna. 0 decizii deschise, gata de implementare. Audit trail + GSTACK REVIEW REPORT scrise in PRD; niciun commit. PRD: prd-5.17
5.18 Corpus k-NN din exemple reale etichetate (mapare operatii): pre-filtru determinist NUL + etichetator offline multi-backend + generator seed pe frecventa + seeder mapping_suggestions (SILVER populat in productie) + embeddings indexeaza corpusul etichetat (nu nomenclatorul) + enrich_suggestions = NUL > GOLD > exact > k-NN + badge sursa in editor (US-007). Suggestion-only (#13), zero LLM la runtime DONE 2026-06-29 7 stories (US-001..007) TDD. Seed real produs cu subagenti Haiku (decizie user 2026-06-29 — abatere documentata de la D4/LM Studio: GPU box jos; Haiku = motor mai bun, validare 157 op Haiku ~22/30 corect vs Groq ~0 la dezacorduri): app/data/operatii-etichetate.json rescris 3758 (Groq partial) -> 17181 operatii distincte (source="haiku_seed", ordine frecventa, NUL=2200). Seeder init_db INSERT OR IGNORE idempotent; embeddings k-NN pe denumire_normalizata (query normalizat simetric, F1); precedenta NUL>GOLD>exact>k-NN cu abtinere sub prag. US-007 badge confirmat/similar/non-operatie pe sugestia fuzzy (cerere user la CLOSE). VERIFY context curat PASS: suita 1392 passed, 1 deselected (live); smoke init_db seed=17181/NUL=2200/idempotent; toate codurile in nomenclator (zero cod gunoi -> zero risc HTTP 500/ORA-12899); E2E render live al badge-urilor (confirmat/similar/non-operatie). CLOSE /code-review high (main..HEAD, 3 finder x 8 unghiuri): calea runtime curata, invariant #13 intact; 3 findings low/cosmetic REPARATE + lock-uite (FD leak tool offline -> with open; cod whitespace -> NULL in seed_suggestions + test; docstring embeddings). Config: seed_operatii_enabled=True + embeddings_enabled=True default (ambele suggestion-only, dezactivabile prin env; embeddings lazy-load ~230MB la prima cerere /mapari). Commit-uri 756f777 (core+seed) + 308fee6 (fix lateral start-test ONNX). Calitate seed la scara ~95%; coduri rare (avarii grave) sparse, ne-verificate uman -> ramane recomandarea esantion uman (Decision #19) inainte de orice auto-send. PRD: prd-5.18

Etapa 4 — Deprioritizat (post Etapa 5, daca apare nevoia din uz real)

# Livrabila Status Data Detalii
4.1 Mapare AI / conector MCP (sugestie peste fuzzy) AMANAT deprioritizat 2026-06-22 in favoarea ergonomiei/integrarii (Etapa 5)
4.2 Editare/anulare prezentari trimise BLOCAT FINALIZATA terminal la RAR — fara flux API; corectia = suport RAR

Amanat / taiat (cu motiv)

Livrabila Status Motiv
Drop-fisier SFTP / email-to-import AMANAT Valideaza intai upload-ul manual (wedge-ul real), apoi re-evalueaza
Contor volum + prag freemium AMANAT Metrici de pret inainte sa existe useri; trivial de adaugat post-validare
Billing complet (Stripe etc.) AMANAT Dupa validarea pragului de volum

4. Open questions / riscuri acceptate

  • Un cont = un agent RAR sau mai multi — afecteaza maparea creds in UI + filtrarea monitorizarii. Relevant pentru Etapa 3.
  • Valori reale sistemReparat — azi se trimite "null"; ce alte valori accepta RAR ramane de probat.
  • R4 (acceptat constient): creds RAR durabile-at-rest (Treapta 2) → la scurgerea cheii Fernet toate parolele sunt decriptabile (vs. doar in-flight pe canalul API). Mitigare: rotatie cheie + redactare loguri.

5. Proces de implementare

5.1 Principii

  1. PLAN separat de EXECUTE/VERIFY, pe sesiuni distincte. Planificarea consuma mult context (model puternic) si produce PRD-ul ca artefact de predare. Executia reia intr-o sesiune noua bazat doar pe PRD — nu pe transcriptul planificarii. Starea persista in PRD, nu in conversatie.
  2. TDD ca contract: testul scris ÎNAINTE = forma executabila a criteriilor de acceptare. Un worker cu test rosu clar nu poate declara fals victoria — testul decide.
  3. Story atomic = unitate de paralelizare SI de rollback: un story = un commit logic = un worker = un test-suite verde.
  4. VERIFY in context curat: un subagent dedicat care primeste DOAR PRD-ul + instructiunile §5.6, NU transcriptul executiei (altfel mosteneste partinirea de confirmare a celui care a implementat).
  5. Single writer: doar sesiunea lead scrie in PRD, ROADMAP si git. Workerii scriu doar cod si teste.
  6. E2E pe canalul real: un flux se verifica prin canalul lui (upload web prin browser, API prin POST /v1/prezentari), nu doar prin apel intern. RAR test = endpoint real.

5.2 Cele 4 faze (separabile pe sesiuni)

  SESIUNE A (Opus/Fable)            SESIUNE B (lead + agent team Sonnet)
  ┌─────────────────────┐          ┌──────────────────────────────────────────────────┐
  │ FAZA 1: PLAN        │  PRD     │ FAZA 2: EXECUTE   FAZA 3: VERIFY   FAZA 4: CLOSE   │
  │ citeste ROADMAP+cod │  aprobat │ TeamCreate +      subagent context  /code-review   │
  │ scrie PRD (stories  │ ───────▶ │ workeri Sonnet    curat: pytest +   writeback dash │
  │ atomice + teste)    │ (in PRD) │ TDD per story     E2E RAR test      propune commit  │
  │ plan-reviews gstack │          │ lead bifeaza PRD  raport in PRD                     │
  │  ▼ POARTA UMANA     │          │                                     ▼ POARTA UMANA  │
  │  aprobare PRD       │          │                                     confirmare commit│
  └─────────────────────┘          └──────────────────────────────────────────────────┘

PLAN poate rula singur intr-o sesiune (scump, model puternic) si se opreste la poarta de aprobare. EXECUTE → VERIFY → CLOSE reiau intr-o sesiune noua din PRD-ul aprobat. Pot fi si inlantuite in aceeasi sesiune daca vrei — starea din PRD le face reluabile oricum.

5.3 PRD per livrabila

  • 1 PRD per livrabila din dashboard: docs/prd/prd-X.Y-<slug>.md (skill /prd).
  • Prima linie dupa titlu: **Stare**: draft (vezi §5.7 pentru tranzitii).
  • Contine obligatoriu: obiectiv, Non-Goals (anti scope-creep), stories atomice (§5.4), riscuri, intrebari deschise (rezolvate cu utilizatorul ÎNAINTE de executie), graful de valuri.
  • PRD-ul nu repeta strategia/contractul — le linkeaza (docs/api-rar-contract.md, acest ROADMAP).
  • Review-uri de plan (aplicate IN PRD inainte de cod): /plan-ceo-review (valoare/scope) + /plan-eng-review (fezabilitate/teste) — obligatorii; /plan-design-review — doar daca atinge UI.

5.4 Story atomic (template)

### US-003: <titlu scurt>
**Ca** <rol> **vreau** <capabilitate> **pentru ca** <motiv>.

- **Depinde de**: US-001
- **Fisiere**: `app/<modul>.py`, `app/web/templates/<x>.html` (~N fisiere)
- **Test intai (RED)**: `tests/test_<x>.py``test_<caz_1>`, `test_<caz_2>`
- **Acceptance criteria**:
  - [ ] <criteriu testabil 1>
  - [ ] <criteriu testabil 2>
- **Verificare E2E**: <browser HTMX / POST /v1/prezentari pe RAR test>

Testul de atomicitate: (a) poate un Sonnet sa-l termine intr-o singura sesiune, cu teste, fara sa intrebe nimic? daca nu → sparge-l. (b) lasa sistemul functional daca e ultimul story? (c) Fisiere

  • Depinde de complete (decid ce se paralelizeaza). (d) backend + UI pentru acelasi comportament = 2 stories.

5.5 Executie — agent team (lead orchestreaza, NU scrie cod)

  • TeamCreate creeaza echipa + lista de task-uri partajata; Agent cu team_name + name + model: sonnet spawneaza teammates adresabili. Lead-ul ii coordoneaza prin SendMessage (clarificari/re-directionare la cald, fara re-spawn) si TaskUpdate (atribuire/inchidere task).
  • Valuri (waves): lead-ul grupeaza stories pe graful de dependente. Val 1 = stories fara Depinde de si fara fisiere comune → teammates paraleli. Val 2 = deblocate de Val 1. Etc.
  • Reguli hard: max 2-3 teammates simultan (server dev + SQLite partajate); fisiere comune = nu paralel (sau isolation: worktree + merge de catre lead); teammates nu comit, nu scriu in PRD/ROADMAP, nu pornesc/opresc servere, nu rezolva ambiguitati singuri (escaladeaza la lead).
  • Raport teammate (prin SendMessage): test RED citat → implementare → test GREEN citat → fisiere atinse → abateri; apoi TaskUpdatecompleted.
  • Dupa fiecare val: lead-ul ruleaza regresia (python3 -m pytest -q) si bifeaza stories in PRD.
  • Livrabile mici pot rula fara TeamCreate (un singur worker sau lead direct) — dar PRD-ul, verificarea in context curat si writeback-ul raman obligatorii.

5.6 VERIFY (subagent cu context curat)

Lead-ul spawneaza un subagent dedicat care primeste DOAR PRD-ul + aceste instructiuni, NU transcriptul:

Esti verificator independent pentru livrabila {X.Y} (PRD: docs/prd/prd-{X.Y}-<slug>.md). Citeste PRD-ul; NU porni de la premisa ca implementarea e corecta.

  1. Suita: python3 -m pytest -q — verde (citeaza output-ul).
  2. Criteriile de acceptare ale fiecarui story din PRD.
  3. E2E pe canalul atins: UI web → ./start.sh test both --send, browser pe http://localhost:8000/ (Playwright MCP sau /browse), fluxul din PRD; canal API → POST /v1/prezentari pe RAR test.
  4. Regresia de aur: fluxul existent nu are voie sa se strice — POST /v1/prezentari (sau import → commit) → worker → FINALIZATA la RAR test, vizibil in dashboard (./start.sh test finalizate).
  5. Raport PASS/FAIL per criteriu cu dovezi. FAIL-urile NU le repari (/qa-only, nu /qa) — le documentezi.

Lead-ul scrie raportul in PRD ca ## Raport VERIFY. Toate PASS → CLOSE. Exista FAIL → inapoi la EXECUTE (stories de fix), apoi VERIFY din nou cu subagent NOU.

5.7 Bootstrap sesiune (detectie faza din starea PRD)

Starea persista in PRD (prima linie dupa titlu), actualizata de lead la fiecare tranzitie: **Stare**: draft → aprobat → in-executie → verify-pass → inchis. Asta face procesul reluabil din orice sesiune noua — starea e in fisiere, nu in conversatie.

Stare gasita Faza de pornire
nu exista docs/prd/prd-{X.Y}-*.md PLAN
PRD **Stare**: draft PLAN (reia stories/review-uri)
PRD **Stare**: aprobat / in-executie, stories nebifate EXECUTE
toate stories bifate, fara ## Raport VERIFY cu PASS VERIFY
## Raport VERIFY = PASS CLOSE
PRD **Stare**: inchis livrabila gata — alege urmatoarea din dashboard

La bootstrap: daca utilizatorul a numit {X.Y}, aceea e; altfel prima WIP din dashboard, apoi prima TODO in ordinea etapelor. Confirma alegerea cu utilizatorul — singura intrebare permisa la start.

5.8 CLOSE + porti umane

  1. /code-review pe diff-ul livrabilei. Probleme → fix acum (worker) sau story nou (inapoi in PRD).
  2. Writeback: in §3 dashboard — status DONE + data + link PRD; actualizeaza "Ultima actualizare". PRD: **Stare**: inchis.
  3. POARTA UMANA: propune commit-ul (mesaj conventional commits, fara emoji; vezi git rules) si ASTEAPTA confirmarea explicita — niciodata commit automat.

5.9 Anti-patterns (opreste-te daca observi)

Anti-pattern Corectia
Teammate "termina" fara output de test citat Raportul e invalid — cere dovezi prin SendMessage
Test scris DUPA implementare ca formalitate Nu e TDD — testul e contractul; refa bucla
Lead-ul scrie cod "ca e mai rapid" Pierde orchestrarea; spawn teammate chiar si pt un fix mic
Stories paralele care ating acelasi fisier Re-planifica valurile sau worktree + merge de catre lead
PRD modificat in executie fara re-review Schimbare de scope → inapoi la PLAN
Lead verifica singur, fara subagent VERIFY Partinire de confirmare — VERIFY cere context proaspat
Continua peste poarta umana Aprobarea PRD si confirmarea commit sunt ale utilizatorului — opreste-te

6. Skill-uri in proces

Faza Skill Rol
PLAN /prd genereaza PRD-ul (docs/prd/prd-X.Y-<slug>.md)
PLAN /plan-ceo-review, /plan-eng-review, /plan-design-review review de plan (primele 2 obligatorii; design doar UI)
EXECUTE /investigate bug neinteles raportat de worker — root cause, nu patch orb
VERIFY /browse, /qa-only browser headless / QA doar-raport (nu repara — pastreaza independenta)
CLOSE /code-review review pe diff-ul livrabilei
oricand /learn salveaza gotcha-uri in .claude/rules/ (nu in acest doc)

7. Intretinere

Acest document se actualizeaza la schimbari de proces (nu per livrabila) si la dashboard (la fiecare livrabila terminata — §3). Lectiile operationale (gotchas, pattern-uri descoperite in executie) merg in .claude/rules/ via /learn, nu aici.