Files
rar-autopass/docs/prd/prd-5.11-ux-import-compact-preview-navigatie.md
Claude Agent 283299ff20 feat(ux): import compact + preview format Trimiteri + navigatie + scoatere auto_send (5.11)
8 stories TDD (echipa Sonnet, lead orchestreaza). US-001 scoate hold-ul auto_send din mapare
(has_no_auto_send->False, simbol pastrat; cod rezolvat->queued). US-002 scoate bifa auto_send
din UI. US-003 preview pas 3 in format .tabel-trimiteri (STARI_PREVIEW + nota_umana_preview,
fara repr Python; view-model prez). US-004 filtre layout/stil ca referinta + buton Custom.
US-005 navigatie Trimiteri/Mapari sub contoare pe toate paginile. US-006 import <details> nativ
colapsabil. US-007 post-commit reveal (OOB _coada/_status + HX-Trigger). US-008 auto-refresh
dupa actiuni (nudge eliminat).

VERIFY context curat PASS (8/8). /code-review high: 3 buguri reparate (tab nav la self-refresh,
pill Custom valori stale, nota_umana_preview precedenta needs_mapping). 934 passed, 1 skipped.
Backend trimitere + schema NEATINSE.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 15:16:28 +00:00

41 KiB
Raw Blame History

PRD 5.11 — Import compact + preview in format Trimiteri + navigatie + simplificare auto_send

Stare: inchis (2026-06-26 — verify-pass + code-review; vezi RAPORT VERIFY si RAPORT AUTOPLAN)

Proces complet: docs/ROADMAP.md §5. Contractul RAR (sursa de adevar de contract): docs/api-rar-contract.md. Starea trece: draft → aprobat → in-executie → verify-pass → inchis (actualizata de lead). Acest PRD nu repeta strategia/contractul — le linkeaza.

1. Obiectiv

