<!-- /autoplan restore point: /home/claude/.gstack/projects/romfast-rar-autopass/main-autoplan-restore-20260629-184940.md -->
# PRD 5.20 — Medii RAR per cont (Testare / Productie): activare, credentiale, selectie per trimitere

**Stare**: aprobat

> Proces complet: `docs/ROADMAP.md` §5. Contract RAR (sursa de adevar): `docs/api-rar-contract.md`.
> Stare: `draft -> aprobat -> in-executie -> verify-pass -> inchis`.

## 1. Obiectiv

Trateaza **Testare** si **Productie** ca doua medii RAR configurabile **per cont**. Fiecare mediu are, independent:
o **bifa de activare** si un **set propriu de credentiale**. Un mediu e *disponibil* pentru trimitere doar daca e
activat SI are credentiale. Din disponibilitate decurge tot UX-ul: cand un singur mediu e disponibil totul merge
acolo (fara selector); cand ambele sunt disponibile, apare selector la import + toggle in statusbar + alegere in
API. Trimiterile arata mereu un **badge** cu mediul tinta. Scop: clientul declara real pe Productie, iar cine are
si cont de test RAR isi poate testa integrarea pe Testare — fara redeploy si fara variabila globala de mediu.

**Premisa verificata (2026-06-29, doua seturi reale)**: test si prod sunt sisteme RAR **complet separate**; un set
de credentiale se autentifica pe **exact unul** (creds dev: test 200 / prod 401; creds client real: test 401 /
prod 200). Deci 2 seturi de creds per cont; un cont prod-only NU poate trimite la test fara cont de test emis de RAR.
Detaliu memorat: vezi memoria de proiect "rar-test-prod-creds-separate".

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

- NU eliminam `AUTOPASS_RAR_ENV` global: ramane **ancora de migrare** + fallback pentru actiuni de sistem fara cont
  (ex. keepalive login). Per-submission are precedenta cand exista.
- NU configuram base_url-uri din UI (raman in `config.py`); NU adaugam un al treilea mediu.
- NU gating pe plan/tier pentru Productie (decizie user: liber). „Guard-ul" e: Productie e tinta doar daca e
  activata + are creds, plus o confirmare unica la activarea Productie (constientizare L.142), NU per trimitere.
- NU schimbam masina de stari, backoff-ul, sau payload-ul `postPrezentare`.
- NU migram automat credentiale de prod ale clientilor — ei le introduc; migrarea doar muta creds-ul existent in
  slotul mediului sub care contul opera efectiv.

## 3. Cerinte transversale (reguli de derivare)

- **REQ-DISP**: `medii_disponibile(cont)` = mediile din {test, prod} cu `enabled=1` SI creds prezente. Sursa unica
  de adevar pentru vizibilitatea selector/toggle si pentru validarea unei tinte cerute.
- **REQ-VIZ**: selector la import + toggle in statusbar apar DOAR cand `len(medii_disponibile) >= 2`. La 1 mediu,
  tinta e implicita (acel mediu), fara selector. La 0, trimiterea e blocata cu mesaj „configureaza credentiale RAR".
- **REQ-BADGE**: orice trimitere afiseaza badge Test/Productie (chiar si la 1 mediu — claritate ca declari real).
- **REQ-DEFAULT**: `rar_env_default(cont)` e mereu unul din mediile disponibile; cont client nou = `prod`. Daca
  default-ul nu mai e disponibil (mediu dezactivat), cade pe singurul disponibil; daca 0 disponibile -> nicio tinta.
- **REQ-CONF**: trimiterea pe Productie nu cere confirmare per-rand; constientizarea vine din badge + o confirmare
  UNICA la activarea mediului Productie in configurare.

## 4. Stories atomice

> Backend + UI pentru acelasi comportament = stories separate. `Fisiere` + `Depinde de` complete.

### US-001: Schema — medii per cont (activare + creds) + env pe submission
**Ca** sistem **vreau** sa stochez per cont activarea si credentialele fiecarui mediu, default-ul, si env-ul tinta
pe fiecare submission **pentru ca** test si prod sunt sisteme separate cu credentiale separate.

- **Depinde de**: —
- **Fisiere**: `app/schema.sql`, `app/db.py` (migrare idempotenta), `tests/test_schema_migrate.py`
- **Test intai (RED)**: `tests/test_schema_migrate.py` — `test_coloane_medii_pe_cont`,
  `test_default_client_prod_on_test_off`, `test_migrare_creds_in_slotul_env_global`, `test_submissions_rar_env`
- **Acceptance criteria**:
  - [ ] `accounts`: `rar_test_enabled INTEGER NOT NULL DEFAULT 0`, `rar_prod_enabled INTEGER NOT NULL DEFAULT 1`
        (ambele CHECK IN (0,1)); `rar_creds_test_enc TEXT`, `rar_creds_prod_enc TEXT`;
        `rar_env_default TEXT NOT NULL DEFAULT 'prod' CHECK (rar_env_default IN ('test','prod'))`
  - [ ] `submissions.rar_env TEXT NOT NULL DEFAULT 'test' CHECK (rar_env IN ('test','prod'))`
  - [ ] **Migrare existenti (NU presupune env-ul)**: `rar_creds_enc` -> slotul `AUTOPASS_RAR_ENV` global de la
        migrare; seteaza `enabled=1` DOAR pe mediul cu creds; `rar_env_default` = acel mediu. Conturi fara creds:
        raman pe default-urile coloanei (prod on / test off). Coloana veche RAMANE acum (dropul e in US-013, dupa
        ce toate citirile trec pe per-env)
  - [ ] **(AUTO-FIX G — CRITIC, amendament AC) Backfill `submissions.rar_env` EXISTENT din `AUTOPASS_RAR_ENV`
        global**, NU lasa pe `DEFAULT 'test'`. Un rand prod pre-migrare etichetat 'test' -> US-006 reconciliaza
        contra endpoint TEST -> no-match -> re-send prod = DUPLICAT REAL IREVERSIBIL. `DEFAULT 'test'` ramane doar
        plasa pentru randuri net-noi (fiecare INSERT din US-004/005/009 seteaza `rar_env` explicit)
  - [ ] **(AUTO-FIX E4/3) Recompute `idempotency_key` pentru randurile existente** la forma env-aware
        (`build_key(account_id, canon, rar_env)` cu `rar_env`-ul backfill-at), ca lookup-urile de dedup (API +
        import) sa nu rateze randuri legacy -> altfel re-POST = duplicat
  - [ ] `test_submissions_rar_env` asserteaza ca un rand PRE-migrare ajunge cu env-ul global (NU 'test') si
        reconciliaza contra endpointului corect
  - [ ] migrare idempotenta pe DB existent, fara pierdere de date
  - [ ] `python3 -m pytest tests/test_schema_migrate.py -q` PASS
