Files
rar-autopass/docs/prd/prd-5.20-target-rar-test-productie.md
Claude Agent b4818349be docs(5.20): PRD medii RAR per cont (Testare/Productie) aprobat + roadmap
Doua medii RAR configurabile per cont, fiecare cu bifa de activare si set
propriu de credentiale. medii_disponibile=enabled AND creds deriva tot UX-ul.
13 stories / 6 valuri. Premisa verificata live: test/prod = sisteme separate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 19:27:50 +00:00

41 KiB

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.pytest_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.pytest_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.pytest_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.pytest_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.pytest_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.pytest_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.pytest_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.pytest_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.pytest_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.pytest_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.pytest_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.pytest_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.pytest_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)

  • Default API = default-ul contului (NU „test" hardcodat), fiindca clientii sunt prod-only. CONFIRMAT.
  • Activare implicita cont nou = Productie on / Testare off; contul operator setat manual pe Testare. CONFIRMAT.
  • Confirmare Productie = o data, la activarea mediului in configurare (nu per trimitere). CONFIRMAT.
  • 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.


/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