<!-- /autoplan restore point: /home/claude/.gstack/projects/romfast-rar-autopass/main-autoplan-restore-20260626-201417.md -->
# PRD 5.12 — Editare unificata in modal + cont cu companie/email/CUI obligatorii + rafinari import (calendar data, mapare cu antet+prima inregistrare, un singur Salveaza, preview compact) + responsive tableta/mobil

**Stare**: inchis (verify-pass 2026-06-26; 8 stories TDD prin agent team, VERIFY context curat PASS + 1 FAIL remediat, /code-review high 3 buguri reparate; regresie 987 passed/1 skipped/0 failed; asteapta confirmare commit — poarta umana)

> 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.
>
> Continua 5.11 ([prd-5.11](prd-5.11-ux-import-compact-preview-navigatie.md)). **Backendul de
> trimitere (worker, masina de stari de trimitere, idempotenta, contract RAR) ramane NEATINS.**
> Atingeri de schema permise (ambele coloane noi, migrare defensiva `_migrate`, ca la 3.3b/3.5/3.6):
> `accounts.email` (US-001) si `import_rows.reviewed` (US-007, marcaj „verificat" per rand de preview).
> Vezi Non-Goals.

## 1. Obiectiv

Continuam dogfooding-ul de first-run inceput in 5.11. Sase frictiuni confirmate E2E in browser
(Playwright pe `exemple/prezentari_test.csv`, 2026-06-26) — toate UI/UX, plus o regula de date pe
conturi:

1. **Editarea unui rand din preview e rupta vizual si arunca o eroare JS.** Modul de editare inline
   (`tr.preview-edit` cu `display:block` intr-un tabel `table-layout:fixed`) colapseaza coloanele —
   antetul si formularul se randeaza pe verticala, caracter cu caracter (reprodus identic cu
   `image copy.png`). La click pe **Anuleaza** se arunca in consola
   `TypeError: Cannot read properties of null (reading 'htmx-internal-data')` (reprodus live).
   Decizie utilizator: **editarea trebuie sa fie un MODAL, ca la Trimiteri, refolosind ACELASI
   formular** (fara cod duplicat).
2. **Data prestatiei se scrie doar manual** (input text cu hint `YYYY-MM-DD`). Trebuie sa se poata
   alege si din **calendar** (`<input type="date">` nativ, decizie utilizator — zero dependinte JS).
3. **Conturile nu au reguli minime de identitate.** Confirmat in baza: toate conturile au `cui=NULL`,
   iar conturile create din CLI/teste nu au niciun utilizator → fara email. Decizie utilizator:
   un cont inregistrat trebuie sa aiba **obligatoriu companie, email si CUI**.
4. **Maparea coloanelor nu arata datele.** Pasul 2 listeaza nume de coloana + 2 exemple stivuite, dar
   nu se vede clar **capul de tabel (numele coloanelor) + valorile primei inregistrari**, ca operatorul
   sa stie ce mapeaza.
5. **Panoul „Operatii de mapat la cod RAR" cere un Salveaza per rand.** La un fisier cu N operatii
   nemapate sunt N butoane „Salveaza" si N submit-uri. Trebuie **un singur buton Salveaza** care
   salveaza toate maparile odata.
6. **Tabelul de preview (pasul 3) nu e compact si are o coloana neclara.** Randurile sunt foarte inalte
   (VIN-ul se sparge pe verticala), iar coloana **„Verificat?"** nu are sens evident in acest pas
   (operatorul nu intelege bifa). Trebuie lista mai compacta si coloana clarificata/eliminata.
7. **Pe tableta si mobil interfata arata prost si articolele din header se suprapun.** Header-ul are grila
   desktop `1fr auto 1fr` (`min-height:92px`, logo 60px) si un singur prag mobil `@media (max-width:767px)`,
   dar **nimic pentru tableta (768–1024px)** — acolo logo + titlu + badge mediu + comutator tema + versiune
   + hamburger se inghesuie si se suprapun. Tot fluxul (header, import, preview, modal, Trimiteri, Mapari,
   Cont) trebuie **compact, functional si ergonomic** pe tableta si telefon, cu tinte touch si fara suprapuneri.

Toate sunt **UI/UX**, cu o singura exceptie de date controlata: identitatea contului (companie/email/CUI
obligatorii, US-001/002).

## 2. Non-Goals (anti scope-creep)

- **Nu** atingem worker-ul, reconcilierea, idempotenta, `build_key`, masina de stari de trimitere sau
  contractul RAR.
- **Nu** schimbam canalul API (`POST /v1/prezentari` / `/valideaza`) si nici logica de mapare
  (`mapping.py` `resolve_prestatii`). Maparea operatie→cod ramane neschimbata; doar UI-ul de mapare din
  pasul de import se reorganizeaza (US-005) si reuseaza `save_mapping`/`reresolve_account` existente.
- **Nu** stergem coloanele DB `auto_send` (deja neutralizate in 5.11) si nu reintroducem conceptul.
- **Nu** schimbam stocarea editarii de preview: ramane `import_rows.override_json` (Approach B din 3.6),
  ruta `POST /_import/{id}/rand/{i}/editeaza` ramane sursa de adevar; doar **suprafata** de editare trece
  din rand-inline in modal.
- **Nu** facem editare in bloc / multi-rand si nici editare a operatiei/codului RAR din modalul de rand
  (codul se mapeaza din panoul „Operatii de mapat", ca azi).
- **Nu** schimbam fluxul de login/parola; un cont poate avea in continuare mai multe loginuri (`users`),
  dar primeste un email canonic de contact pe `accounts` (US-001).
- **Nu** rescriem validarea de continut (`validation.py`); `<input type="date">` produce tot `YYYY-MM-DD`,
  acceptat azi.

## 3. Stories atomice

> Fiecare story: cea mai mica unitate care lasa sistemul functional. Backend + UI pentru acelasi
> comportament = 2 stories. Toate rutele web noi sub `require_login`, scoped pe contul din sesiune
> (404 cross-account), CSRF pe toate POST-urile.
>
> **Cerinta transversala (toate story-urile cu UI): responsive obligatoriu.** Fiecare suprafata noua/atinsa
> (US-002..007) se verifica E2E pe **3 viewport-uri: desktop (≥1280px), tableta (768–1024px) si mobil
> (≤767px / ~390px)** — fara overflow orizontal (`scrollWidth <= clientWidth`), fara suprapuneri, tinte
> touch ≥44px, modal full-screen pe mobil. US-008 acopera header-ul + cadrul global; fiecare story isi
> verifica propria suprafata pe cele 3 viewport-uri.

### US-001: Backend — companie/email/CUI obligatorii pe cont (`accounts.email` + validari)
**Ca** administrator al gateway-ului **vreau** ca orice cont sa aiba companie, email si CUI **pentru ca**
azi conturile pot exista fara email (CLI/teste) si fara CUI, deci nu pot fi identificate fiscal/contactate.

- **Depinde de**: —
- **Fisiere**: `app/schema.sql` (coloana `accounts.email` + `_migrate` defensiv), `app/accounts.py`
  (`create_account` accepta+valideaza `email`; helper `account_is_complete`), `app/web/auth_routes.py`
  (signup: CUI devine obligatoriu; scrie `accounts.email`), `tools/account.py` (CLI create cere
  `--email` + `--cui`), `tests/test_accounts.py`, `tests/test_signup.py` (~6 fisiere)
- **Test intai (RED)**: `tests/test_accounts.py` —
  `test_create_account_fara_email_ridica`, `test_create_account_fara_cui_ridica`,
  `test_email_normalizat_lowercase_trim`, `test_migrare_adauga_coloana_email_idempotent`,
  `test_account_is_complete_false_pe_legacy_incomplet`;
  `tests/test_signup.py` — `test_signup_fara_cui_422`, `test_signup_scrie_email_pe_account`,
  `test_signup_cui_existent_mesaj_prietenos` (NU mesajul tehnic cu `activate --account`).
- **Acceptance criteria**:
  - [x] Migrare: `accounts.email TEXT` (nullable la nivel de schema pentru conturile legacy), `_migrate`
        defensiv idempotent (ca `users.is_admin` la 3.3b). Contul de sistem id=1 ramane fara email (exceptat).
  - [x] `create_account(conn, name, cui, email, active)` — `name`/`cui`/`email` goale → `ValueError`
        cu cauza+fix (catalog `errors.py` daca exista cod potrivit); `email` normalizat (trim+lower);
        `cui` normalizat (trim+upper, ca azi). CUI duplicat → mesajul existent.
  - [x] Signup web: `cui` devine **obligatoriu** (azi optional); la succes scrie `accounts.email = email`-ul
        utilizatorului. Lipsa CUI → re-randare formular cu eroare (422), pastrand campurile.
  - [x] **CUI duplicat la signup = mesaj prietenos, NU cel tehnic** (decizie user 2026-06-26, optiunea 1):
        „Aceasta firma (CUI …) e deja inregistrata. Cere accesul de la administratorul contului." — fara
        referinta la CLI `activate --account`. **Model: 1 firma = 1 cont = 1 login**; fluxul de
        invitatie/alaturare a unui al doilea email pe aceeasi firma e deferit la TODOS (optiunea 2).
  - [x] **Canal de contact concret in mesaj** (T3 gate /autoplan, aprobat 2026-06-26): mesajul include un
        email/canal de suport configurabil din settings (ex. `support_email`); daca setarea lipseste,
        fallback la formularea de mai sus. Operatorul primeste un pas urmator real, nu doar „cere accesul".
        Nu mai lasam mesajul tehnic ridicat de `create_account` sa ajunga verbatim in signup — detectam
        CUI duplicat in handler-ul de signup si compunem mesajul prietenos acolo (NU `error=str(exc)`).
  - [x] CLI `tools/account.py create` cere `--email` + `--cui` (refuza fara ele); `--with-key` neschimbat.
  - [x] `account_is_complete(row)` (companie + email + CUI ne-goale) — helper pur, fara efecte.
  - [x] **NU** atinge `users`, `submissions`, worker-ul sau idempotenta.
- **Verificare E2E**: TestClient — signup fara CUI → 422; signup complet → `accounts.email` populat;
  `create_account` fara email/cui → ValueError.

### US-002: UI — gate de activare + pagina Cont editeaza companie/email/CUI + banner legacy
**Ca** operator/administrator **vreau** sa vad si sa completez companie/email/CUI **pentru ca**
conturile incomplete (legacy) trebuie aduse la regula fara re-inregistrare.

- **Depinde de**: US-001
- **Fisiere**: `app/web/templates/_cont.html` (sectiune noua „Date firma"), `app/web/routes.py`
  (ruta `POST /cont/date-firma` scoped sesiune + CSRF; context `account_meta`+`cont_incomplet`),
  `app/web/templates/admin.html` + `app/web/routes.py` (gate activare pe `account_is_complete`),
  `app/web/templates/_banner.html` sau `_acasa.html` (banner „Completeaza datele firmei"),
  `tests/test_web_cont.py`, `tests/test_admin.py` (~6 fisiere)
- **Test intai (RED)**: `tests/test_web_cont.py` —
  `test_cont_afiseaza_companie_email_cui`, `test_post_date_firma_actualizeaza`,
  `test_post_date_firma_cui_duplicat_eroare`, `test_banner_cont_incomplet_pe_legacy`;
  `tests/test_admin.py` — `test_activare_cont_incomplet_refuzata`.
- **Acceptance criteria**:
  - [x] `_cont.html` are o sectiune „Date firma" (deasupra cheii API) cu companie + email + CUI editabile,
        prefilled din `accounts`; `POST /cont/date-firma` valideaza (reuse `create_account`-style) + CSRF +
        scoped sesiune; eroare pe CUI duplicat / camp gol, mesaj 3-niveluri.
  - [x] Banner ne-blocant „Completeaza datele firmei (email/CUI)" pe Acasa cand `account_is_complete` e fals;
        dispare dupa completare. NU blocheaza importul/uploadul.
  - [x] In panoul admin, butonul **Activeaza** e dezactivat (cu tooltip) pe conturi incomplete —
        nu activam la RAR un cont fara identitate completa.
  - [x] Fara regresie pe rutele existente din `_cont.html` (cheie API, creds RAR).
- **Verificare E2E**: browser pe `/?tab=cont` — completez email+CUI → banner dispare; admin nu poate
  activa un cont incomplet.

### US-003: UI — pasul „Potriveste coloanele" arata antet + prima inregistrare
**Ca** operator **vreau** sa vad numele coloanelor din fisier si valorile primului rand **pentru ca**
sa stiu exact ce date mapez la fiecare camp RAR.

- **Depinde de**: —
- **Fisiere**: `app/web/templates/_mapcoloane.html`, `app/web/routes.py` (`web_upload_import` /
  `web_save_mapare_coloane` paseaza deja `sample_rows`; expune `prima_inregistrare`),
  `tests/test_web_mapcoloane.py` (~3 fisiere)
- **Test intai (RED)**: `tests/test_web_mapcoloane.py` —
  `test_mapcoloane_arata_cap_tabel_coloane`, `test_mapcoloane_arata_valori_prima_inregistrare`,
  `test_mapcoloane_fara_randuri_degradeaza` (fisier cu antet, fara randuri de date → fara crash).
- **Acceptance criteria**:
  - [x] Deasupra (sau langa) randurile de mapare, un mic tabel orizontal cu **un cap de tabel = numele
        coloanelor din fisier** si **un rand = valorile primei inregistrari** (truncate la o lungime
        rezonabila, `title` pe valoare integrala). Foloseste `.tablewrap` pentru scroll orizontal pe mobil.
  - [x] Fiecare coloana din capul de tabel ramane vizual asociata cu select-ul ei de mapare (ex. aceeasi
        ordine, sau evidentiere la hover) — operatorul vede „coloana X (valoare „...") → campul canonic Y".
  - [x] Fisier fara randuri de date → se arata doar capul de tabel, fara „prima inregistrare" (fara crash).
  - [x] Nicio schimbare de backend de parsare/mapare; doar randare (datele exista deja in `sample_rows`).
- **Verificare E2E**: browser pasul 2 — upload `prezentari_test.csv` → vad antetul real + valorile randului 1.

### US-004: UI+backend — un singur „Salveaza" pe „Operatii de mapat la cod RAR"
**Ca** operator **vreau** sa salvez toate maparile de operatii dintr-un singur click **pentru ca**
azi e cate un buton per operatie si trebuie apasat pe fiecare.

- **Depinde de**: —
- **Fisiere**: `app/web/templates/_preview_import.html` (panoul de mapare → un singur `<form>`),
  `app/web/routes.py` (ruta noua `POST /_import/{id}/mapare-operatii` plural; pastreaza
  `mapare-operatie` singular pentru compat sau o inlocuieste — vezi AC), `tests/test_web_mapare_op.py`
  (~3 fisiere)
- **Test intai (RED)**: `tests/test_web_mapare_op.py` —
  `test_mapare_operatii_salveaza_multiple_intr_un_post`,
  `test_mapare_operatii_ignora_randuri_neselectate` (op fara cod ales → nesalvata, nu eroare),
  `test_mapare_operatii_re_rezolva_blocatele` (randurile cu cod ales trec din `needs_mapping`).
- **Acceptance criteria**:
  - [x] Panoul „Operatii de mapat la cod RAR" devine UN singur `<form>` cu un select per operatie +
        **un singur buton „Salveaza maparile"** la final.
  - [x] `POST /_import/{id}/mapare-operatii` primeste perechi `(cod_op_service, cod_prestatie)` (liste
        paralele), apeleaza `save_mapping` pentru fiecare operatie cu cod ales (reuse exact, fara logica
        noua de mapare), apoi **o singura** recompute `_web_compute_preview` + re-randare `#import-section`.
  - [x] Operatiile fara cod ales (`— alege cod RAR —`) sunt ignorate (nu produc eroare, nu se salveaza).
  - [x] Toggle-ul auto_send NU reapare (eliminat in 5.11).
  - [x] CSRF + scoped sesiune + guard batch committed (409) pastrate.
- **Verificare E2E**: browser pasul 3 — aleg coduri pentru toate operatiile, un click pe „Salveaza
  maparile" → toate randurile trec din „Cod RAR lipsa", o singura re-randare.

### US-005: Refactor — formular de editare partajat (DRY) intre Trimiteri si preview
**Ca** dezvoltator **vreau** un singur formular de editare de continut **pentru ca** sa nu existe cod
duplicat intre modalul Trimiteri si editarea de preview (sursa bug-urilor inline din 3.6/5.11).

- **Depinde de**: —
- **Fisiere**: `app/web/templates/_form_editare.html` (NOU — partial cu campurile vehicul/data/odo),
  `app/web/templates/_trimitere_detaliu.html` (consuma partial-ul), `app/web/templates/_macros.html`
  (macro `camp` extins cu `tip='date'`), `tests/test_web_form_editare.py` (~4 fisiere)
- **Test intai (RED)**: `tests/test_web_form_editare.py` —
  `test_form_editare_are_input_date_pe_data_prestatie`,
  `test_trimitere_detaliu_foloseste_form_partajat`,
  `test_camp_macro_randeaza_type_date`.
- **Acceptance criteria**:
  - [x] Partial `_form_editare.html` randeaza grila responsiva existenta
        (`repeat(auto-fit, minmax(200px,1fr))`) cu campurile: `nr_inmatriculare`, `vin`, `data_prestatie`,
        `odometru_final`, `odometru_initial`, plus map de erori per-camp (tipar `corectie_errors`).
        Parametrizat prin: URL de POST, valorile curente, harta de erori, eticheta butonului primar.
  - [x] **`data_prestatie` = `<input type="date">`** (calendar nativ); valoarea ramane `YYYY-MM-DD`.
        Daca valoarea curenta nu e `YYYY-MM-DD` valid, inputul degradeaza grijuliu (gol + hint), fara crash.
  - [x] `_trimitere_detaliu.html` randeaza acelasi partial in ramura `editabil` — comportamentul modalului
        Trimiteri (post `/corecteaza`, select cod RAR pe needs_data/needs_mapping) ramane identic.
  - [x] Macro `camp` suporta `tip='date'` fara sa strice apelurile `type='text'` existente.
- **Verificare E2E**: browser — modalul Trimiteri (rand `needs_data`) arata un calendar la Data prestatie;
  salvarea+revalidarea functioneaza ca azi.

### US-006: UI — „Editeaza" din preview deschide MODALUL (acelasi formular), nu rand inline
**Ca** operator **vreau** sa editez un rand de preview intr-un modal curat **pentru ca** editarea inline
e rupta vizual si arunca eroare la Anuleaza.

- **Depinde de**: US-005
- **Fisiere**: `app/web/templates/_preview_rand.html` (scoate ramura `editing`/`tr.preview-edit` +
  scriptul de mutual-exclusion; butonul „Editeaza" tinteste modalul global), `app/web/routes.py`
  (ruta GET fragment editare preview → randeaza `_form_editare.html` in `#detaliu-modal-body`;
  POST `/_import/{id}/rand/{i}/editeaza` ramane, dar raspunde cu inchidere modal + OOB pe rand+contoare),
  `app/web/templates/_preview_import.html` (foloseste modalul global `#detaliu-modal`),
  `tests/test_web_preview_edit.py` (~5 fisiere)
- **Test intai (RED)**: `tests/test_web_preview_edit.py` —
  `test_editeaza_preview_serveste_fragment_modal` (NU `tr.preview-edit`),
  `test_salvare_preview_inchide_modal_si_oob_rand`,
  `test_anuleaza_nu_lasa_rand_orfan` (regresie pe eroarea htmx null),
  `test_editare_preview_scoped_404_alt_cont`, `test_editare_batch_committed_409`.
- **Acceptance criteria**:
  - [x] Butonul „Editeaza" pe rand face `hx-get` catre fragmentul de editare cu `hx-target="#detaliu-modal-body"`
        (acelasi mecanism de modal ca la Trimiteri, deschis prin clasa/markup existent in `base.html`).
  - [x] Fragmentul randeaza `_form_editare.html` cu POST la `/_import/{id}/rand/{i}/editeaza`,
        `hx-target="#detaliu-modal-body"`. La succes: **modalul se inchide** (`HX-Trigger: inchideModal`,
        ca la `/corecteaza`) si randul + contoarele se actualizeaza prin **OOB swap** (reuse `include_oob`).
  - [x] **Ramura `editing` / `tr.preview-edit` + scriptul inline de mutual-exclusion sunt ELIMINATE** din
        `_preview_rand.html` (sursa colapsarii pe verticala + a erorii `htmx-internal-data` la Anuleaza).
  - [x] „Anuleaza" = inchiderea modalului (mecanismul global), fara cerere catre `/_import/.../rand/{i}`,
        deci fara eroarea JS reprodusa. Test de regresie pe consola curata.
  - [x] Mutatie pura pe `override_json` pastrata (ruta neschimbata logic); scoping JOIN→404,
        guard committed→409 raman.
  - [x] Pe eroare de validare, modalul ramane deschis cu valorile + erorile per-camp (tipar Trimiteri).
- **Verificare E2E**: browser pasul 3 — Editeaza → modal cu calendar + campuri; completez data → Salveaza →
  modal se inchide, randul trece pe „Gata de trimis", contoarele cresc; Anuleaza → modal se inchide,
  **0 erori in consola**.

### US-007: UI — preview compact + scoaterea coloanei „Verificat?"
**Ca** operator **vreau** o lista de preview compacta si fara coloane neclare **pentru ca** randurile
sunt prea inalte (VIN pe verticala) si nu inteleg bifa „Verificat?".

- **Depinde de**: US-006
- **Fisiere**: `app/schema.sql` (coloana `import_rows.reviewed` + `_migrate` defensiv),
  `app/web/templates/_preview_rand.html`, `app/web/templates/_preview_import.html`
  (scoate coloana `col-verificat` + logica inline `reviewed_rows` din tabel),
  `app/web/templates/_form_editare.html` / fragmentul modal (buton „Confirma valorile" pe `needs_review`),
  `app/web/templates/base.html` (latimi `col-*` recalibrate, anti-overflow),
  `app/api/v1/import_router.py` + `app/web/routes.py` (citesc `reviewed` in `_resolve_row_for_preview` /
  `_web_compute_preview` ca `needs_review`-confirmat → `ok`; gate `n_confirmat` la commit foloseste
  `reviewed`, nu bife inline; ruta care seteaza `reviewed=1`), `tests/test_web_preview_compact.py`,
  `tests/test_import_review.py` (~7 fisiere)
- **Test intai (RED)**: `tests/test_web_preview_compact.py` —
  `test_preview_fara_coloana_verificat`,
  `test_preview_vin_nu_se_sparge_pe_verticala` (VIN intr-o singura linie / wrap controlat);
  `tests/test_import_review.py` —
  `test_needs_review_exclus_din_gata_pana_la_confirmare`,
  `test_confirmare_in_modal_seteaza_reviewed_si_devine_ok`,
  `test_reviewed_nu_intra_in_payload_sau_idempotency` (marcaj separat, NU camp de continut),
  `test_migrare_adauga_coloana_reviewed_idempotent`,
  `test_editare_valoare_pe_needs_review_reseteaza_reviewed` (daca schimbi valoarea, re-cere confirmare).
- **Acceptance criteria**:
  - [x] Coloana **„Verificat?" eliminata** din tabelul de preview; antetul si celulele scad la 8 coloane.
  - [x] Randuri compacte: VIN nu se mai sparge pe verticala (latime minima pe coloana Vehicul / `white-space`
        controlat); fara overflow orizontal la 1280px (`scrollWidth <= clientWidth`); cardurile <768px raman.
  - [x] **Decizie inchisa (Q1): confirmare in modal, rand exclus pana confirmi.** Un rand `needs_review`:
        - apare cu pill „Verifica valori" + motivul concret in „Note" (data ambigua / formule Excel / coercion);
        - este **exclus din „gata de trimis"** (nu intra in `n_confirmat`) pana cand operatorul il deschide in
          modal (US-006) si apasa **„Confirma valorile"** (sau il corecteaza), ceea ce seteaza
          `import_rows.reviewed=1`; abia atunci randul devine `ok` la recalculul `_resolve_row_for_preview`.
  - [x] **Banner discoverability deasupra tabelului** (T1 gate /autoplan, aprobat 2026-06-26): cand exista randuri
        `needs_review`, un banner ne-blocant deasupra tabelului explica: „Randurile cu <pill>Verifica valori</pill>
        nu pleaca la RAR pana le deschizi si confirmi in modal." Fara el, gate-ul mutat din coloana vizibila in
        modal devine usor de ratat (operatorul crede ca pill-ul e informativ). Bannerul dispare cand
        `summary.needs_review == 0`.
  - [x] **Buton explicit „Confirma valorile"** (T2 gate /autoplan, aprobat 2026-06-26): in modal (US-006), randurile
        `needs_review` au un buton SEPARAT „Confirma valorile" care seteaza `reviewed=1` — atestare explicita,
        distincta de salvarea unei corectii de continut. NU se seteaza `reviewed=1` implicit la orice save
        (altfel operatorul ar atesta o valoare ambigua fara intentie). Salvarea unei CORECTII pe un rand deja
        confirmat reseteaza `reviewed` (vezi AC urmator).
  - [x] **Marcaj separat, nu camp de continut**: `import_rows.reviewed` (nullable/int, migrare defensiva) NU
        intra in payload, in `override_json` sau in cheia de idempotenta. Daca utilizatorul **schimba** o
        valoare a unui rand deja confirmat, `reviewed` se reseteaza (re-cere confirmare).
  - [x] Comitul ramane gate HARD pe `n_confirmat` (niciun rand ambiguu nu pleaca la RAR fara confirmare
        umana explicita) — acum derivat din `reviewed`, nu din bife inline `reviewed_rows`.
  - [x] Bara de confirmare („Trimite la RAR") si contoarele raman corecte dupa editari/confirmari (OOB),
        fara coloana Verificat?.
  - [x] Guard committed→409 si scoping JOIN→404 pe ruta de confirmare (acelasi tipar ca `/editeaza`).
- **Verificare E2E**: browser pasul 3 (cu un xlsx cu data ambigua / VIN numeric) — lista compacta, fara
  coloana Verificat?, VIN pe o linie; randul `needs_review` ramane exclus din „gata de trimis" pana il
  confirm in modal („Confirma valorile") → devine „Gata de trimis", contorul creste.

### US-008: UI — responsive tableta + mobil (header fara suprapuneri + cadru compact/ergonomic)
**Ca** operator pe telefon/tableta **vreau** o interfata compacta, fara articole de header suprapuse
**pentru ca** azi pe mobil arata prost si elementele din header se calca unele pe altele.

- **Depinde de**: — (header/cadru global); coordonat cu US-006/007 pentru modal+preview pe mobil
- **Fisiere**: `app/web/templates/base.html` (header grid + media queries tableta 768–1024 + mobil ≤767,
  modal full-screen, `.cont-menu`, tinte touch), eventual `app/web/templates/_status.html` /
  `_acasa.html` (contoare + nav pe randuri inguste), `tests/test_web_responsive.py` (~3 fisiere)
- **Test intai (RED)**: `tests/test_web_responsive.py` —
  `test_header_are_breakpoint_tableta` (exista reguli `@media` intre 768 si 1024 pentru header),
  `test_header_elemente_nu_au_min_height_fix_pe_mobil`,
  `test_modal_full_screen_pe_mobil` (clasa/regula prezenta). (Testele de markup/CSS; pixel-level la E2E.)
- **Acceptance criteria**:
  - [x] **Header fara suprapuneri pe tableta (768–1024px)**: logo + titlu + badge mediu + comutator tema +
        versiune + hamburger se aseaza fara sa se calce (grid/flex care wrap-uieste sau ascunde versiunea/
        titlul lung); `min-height:92px` nu forteaza inghesuirea. Pe mobil (≤767px) raman regulile existente,
        verificate ca nu se suprapun la ~390px latime.
  - [x] **Compact + ergonomic**: spatieri reduse pe mobil, tinte interactive ≥44px (butoane, pill-uri,
        linkuri nav, intrari hamburger), fara dublu-scroll; modalul de editare (US-006) e **full-screen**
        pe mobil (nu o casuta minuscula).
  - [x] **Fara overflow orizontal** pe niciuna din paginile principale (Acasa/import, preview pas 3, Mapari,
        Cont, login/signup) la 768px si la ~390px (`scrollWidth <= clientWidth`).
  - [x] Contoarele de status + nav-ul „Trimiteri/Mapari" se aseaza pe randuri lizibile pe mobil (fara taiere).
  - [x] Light/Dark/Petrol/Auto raman corecte pe toate viewport-urile (fara regresie de tema).
- **Verificare E2E**: browser Playwright cu `browser_resize` la **390×844 (mobil)**, **820×1180 (tableta)**
  si **1280×800 (desktop)** — screenshot pe Acasa/import, preview pas 3 (cu modal deschis) si Cont; header
  fara suprapuneri pe toate trei; 0 overflow orizontal; tinte touch ok.

## 4. Riscuri

- **R1 — Gate `needs_review` la scoaterea coloanei.** Coloana „Verificat?" era gate-ul HARD prin care
  randurile cu valori ambigue (data ambigua, formula Excel) intrau in trimitere doar dupa bifa umana.
  Scoaterea ei naiva ar auto-include randuri ambigue (declaratie ireversibila la RAR). Mitigare:
  confirmarea se muta in modalul de editare (US-007 AC); `n_confirmat` ramane gate HARD. Vezi Q1.
- **R2 — Refactor formular partajat (US-005) atinge modalul Trimiteri (cale LIVE).** `_trimitere_detaliu.html`
  e folosit pentru corectii reale care re-trimit la RAR. Mitigare: US-005 = refactor fara schimbare de
  comportament; teste byte-compat pe post `/corecteaza` + regresia existenta verde inainte de US-006/007.
- **R3 — `<input type="date">` si valori ne-`YYYY-MM-DD`.** Fisiere cu data in alt format ajung in editare
  ca text ne-valid pentru inputul date (s-ar goli). Mitigare: AC US-005 — degradare grijulie (gol + hint),
  fara pierdere tacuta; data ramane editabila si re-validata la salvare.
- **R4 — Migrare `accounts.email`.** Conturi legacy raman cu `email=NULL`. Mitigare: coloana nullable +
  `account_is_complete` (banner + gate activare), nu hard-block; contul de sistem id=1 exceptat.
- **R5 — Eroarea htmx `htmx-internal-data`.** Reprodusa la Anuleaza pe editarea inline. Mitigare: US-006
  elimina complet ramura inline + scriptul; test de regresie pe consola curata.
- **R6 — Responsive = fisier fierbinte `base.html`.** US-008 atinge header + media queries, fisier partajat
  cu alte story-uri (US-007 latimi `col-*`). Mitigare: serializare la lead (NU paralel pe `base.html`);
  verificare pixel pe 3 viewport-uri ca breakpoint-ul de tableta nu strica desktop-ul/mobilul existent.

## 5. Intrebari deschise

> Se rezolva cu utilizatorul ÎNAINTE de executie (poarta de aprobare PRD).

- **Q1 (gate `needs_review`) — INCHIS (user, 2026-06-26): confirmare in modal, rand exclus pana confirmi.**
  Context — `needs_review` apare cand validarea TRECE dar parsarea fisierului a fost incerta, in 3 cazuri
  (sursa: `import_parse.py` + `import_router.py:201-230`), aproape exclusiv la **xlsx** (la CSV nu se
  declanseaza — de-aceea coloana e goala in cazul comun):
    1. **Data ambigua** — zi ≤12 si format neclar (`05.06` = 5 iun. sau 6 mai?).
    2. **Coloana cu formule Excel** fara valori calculate (rata mare de celule goale).
    3. **Coercion suspect** la citire xlsx — VIN numeric (pierde zerourile din fata) / odometru ca float.
  Decizie: scoatem coloana mereu-prezenta „Verificat?"; randul `needs_review` ramane **exclus din „gata de
  trimis"** pana e deschis in modal si **confirmat** („Confirma valorile") sau corectat, persistand
  `import_rows.reviewed=1` (marcaj separat, NU camp de continut → nu intra in payload/idempotenta).
  Implementat in US-007.
- **Q2 (model cont-email) — INCHIS (user, 2026-06-26): model A** (email canonic pe `accounts`), cu
  **1 firma = 1 cont = 1 login**. CUI ramane unic; al doilea email pe acelasi CUI e respins la signup cu
  mesaj prietenos (US-001). Fluxul de invitatie/alaturare (mai multi utilizatori per firma) → TODOS.
- **Q3 (CLI legacy `tools/account.py`)**: facem `--email`/`--cui` obligatorii rupe scripturile vechi de
  test? Daca da, pastram un flag `--allow-incomplete` doar pentru teste, sau actualizam fixture-urile.

## 6. Valuri de executie (graful de dependente)

```
Val 1 (paralel, fisiere disjuncte):
  [US-001]  accounts.email + validari companie/email/CUI        (schema/accounts/auth_routes/cli)
  [US-003]  mapcoloane: antet + prima inregistrare              (_mapcoloane.html/routes)
  [US-004]  un singur Salveaza pe operatii                      (_preview_import.html/routes)
  [US-005]  formular de editare partajat (DRY) + input date     (_form_editare/_trimitere_detaliu/_macros)

Val 2 (deblocate de Val 1):
  [US-002]  Cont editeaza date firma + gate activare + banner   (dep US-001; _cont/admin/routes)
  [US-006]  Editeaza preview → modal (acelasi formular)         (dep US-005; _preview_rand/_preview_import/routes)

Val 3 (deblocat de US-006; ating base.html → serializate):
  [US-007]  preview compact + scoate „Verificat?" + gate review (dep US-006; _preview_*/base.css/import_router)
  [US-008]  responsive tableta+mobil + header fara suprapuneri  (base.html media queries; coordonat cu US-006/007)
```

Fisiere fierbinti partajate (serializate de lead, NU paralel pe acelasi fisier): `routes.py`
(US-001/002/003/004/006), `_preview_import.html` (US-004/006/007), `_preview_rand.html` (US-006/007),
`base.html` (US-007 latimi `col-*` + US-008 header/media queries — serializate strict intre ele). Vezi ROADMAP §5.5.

---

## Raport VERIFY

> Faza VERIFY rulata de subagent verificator independent (context curat, PRD-only, ROADMAP §5.6),
> 2026-06-26. Lead orchestrare prin agent team (8 teammates Sonnet TDD pe valuri cu fisiere disjuncte;
> `routes.py` si `base.html` serializate ca fisiere fierbinti). Backend trimitere (worker, masina de
> stari de trimitere, idempotenta `build_key`, contract RAR, canal API) NEATINS — confirmat
> `git diff --stat` (app/worker/, app/idempotency.py, app/mapping.py, app/validation.py = 0 modificari).

### Rezultat: PASS (toate 8 stories)

- **Suita**: `python3 -m pytest -q` -> **987 passed, 1 skipped, 0 failed** (baseline 934 -> +53 teste noi).
  Live RAR `FINALIZATA` = opt-in indisponibil in mediu (normal, ca la livrabilele anterioare).
- **PASS/FAIL per story** (dovezi cod + teste, verificator independent):
  - US-001 accounts email/CUI — PASS (migrare defensiva, create_account valideaza, account_is_complete
    id=1 exceptat, signup CUI obligatoriu + mesaj prietenos T3, CLI --email/--cui).
  - US-002 Cont date firma + gate activare + banner — PASS.
  - US-003 mapcoloane antet + prima inregistrare — PASS (confirmat E2E browser).
  - US-004 un singur Salveaza pe operatii — PASS (ruta plurala, D#12 skip invalid).
  - US-005 formular editare partajat + input date — PASS (D#5/D#6/D#10).
  - US-006 Editeaza preview -> MODAL — PASS (ramura inline eliminata, Anuleaza fara eroare htmx, E2E 0 erori consola).
  - US-007 preview compact + gate review in modal — PASS (reviewed marcaj separat, NU in payload/idempotenta;
    gate HARD pe ambele canale; T1 banner; T2 buton Confirma; D#9 reset).
  - US-008 responsive tableta + mobil — PASS (E2E pe 390/820/1280, header fara suprapuneri, D#13 verificat).
- **Invariante critice**: R2 (submissions neatins dupa editare preview) PASS; reviewed in afara
  payload/override/idempotency PASS; migrari idempotente PASS; ramura inline `tr.preview-edit` eliminata PASS.

### VERIFY a gasit 1 FAIL -> remediat TDD, re-confirmat
- FAIL: `signup.html` eticheta CUI „(optional)" + input fara `required` (contrazicea AC US-001 „CUI obligatoriu";
  serverul respingea corect 422 dar UI comunica gresit). Reparat TDD (eticheta `*` + `required`),
  test de lock `test_signup_html_cui_obligatoriu_ui`.

### Faza CLOSE — `/code-review high` (8 unghiuri prin subagenti, verificare cod first-hand)
3 buguri reale reparate TDD (regresie finala 987 passed):
1. **HIGH** — `confirma-review` folosea `hx-swap="none"` -> scriptul `updateN()` din continutul principal nu
   se executa -> `n_confirmat` ramanea stale -> „Trimite la RAR" pica pe gate HARD 422 (fluxul confirma->commit
   US-007 rupt la prima incercare). Fix: formularul Confirma valorile aliniat la `hx-target="#detaliu-modal-body"`
   `hx-swap="innerHTML"` (ca /editeaza).
2. **MEDIUM** — email duplicat la signup arata mesajul gresit „firma e deja inregistrata" (`"deja folosit"`
   prindea si `ValueError("email deja folosit")` din `create_user`). Fix: detectie email-dup inaintea CUI-dup,
   mesaj specific emailului.
3. **MEDIUM (a11y)** — butonul Editeaza din preview deschidea modalul ocolind `open()` (fara inert/focus-trap/
   focus-return). Fix: handler-ul global `htmx:beforeRequest` trateaza si `.btn-editeaza` -> `open()`; JS inline eliminat.
Notat ca debt (neblocant): API preview re-deriva needs_review peste DB `resolved_status` cross-channel (web commit
numara oricum `reviewed=1`); mesaje prietenoase „camp gol" dead-code in cont_date_firma/signup (edge mascat de HTML
required); `zip()` truncheaza la liste POST inegale; `id` cont in mesajul CUI-duplicat; duplicari de cleanup
(context modal, markup banner, N query nomenclator).

### Nedovedit in sesiune
- Live RAR `FINALIZATA` prin `--send` (opt-in, lipsa creds/mediu) — risc minim, backend trimitere NEATINS.

---

## GSTACK REVIEW REPORT (/autoplan, 2026-06-26)

Branch: main · Commit: 283299f · Voci: Claude subagents (CEO/Design/Eng/DX) + verificare cod first-hand.
**Codex = INDISPONIBIL** (usage limit, reset 2026-07-18) -> mod `[subagent-only]` pe toate fazele.
Restore point: vezi comentariul HTML din capul fisierului. Test plan: `~/.gstack/projects/romfast-rar-autopass/main-prd5.12-test-plan-20260626.md`.

### Rezumat
PRD matur: Q1/Q2 inchise de user, Non-Goals clare, graf de valuri, R1-R6. Rutele si fisierele citate exista
toate in cod. Review-ul a confirmat fezabilitatea si a gasit **4 lacune de specificatie reale** (nu blocante,
dar de inchis inainte de executie) + cateva rafinari. Niciun User Challenge (un singur model activ -> nu se
poate forma consens cross-model; recomandarile de mai jos sunt sugestii, nu provocari).

### Decision Audit Trail

| # | Faza | Decizie | Clasificare | Principiu | Rationament | Respins |
|---|------|---------|-------------|-----------|-------------|---------|
| 1 | CEO | NU splitam in 5.12a/5.12b | Taste | P3/P6 | Valurile izoleaza deja US-001/002 (Val1/Val2) pe fisiere disjuncte; split adauga overhead de release fara castig tehnic pt. echipa mica | Split in 2 release-uri (CEO subagent) |
| 2 | CEO | Respins „testeaza worker-ul intai" (F1/F3/F8) | Mechanical | P3 | Non-Goals ingheata explicit worker/contract/idempotenta; conflateaza acest PRD UI cu munca de backend separata | CEO subagent F1/F3/F8 |
| 3 | CEO | First-run E2E smoke -> ramane in TODOS (deja listat) | Mechanical | P3 | Deja deferat din 5.11; recomandat, neblocant | A bloca 5.12 pe el |
| 4 | CEO | needs_review: pastram gate-ul, nu cerem date de utilizare | Mechanical | P1 | Gate-ul e safety-critical (declaratie ireversibila RAR); US-007 muta UI-ul, nu sterge gate-ul | CEO F5 (gather usage data first) |
| 5 | Eng | Partial partajat = DOAR campuri vehicul+data+err/fix; cod_prestatie select + nemapate_inline RAMAN in `_trimitere_detaliu` | Mechanical | P5/P4 | `_trimitere_detaliu` are 2 surse de cod (select + sectiune mapare inline) imposibil de absorbit fara branching fragil | Partial „atotcuprinzator" |
| 6 | Eng | US-005 parametrizeaza si `fix_map` (+ aria-label cu VIN) | Mechanical | P1 | Forma preview are fix-hints + aria-label cu context VIN; lista PRD le omitea -> ar pierde info la extractie | A lasa lista PRD ca atare |
| 7 | Eng | `import_rows.reviewed INTEGER DEFAULT 0` (nu NULL) | Mechanical | P5 | Gate-ul devine `reviewed=0` clar, fara ambiguitate NULL vs 0 | DEFAULT NULL |
| 8 | Eng | Gate commit derivat din DB `reviewed` pe AMBELE canale; API `reviewed_rows` pastrat dar seteaza `reviewed=1` (contract stabil) | Mechanical | P1/P5 | Evita divergenta web/API si pastreaza contractul `/v1/import/.../commit` | A schimba doar web-ul (divergenta tacuta) |
| 9 | Eng | reset `reviewed` la schimbare valoare se implementeaza in calea editeaza/override | Mechanical | P1 | E un AC US-007 fara loc de implementare numit; `apply_row_override` e locul | A-l lasa nespecificat |
| 10 | Design | `<input type=date>` ne-ISO: gol + hint + valoare bruta in hidden, fara pierdere | Taste->auto | P1 | Previne pierderea tacuta de date pe formate Excel; backend deja marcheaza needs_review | A goli pur si simplu inputul |
| 11 | Design | US-003 fisier fara randuri: mesaj explicit „antet fara randuri de date" + blocheaza Continua | Mechanical | P1 | Edge case altfel = esec tacut | Doar „fara crash" |
| 12 | US-004 | Bulk mapping: validare per-item, skip invalid + sumar, restul salvate, 1 re-render | Mechanical | P1 | PRD acopera „fara cod = ignorat" dar nu „cod invalid pe 1 din N" | All-or-nothing |
| 13 | US-008 | Modal full-screen mobil: VERIFICA, nu re-adauga (exista base.html:407) | Mechanical | P4 | Regula deja prezenta la `@media max-width:767px` | A re-implementa |
| 14 | DX | Q3: actualizam fixture-urile via factory in `conftest.py`, FARA `--allow-incomplete` in prod | Taste | P5/P4 | Escape-hatch lasa o veruca in codul de productie; factory centralizat e curat si mai bun pe termen lung | `--allow-incomplete` flag |
| T1 | Design | needs_review: banner persistent deasupra tabelului | Taste -> APROBAT user 2026-06-26 | P1/P5 | Gate-ul mutat in modal devine usor de ratat; bannerul il face explicit | Doar pill+tooltip |
| T2 | Design/Eng | „Confirma valorile" = buton explicit separat (nu implicit pe save) | Taste -> APROBAT user 2026-06-26 | P5 | Atestare explicita pe valori ambigue; evita confirmarea accidentala | Implicit pe orice save |
| T3 | DX | Mesaj CUI duplicat include canal de contact configurabil (fallback la actual) | Taste -> APROBAT user 2026-06-26 | P1 | Operatorul primeste un pas urmator real; detectie in handler signup, nu `str(exc)` | Pastreaza mesajul ca in PRD |

### NOT in scope (confirmat)
- Worker, reconciliere, idempotenta, `build_key`, masina de stari de trimitere, contract RAR (Non-Goals).
- Canal API `POST /v1/prezentari` / `/valideaza` si `mapping.resolve_prestatii` — neschimbate.
- Multi-utilizatori per firma (flux invitatie/alaturare) -> TODOS.
- First-run E2E smoke ca poarta de release -> TODOS (deja deferat din 5.11).
- Split 5.12a/5.12b -> respins (vezi D#1).

### What already exists (de refolosit, nu reconstruit)
- Modal global `#detaliu-modal` + `inchideModal` (`HX-Trigger-After-Settle`, routes.py:1235/1394) — US-006 il refoloseste.
- `include_oob` pentru OOB swap rand+contoare — US-006/007 il refolosesc.
- `save_mapping` / `reresolve_account` — US-004 le refoloseste (fara logica noua de mapare).
- Macro `camp` exista INLINE in ambele forme (`_preview_rand.html:51`, `_trimitere_detaliu.html:98`) — US-005 il EXTRAGE (nu „extinde in `_macros.html`" cum spune lista de fisiere; `_macros.html` are azi doar `autosend_toggle` gol).
- Modal full-screen mobil + tinte touch 44px — deja in base.html (`@media max-width:767px`, liniile 407-427). US-008 = tableta + verificare, nu rescriere.
- `_migrate` defensiv idempotent (tipar `users.is_admin` 3.3b) — US-001/007 il urmeaza.

---

## Faza 1 — CEO (strategie & scope)

CEO DUAL VOICES — CONSENSUS:
```
  Dimensiune                            Claude   Codex   Consens
  ------------------------------------- -------- ------- ---------
  1. Premise valide?                    DA*      N/A     n/a (1 voce)
  2. Problema corecta?                  DA       N/A     n/a
  3. Calibrare scope?                   DISAGREE N/A     -> taste (split?)
  4. Alternative explorate suficient?   PARTIAL  N/A     n/a
  5. Riscuri competitive acoperite?     DA       N/A     n/a
  6. Traiectorie 6 luni sanatoasa?      DA       N/A     n/a
  * premise = decizii user deja luate (Q1/Q2 inchise, modal/calendar = „decizie utilizator")
```
**Examinat, nimic blocant pe strategie.** PRD-ul rezolva first-run friction confirmat E2E; scope-ul e calibrat
prin valuri. CEO subagent a recomandat split-ul in 2 release-uri (D#1, respins) si a ridicat findings de „testeaza
worker-ul" care cad in afara Non-Goals (D#2, respinse). Single-critical pastrat: Q3 (backward-compat CLI) — real,
mutat la faza DX/Eng. Dream-state delta: 5.12 inchide first-run UX; ramane (separat) poarta E2E smoke + flux
multi-user firma.

## Faza 2 — Design (UI/UX)

Litmus (Claude design; Codex n/a):
```
  Dimensiune                       Scor  Nota
  -------------------------------- ----- -------------------------------------------
  Ierarhie informatie (mapcoloane) 7/10  US-003 ok; recomandat cap-tabel sticky pe fisiere cu 15+ coloane
  Stari (load/empty/error/partial) 6/10  empty-file (US-003) si date ne-ISO (US-005) sub-specificate
  Gate needs_review in modal       6/10  LANDMINE: gate HARD mutat dintr-o coloana vizibila intr-un modal
  Responsive tableta (US-008)      7/10  breakpoint lipseste azi; spec sa fie pixel-exact, nu aspirational
  Interactiune modal (US-006/007)  6/10  „Confirma valorile" = buton separat vs implicit-pe-save (ambiguu)
```
**Issue-uri auto-decise:** D#10 (date ne-ISO), D#11 (empty-file mesaj). **Taste surfaced la gata:** banner
discoverability pe needs_review (T1) + buton „Confirma valorile" explicit (T2).

## Faza 3 — Eng (arhitectura & teste)

ENG DUAL VOICES — CONSENSUS:
```
  Dimensiune                  Claude   Codex   Consens
  --------------------------- -------- ------- ---------
  1. Arhitectura sanatoasa?   DA(cond) N/A     n/a — cond. pe partial corect parametrizat
  2. Acoperire teste?         PARTIAL  N/A     n/a — vezi test plan, 4 gap-uri
  3. Riscuri performanta?     DA       N/A     n/a — irelevant (UI/CRUD mic)
  4. Securitate?              DA       N/A     n/a — CSRF+scoped pastrate pe rute noi
  5. Cai de eroare?           PARTIAL  N/A     n/a — bulk mapping partial, date ne-ISO
  6. Risc deployment?        DA       N/A     n/a — 2 migrari nullable defensive
```

Diagrama arhitectura (componente noi vs existente):
```
  US-001  create_account(+email)  ->  auth_routes.signup ──┐
          accounts.email (migrare) ->  tools/account.py CLI ┤ (3 call-sites de actualizat)
                                       account_is_complete  ┘
  US-005  _form_editare.html (NOU) <── _trimitere_detaliu.html  (cod_prestatie select + nemapate_inline RAMAN aici)
                                  └──< _preview_rand.html (US-006: ramura inline ELIMINATA)
  US-006  preview „Editeaza" -> #detaliu-modal-body (GET fragment) -> POST /editeaza -> inchideModal + OOB
  US-007  import_rows.reviewed (migrare) -> _resolve_row_for_preview -> gate n_confirmat
            ├── web  routes.py /confirma   (citeste DB reviewed)
            └── API  import_router commit_import (reviewed_rows -> seteaza reviewed=1; contract stabil)
  US-008  base.html @media (768-1024) NOU + verificare 767 existent
```

**Findings auto-decise:** D#5 (partial scope), D#6 (fix_map), D#7 (reviewed DEFAULT 0), D#8 (gate pe 2 canale),
D#9 (reset reviewed in apply_row_override), D#12 (bulk partial). Test plan scris pe disc (44 codepath-uri,
4 gap-uri marcate). **Invariant critic confirmat (R2):** editarea preview ramane override-only, NU re-queue —
test obligatoriu (#24/#25 in test plan): dupa editare preview, `submissions` neatins.

## Faza 3.5 — DX (CLI + erori + contract API)

DX CONSENSUS (Claude; Codex n/a):
```
  Dimensiune                        Nota
  --------------------------------- -------------------------------------------
  CLI create --email/--cui          Q3 nerezolvat: a face flag-uri obligatorii rupe fixture-urile
  Mesaj eroare CUI duplicat         prietenos da, dar „cere accesul de la admin" nu spune CUM
  Contract API commit reviewed_rows risc de divergenta tacuta -> rezolvat de D#8 + test #39
  Migrare fixture-uri               recomandat factory in conftest.py (DX gap real)
```
**Auto-decis:** D#14 (Q3 -> factory, fara `--allow-incomplete`). **Taste surfaced:** mesaj CUI duplicat sa includa
un canal de contact concret (T3).

### Cross-Phase Themes
- **Tema A — Gate-ul needs_review (Design + Eng).** Design: mutarea in modal ascunde gate-ul (discoverability).
  Eng: gate-ul trebuie sa fie DB-backed pe ambele canale + reset la editare. Semnal high-confidence: tratati
  needs_review ca feature de sine statator in US-007, nu ca „stergere de coloana". -> T1 + D#8/D#9.
- **Tema B — Sub-specificarea „Confirma valorile" (Design + Eng).** Ambii: cand se seteaza `reviewed=1`?
  Buton separat vs implicit pe save. -> T2.
- **Tema C — Q3 backward-compat (CEO + DX + Eng).** Toate trei: a face email/CUI obligatorii rupe fixture-uri.
  -> D#14 (factory).

### Implementation Tasks (aggregate)
_Niciun fisier `tasks-*.jsonl` per faza (autoplan ruleaza review-urile inline, nu skill-urile standalone)._
Task-urile concrete = AC-urile din US-001..008 + cele 14 decizii din audit trail + 4 gap-urile din test plan.

### Status: DONE_WITH_CONCERNS
Concerns (de inchis inainte de executie, niciunul blocant): cele 3 taste decisions de la gate (T1 banner,
T2 buton confirma, T3 contact CUI) + integrarea celor 14 decizii in AC-urile US. Codex indisponibil -> review
single-voice; re-ruleaza dupa 2026-07-18 daca vrei al doilea unghi adversarial.