- **Verificare E2E**: DB pre-migrare cu `AUTOPASS_RAR_ENV=test` -> creds aterizeaza in `rar_creds_test_enc`,
  `rar_test_enabled=1`, `rar_env_default='test'`.

### US-002: Logica de disponibilitate si default efectiv
**Ca** sistem **vreau** un helper unic care intoarce mediile disponibile si default-ul efectiv al unui cont
**pentru ca** vizibilitatea UI, API-ul si worker-ul sa decida identic (REQ-DISP/REQ-DEFAULT).

- **Depinde de**: US-001
- **Fisiere**: `app/rar_env.py` (nou) sau `app/mapping.py`, `tests/test_rar_env_disponibil.py`
- **Test intai (RED)**: `tests/test_rar_env_disponibil.py` — `test_doar_prod_cu_creds`, `test_ambele`,
  `test_zero_cand_lipsesc_creds`, `test_default_cade_pe_singurul_disponibil`, `test_enabled_fara_creds_nu_e_disponibil`
- **Acceptance criteria**:
  - [ ] `medii_disponibile(account) -> list[str]` (subset din ['test','prod']) = enabled AND creds prezente
  - [ ] `rar_env_efectiv(account) -> 'test'|'prod'|None` aplica REQ-DEFAULT
  - [ ] `python3 -m pytest tests/test_rar_env_disponibil.py -q` PASS
- **Verificare E2E**: —

### US-003: Idempotenta include rar_env
**Ca** sistem **vreau** ca `build_key` sa incorporeze `rar_env` **pentru ca** aceeasi prezentare la test si apoi
la prod sunt doua trimiteri reale distincte, nu un duplicat.

- **Depinde de**: —
- **Fisiere**: `app/idempotency.py`, `tests/test_idempotency.py`
- **Test intai (RED)**: `tests/test_idempotency.py` — `test_key_difera_intre_test_si_prod`, `test_key_stabil_pe_env`
- **Acceptance criteria**:
  - [ ] `build_key(account_id, canon, rar_env)` -> chei diferite test vs prod pe acelasi continut; stabil pe re-apel
  - [ ] toate apelurile (`router.py`, `import_router.py`) trec env-ul rezolvat
  - [ ] `python3 -m pytest tests/test_idempotency.py -q` PASS
- **Verificare E2E**: —

### US-004: Rezolvare tinta la ingestie (cerere > default cont) + respinge tinta indisponibila
**Ca** sistem **vreau** sa decid env-ul unui submission si sa resping tintele indisponibile **pentru ca** o tinta
fara mediu activ/creds nu trebuie sa intre in coada.

- **Depinde de**: US-002
- **Fisiere**: `app/validation.py`, `app/mapping.py`, `tests/test_rar_env_resolve.py`
- **Test intai (RED)**: `tests/test_rar_env_resolve.py` — `test_cerere_castiga`, `test_fallback_default_cont`,
  `test_tinta_indisponibila_respinsa`, `test_valoare_invalida`
