<!-- /autoplan restore point: /home/claude/.gstack/projects/romfast-rar-autopass/main-autoplan-restore-20260626-095534.md -->
# 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.py` —
  `test_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.py` —
  `test_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.py` —
  `test_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.py` —
  `test_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.

### US-005: Link-uri de navigatie sub contoare pe toate paginile (UI)
**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.py` —
  `test_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.py` —
  `test_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.py` —
  `test_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.py` —
  `test_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 -q` → **929 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_send`→`return 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.

---

<!-- ============================================================= -->
<!-- /autoplan REVIEW REPORT — generat 2026-06-26, commit 412102b   -->
<!-- Codex indisponibil (usage limit) -> dual voices = subagent-only -->
<!-- ============================================================= -->

# 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.

<!-- AUTONOMOUS DECISION LOG -->
## 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.