Reparam un set de bug-uri si frictiuni UX descoperite la dogfooding pe o baza goala (prima utilizare), confirmate in browser (E2E Playwright pe prezentari_test.csv):

  1. Dupa primul import ramai blocat — wizard-ul se reseteaza la pasul 1, mesajul „vezi mai jos in Trimiterile tale" trimite la o sectiune care nu exista in DOM la first-run (trimiteri-section absent), iar lista nu apare fara reload manual.
  2. Navigatie infundata — din ?tab=mapari / ?tab=jurnal (si Cont/Integrare/Nomenclator) nu exista niciun link inapoi la Trimiteri; logo-ul nu e link; meniul hamburger nu are „Trimiteri".
  3. Tabelul de preview (pasul 3) e neingrijit — overflow orizontal taie coloanele Verificat?/Actiuni (butonul Editeaza), formularul de editare inline se taie, coloana „Note" scapa un repr Python brut ([{'cod_op_service': ...}]) iar „Stare" arata coduri brute (needs_mapping/needs_data).
  4. auto_send=0 produce o stare falsa — un rand mapat (ex. OE-2) apare ca needs_mapping cu mesaj tehnic („cod mapat cu auto_send=0…") si fara actiune; bifa „In coada automat" adauga complexitate si confuzie. Decizie utilizator (2026-06-26): scoatem complet conceptul auto_send din UI.
  5. Randul de filtre arata neuniform — pill-urile au stil outline diferit de butonul solid Filtreaza si stau in dreapta lui; la hover deveneau rosu plin si textul devenea ilizibil.
  6. Wizard-ul de import ocupa tot ecranul — stepper + upload sunt doua carduri mari stivuite.

Toate sunt UI/UX + o simplificare de mapare (auto_send). Backendul de trimitere (worker, masina de stari de trimitere, idempotenta, contract RAR) ramane neatins, cu o singura exceptie controlata: logica de mapare nu mai „tine" randuri pe auto_send (US-001).

2. Non-Goals (anti scope-creep)

  • Nu atingem worker-ul, reconcilierea, idempotenta sau contractul RAR.
  • Nu schimbam canalul API (POST /v1/prezentari / /valideaza) — doar UI web + mapping.py. (Campul auto_send din payload-ul API, daca exista, ramane acceptat dar ignorat — vezi US-001.)
  • Nu stergem coloanele DB operations_mapping.auto_send / operation_text_rules.auto_send (migrare distructiva inutila) — le lasam cu default 1 si nu le mai citim pentru a tine randuri.
  • Nu rescriem categoriile de filtrare cu etichetele din referinta (Facturate/Anulate/Diferente etc.) — pastram categoriile reale autopass (Toate / needs_mapping / needs_data / error). Adoptam doar layout-ul si stilul vizual din referinta (image.png).
  • Nu schimbam fluxul de erori pe 3 niveluri (5.4) — doar consumam helperele existente in preview.

3. Stories atomice

Fiecare story: cea mai mica unitate care lasa sistemul functional. Backend + UI pentru acelasi comportament = 2 stories. Fisiere + Depinde de complete (decid paralelizarea).

US-001: Scoate „hold pe auto_send" din logica de mapare (backend)

Ca operator vreau ca o operatie mapata la un cod RAR sa intre direct in coada pentru ca bifa auto_send introducea o stare needs_mapping falsa si confuza pe randuri deja corecte.

  • Depinde de: —
  • Fisiere: app/mapping.py, app/web/routes.py (DOUA puncte: post_mapeaza_inline ~1018-1069 parsare form auto_send + delegare reresolve_account; ramura has_no_auto_send din post_corectie_trimitere ~1166 — referinta „~1160-1185" din draft arata gresit catre mapeaza), app/api/v1/import_router.py (importa has_no_auto_send ~linia 48, il foloseste in _resolve_row_for_preview ~233 — OMIS in draft; vezi AC „nu sterge simbolul"), tests/test_mapping.py, tests/test_web_mapeaza.py, tests/test_t6_auto_send.py + tests/test_text_rule_autosend.py (de sters/rescris — encodeaza invariantul VECHI; vor deveni RED) (~6 fisiere)
  • Test intai (RED): tests/test_mapping.pytest_operatie_mapata_intra_in_queued_indiferent_de_autosend, test_regula_text_rezolvata_nu_mai_tine_randul, test_fara_stare_needs_mapping_pe_auto_send_oprit, test_niciun_rand_existent_nu_se_dezgheata (AC dezghet), test_canal_api_auto_send_ignorat_intra_queued (classify_prezentare, mapping_meta auto_send=0 → queued)
  • Acceptance criteria:
    • resolve_prestatii NU mai marcheaza regula_fara_autosend / nu mai produce ramura AUTO_SEND_OPRIT; o operatie cu cod rezolvat (mapare exacta SAU regula text) → queued.
    • has_no_auto_send NU se sterge — se neutralizeaza (return False) si ramane DEFINIT (importat in routes.py:70 SI import_router.py:48; stergerea simbolului → ImportError la load → app nu porneste). „Eliminat" si „intoarce mereu False" NU sunt echivalente: alege a doua.
    • Toate cele 4 callsite-uri tratate: clasificare (mapping.py ~413), reresolve_account (~664 + cheia stat review_manual), corectie (routes.py ~1166), preview (import_router.py ~233).
    • /trimitere/{id}/mapeaza: dupa mapare, randul cu cod valid trece queued (nu needs_mapping cu mesaj auto_send); raspuns fara cardul „auto-send oprit".
    • needs_mapping ramane DOAR pentru operatii fara cod RAR rezolvat (semantica reala).
    • Coloanele DB raman; save_mapping accepta inca auto_send (default 1) dar valoarea nu mai tine randuri (compat migrare). Niciun rand existent nu se „dezgheata" automat fara actiune.
    • Randuri legacy needs_mapping-din-auto_send (cod deja prezent) raman blocate pe test/prod fara afordanta de mapare (_nemapate_pentru_submission ~881 intoarce []). DECIZIE explicita: requeue one-time la deploy (reresolve_account per cont, acum le trece queued) SAU documentam corectia inline ca singura iesire. (De notat in raportul VERIFY.)
  • Verificare E2E: POST /trimitere/{id}/mapeaza din panoul de detaliu (browser) → rand queued.

US-002: Scoate bifa „In coada automat" din UI (Mapari + preview + detaliu)

Ca operator vreau sa nu mai vad bifa auto_send nicaieri pentru ca nu mai are efect (US-001) si crea confuzie.

  • Depinde de: US-001
  • Fisiere: app/web/templates/_macros.html (macro autosend_toggle), app/web/templates/_mapari.html, app/web/templates/_preview_import.html, app/web/templates/_trimitere_detaliu.html, tests/test_web_mapari.py (~5 fisiere)
  • Test intai (RED): tests/test_web_mapari.pytest_mapari_fara_toggle_autosend, test_preview_panou_mapare_fara_autosend, test_detaliu_mapare_inline_fara_autosend
  • Acceptance criteria:
    • Macro-ul autosend_toggle eliminat (sau golit) si scos din cele 3 sabloane.
    • Panoul „Operatii de mapat la cod RAR" (preview) si tab-ul Mapari salveaza maparea fara nicio referinta la „In coada automat" / „auto_send".
    • Coloana „In coada" din tabelul Mapari operatii salvate + reguli text dispare.
    • Niciun text rezidual „auto_send" / „Tine pentru verificare" in sabloane.
  • Verificare E2E: browser pe /?tab=mapari + panoul de mapare din preview — fara bifa.

US-003: Preview pas 3 — format identic cu tabelul Trimiteri (UI)

Ca operator vreau ca tabelul de preview sa arate exact ca lista Trimiteri pentru ca acum scapa text intern brut, taie coloane si formularul de editare.

  • Depinde de: —
  • Fisiere: app/web/templates/_preview_import.html, app/web/templates/_preview_rand.html, app/web/templates/base.html (refolosire .tabel-trimiteri + latimi col-* pt coloanele extra), app/web/payload_view.py (prezentare_din_payload accepta dict → row.resolved direct; OMIS), stratul de adaptare in builderele de preview (app/web/routes.py _web_compute_preview ~1851 SI app/api/v1/import_router.py _resolve_row_for_preview ~122) — construieste un view-model tip prez + traduce resolved_status→eticheta, OMIS in draft, app/web/labels.py (NU reutilizare directa — vezi AC; necesita un map de stari PREVIEW), tests/test_preview_import.py (~6 fisiere)
  • Test intai (RED): tests/test_preview_import.pytest_preview_nu_contine_repr_python (fixture cu rand needs_mapping/unmapped REAL — altfel trece in gol), test_preview_stare_eticheta_umana (acopera ok/needs_review/already_sent/duplicate_in_file), test_preview_foloseste_clasa_tabel_trimiteri
  • Acceptance criteria:
    • NU reutiliza eticheta_stare/eticheta_scurta direct: ridica KeyError pe starile de preview (ok/needs_review/already_sent/duplicate_in_file — absente in STARI_SUBMISSION). Adauga un map de stari preview→eticheta umana (extinde labels.py sau map nou), inclusiv text pentru already_sent/duplicate_in_file.
    • NU pasa row.errors (lista Python) in motiv_uman/parse_erori (asteapta string JSON → str() + json.loads esueaza → fallback raw[:160] = ACELASI repr pe care US-003 il repara). Stratul de adaptare serializeaza erorile (json.dumps) sau formateaza uman inainte de render.
    • Tabelul de preview foloseste .tabel-trimiteri, fara overflow la 1280px (scrollWidth <= clientWidth). Necesita: data-eticheta pe TOATE celulele (carduri <768px le citesc via td::before) + latimi col-* pt cele 4 coloane extra (Verificat?/Actiuni/Note/etc.) sub table-layout:fixed.
    • Coloana „Note" → mesaj uman, niciodata repr Python ([{'cod_op_service': ...}]).
    • „Stare" → pill uman (ca la Trimiteri), nu cod brut needs_mapping/needs_data.
    • Vehicul (nr + VIN sub), operatie (+ cod RAR sub) randate via view-model prez (din payload_view).
    • Formularul inline colspan e full-width sub rand dar IESE din grila table-layout:fixed (rand display:block sau editor in afara tabelului fix), cu Salveaza/Anuleaza mereu vizibile.
    • Stare „filtrat la zero" (filter JS din _preview_import.html ascunde toate randurile) afiseaza un mesaj, nu tabel gol mut; filtrul coexista cu cardurile td{display:block}.
  • Verificare E2E: browser pasul 3 — coloane intregi, fara repr brut, editare necliata, mobil + desktop.

US-004: Randul de filtre Trimiteri — layout + stil ca referinta (UI)

Ca operator vreau un rand de filtre uniform si lizibil pentru ca pill-urile aveau alt stil decat butonul Filtreaza, stateau in dreapta si la hover deveneau rosu ilizibil.

  • Depinde de: —
  • Fisiere: app/web/templates/_coada.html, app/web/templates/_pills.html, app/web/templates/base.html (CSS .pill-cat + hover + layout), tests/test_web_filtre.py (~4 fisiere)
  • Test intai (RED): tests/test_web_filtre.pytest_pill_uri_in_stanga_controalelor, test_pill_categorie_stil_uniform, test_quick_pills_data_seteaza_interval
  • Acceptance criteria:
    • Layout ca image.png: pill-uri rapide de data (Azi / 7 zile / 30 zile / Custom) in STANGA, camp de cautare la mijloc, pill-uri de stare cu contoare la dreapta — un singur stil de pill.
    • Pill-urile NU mai stau margin-left:auto izolate la dreapta butonului.
    • Stare activa, dezambiguizata: pill-ul „Toate" (reset) = --accent plin; pill-urile de CATEGORIE = culoarea lor de categorie cand sunt active (NU toate accent — „accent plin" din draft contrazice schema per-categorie din _pills.html). Enumera token-ul de prim-plan per categorie ca sa garantezi AA, SAU foloseste o pereche fixa (alb pe saturat) cu valori verificate.
    • Hover lizibil, regula explicita: hover = background:color-mix(in srgb, currentColor 12%, transparent) (nu filter:brightness actual, nu rosu plin); pill-ul ACTIV suprima hover-ul. Acelasi mecanism pe reset si pe categorie.
    • Focus pastrat: inelul :focus-visible (outline accent) ramane pe toate cele 3 variante de pill dupa rescrierea CSS (US-004 atinge exact acest bloc — usor de pierdut).
    • Quick-pills de data seteaza data_de/data_pana (preset) si reincarca lista (HTMX), pastrand pill-ul de stare activ.
    • Functioneaza in Light/Dark/Petrol cu token-uri concrete enumerate (nu „verifica AA" abstract).
  • Verificare E2E: browser — comutare quick-pill data + stare, hover citibil pe toate temele.

Ca operator vreau sa ajung oricand inapoi la Trimiteri / Mapari pentru ca din Mapari/Jurnal nu mai aveam cale de intoarcere.

  • Depinde de: —
  • Fisiere: app/web/templates/base.html (header + #cont-menu), AMBELE dashboard.html SI _status.html (ambele randeaza <div id="status-bar"> — pe cai diferite: full-page vs OOB/partial; „sau" din draft risca nav prezenta la load dar pierduta la refresh + duplicat de id), tests/test_web_nav.py (~3 fisiere)
  • Test intai (RED): tests/test_web_nav.pytest_nav_trimiteri_mapari_pe_mapari, test_nav_trimiteri_pe_jurnal, test_logo_linkeaza_acasa
  • Acceptance criteria:
    • Sub contoarele din #status-bar, pe FIECARE pagina (acasa/mapari/jurnal/cont/integrare/ nomenclator): rand de link-uri Trimiteri + Mapari (cu badge needs_mapping daca exista), cu marcaj activ pe pagina curenta. Sursa marcajului activ = o variabila de context numita explicit (ex. tab_activ, comparata cu ?tab=), nu ghicita de implementator.
    • Badge-ul needs_mapping reutilizeaza O SINGURA sursa (acelasi camp ca _mapari_badge din hamburger / blocate_total), nu un al doilea contor calculat diferit.
    • Logo-ul ROMFAST + titlul linkeaza la / (Trimiteri).
    • Meniul hamburger capata si „Trimiteri" (Acasa) ca prima intrare.
    • Niciun deadlock: din orice tab se ajunge la Trimiteri intr-un click.
  • Verificare E2E: browser — din Mapari si Jurnal, un click → Trimiteri.

US-006: Import = container compact colapsabil (UI)

Ca operator vreau ca importul sa nu ocupe tot ecranul pentru ca stepper-ul + upload-ul mare stau in cale dupa ce am deja trimiteri.

  • Depinde de: —
  • Fisiere: app/web/templates/_acasa.html, app/web/templates/_upload.html, app/web/templates/_stepper.html, app/web/templates/base.html (CSS/JS accordion), tests/test_web_acasa.py (~4 fisiere)
  • Test intai (RED): tests/test_web_acasa.pytest_import_colapsat_cand_are_trimiteri, test_import_deschis_la_first_run
  • Acceptance criteria:
    • Stepper + upload intr-UN singur container („Importa un fisier"), nu doua carduri.
    • Colapsat implicit cand contul are deja trimiteri (are_trimiteri=True); auto-deschis la first-run (are_trimiteri=False).
    • In timpul fluxului (mapcoloane/preview) containerul ramane deschis (nu se inchide intre pasi).
    • Implementare cu <details> nativ (disclosure CSS-only): serverul seteaza atributul open din are_trimiteri, deci „fara JS → degradare la deschis" si „colapsat la returning" sunt ambele corecte fara toggle JS (un toggle JS pur ar lasa returning-user-ul fara-JS cu ecranul permanent deschis = exact bug-ul reparat). aria-expanded/focus pastrate.
    • Ordinea de stivuire definita pe cele 4 combinatii (are_creds × are_trimiteri) — accordion, „Primii pasi", trimiteri-section nu se suprapun la first-run-cu-creds.
  • Verificare E2E: browser — first-run deschis; dupa ce exista trimiteri, colapsat; click → extins.

US-007: Dupa commit, lista Trimiteri apare + se reimprospateaza automat (UI + glue)

Ca operator vreau sa-mi vad trimiterile imediat dupa import pentru ca acum mesajul trimite la o sectiune inexistenta si nimic nu se actualizeaza fara reload.

  • Depinde de: US-006
  • Fisiere: app/web/routes.py (web_confirma_import ~2757 intoarce AZI doar _upload.html via hx-target=#import-section, outerHTML — un swap outerHTML pe #import-section NU poate materializa un frate #trimiteri-section; alege mecanismul de dezvaluire — vezi AC), app/web/templates/_upload.html, app/web/templates/_acasa.html, app/web/templates/_coada.html, app/web/templates/_status.html + dashboard.html (OOB pe #status-bar — e in afara lui acasa-section, nu se actualizeaza la re-randarea _acasa/_upload), tests/test_import_commit.py (~6 fisiere)
  • Test intai (RED): tests/test_import_commit.pytest_commit_raspuns_contine_trimiteri_section, test_commit_raspuns_seteaza_hx_trigger_trimiteriChanged (asertie pe header literal), test_first_run_dupa_commit_arata_lista, test_commit_actualizeaza_status_bar (OOB contoare)
  • Acceptance criteria:
    • Mecanism de dezvaluire ales explicit: fie (a) re-randam _acasa.html complet si retargetam pe #acasa-section, fie (b) emitem un OOB swap care injecteaza _coada.html. Minimal fata de codul actual (return _upload.html-only) = (b). La first-run #submissions-wrap proaspat injectat isi declanseaza singur hx-trigger="load".
    • Raspunsul seteaza HX-Trigger: trimiteriChanged (lipseste azi pe confirma; cf. post_mapeaza_inline:1066) — altfel la returning-user (sectiune deja in DOM) randurile noi queued nu apar. Atentie la dublu-load daca re-randam si _acasa (inofensiv, de notat).
    • Containerul de import se colapseaza, iar lista Trimiteri se reincarca automat si arata randurile.
    • Contoarele #status-bar se actualizeaza via OOB swap (sunt in _status.html/dashboard.html, in afara acasa-section — re-randarea _acasa nu le atinge), imediat, nu la poll-ul de 15s.
    • Mesajul de succes ramane onest („S-au pus in coada N prezentari") si pointeaza la o sectiune care chiar exista.
  • Verificare E2E: browser, baza goala — import → commit → lista apare + contoare actualizate, fara reload.

US-008: Auto-refresh dupa actiuni, fara „Reincarca" manual (UI)

Ca operator vreau ca lista sa se actualizeze singura dupa ce actionez pentru ca butonul manual „Reincarca" (nudge „Date noi") trecea neobservat (ex. dupa ce am mapat un cod si s-a trimis la RAR).

  • Depinde de: US-007
  • Fisiere: app/web/templates/base.html (JS poller/nudge), app/web/templates/_coada.html, app/web/templates/_submissions.html, tests/test_web_refresh.py (~3 fisiere)
  • Test intai (RED): tests/test_web_refresh.pytest_actiune_proprie_reincarca_automat, test_nudge_nu_mai_blocheaza_actualizarea
  • Acceptance criteria:
    • Dupa o actiune proprie (mapare inline, corectie, repune, commit import) lista se reincarca automat (fara click pe „Reincarca").
    • Poll-ul de fundal: cand detecteaza date noi declansate de actiuni proprii, aplica refresh automat; nudge-ul manual ramane doar pentru schimbari externe (alt proces/worker) — sau se elimina daca devine redundant. (Decizie de implementare documentata in raport.)
    • Nu se reseteaza filtrul/pagina curenta la auto-refresh (pastreaza #filtre-trimiteri).
  • Verificare E2E: browser — mapare inline a unui cod → randul devine queued/sent fara click manual.

4. Riscuri

  • R1 — Scoaterea auto_send rastoarna „default-ul de siguranta CEO" (reguli text / mapari tineau randul pentru verificare). Acceptat constient de utilizator (2026-06-26): mapped → queued direct. Mitigare: randurile genuin nemapate raman needs_mapping (nu pleaca), iar preview-ul are gate per-rand („Verificat?") inainte de commit. Documentam in CLAUDE.md (invariantul auto_send) ca a fost retras.
  • R2 — Preview in format Trimiteri: tabelul Trimiteri presupune un view-model (vehicul/op/cod RAR); randurile de preview vin din alt drum (_resolve_row_for_preview). Risc de divergenta de campuri. Mitigare: refolosim payload_view / labels ca pe canalul Trimiteri; test anti-repr.
  • R3 — Accordion + HTMX: colapsarea nu trebuie sa ascunda pasii in timpul fluxului mapcoloane/preview. Mitigare: container deschis cat timp import-section randeaza un pas != upload slim; test dedicat.
  • R4 — Regresie tabel: .tabel-trimiteri are reguli responsive (carduri <768px) — preview-ul are coloane diferite (Verificat?/Actiuni). Mitigare: verificare E2E mobil + desktop.

5. Intrebari deschise

Rezolvate cu utilizatorul la planificare (2026-06-26) — vezi raspunsurile incorporate mai sus: Q1 filtre = layout complet ca referinta + fix hover lizibil; Q2 preview = format ca Trimiteri; Q3 = scoatem complet bifa auto_send (Mapari + Trimiteri); Q4 = acordeon compact + lista apare/ refresh automat dupa commit + link-uri Trimiteri/Mapari sub contoare.

  • (rezolvat) Pastram coloanele DB auto_send? → DA, default 1, ne-citite pentru hold (non-distructiv).
  • (deschis, minor) Nudge-ul „Date noi" pentru schimbari externe: il pastram redus sau il eliminam? → decizie la implementare (US-008), documentata in raport.

6. Valuri de executie (graful de dependente)

Val 1 (paralel, fisiere disjuncte):
  [US-001]  mapping.py + routes mapeaza            (backend)
  [US-003]  preview format Trimiteri               (_preview_*.html, base.css)
  [US-004]  filtre layout+stil+hover               (_coada/_pills/base.css)
  [US-005]  navigatie sub contoare                 (base.html/_status/dashboard)
  [US-006]  import accordion compact               (_acasa/_upload/_stepper)

Val 2 (deblocate de Val 1):
  [US-002]  scoate toggle auto_send din UI         (dep US-001; _macros/_mapari/_preview/_detaliu)
  [US-007]  post-commit reveal+refresh             (dep US-006; routes/_acasa/_upload/_coada)

Val 3:
  [US-008]  auto-refresh dupa actiuni              (dep US-007; base.js/_coada/_submissions)

Atentie la fisiere fierbinti partajate intre stories (serializare de catre lead): base.html (US-004 CSS, US-005 header/menu, US-006 accordion JS) si _coada.html / _preview_import.html apar in mai multe stories — NU paralel pe acelasi fisier (vezi ROADMAP §5.5).


Raport VERIFY

Completat de subagentul verificator (context curat, 2026-06-26) in faza VERIFY — ROADMAP §5.6. Executie: echipa de teammates Sonnet (lead orchestreaza, NU scrie cod), 6 runde TDD pe valuri cu fisiere disjuncte; base.html/routes.py/_coada.html/_status.html serializate ca fisiere fierbinti.

VERDICT GLOBAL: PASS → verify-pass / CLOSE. 8/8 stories trec criteriile de acceptare, cu dovezi cod + teste + randare runtime (verificatorul a pornit aplicatia reala si a inspectat HTML-ul randat).

  • Suita: python3 -m pytest -q929 passed, 1 skipped (skip = test_live_rar, gated corect pe marker live + AUTOPASS_LIVE_RAR). Smoke boot python3 -c "import app.main" → OK (critic US-001: has_no_auto_send pastrat → fara ImportError). (Dupa adaugarea testelor cu nomenclatura PRD pe US-008: 931 passed.)
  • US-001 PASS — has_no_auto_sendreturn False (definit + importat in routes.py:72 si import_router.py:48); resolve_prestatii nu mai marcheaza regula_fara_autosend; ramura AUTO_SEND_OPRIT scoasa din classify; cele 4 callsite tratate; canal API auto_send=0 → queued; needs_mapping doar pt unmapped real; coloane DB raman; teste vechi rescrise (nu sterse). Decizie randuri legacy: reresolve_account le re-trece queued la deploy (documentat).
  • US-002 PASS — macro autosend_toggle golit, simbol pastrat; 0 reziduuri auto_send / „In coada automat" in template-uri (grep) + 0 in dashboard-ul randat.
  • US-003 PASS — STARI_PREVIEW map nou in labels.py (fara KeyError pe stari preview); nota_umana_preview (errors ca lista → fara repr brut); view-model prez din payload_view (accepta dict); .tabel-trimiteri + col-* + data-eticheta pe toate celulele + editor tr.preview-edit (scapa grila fixa) + mesaj „filtrat la zero".
  • US-004 PASS — quick-pills data STANGA / cautare MIJLOC / pills stare DREAPTA; hover color-mix(currentColor 12%), :focus-visible accent, categorie activa=currentColor, reset=--accent, activ suprima hover. (Nota minora: butonul „Custom" — vezi mai jos.)
  • US-005 PASS — nav Trimiteri+Mapari in _status.html randat pe fiecare pagina (dashboard.html incarca fragmentul, fara duplicat de id), activ din tab_activ, badge din sursa unica counts.needs_mapping; logo+titlu link /; hamburger „Trimiteri" prima. Confirmat runtime (aria-current="page" pe Mapari la ?tab=mapari).
  • US-006 PASS — <details id="import-details" {open if not are_trimiteri}> nativ (fara toggle JS); runtime: first-run open + placeholder #trimiteri-section; returning colapsat + lista plina.
  • US-007 PASS — web_confirma_import_upload slim + OOB _coada (#trimiteri-section) + OOB _status (#status-bar) + header HX-Trigger: trimiteriChanged; #submissions-wrap se auto-incarca; mesaj de succes onest catre o sectiune care chiar exista.
  • US-008 PASS — actiuni proprii emit trimiteriChanged → reincarcare; poller compara data-v si cheama reincarcaTrimiteri() cu hx-include="#filtre-trimiteri" (pastreaza filtru+pagina); nudge „Date noi" ELIMINAT (decizie documentata: distinctia propriu-vs-extern nu e posibila pe client).
  • E2E: PROBAT la nivel de aplicatie reala (uvicorn :8011, login sesiune, HTML randat real pentru accordion/nav/logo/filtre/zero-reziduu auto_send). NEPROBAT: click-through Playwright complet pe upload→preview→commit si testul live RAR FINALIZATA (gated, fara creds web in mediu) — acelasi status ca livrabilele anterioare; backend trimitere neatins, risc minim.
  • Regresia de aur: PASS la nivel de teste — test_api (POST /v1/prezentari) + test_import_e2e (import→commit→queued) + worker reconcile/rar_errors verzi; worker/idempotenta/build_key/contract RAR NEATINSE (non-goals respectate).

Note minore (non-blocante, follow-up):

  1. US-004 „Custom": AC enumera 4 quick-pills (Azi/7zile/30zile/Custom); doar 3 randate ca butoane (JS-ul suporta ramura 'custom', dar fara buton). De adaugat butonul SAU scos „Custom" din AC.
  2. Cod/comentarii vestigiale in import_router.py (_motiv_clasificare ramura needs_mapping/auto_send acum inaccesibila; comentarii care inca spun „auto_send gate"). Pur cosmetic.

RAPORT AUTOPLAN

Faza 1 — CEO (strategie & scope)

0A. Provocarea premiselor

  • Premisa centrala (US-001): "auto_send hold = stare falsa". Citind mapping.py:252-254 si 434-447, hold-ul era un gate de siguranta intentionat, nu un bug. Reformulare onesta: scoatem un gate de siguranta pentru ca frictiunea > riscul de ireversibilitate perceput. GATE PREMISA: utilizatorul a confirmat (2026-06-26) scoaterea completa — premisa acceptata constient, documentata in R1.
  • Premisa "preview-ul are gate Verificat? care compenseaza" e PARTIALA: gate-ul exista doar pe calea import web; canalul API + remaparea inline (routes.py:1166) trec direct in queued. Acceptat de utilizator la gate.
  • Restul premiselor (overflow tabel, repr Python in Note, hover rosu ilizibil, nav infundata, wizard mare, reveal post-commit rupt) = confirmate in cod (vezi Faza 3).

0B. Ce exista deja (mapare sub-probleme -> cod)

Sub-problema Cod existent de refolosit
Etichete umane stare/motiv labels.py: eticheta_stare, motiv_uman, parse_erori
Viewmodel rand trimitere payload_view.py + r.prez.* in _submissions.html
Tabel responsive .tabel-trimiteri + carduri <768px in base.html
Pills stare + contoare _pills.html + filtreazaStare() in base.html
Refresh lista HTMX trimiteriChanged from:body (deja cablat in _coada.html)
Sectiune trimiteri #trimiteri-section exista in _coada.html (doar conditionat de are_trimiteri)

0C. Dream-state delta

  • ACUM: 8 frictiuni de first-run, una mascand o decizie de siguranta ireversibila.
  • ACEST PLAN: first-run curat (import -> preview ingrijit -> commit -> lista apare/refresh), nav fara fundaturi, mapare fara concept auto_send.
  • IDEAL 12 luni: un E2E smoke de first-run ca poarta de release (codifica scriptul de dogfooding) ca aceste 8 simptome sa nu reapara. Recomandare deferata (vezi TODOS).

0C-bis. Alternative (US-001)

Abordare Efort Risc Verdict
Scoatere completa (ales) mic gate pierdut pe API/inline ALES de utilizator
Hold doar pe text-rules unattended mic minim (pastreaza net unde conteaza) respins de utilizator la gate
Default per-cont (ca on_unmapped_error_default) mediu reversibil, dar pastreaza complexitate respins de utilizator

0D-0F. Mod = SELECTIVE EXPANSION. Premisa confirmata la gate. Procedam.

Voci duale CEO (subagent-only; Codex indisponibil)

CLAUDE SUBAGENT (CEO): 11 constatari. Critice: (F1) US-001 e o decizie clasa-siguranta impachetata cu UX cosmetic — risc de aprobare-prin-asociere; (F6) regret 6 luni = o regula text gresita auto-trimite FINALIZATA terminal nerecuperabil. Hi: F3 (premisa laundering), F4 (mitigare R1 supraevaluata — nu acopera canalul API), F5 (cazul periculos real = text-rules unattended), F8 (alternativa default-per-cont neanalizata), F10 (over-bundling). Recomandare subagent: split US-001/002 din restul. Utilizatorul a ales full removal la gate — F4/F5/F6 raman ca follow-up optional, nu blocant.

CEO DUAL VOICES — CONSENSUS:
  Dimensiune                          Claude  Codex  Consensus
  1. Premise valide?                  Partial  N/A   flag (gate trecut de user)
  2. Problema corecta?                Da       N/A   confirmat de 1 voce
  3. Scope calibrat?                  Nu(F10)  N/A   flag (over-bundle, dar waves ok)
  4. Alternative explorate?           Nu(F8)   N/A   flag (rezolvat la gate)
  5. Riscuri piata/legal acoperite?   Partial  N/A   flag (R1 acceptat)
  6. Traiectorie 6 luni sanatoasa?    Partial  N/A   flag (F6 -> TODOS)
Codex = N/A (usage limit). Single-critical din 1 voce = flagat oricum.

NU in scope (confirmat)

Worker / reconciliere / idempotenta / contract RAR / canal API (payload) / coloane DB auto_send (raman, default 1) / categorii filtrare (raman cele reale autopass) / fluxul de erori 3-niveluri.

Registru Erori & Salvare (relevant acestui plan)

Suprafata Esec Salvare existenta
Import upload fisier invalid / multi-foaie eroare_upload / select foaie (_upload.html)
Preview rand cod necunoscut nomenclator promovat la cod_op_service -> needs_mapping (nu se trimite raw)
Commit rand needs_mapping exclus din commit (ramane in lista)

Sumar CEO

Plan sanatos ca directie. Singurul flag strategic (US-001 fara control compensator pe calea unattended) acceptat constient la gate. US-003-008 = castiguri de first-run cu risc redus; US-007/008 cele mai sigure. Recomandare: pastram PRD-ul unit (waves deja serializeaza fisierele fierbinti), adaugam 1 item TODOS (E2E first-run + control optional text-rule).

Faza 2 — Design (UI scope: DA)

Voci duale Design (subagent-only; Codex indisponibil)

CLAUDE SUBAGENT (design): constatari grounded in template-uri reale.

  • F2.4 (CRITIC): eticheta_stare/eticheta_scurta ridica KeyError pe starile de preview (ok/needs_review/already_sent/duplicate_in_file) — reutilizarea „ca la Trimiteri" crapa preview-ul. → US-003 AC.
  • F3.1 (CRITIC): „activa = accent plin" contrazice pill-urile colorate per-categorie (_pills.html:10). Reset = accent; categorie = culoarea ei. → US-004 AC.
  • F2.1/F2.2/F2.3 (high): celulele de preview n-au data-eticheta (carduri <768px ilizibile); coloanele extra n-au latimi col-* sub table-layout:fixed; editorul colspan mosteneste latimea care depaseste. → US-003 AC.
  • F3.2/F3.3 (high): token-uri de contrast/hover neenumerate per tema/categorie — cel mai mare risc de „haunt". → US-004 AC.
  • F2.6 (high): preview n-are view-model prez; adaptorul lipseste din Fisiere. → US-003 Fisiere.
  • F4.1/F4.2 (high): #status-bar definit in DOUA locuri; variabila de tab activ nenumita. → US-005 Fisiere+AC.
  • F1.3 (medium): degradarea fara-JS contrazice „colapsat la returning" — necesita <details> nativ. → US-006 AC.
DESIGN LITMUS — CONSENSUS:
  Dimensiune                          Claude  Codex  Consensus
  1. Ierarhie info (accordion)        ok*     N/A    confirmat (1 voce) *cu state-table
  2. Stari lipsa (preview)            NU      N/A    flag CRITIC (F2.4) -> US-003
  3. Matrice pill hover/active/focus  NU      N/A    flag CRITIC (F3.1) -> US-004
  4. Nav activ + badge                Partial N/A    flag (F4) -> US-005
  5. Specificitate AC                 Partial N/A    flag (token-uri, view-model)
Codex = N/A (usage limit).

Faza 3 — Eng (arhitectura, teste, risc)

Diagrama de dependente (componente noi vs existente)

[import upload] -> _upload.html (#import-section, outerHTML swap)
                      |  US-006: invelit in <details> (open=are_trimiteri)
                      v
[web_confirma_import ~2757] --returneaza--> _upload.html  (AZI: doar atat -> bug US-007)
   US-007 fix: + OOB inject _coada.html (#trimiteri-section) + HX-Trigger trimiteriChanged
               + OOB #status-bar (_status.html / dashboard.html)
                      |
                      v
[#submissions-wrap] --hx-trigger: load, trimiteriChanged from:body--> /_fragments/submissions
                      |                                                     |
                      v                                                     v
                _submissions.html (r.prez view-model)              _pills.html (OOB)  <- US-004 CSS

[mapping.py resolve_prestatii] --auto_send hold SCOS (US-001)--> status: queued | needs_mapping(real)
   has_no_auto_send: NEUTRALIZAT (return False), simbol PASTRAT (importat in routes.py + import_router.py)
   callsite-uri: clasificare ~413 | reresolve ~664 | corectie routes ~1166 | preview import_router ~233

[preview builders] _web_compute_preview ~1851 / _resolve_row_for_preview ~122
   US-003: + adaptor resolved_status -> eticheta umana + view-model prez (payload_view) + json.dumps(errors)

Voci duale Eng (subagent-only; Codex indisponibil)

CLAUDE SUBAGENT (eng): 13 constatari verificate in cod.

  • F1 (HIGH/boot-crash): import_router.py:48 importa has_no_auto_send, :233 il foloseste — al 4-lea callsite, OMIS din US-001 Fisiere. Stergerea simbolului → ImportError → app nu porneste. „Eliminat" ≠ „return False". → US-001.
  • F4 (HIGH): test_t6_auto_send.py + test_text_rule_autosend.py encodeaza holdul vechi → devin RED, neprogramate. → US-001.
  • F5/F6 (HIGH): motiv_uman/parse_erori asteapta string JSON; row.errors (lista) → fallback raw[:160] = ACELASI repr. Necesita strat de adaptare in buildere. → US-003.
  • F2 (medium): referinta de linie „~1160-1185" arata gresit; sunt 2 puncte (mapeaza ~1032 form, corectie ~1166). → US-001.
  • F3 (medium): randuri legacy needs_mapping-din-auto_send raman fara afordanta (_nemapate_pentru_submission ~881 → []). → US-001 AC dezghet.
  • F7 (medium): payload_view.py necesar dar omis din US-003 Fisiere. → US-003.
  • F8/F9/F10 (HIGH): US-007 — outerHTML pe #import-section nu materializeaza frate #trimiteri-section; lipseste HX-Trigger; #status-bar (alt fisier) nu se actualizeaza. → US-007.
  • F11/F13 (low): waves §6 supravand paralelismul pe base.html (3 stories, regiuni disjuncte → serializate de lead); save_mapping scrie auto_send=0 dupa US-002 (inofensiv cat e ignorat).
ENG DUAL VOICES — CONSENSUS:
  Dimensiune                          Claude  Codex  Consensus
  1. Arhitectura sanatoasa?           Da      N/A    confirmat (1 voce)
  2. Acoperire teste suficienta?      NU      N/A    flag (F4 + gap-uri) -> test plan
  3. Riscuri performanta?             ok      N/A    nimic flagat (batch lookup already_sent fara N+1)
  4. Securitate?                      ok      N/A    nimic nou (CSRF/auth neatinse de UI)
  5. Cai de eroare tratate?           Partial N/A    flag (boot-crash F1, KeyError F5/F6)
  6. Risc de deploy gestionabil?      Partial N/A    flag (randuri legacy F3)
Codex = N/A (usage limit).

Test plan (artefact pe disc)

~/.gstack/projects/romfast-rar-autopass/main-5.11-test-plan-20260626.md — 18 codepath-uri mapate la acoperire, suite de rulat (inclusiv smoke de boot import app.main dupa US-001), 3 gap-uri critice.

Registru moduri de esec (cu flag-uri critice)

Mod de esec Trigger Gravitate Mitigare in plan
App nu porneste stergerea has_no_auto_send CRITIC US-001 AC: neutralizare, nu stergere + smoke boot
Preview crapa la render reutilizare eticheta_stare pe stari preview CRITIC US-003 AC: map de stari preview
Repr Python reapare in Note row.errors in motiv_uman HIGH US-003 AC: adaptor json.dumps
Returning-user nu vede randuri noi lipsa HX-Trigger pe confirma HIGH US-007 AC: header trimiteriChanged
Randuri legacy blocate fara iesire needs_mapping-din-auto_send pe prod MEDIUM US-001 AC: requeue one-time SAU doc corectie

Cross-phase themes

  • Theme: vocabularul de stari preview ≠ submission — flagat INDEPENDENT in Faza 2 (Design F2.4) si Faza 3 (Eng F5/F6). Semnal de incredere mare: US-003 nu poate reutiliza direct labels.py; necesita un strat de traducere + view-model. Cea mai importanta corectie a planului.
  • Theme: Fisiere sub-dimensionate fata de AC — US-001 (import_router), US-003 (payload_view + buildere), US-007 (_status.html) — toate omiteau fisiere pe care propriile AC le cer. Corectat in stories.

Corectie graf de executie (§6)

Wave 1 NU e complet paralel: base.html e atins de US-004 (CSS pill), US-005 (header/nav), US-006 (<details>) — regiuni disjuncte, dar lead-ul le SERIALIZEAZA (3 edituri pe acelasi fisier). Paralelismul real al Wave 1 e mai mic decat anunta graful. _coada.html (US-004→007→008) e serializat oricum de dependente.

Deferate la TODOS.md

  • E2E smoke de first-run ca poarta de release (CEO F2).
  • Control compensator optional pe auto-trimitere unattended (CEO F5/F6) — risc rezidual acceptat de user.

Decision Audit Trail

# Faza Decizie Clasificare Principiu Rationament Respins
1 CEO Premisa auto_send: full removal GATE (user) Utilizatorul a confirmat la gate hold text-rule-only; default per-cont
2 CEO Pastram PRD unit (nu split US-001/002) Taste P3/P6 Waves serializeaza deja; pre-launch, risc real ~0 split in 2 PRD-uri (subagent F1/F10)
3 CEO E2E first-run -> TODOS, nu in scope acum Mechanical P3 Boil-lake separat, nu blocheaza 5.11 inclus in 5.11
4 Eng US-001: neutralizare has_no_auto_send, NU stergere Mechanical P5 Stergerea = ImportError (import_router) = boot crash stergere simbol
5 Eng US-001 Fisiere += import_router.py + teste vechi Mechanical P1/P2 Callsite real + teste care devin RED lasa Fisiere ca-n draft
6 Eng US-001: randuri legacy -> decizie requeue/doc Taste P1 In blast radius; impact pe prod DB ignora (lasa blocate tacit)
7 Design+Eng US-003: strat adaptare + map stari preview Mechanical P1 Reutilizare directa crapa/repr — cross-phase theme reutilizare directa labels
8 Design+Eng US-003 Fisiere += payload_view + buildere Mechanical P1/P2 AC cere view-model prez inexistent pe calea preview doar template+labels
9 Design US-003: data-eticheta + col-* + colspan escape Mechanical P1 Altfel overflow/mobil rup (AC propriu) doar clasa .tabel-trimiteri
10 Design US-004: reset=accent, categorie=culoare proprie Mechanical P5 „accent plin" contrazice schema per-categorie toate accent
11 Design US-004: token-uri hover/active/focus enumerate Mechanical P1/P5 „verifica AA" abstract = haunt lasa la implementator
12 Design US-005: AMBELE status-bar + var tab_activ Mechanical P5 „sau" risca nav pierduta la refresh + dup id un singur fisier
13 Design US-006: <details> nativ Mechanical P5 Toggle JS pur rupe degradarea fara-JS toggle JS
14 Eng US-007: OOB inject _coada + HX-Trigger + OOB status-bar Mechanical P1/P5 outerHTML nu materializeaza frate; lipsa trigger „include/dezvaluie" vag

Stare review

  • Faza 1 CEO: rulat (subagent-only). Premisa confirmata la gate.
  • Faza 2 Design: rulat (subagent-only). 2 critice -> AC corectate.
  • Faza 3 Eng: rulat (subagent-only). 1 boot-crash + cross-phase theme -> stories corectate.
  • Faza 3.5 DX: SARIT — fara suprafata developer-facing (planul exclude canalul API; UI = operator).
  • Codex: indisponibil toata sesiunea (usage limit pana Jul 18) -> toate vocile = subagent-only.