- **Acceptance criteria**:
  - [ ] precedenta: valoare ceruta (daca e in `medii_disponibile`) > `rar_env_efectiv(cont)`
  - [ ] tinta ceruta dar indisponibila -> eroare clara („mediul X nu e activat / fara credentiale"), fara enqueue
  - [ ] valoare invalida (≠ test/prod) -> eroare de validare, fara fallback silentios
  - [ ] `python3 -m pytest tests/test_rar_env_resolve.py -q` PASS
- **Verificare E2E**: —

### US-005: API — camp `rar_target` pe POST /v1/prezentari si /valideaza
**Ca** integrator ROAAUTO **vreau** sa pot preciza `rar_target`, cu default = default-ul contului meu **pentru ca**
sa aleg unde declar fara sa stiu env-ul global.

- **Depinde de**: US-003, US-004
- **Fisiere**: `app/api/v1/router.py`, `app/models.py`, `tests/test_api_rar_target.py`
- **Test intai (RED)**: `tests/test_api_rar_target.py` — `test_default_din_cont_cand_lipseste`,
  `test_target_explicit`, `test_target_indisponibil_respins`, `test_get_ecou_rar_env`, `test_valoare_invalida_422`
- **Acceptance criteria**:
  - [ ] camp optional `rar_target: "test"|"prod"` pe `POST /v1/prezentari` si `/valideaza`
  - [ ] absent -> `rar_env_efectiv(cont)` (pt client prod-only = `prod`)
  - [ ] tinta indisponibila -> raspuns clar, fara enqueue; `SubmissionResult` + GET ecou-iesc `rar_env`
  - [ ] valoare invalida -> 422 fara echo de input (handler global pastrat)
  - [ ] `python3 -m pytest tests/test_api_rar_target.py -q` PASS
- **Verificare E2E**: `POST /v1/prezentari` fara `rar_target` pe un cont prod-only -> submission env=prod.

### US-006: Worker — sesiuni si trimitere per (cont, env)
**Ca** worker **vreau** login/JWT separat per `(account_id, rar_env)`, cu base_url + creds corecte per submission
**pentru ca** test si prod sunt sisteme RAR diferite.

- **Depinde de**: US-001
- **Fisiere**: `app/worker/__main__.py` (`AccountSessions`), `app/rar_client.py` (base_url per env),
  `app/reconcile.py`, `tests/test_worker_rar_env.py`
- **Test intai (RED)**: `tests/test_worker_rar_env.py` — `test_sesiune_separata_per_env`,
  `test_base_url_dupa_submission`, `test_creds_din_slotul_env`, `test_reconcile_pe_env_corect`
- **Acceptance criteria**:
  - [ ] cheia cache sesiune = `(account_id, rar_env)`; JWT/keepalive/last_rar_login_ok per env
  - [ ] `RarClient` primeste env/base_url explicit (nu doar `settings.rar_base_url`)
  - [ ] creds alese: submission efemere -> `accounts.rar_creds_{env}_enc`; lipsa -> blocaj clar (nu trimite)
  - [ ] reconcilierea cauta in `finalizate` pe endpoint-ul `submission.rar_env`
  - [ ] purjarea atinge DOAR `submissions.rar_creds_enc`, NU `accounts.rar_creds_{env}_enc`
  - [ ] `python3 -m pytest tests/test_worker_rar_env.py -q` PASS
- **Verificare E2E**: doua submission-uri (test + prod, creds prezente) -> doua login-uri distincte in jurnal.

### US-007: Validare login pe env-ul ales (signup / preview / test integrare)
**Ca** sistem **vreau** ca validarea credentialelor sa loveasca mediul caruia ii apartin **pentru ca** o parola
prod nu se valideaza contra RAR test si invers (confirmat: 401 incrucisat).

- **Depinde de**: US-002
- **Fisiere**: `app/web/routes.py`, `app/rar_client.py`, `app/web/templates/_integrare.html`,
  `tests/test_validare_env.py`
- **Test intai (RED)**: `tests/test_validare_env.py` — `test_valideaza_pe_env_creds`, `test_mesaj_distinge_env`
- **Acceptance criteria**:
  - [ ] validarea (signup, „testeaza integrarea", preview) foloseste env-ul setului de creds verificat
  - [ ] mesaj distinct „creds invalide pe TESTARE" vs „pe PRODUCTIE"
  - [ ] `python3 -m pytest tests/test_validare_env.py -q` PASS
- **Verificare E2E**: in UI „testeaza integrarea" cu creds prod -> login pe endpoint prod.

### US-008: Configurare cont — doua medii (bifa activare + creds), default, confirmare prod
**Ca** titular de cont **vreau** sa activez fiecare mediu, sa-i introduc credentialele si sa aleg default-ul
**pentru ca** vreau sa controlez unde se poate trimite si unde merge implicit.

- **Depinde de**: US-001, US-007
- **Fisiere**: `app/web/routes.py`, `app/web/templates/_cont.html`, `app/crypto.py` (refolosit),
  `tests/test_cont_medii.py`
- **Test intai (RED)**: `tests/test_cont_medii.py` — `test_activeaza_si_salveaza_creds_per_env`,
  `test_default_doar_dintre_disponibile`, `test_activare_prod_cere_confirmare`, `test_creds_criptate_fara_echo`
- **Acceptance criteria**:
  - [ ] doua sectiuni „Testare" si „Productie": fiecare cu bifa Activeaza + campuri email/parola; default client =
        Productie bifat, Testare nebifat
  - [ ] la salvare, creds-ul fiecarui mediu activat e validat prin login pe acel env (US-007); invalid -> nu se
        marcheaza disponibil
  - [ ] selectorul de default ofera DOAR mediile disponibile; nu poti seta default un mediu indisponibil
  - [ ] activarea mediului Productie cere o confirmare unica „Inteleg ca trimiterile pe Productie sunt declaratii
        reale (L.142)"
  - [ ] creds criptate Fernet in `rar_creds_{env}_enc`, niciodata reflectate inapoi in pagina
  - [ ] `python3 -m pytest tests/test_cont_medii.py -q` PASS
- **Verificare E2E**: activez Testare + creds valide si Productie + creds invalide -> doar Testare devine disponibil.

### US-009: Import web — selector mediu conditionat de disponibilitate
**Ca** operator **vreau** sa aleg mediul la import doar cand am ≥2 disponibile, pre-bifat pe default **pentru ca**
la un singur mediu alegerea e inutila.

- **Depinde de**: US-002, US-004
- **Fisiere**: `app/import_router.py`, `app/import_parse.py`, `app/web/templates/_upload.html`,
  `_preview_import.html`, `tests/test_import_rar_env.py`
- **Test intai (RED)**: `tests/test_import_rar_env.py` — `test_selector_ascuns_la_un_mediu`,
  `test_selector_prezent_si_prebifat_la_doua`, `test_commit_seteaza_env_pe_submissions`
- **Acceptance criteria**:
  - [ ] selector Test/Prod apare DOAR daca `len(medii_disponibile) >= 2`; initial = `rar_env_efectiv`
  - [ ] la 1 mediu: fara selector, toate randurile primesc acel mediu
  - [ ] la commit, toate submission-urile lotului primesc `rar_env` ales
  - [ ] `python3 -m pytest tests/test_import_rar_env.py -q` PASS
- **Verificare E2E**: cont prod-only -> import fara selector, submissions env=prod; cont cu ambele -> selector pre-bifat.

### US-010: Badge mediu in liste, preview, jurnal, audit + ecou API
**Ca** utilizator **vreau** sa vad pe fiecare trimitere mediul tinta **pentru ca** sa nu confund testul cu realul.

- **Depinde de**: US-001
- **Fisiere**: `app/web/templates/_submissions.html`, `_coada.html`, `_trimitere_detaliu.html`,
  `_preview_rand.html`, `_jurnal.html`, `app/web/routes.py` (audit export), `app/api/v1/router.py` (GET),
  `tests/test_badge_rar_env.py`
- **Test intai (RED)**: `tests/test_badge_rar_env.py` — `test_badge_in_lista`, `test_audit_contine_rar_env`,
  `test_get_ecou_rar_env`
- **Acceptance criteria**:
  - [ ] badge vizibil (Test vs Productie, culori distincte) in lista, preview rand, detaliu, jurnal
  - [ ] `rar_env` in audit export si in `GET /v1/prezentari(/{id})`
  - [ ] `python3 -m pytest tests/test_badge_rar_env.py -q` PASS
- **Verificare E2E**: rand prod -> badge „Productie"; export audit contine coloana.

### US-011: Statusbar — indicator mediu + toggle conditionat
**Ca** operator **vreau** sa vad in statusbar mediul default si sa-l pot schimba cand am ≥2 medii **pentru ca**
sa stiu mereu unde trimit si sa comut rapid.

- **Depinde de**: US-002, US-008
- **Fisiere**: `app/web/templates/_status.html`, `base.html`, `app/web/routes.py` (ruta toggle account-scoped),
  `tests/test_statusbar_env.py`
- **Test intai (RED)**: `tests/test_statusbar_env.py` — `test_afiseaza_env_default`,
  `test_toggle_doar_la_doua_medii`, `test_toggle_schimba_default`
- **Acceptance criteria**:
  - [ ] statusbar afiseaza mediul default al contului logat (Test/Productie), distinct vizual
  - [ ] toggle apare DOAR la `len(medii_disponibile) >= 2`; comutarea schimba `rar_env_default` (HTMX, fara reload)
  - [ ] la 1 mediu: doar eticheta statica
  - [ ] `python3 -m pytest tests/test_statusbar_env.py -q` PASS
- **Verificare E2E**: cont cu ambele -> click statusbar schimba default; cont prod-only -> eticheta fixa „Productie".

### US-012: Audit + e2e pe medii
**Ca** lead **vreau** evenimente de audit la activare mediu / schimbare default / blocaj tinta, plus teste e2e
**pentru ca** orice atingere a mediului Productie trebuie trasabila.

- **Depinde de**: US-005, US-006, US-009, US-011
- **Fisiere**: `app/audit.py`/`log_event`, `tests/test_e2e_rar_env.py`
- **Test intai (RED)**: `tests/test_e2e_rar_env.py` — `test_lant_import_pana_la_queued`, `test_activare_prod_logata`,
  `test_tinta_indisponibila_blocata_si_logata`
- **Acceptance criteria**:
  - [ ] audit la: activare/dezactivare mediu, schimbare `rar_env_default`, blocaj tinta indisponibila
  - [ ] e2e (TestClient + SQLite temporar) acopera import->queued cu env corect, ambele cai
  - [ ] `python3 -m pytest tests/test_e2e_rar_env.py -q` PASS
- **Verificare E2E**: jurnal arata „mediu Productie activat" + „default schimbat" cu cont + timestamp.

### US-013: Retragerea `accounts.rar_creds_enc` (toate citirile -> per-env, apoi DROP)
**Ca** sistem **vreau** ca toate cele ~40 de locuri care citesc `accounts.rar_creds_enc` sa treaca pe coloanele
per-mediu si apoi sa sterg coloana veche **pentru ca** modelul per-env sa fie sursa unica, fara schema dubla.

- **Depinde de**: US-005, US-006, US-008 (consumatorii principali deja pe per-env)
- **Fisiere**: `app/worker/__main__.py` (fallback + bucla keepalive „toate conturile cu creds"),
  `app/web/routes.py` (indicatorii `are_creds`), `app/api/v1/integrare_router.py` (`are_creds_rar`),
  `app/api/v1/router.py` (`POST /v1/conturi/rar-creds` devine env-aware), `app/accounts.py` (purge la stergere cont),
  `app/db.py` (DROP cu garda), `app/models.py`, `tests/test_retragere_creds_enc.py`
- **Test intai (RED)**: `tests/test_retragere_creds_enc.py` — `test_niciun_read_pe_coloana_veche`,
  `test_conturi_rar_creds_env_aware`, `test_are_creds_pe_per_env`, `test_drop_cu_garda_blocat_daca_lipsa_copiere`
- **Acceptance criteria**:
  - [ ] worker fallback + keepalive citesc `rar_creds_{env}_enc` (per env), nu coloana veche
  - [ ] `are_creds` (web) + `are_creds_rar` (integrare) devin per-mediu („are creds pe Testare/Productie")
  - [ ] `POST /v1/conturi/rar-creds` primeste mediul (`rar_target`/`env`) si scrie in slotul corect — **schimbare
        de contract API**, documentata in `docs/api-rar-contract.md`
  - [ ] purjarea la stergere cont (`accounts.py`) sterge ambele sloturi per-env
  - [ ] **DROP cu garda**: migrarea verifica intai ca fiecare `rar_creds_enc` non-null a aterizat intr-un slot
        per-env (assert), apoi `ALTER TABLE accounts DROP COLUMN rar_creds_enc` (SQLite 3.45 OK); verificare esuata
        -> NU dropa, ridica eroare (fail-safe)
  - [ ] **(AUTO-FIX 6a — CRITIC) Elimina ATOMIC blocul `ADD COLUMN rar_creds_enc` din `db.py:77-78`** in aceeasi
        migrare cu DROP-ul. Altfel urmatorul boot vede coloana absenta si o re-ADD goala -> ping-pong perpetuu,
        garda se rupe. Garda e one-way: dropeaza doar cand sloturile per-env sunt populate SI coloana inca exista
  - [ ] **(AUTO-FIX 6b — HIGH) DROP-ul nu crapa boot-ul**: `init_db/_migrate` ruleaza la fiecare pornire a ambelor
        procese; un `DROP COLUMN` care arunca (SQLite < 3.35 / assert garda esuat) propaga -> API + worker
        crash-loop. Prinde + degradeaza (log + lasa coloana pe loc), NU arunca. Asserteaza `sqlite_version() >= 3.35`
        (verifica SQLite din imaginea Docker, nu doar dev box) si sare drop-ul gracios sub acel prag
  - [ ] **(AUTO-FIX 6c — HIGH) Re-ruleaza backfill old->new IMEDIAT inainte de assert**: creds setate via
        `POST /v1/conturi/rar-creds` intre deploy-ul US-001 si US-013 aterizeaza doar in coloana veche; copiaza-le
        in slotul per-env (ancora globala) inainte de garda, altfel garda blocheaza drop-ul la nesfarsit
  - [ ] **(AUTO-FIX 6d) Verificare prin `PRAGMA table_info(accounts)`** ca `rar_creds_enc` lipseste, NU doar prin
        grep (ambele coloane — `accounts` si `submissions` — au acelasi nume; purjarea worker-ului ramane pe
        `submissions.rar_creds_enc`)
  - [ ] `grep -rn "rar_creds_enc" app/` nu mai gaseste citiri pe `accounts` (doar `submissions.rar_creds_enc` ramane)
  - [ ] `python3 -m pytest tests/test_retragere_creds_enc.py -q` PASS
- **Verificare E2E**: dupa migrare, `PRAGMA table_info(accounts)` nu mai contine `rar_creds_enc`; fluxul de cont
  (salvare creds, worker trimite) functioneaza pe per-env.

## 5. Riscuri

- **Trimitere reala accidentala** (FINALIZATA terminal, L.142): atenuat prin badge omniprezent + Productie disponibil
  doar dupa activare explicita + creds + confirmare unica la activare. NU exista anulare la RAR.
- **Default invalid dupa dezactivare mediu**: REQ-DEFAULT recalculeaza; teste US-002 acopera caderea pe disponibil.
- **Migrare ambigua** (CONFIRMAT): `rar_creds_enc` poate fi test SAU prod; migrarea aterizeaza in slotul
  `AUTOPASS_RAR_ENV` global + activeaza doar acel mediu. De validat pe DB-ul real inainte de deploy.
- **Client prod-only nu poate testa**: corect by design; UI explica explicit (nu „creds invalide"), nu ofera Testare
  fara creds test.
- **Idempotenta**: schimbarea cheii (US-003) cere ca TOATE apelurile sa treaca env-ul; grep dupa `build_key` + teste.
- **Retragere `rar_creds_enc` (US-013)**: ~40 citiri + endpoint API `POST /v1/conturi/rar-creds` (contract). Blast
  radius mare, dar single-release e mai curat decat schema dubla. DROP cu garda (assert copiere) = fara pierdere
  de date; produsul e in TESTE (putine conturi reale). Recuperarea via coloana veche dispare dupa DROP — acceptat.

## 6. Intrebari deschise — REZOLVATE (user 2026-06-29)

- [x] **Default API** = default-ul contului (NU „test" hardcodat), fiindca clientii sunt prod-only. CONFIRMAT.
- [x] **Activare implicita cont nou** = Productie on / Testare off; contul operator setat manual pe Testare. CONFIRMAT.
- [x] **Confirmare Productie** = o data, la activarea mediului in configurare (nu per trimitere). CONFIRMAT.
- [x] **`rar_creds_enc` vechi** = se STERGE in acest PRD (US-013), nu in 5.2x. DROP cu garda (assert copiere),
      toate citirile mutate pe per-env, endpoint `POST /v1/conturi/rar-creds` devine env-aware. CONFIRMAT.

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

```
Val 1: [US-001] [US-003]                 ← schema + idempotenta (fisiere distincte) → paralel
Val 2: [US-002]                          ← deblocat de US-001
Val 3: [US-004] [US-006] [US-007]        ← rezolvare ingestie / worker / validare → paralel
Val 4: [US-005] [US-008] [US-009] [US-010] ← API / config cont / import / badge → paralel
Val 5: [US-011]                          ← statusbar (depinde de US-008)
Val 6: [US-012] [US-013]                  ← audit + e2e; retragere rar_creds_enc + DROP (depind de tot)
```

---

## Raport VERIFY

> Completat de subagentul verificator (context curat) in faza VERIFY — vezi ROADMAP §5.6.
> PASS/FAIL per criteriu, cu dovezi. Lipseste pana la VERIFY.

---

<!-- AUTONOMOUS DECISION LOG -->
## /autoplan Review (2026-06-29, commit 7371c37)

Voci: Claude (primar) + Claude subagent (independent). Codex indisponibil (usage limit, revine 18 iul) -> mod `[subagent-only]`. Poarta premisa: user a ales **"Build full per-account multi-env (as planned)"** — premisa de baza (sisteme separate) verificata live; nevoia de dashboard unic justifica per-cont peste 2 deployment-uri pinned.

### Auto-fixuri (corectitudine/siguranta — incorporate in stories)

| # | Story | Gap (gasit de) | Fix incorporat | Principiu |
|---|-------|----------------|----------------|-----------|
| G | US-001 | **CRITIC** (subagent): migrarea backfill-eaza creds dar NU `submissions.rar_env` existent; randuri prod pre-migrare cad pe DEFAULT 'test' -> US-006 reconciliaza contra endpoint TEST -> no-match -> **re-send prod = duplicat real ireversibil** | Migrarea backfill-eaza `submissions.rar_env` din `AUTOPASS_RAR_ENV` global (DEFAULT 'test' doar pentru randuri net-noi). Test: rand prod pre-migrare reconciliaza contra endpoint prod | P1 completeness + siguranta |
| L | **US-005/US-013** (NU US-006 — eng finding 5: write-back e in `router.py`, pe care US-006 nu-l atinge) | HIGH (ambele voci, `router.py:250`): write-back creds efemere API -> `accounts.rar_creds_enc` durabil nu e rutat pe slotul `submission.rar_env` | Write-back tinteste `accounts.rar_creds_{submission.rar_env}_enc` + test. **Plus**: nu auto-propaga creds API NEVALIDATE in slotul durabil per-env (ar putea clobber-i un slot login-validat); propaga doar dupa login reusit | P1 |
| K | US-013 | HIGH (subagent): `POST /v1/conturi/rar-creds` e contract extern; env-aware in-place = breaking | Endpoint **aditiv**: param `env` optional, default = default cont; apelanti vechi neatinsi. (Independent de decizia DROP) | P5 explicit + back-compat |
| M2 | US-013 | MEDIUM (Claude): `_keepalive_target` alege un cont fara notiune de env dupa per-env | Keepalive foloseste ancora globala `AUTOPASS_RAR_ENV` + un cont cu creds in slotul acelui env | P5 |
| M3 | US-003 | MEDIUM (Claude): `_already_sent_lookup` (import_router.py:369) are dual-lookup legacy; adaugarea env in cheie cere extinderea lui, nu doar a parametrului | US-003 extinde dual-lookup (cheie noua env-aware + fallback legacy) | P1 |
| D | US-001 | HIGH (subagent): corectitudinea migrarii e "de validat manual"; trebuie poarta testata | Script de audit pre-migrare (raporteaza slot-ul atribuit) + assert DROP-cu-garda existent ca poarta, nu nota manuala | P1 |
| M | US-012 | MEDIUM (subagent): niciun test live dual-env; riscul dominant (rutare gresita env) e exact ce SQLite nu prinde | Test live opt-in dual-env (extinde `test_live_rar`): 1 rand test + 1 prod -> 2 login-uri, 2 endpoint-uri, badge corecte, reconciliere pe env corect | P1 |
| backup | US-013 | MEDIUM (Claude): "recovery via coloana veche dispare dupa DROP — acceptat" | Inainte de DROP, dump coloana veche criptata intr-un backup timestamped (recuperare supravietuieste DROP) | P2 boil-lake |

### Decizii user la poarta finala (REZOLVATE 2026-06-29) — APROBAT

- **A (DROP US-013) -> PASTREAZA single-release.** User: "aplicatia e doar in teste, nu folosita de clienti" -> blast radius mic, rollback-ul conteaza mai putin. Decizia §6 ramane. **Garzile 6a/6b/6c sunt obligatorii in AC US-013** (eliminare atomica bloc ADD, catch+degrade fara boot-crash, re-backfill interim) + backup criptat inainte de DROP. NU se amana.
- **J/H1 (interlock prod) -> doar butonul de commit colorat (F8), FARA modal.** REQ-CONF ramane. Lantul: bifa activare (o data) + badge "fierbinte" + buton "Declară la PRODUCȚIE (real)". Fara confirmare per-commit (evita oboseala de click; clientii prod-only oricum n-au selector).
- **H (fallback default) -> doar toast zgomotos (F5), FARA re-confirmare.** REQ-DEFAULT auto-fallback ramane; toast-ul "Mediul implicit a trecut pe X" face flip-ul vizibil. Fara gate suplimentar.

### Taste (recomandari acceptate — fara override)
- **T1**: token dedicat `--prod` (brick) pentru badge-ul Productie. **T2**: `rar_env` ca nume unic input+output (scoate `rar_target`/`env`).

### Taste decisions (auto-decise cu recomandare — override la poarta)
- **T1 — token culoare Productie**: rosu (`--err`) se ciocneste cu erorile, amber (`--warn`) cu badge-ul legacy. Recomandat: token dedicat `--prod` (brick inchis) SAU `--accent` plin. (design F2)
- **T2 — nume camp request**: recomandat `rar_env` peste tot (un singur nume input+output), scoate `rar_target`/`env`. (DX F1)

### Teme cross-fază (semnal de incredere ridicat — aparut independent in 2+ faze)
- **Siguranta declaratiei reale ireversibile** — TOATE 4 fazele (CEO G/H1/J, Design F1/F8/F10, Eng 1b/3/G, DX F2/F3/F4). Semnalul dominant: badge + interlock + discoverability + rutare env corecta converg pe "nu declara real din greseala".
- **Flip silentios al mediului default** — CEO-H, Design-F5, DX-F3 (3 faze). Fa flip-ul zgomotos + nu auto-promova prod silentios.
- **Risc DROP US-013** — CEO-A, Eng 6a/6b/6c (2 faze). Intareste amanarea DROP-ului.
- **Ambiguitate spec/nume care musca implementer-ul** — Design-F14, Eng-4a, DX-F1/F7. Auto-fixurile TREBUIE sa intre in AC + contract inainte de implementare.

### NOT in scope (confirmat)
Eliminarea ancorei globale `AUTOPASS_RAR_ENV`; base_url din UI; al treilea mediu; gating plan/tier pe prod; schimbari masina-stari/backoff/payload; auto-migrare creds prod client. (PRD §2)

### Ce exista deja (leverage)
`crypto.py` Fernet (creds per-env), `AccountSessions` (re-key (cont,env)), `RarClient` (primeste settings; +param env), `config.rar_base_url_test/prod` (deja prezent), `build_key` (+param), `account_scope_clause`. Fara infra noua.

### Auto-fixuri DESIGN (structurale — incorporate in stories)

Voci: Claude (primar) + Claude subagent. Scorecard: 1 CRITIC, 7 HIGH, 5 MEDIUM, toate CONFIRMED.

| # | Story | Gap | Fix incorporat | Sev |
|---|-------|-----|----------------|-----|
| F1 | US-010 | **CRITIC**: "culori distincte" e singura spec a singurului guard vizual contra riscului dominant | Badge **normativ**: Productie = fill plin, saturat, text alb, iconita + cuvant complet UPPERCASE cu diacritice ("PRODUCȚIE"); Testare = outline/tint linistit (muted/accent), receding. Asimetria de greutate ESTE designul | CRITIC |
| F2 | US-010 | HIGH: rosu (`--err`) rezervat erorilor, amber (`--warn`) ocupat de `.badge-env` legacy + needs_* | Token dedicat `--prod` (ex. brick `#B4452F`) SAU `--accent` plin pentru Productie; hex/token scris in AC, nu improvizat per template. (taste: hexul exact -> poarta) | HIGH |
| F3/F12 | US-010 | HIGH: "Test/Testare/prod/PRODUCTIE" folosite interschimbabil; bypass `labels.py` | `labels.py` adaugat in Fisiere: `ETICHETE_ENV` + `eticheta_env(env)->(text,css)` (oglindeste `eticheta_scurta`). Productie UPPERCASE+diacritice, Testare title-case; clase `.badge-prod/.badge-test` definite o data in base.html langa `.sugg-sursa` | HIGH |
| F11 | US-011 | HIGH: `.badge-env` EXISTENT in header arata `AUTOPASS_RAR_ENV` global -> dupa 5.20 e semantic gresit; doua indicatoare env cu surse diferite in acelasi viewport | US-011 retrage/repurpune header `.badge-env` (preferat: scos pentru user logat, inlocuit de indicatorul account-scoped din statusbar). NU coexista doua surse de adevar | HIGH |
| F4 | US-009 | HIGH: starea 0-medii e numita dar nedesignata; blocaj la commit (dupa munca) = calea minima | Blocaj la UPLOAD (nu commit): banner `--warn` (refoloseste pattern "Cont in asteptare", `_status.html:8`) + CTA link `?tab=cont`, inainte de drop-zone | HIGH |
| F5 | US-011 | HIGH: schimbarea silentioasa a default-ului (mediu dezactivat) nu are UI -> target real/test comuta fara ca userul sa stie | Toast explicit (componenta `#toast` exista) la schimbarea `rar_env_default` ca efect al disponibilitatii: "Mediul implicit a trecut pe X". Leaga de CEO-H | HIGH |
| F8 | US-009 | HIGH: o bifa la activare apoi nimic = sub-avertizare; modalul per-trimitere a fost respins (REQ-CONF) | Butonul de commit POARTA greutatea cand target=Productie: "Declară la PRODUCȚIE (real)" + culoarea Productie (FARA modal, FARA click extra -> nu incalca REQ-CONF). Copy bifa activare: adauga ireversibilitatea ("declarații oficiale, finale și fără anulare") | HIGH |
| F6/F7 | US-008/US-011 | MEDIUM: stari loading/error pt toggle HTMX + validare creds la RAR nespecificate; stare per-sectiune (activat-fara-creds-valide) | toggle: `hx-indicator` + disabled in zbor, pe esec NU schimba default + eroare; US-008 validare creds arata `htmx-indicator` ("se verifica la RAR…") + esec in `.banner` cu copy per-env (US-007); fiecare sectiune arata 3 stari: dezactivat / activat-fara-creds / disponibil | MEDIUM |
| F9/F10 | US-009 | MEDIUM/HIGH: selectorul absent la 1 mediu = env invizibil la import; default pre-bifat prod la prima trimitere | Mereu randeaza un indicator env la import (eticheta statica la 1 mediu, toggle la >=2, ACEEASI pozitie). Prod pre-bifat e sigur DOAR daca F8+F9 livreaza impreuna — legate explicit in AC | HIGH |
| F13 | US-010 | MEDIUM: sa nu forkeze un badge structural nou | Refoloseste idiomul `.sugg-sursa` (10px, weight 700, tint+border) pt Testare; Productie = aceeasi geometrie dar fill plin+alb+icon (spargerea e semnalul) | MEDIUM |

### Auto-fixuri ENG (corectitudine/deploy — incorporate in stories)

Voci: Claude (primar) + Claude subagent (verificat contra codului real). **Meta (eng 4a): toate auto-fixurile de mai jos sunt NORMATIVE si trebuie sa intre in AC-ul story-urilor inainte de implementare — un implementer care urmeaza AC-ul literal, fara ele, livreaza bug-urile critice.** G + 6a deja imbinate in AC US-001/US-013.

| # | Story | Gap (vs cod real) | Fix | Sev |
|---|-------|-------------------|-----|-----|
| E1/1a | US-006 | `get_token` purjeaza `submissions.rar_creds_enc WHERE account_id=?` -> dupa re-key, login TEST sterge creds efemere ale submission-urilor PROD ale contului -> prod blocat | `WHERE account_id=? AND rar_env=?` + test `test_purge_creds_doar_pe_env` | HIGH |
| 1b/E6 | US-006 | `recover_orphans` filtreaza doar pe `account_id`; iterat per sesiune (cont,env) reconciliaza orfanii prod contra endpoint TEST -> no-match -> re-POST prod = DUPLICAT real | +`rar_env` in WHERE; apelat per (cont,env) din `active()`; test orfan env A nereconciliat contra env B | HIGH/CRITIC |
| 3/E4 | US-003 | API channel (`router.py:223`) NU are dual-lookup; re-POST al unui rand pre-5.20 cu cheie env-aware rateaza randul legacy -> duplicat. Import dual-lookup ignora env-ul randului matchuit | Recompute-keys la migrare (US-001, vezi acolo) acopera ambele canale uniform; daca pastrezi dual-lookup, exista si in `router.py` SI gate pe `matched_row.rar_env==target_env` | HIGH |
| 1c/E8 | US-006 | `claim_one` nu selecteaza `s.rar_env` -> worker nu poate alege cheia sesiune/base_url/slot | AC explicit: claim selecteaza + propaga `rar_env` in dict-ul `claimed` | MEDIUM |
| 1d | US-006/US-001 | `worker_heartbeat` e un singur rand global (`WHERE id=1`); US-006 cere `last_rar_login_ok` PER env dar US-001 nu adauga schema per-env -> neimplementabil ca scris | Decizie: pastreaza heartbeat global (JWT/sesiune per env e suficient), scoate "per env" din AC US-006; SAU adauga coloana in US-001. Recomandat: global | MEDIUM |
| 1e | US-006 (doc) | `_refresh_nomenclator` upsert intr-un `nomenclator_rar` env-less la fiecare login; login test suprascrie cu coduri test, prod cu prod -> un cod valid pe prod poate fi respins la ingestie daca ultimul refresh a fost test | Documenteaza presupunerea (nomenclator identic intre medii — aceleasi 18 coduri) SAU scope per-env (out of scope acum). Minim: nota explicita | MEDIUM |
| 5 | US-005/US-013 | write-back creds API nevalidate -> slot durabil (vezi L de mai sus) | re-asignat la US-005/US-013; propaga doar dupa login reusit | MEDIUM/HIGH |
| 6a..6d | US-013 | ping-pong re-ADD / boot-crash / interim-creds / grep ambiguu | imbinate in AC US-013 (vezi acolo) | CRITIC/HIGH |

### ENG DUAL VOICES — CONSENSUS TABLE
```
  Dimension                      Claude   Subagent  Consensus
  ────────────────────────────── ──────── ───────── ────────────────────
  1. Architecture sound?         da/cond  da/cond   CONFIRMED (cond. fixuri)
  2. Test coverage sufficient?   lacune   +API b/c  CONFIRMED lacune
  3. Performance risks?          low      low       CONFIRMED low
  4. Security (creds routing)?   L/5      5+unvalid CONFIRMED
  5. Error paths (boot)?         E1/E9    6a/6b CRIT CONFIRMED (boot-crash)
  6. Deployment risk (DROP)?     migrare  CRIT/HIGH CONFIRMED ELEVAT -> intareste challenge A
```
Codex: indisponibil (N/A). Mesaj-cheie: caile de duplicat ireversibil (1b, 3) si boot-crash/ping-pong (6a, 6b) musca in productie; intaresc recomandarea de a amana DROP-ul (challenge A).

### Diagrama teste (codepath -> acoperire)
| Codepath nou | Story test | Stare |
|---|---|---|
| `medii_disponibile`/`rar_env_efectiv` | US-002 | acoperit |
| resolve target (cerere>default), respinge indisponibil | US-004 | acoperit |
| idempotency env-aware + **recompute legacy** | US-003/US-001 | GAP recompute -> adaugat |
| **migrare backfill `submissions.rar_env`** | US-001 | GAP (G) -> adaugat in AC |
| worker sesiune (cont,env) + base_url per env | US-006 | acoperit |
| **purge creds scoped pe env** | US-006 | GAP (E1) -> adaugat |
| **recover_orphans per env** | US-006 | GAP (1b) -> adaugat |
| **write-back slot routing** | US-005/013 | GAP (L/5) -> adaugat |
| reconcile endpoint per env (inline + **orfani**) | US-006 | inline acoperit; orfani GAP -> adaugat |
| **keepalive env (ancora globala)** | US-013 | GAP (M2) -> adaugat |
| DROP garda: assert + **idempotent re-run** + **fail-loud/no-crash** | US-013 | partial -> intarit (6a/6b/6c) |
| **API-channel idempotency back-compat** | US-003 | GAP (3) -> adaugat |
| badge/labels env | US-010 | acoperit |
| API `rar_target` default/explicit/invalid/indisponibil | US-005 | acoperit |
| config 2 sectiuni + confirmare prod | US-008 | acoperit |
| statusbar toggle viz + **retragere header `.badge-env`** | US-011 | toggle acoperit; header GAP (F11) -> adaugat |
| **live dual-env smoke** | US-012 | GAP (M) -> adaugat opt-in |

### Auto-fixuri DX (contract API extern — incorporate in stories)

Voci: Claude (primar) + Claude subagent (perspectiva integrator VFP/ROAAUTO). Riscul ireversibilitatii ridica stacheta pe claritate nume / eroare / discoverability pre-trimitere.

| # | Story | Gap | Fix | Sev |
|---|-------|-----|-----|-----|
| F1 | US-005/US-013 | Trei nume pt un concept: input `rar_target`, echo/DB `rar_env`, rar-creds `env` (US-013 AC scrie literal "rar_target/env") | **Un singur cheie: `rar_env`** pe input + output + rar-creds (englez snake, consistent cu coloana si `on_unmapped_error`). Scoate `rar_target`/`env`. (taste usor -> poarta) | HIGH |
| F2 | US-004 | Eroarea "mediu indisponibil" e proza, fara `cod`/envelope 6-chei/status; `errors.py` nu e in Fisiere | `RAR_MEDIU_INDISPONIBIL` in `errors.CATALOG` (problema/cauza cu lista disponibile/fix "activeaza in Cont"); adauga `errors.py` la Fisiere US-004; distinge literal-invalid (422 pydantic) de valid-dar-indisponibil (cod dedicat); acopera si cazul 0-medii | HIGH |
| F3 | US-004/contract | Flip runtime test->prod prin canal web: operator comuta disponibilitatea -> apelant API fara `rar_env` trece silentios pe prod (real). Migrarea previne flip la DEPLOY, nu la RUNTIME | Mitigat de F4+F5 (probe pre-trimitere); documenteaza reasignarea ca comportament cunoscut; leaga de CEO-H | HIGH |
| F4 | US-010 (sau story noua) | Niciun GET nu expune `medii_disponibile`/`rar_env_default` -> integratorul afla env-ul doar din eroare sau dupa o trimitere reala | `GET /v1/conturi/medii` account-scoped: `{medii_disponibile, rar_env_default, test:{enabled,has_creds}, prod:{...}}` (refoloseste helper US-002, <1 fisier) | HIGH |
| F5 | US-005 | `ValidareResult` (dry-run) NU ecou-ieste `rar_env`; dry-run e canalul sigur de a confirma unde ar ateriza o trimitere reala | adauga `rar_env: str` la `ValidareResult` + `/valideaza`; `models.py` | MEDIUM |
| F6 | US-004/US-005 | Respingere whole-request vs per-rand inconsistenta cu `on_unmapped_error` (per-rand, 200) | Decide + documenteaza; recomandat: corp parsabil imbogatit cu `cod` (prietenos VFP), noteaza asimetria intentionat | MEDIUM |
| F7 | US-005/US-010/US-004/US-013 | Contractul (sursa adevar) actualizat doar pt rar-creds; lipsesc field-ul nou, echo-ul, cod-ul nou. **`/v1/conturi/rar-creds` NU e documentat deloc azi** -> US-013 e documentare de la zero, nu amendament | AC explicit "update `api-rar-contract.md`" pe fiecare; US-013 documenteaza endpoint-ul intreg (req/resp, param env, slot default) | HIGH |
| F8 | US-013 (doc) | `env` optional default = slot default cont: integrator cu creds TEST pe cont nou (default prod) le scrie silentios in slot prod -> US-007 le respinge "invalide pe PRODUCTIE" desi sunt valide (test) | pastreaza aditiv; documenteaza ca omiterea `env` tinteste slotul default; mesaj validare sugereaza nepotrivire env ("creds valide pentru alt mediu?") | MEDIUM |

### DX DUAL VOICES — CONSENSUS TABLE
```
  Dimension                       Claude  Subagent  Consensus
  ─────────────────────────────── ─────── ───────── ──────────────
  1. Getting started (aditiv)?    low fr  low fr    CONFIRMED low
  2. Naming guessable?            D1 incon F1 3-nume CONFIRMED -> rar_env
  3. Error messages actionable?   D2 gap   F2 gap    CONFIRMED gap
  4. Docs findable & complete?    D4 gap   F7 gap+   CONFIRMED gap
  5. Back-compat safe?            D3 resid F3 runtime CONFIRMED (1 rezidual)
  6. Discoverability pre-send?    D5 gap   F4 gap    CONFIRMED gap
```
Codex: indisponibil (N/A). DX scor initial: ~6/10 (model API solid + aditiv, dar nume inconsistent + eroare neimbogatita + zero discoverability + contract neactualizat). Tinta dupa fixuri: ~9/10.

### Jurnal integrator (condensat)
| Etapa | Azi (plan brut) | Dupa fixuri DX |
|---|---|---|
| Afla env-urile contului | doar din eroare / dupa trimitere reala | `GET /v1/conturi/medii` |
| Trimite | `rar_target` (nume #1) | `rar_env` (un nume) |
| Confirma tinta fara trimitere reala | imposibil (valideaza nu ecou-ieste) | `/valideaza` ecou-ieste `rar_env` |
| Eroare tinta indisponibila | proza, fara cod | `cod: RAR_MEDIU_INDISPONIBIL` + fix |
| Citeste rezultatul | `rar_env` (nume #2) | `rar_env` (acelasi) |
| Doc | contract fara field/endpoint | contract complet |

## 8. Raport VERIFY — LIVRAT 2026-07-02

Toate 13 stories implementate TDD (RED->GREEN) prin subagenti sonnet; Opus a coordonat,
verificat si comis (git interzis subagentilor; commit dupa fiecare story, dupa incidentul
`git stash` care a distrus munca necomisa in sesiunea anterioara).

### Comituri (in ordine)
- `1648960` US-008 — configurare doua medii per cont + confirmare Productie unica (L.142) + selector default validat post-update.
- `3eaf1ca` fix test stale `test_list_accounts_ordonat_fara_creds` (coloane `requested_plan`/`consent_at`, ne-legat de 5.20).
- `d1978e2` US-011 — statusbar indicator mediu default + toggle la >=2 medii (HTMX, account-scoped) + retragere `badge-env` global din header pt utilizatorul logat.
- `0a1df31` US-010 — badge mediu (`PRODUCȚIE` fill de atentie / `Testare` outline) in liste/preview/detaliu/jurnal + `labels.eticheta_env` + `rar_env` in audit export si `GET /v1/prezentari(/{id})`; statusbar aliniat la aceeasi conventie.
- `3d3eb71` US-012 — audit `rar_env_activat`/`rar_env_dezactivat`/`rar_env_default_schimbat`/`rar_env_blocat` + teste e2e import->queued pe env corect (ambele canale).
- `b1d825e` US-013 — retragerea `accounts.rar_creds_enc`: ~15 citiri mutate pe sloturile per-env, `POST/DELETE /v1/conturi/rar-creds` env-aware (contract aditiv), DROP cu garda.

### DROP cu garda (US-013, cele 4 auto-fixuri)
- **6a**: eliminat `ADD COLUMN rar_creds_enc` din `db.py` (fara ping-pong re-ADD dupa DROP); `schema.sql` fara coloana pe DB fresh.
- **6b**: intreg DROP-ul in `try/except` fail-safe (nu crapa boot-ul ambelor procese) + garda `sqlite_version >= 3.35`.
- **6c**: re-backfill old->new (ancora globala `AUTOPASS_RAR_ENV`) imediat inainte de assert.
- **Garda orfane**: DROP anulat daca vreun `rar_creds_enc` non-null nu a aterizat in niciun slot per-env (fail-safe, fara pierdere de date).
- **Backup** criptat `accounts_rar_creds_enc_backup` inainte de DROP.
- **6d**: verificare prin `PRAGMA table_info(accounts)` (NU grep — `submissions` are aceeasi coloana, ramane neatinsa).
- Idempotenta la boot repetat verificata manual (boot fresh dropeaza; al doilea boot fara re-ADD, fara crash).

### Rezultat suita
`python3 -m pytest -q -m "not live"` -> **1455 passed, 1 deselected (live)**. Cele 3 esecuri sunt NE-legate de 5.20:
- `test_web_responsive::test_login_branded_nu_schelet`, `test_landing_limita_60` — pre-existente (landing/login, semnalate din checkpoint).
- `test_web_status::test_granita_miez_noapte_local_ro` — flake nocturn: testul construieste boundary = `UTC-ziua-trecuta 22:00` si compara cu `date('now','localtime')` in RO; esueaza in fereastra de dupa miezul noptii RO (rulare la 21:02 UTC = 00:02 RO). Bug de test (nu de cod: `_status_counts`/SQL neatins de 5.20), de reparat deterministic separat.

grep `rar_creds_enc` in `app/` = doar referinte pe `submissions` (efemer per-cerere). Contract API actualizat in `docs/api-rar-contract.md`.
