Inlocuieste cele 3 controale de asociere cod RAR cu un singur rand de chips + un singur select care adauga instant la change. Stare = un hidden chips_state JSON versionat; post_form_chips redus la 2 actiuni (add/remove). Optgroup Sugestii (fuzzy/k-NN) + optiune "Nu se declara la RAR" in select, cu tinta implicita evidentiata si placeholder care o numeste. exclus persistat prin payload_json (treapta noua de precedenta in resolve_prestatii, round-trip complet). Siguranta: itemii exclusi sunt scosi din payload la momentul trimiterii (worker split_prestatii_excluse inainte de build_rar_payload + filtru defensiv), ca sa nu ajunga NICIODATA la RAR ca codPrestatie:null. Suita: 1680 passed, 1 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 KiB
PRD 5.23 — Editor prestatii unificat in modalul "Editare rand" (un select, un rand de chips)
Stare: inchis (2026-07-08; executie echipa agenti Sonnet TDD, VERIFY context curat PASS, code-review CLOSE = 1 blocker de siguranta prins + reparat. Vezi Anexa /autoplan, GSTACK REVIEW REPORT, Raport VERIFY; mockup final aprobat: select cu placeholder-tinta)
Proces:
docs/ROADMAP.md§5. Contract RAR:docs/api-rar-contract.md. Context vizual: screenshot2026-07-07-003.jpg(modal "Editare rand 4", badge "Cod RAR lipsa").
1. Obiectiv
Modalul "Editare rand" (import preview + corectie Trimiteri) are azi TREI controale pentru aceeasi sarcina — asocierea codurilor RAR la prestatii: (1) rand per operatie cu select "— alege cod RAR —"
- buton "Adauga", (2) container separat de chips pentru coduri libere (ex.
OE-1 ×), (3) select "+ Adauga alta operatie / cod RAR" cu buton "+". Utilizatorul nu stie care control face ce, iar chips-urile apar in containere diferite, pe randuri diferite.
Livrabila: un singur control — un rand unic de chips (toate codurile, legate de operatie sau libere) + un singur select care adauga chip instant la selectie (fara butoane "Adauga"/"+"). Selectul primeste sugestii fuzzy/k-NN pentru operatia nemapata si optiunea "Nu se declara la RAR".
2. Non-Goals (anti scope-creep)
- NU se schimba panoul de mapare (
_mapari.html,_preview_import.html). EXCEPTIE confirmata in review (eng, 2026-07-07):resolve_prestatiiprimeste O SINGURA treapta noua de precedenta —exclus=1explicit pe item (din override/corectie) supravietuieste re-rezolvarii (aziit.pop("exclus", None)lamapping.py:298il sterge, ceea ce face US-004 imposibil altfel). Restul precedentei ramane neatins. - NU se schimba contractul API
POST /v1/prezentari.override_json["prestatii"]castiga campulexcluspe item; itemii exclusi RAMAN inpayload_json(adnotati), nu mai sunt eliminati la salvare —split_prestatii_excluseii scoate doar din payload-ul trimis la RAR. - NU se schimba validarea codului fata de nomenclator la salvare (invariant ORA-12899) — ramane.
- NU se adauga cautare/autocomplete text in select (ramane
<select>nativ; imbunatatire separata). - NU se atinge butonul "salveaza ca regula" de la Trimiteri — ramane, doar mutat pe chip-ul nou.
3. Comportamentul controlului unificat (spec)
Prestatii — coduri RAR
┌───────────────────────────────────────────────────────────────┐
│ [⚠ OP-ITP · fara cod] [OE-1 ×] [— alege cod RAR — ▾] │
└───────────────────────────────────────────────────────────────┘
- Un singur container
.chipscu toate elementele: chips-uri cod (× sterge), chips-uri warning pentru operatii nemapate, si selectul unic la capat. Wrap natural doar la lipsa de spatiu — niciodata containere/chenare separate pe zone. - Chip cod legat de operatie: eticheta
COD, titlu/tooltip cu denumirea operatiei sursa (ex.OE-8 — Inlocuire anvelope).×scoate codul; daca operatia ramane fara cod, reapare chip-ul warning al operatiei. - Chip cod liber (fara operatie sursa): identic vizual, tooltip "cod adaugat manual".
- Chip warning (
⚠ OP-ITP · fara cod): reprezinta operatia din import nemapata. Click pe el il face tinta activa (evidentiat); implicit tinta = prima operatie nemapata. - Selectul unic,
hx-trigger="change"→POST /form-chipscuchips_action=add:- daca exista tinta activa (operatie nemapata) → codul se leaga de acea operatie (chip warning → chip cod); tinta trece automat la urmatoarea operatie nemapata;
- placeholder-ul selectului numeste tinta (decizie gate D2, 2026-07-07): cu tinta activa →
Cod pentru OP-X — alege; fara tinta →— adauga cod RAR —. Legatura cod↔operatie e explicita la momentul alegerii, fara text suplimentar sub control; - fara operatii nemapate → codul se adauga ca chip liber;
- dupa adaugare selectul revine la placeholder; chip-ul nou primeste evidentierea
.chip-nou.
- Continutul selectului, cand tinta e o operatie nemapata:
optgroup "Sugestii"sus: sugestia principala + fuzzy/k-NN top-3 pentru denumirea operatiei (aceleasi surse ca in_preview_import.html:89-121);- optiunea
"Nu se declara la RAR (exclude operatia)"= sentinel__NEDECLARAT__(EXCLUDE_SENTINEL,app/mapping.py:44) → operatia primeste chip distinctNedeclarat(stil mut, ×-ul readuce chip-ul warning), item anotatexclusin starea chips; - restul nomenclatorului, ca azi.
Fara tinta (doar cod liber): fara optgroup Sugestii si fara
__NEDECLARAT__.
- Dedup: acelasi
(operatie, cod)nu se adauga de doua ori (comportament existent pastrat). - Fara text explicativ permanent sub control (decizie utilizator la aprobarea mockup-ului,
2026-07-07): starea tintei se comunica DOAR vizual (stilul chip-ului warning evidentiat);
mesajele
chips_ok/chips_errorraman exclusiv ca feedback tranzitoriu la actiuni. - Mockup aprobat: artifact "Mockup — Editor prestatii unificat (PRD 5.23)".
- Modul plat (corectii fara operatii din import) foloseste ACELASI control: zero chips warning,
selectul adauga doar coduri libere. Logica
has_r_odo/data-has-r-odo(reveal odometru initial pe R-ODO/I-ODO) si stilulchip-warnpe aceste coduri se pastreaza neschimbate.
3.1 Specificatie vizuala si de stari (din review-ul de design, 2026-07-07)
Scara de dominanta vizuala — UN SINGUR tratament puternic simultan:
| Element | Fundal / chenar / text | Nota |
|---|---|---|
| Chip tinta activa | fundal warn-soft, chenar SOLID 1px --warn + inel 2px warn-transparent |
singurul element "tare" din rand |
| Chip warning (ne-tinta) | fundal warn-soft, chenar DASHED 1px --warn |
click → devine tinta |
| Chip cod | fundal --card2-albastru (--accent 15%), text --accent, chenar subtil |
eticheta COD mono |
| Chip Nedeclarat | fundal gri mut, text taiat (line-through), chenar dashed gri | NU discret pana la invizibil |
.chip-nou |
animatie de emfaza >=1.5s (fade), tranzitorie | nu concureaza cu tinta |
| Chip R-ODO/I-ODO | chip-warn existent, neschimbat |
reveal odometru pastrat |
Invariante de interactiune:
- Ordinea chips e STABILA: operatiile in ordinea din import, codurile libere la coada; o rezolvare nu re-ordoneaza randul (warning → cod in acelasi slot).
- Cat exista operatii nemapate, EXISTA tinta (implicit prima nemapata); click pe tinta activa = no-op (nu se poate "deselecta" — adaugarile libere sunt posibile doar fara warnings).
- Click pe chip warning = comutare de tinta CLIENT-SIDE (toggle clasa + hidden
chips_target_index), fara round-trip; indexul tintei pleaca la server la urmatorul add. - Selectul are id stabil (
chips-picker); dupa swapouterHTML, focusul revine pe select. - Optiunile selectului:
COD — denumire nomenclator; in optgroup "Sugestii" acelasi format (optgroup-ul e singura marca de sugestie). Eticheta chip warning: max ~18ch + ellipsis, text complet intitle.
Tabel de stari (ce VEDE utilizatorul):
| Stare | Ce se vede |
|---|---|
| Loading (add in zbor) | selectul disabled (hx-disabled-elt="this") + stil .htmx-request pe sectiune; dedup face inofensiv un dublu-fire |
| Eroare add (400/500/retea) | mesaj chips_error SUB control (pattern 5.22, persista pana la urmatoarea actiune); selectul re-activat; tinta neschimbata; hx-on::response-error acopera esecul de retea |
| Gol (mod plat, zero chips) | doar selectul cu placeholder "— adauga cod RAR —"; container cu min-height (modalul nu salta la primul chip) |
| Succes partial | chip-ul nou cu emfaza >=1.5s; tinta avanseaza (vezi decizia de la gate) |
| Complet (zero nemapate) | mesaj tranzitoriu "Toate operatiile au cod" (chips_ok); optgroup Sugestii si __NEDECLARAT__ dispar din select |
| Nedeclarat | mesajul numeste operatia: "OP-X nu se va declara la RAR" |
| Nomenclator gol | empty state existent (pastrat) |
4. Stories atomice
US-001: Stare chips extinsa cu exclus + actiuni add/remove unificate in backend
Ca dezvoltator vreau o singura pereche de actiuni add/remove pe starea chips (cu tinta
optionala si suport sentinel __NEDECLARAT__) pentru ca azi exista 4 actiuni suprapuse
(add, add_flat, add_extra, remove_flat) care dubleaza logica.
- Depinde de: —
- Fisiere:
app/web/routes.py(post_form_chips:2402-2521,_chips_state_from_form:3862-3918),tests/test_web_chips.py(~2 fisiere) - Test intai (RED):
tests/test_web_chips.py—test_add_cu_tinta_leaga_de_operatie,test_add_fara_tinta_adauga_cod_liber,test_add_nedeclarat_marcheaza_exclus,test_remove_cod_readuce_operatia_nemapata,test_dedup_operatie_cod - Acceptance criteria:
- Starea chips serializata intr-UN SINGUR hidden
chips_state= JSON versionat ({"v":1,"items":[{"cod":"","op":"","den":"","exclus":0},...]}) — decizie gate D4: elimina structural clasa de bug-uri de aliniere pe index (2 regresii in 2 release-uri)._chips_state_from_formparseaza JSON-ul; JSON invalid → eroare vizibila, nu stare goala. - Compat tranzitorie la deploy: daca
chips_statelipseste dar exista listele vechi (cod_prestatie/chip_op_service/chip_denumire), parserul cade inapoi pe ele cuexclus=0(form-uri deschise peste deploy); fallback-ul se sterge in release-ul urmator. chips_stateprezent mereu (lista goala ={"v":1,"items":[]}): golirea intentionata a chips se persista la salvare (inlocuieste santinelachips_present).chips_action=add+chips_target_index=ileaga codul de operatia i; fara target → chip liber; cod__NEDECLARAT__+ target → item cuexclus=1si faracod_prestatie.chips_action=remove(index unic) acopera si fostulremove_flat; actiunileadd_flat/add_extra/chips_add_cod_{i}/chips_add_cod_flatsunt eliminate.- Tinta implicita dupa un add reusit = urmatoarea operatie nemapata (sau nici una).
- Validare tinta SEMANTICA, nu doar in-range:
chips_target_indextrebuie sa arate spre o operatie nemapata si ne-exclusa; altfelchips_error(acopera POST fabricat si index stale dupa un remove). chip_exclusparsat strict ("1"→1, orice altceva→0);__NEDECLARAT__fara tinta valida →chips_errorexplicit.- Testele existente pe actiunile vechi (
tests/test_web_corectie_prestatii.py,tests/test_web_form_editare_slim.py) sunt ACTUALIZATE in acelasi val (suita nu ramane rosie intre valuri). - Emfaza chip nou pe INDEX (
chips_added_index), nu pe valoarea codului (doua operatii pot avea legitim acelasi cod). python3 -m pytest -qtrece.
- Starea chips serializata intr-UN SINGUR hidden
- Verificare E2E: acoperit de US-005.
US-002: Template unificat — un container, un select, fara butoane Adauga/+
Ca operator vreau un singur rand de chips si un singur select care adauga instant pentru ca azi nu stiu care din cele 3 controale trebuie folosit.
- Depinde de: US-001
- Fisiere:
app/web/templates/_chips_prestatii.html(rescriere),app/web/templates/base.html(CSS.chips/.chip*:815-843, eliminare.op-row),tests/test_web_chips.py(~3 fisiere) - Test intai (RED):
tests/test_web_chips.py—test_render_un_singur_container_chips,test_render_fara_op_row_si_fara_butoane_adauga,test_chip_warning_pentru_operatie_nemapata - Acceptance criteria:
- Un singur container
.chipscontine: chips cod (cu tooltip operatia sursa), chips warning operatii nemapate, chipNedeclaratpentru itemi exclusi, selectul unic la capat. - Selectul (nume camp:
chips_pick, id stabilchips-picker) arehx-trigger="change",hx-post="/form-chips",hx-target="#chips-section",hx-swap="outerHTML",hx-include="closest form"(transporta CSRF + starea hidden — omiterea = 403) sihx-disabled-elt="this"(capcana htmx din 5.22 — NU mosteni de la form). - Selectul revine la placeholder dupa ORICE raspuns (succes SI eroare); valoarea ramasa in
chips_pickNU e aplicata la Salveaza pe niciuna din cai (regresiac6e29aanu reapare sub alt nume — codul se adauga DOAR prin actiunea add). - Pe durata unui request /form-chips, INTREAGA sectiune e inerta (
pointer-events:nonepe.htmx-requestsau echivalent) — click pe × / chip warning mid-flight nu pierde actiuni. - Click pe chip warning comuta tinta CLIENT-SIDE (clasa + hidden
chips_target_index), fara round-trip; click pe tinta activa = no-op. - Focus restaurat pe
#chips-pickerdupa swap. - Zero aparitii
op-row,Adauga,add_flat,chips_add_cod_in template. chips_submission_ide emis ca hidden in sectiune si ecouat de/form-chips, astfel incat "salveaza ca regula" ramane disponibil si DUPA re-randari (azi dispare la prima interactiune — bug perpetuat altfel).
- Un singur container
- Verificare E2E: acoperit de US-005.
US-003: Sugestii fuzzy/k-NN + optiunea "Nu se declara la RAR" in selectul unic
Ca operator vreau sugestiile de mapare direct in selectul din modal pentru ca azi ele exista doar in panoul de mapare, iar in modal caut manual prin tot nomenclatorul.
- Depinde de: US-001, US-002
- Fisiere:
app/web/routes.py(post_form_chips— construire sugestii pentru operatia tinta, refolosind sursele din preview),app/web/templates/_chips_prestatii.html,tests/test_web_chips.py(~3 fisiere) - Test intai (RED):
tests/test_web_chips.py—test_select_are_optgroup_sugestii_pt_tinta,test_select_are_nedeclarat_doar_cu_tinta,test_select_fara_tinta_fara_sugestii - Acceptance criteria:
- Cu tinta activa:
optgroup "Sugestii"cu sugestia principala + top-3 fuzzy/k-NN pentrudenumire-a operatiei; sub el optiunea__NEDECLARAT__; apoi nomenclatorul complet. - Fara tinta: selectul listeaza doar nomenclatorul (fara Sugestii, fara
__NEDECLARAT__). - Sugestiile folosesc aceleasi functii ca
_preview_import.html(fara drum nou de cod). - Degradare gratioasa: motor de sugestii rece/dezactivat → select DOAR cu nomenclatorul (fara optgroup), fara eroare si fara blocare pe warmup (lock non-blocking, PRD 5.21).
python3 -m pytest -qtrece.
- Cu tinta activa:
- Verificare E2E: acoperit de US-005.
US-004: Persistarea exclus prin salvare (import + Trimiteri) — cu round-trip complet
Ca operator vreau ca excluderea aleasa in modal sa se pastreze la salvare, sa produca starea corecta si sa fie REVERSIBILA la redeschidere pentru ca altfel optiunea din select ar fi cosmetica sau, mai rau, operatia ar fi declarata contra intentiei mele (RAR e ireversibil).
Corectie din review (eng, CONFIRMATA in cod): pipeline-ul actual sterge
exclusper-item (resolve_prestatiifaceit.pop("exclus", None),mapping.py:298) si elimina itemii exclusi dinpayload_jsonla corectie (routes.py:1744). Fara fix-urile de mai jos, un item exclus din modal ar revenineeds_mappingsau — daca operatia are mapare pe cont — ar fi DECLARAT la RAR.
- Depinde de: US-001
- Fisiere:
app/mapping.py(resolve_prestatii— treapta noua: item-exclus explicit supravietuieste),app/web/routes.py(web_editeaza_rand,post_corectie_trimitere:1619,_prestatii_chips_from_payload:1336 + toti constructorii de context chips),app/api/v1/import_router.py(apply_row_override:319-366),tests/test_web_editare_rand.py(~4 fisiere) - Test intai (RED):
tests/test_web_editare_rand.py—test_salvare_pastreaza_exclus_in_override,test_exclus_supravietuieste_resolve_chiar_cu_mapare_pe_cont,test_redeschidere_modal_arata_chip_nedeclarat_si_x_readuce_warning,test_rand_toate_operatiile_excluse_devine_excluded,test_salvare_trimitere_cu_exclus - Acceptance criteria:
resolve_prestatiipastreazaexclus=1venit explicit pe item (precedenta: item-exclus > cod explicit > regula exclus cont > mapare > reguli text); restul treptelor neschimbate.- Itemii exclusi RAMAN in
payload_json/override_jsonadnotati cuexclus=1;split_prestatii_excluseii scoate DOAR din payload-ul trimis la RAR si din cheia idempotenta. - Toti constructorii de chips (
_prestatii_chips_from_payload, preview, re-render eroare) propagaexclus→ chipNedeclaratreapare la redeschidere;×il readuce la warning. - Rand cu toate operatiile excluse → stare preview
excluded("Nedeclarat"); la Trimiteri →needs_datacu motiv explicit (invariantele existente). - Validarea cod-vs-nomenclator la salvare ramane; sentinelul
__NEDECLARAT__e RESPINS explicit daca apare cacod_prestatiein starea hidden (nu doar in select), pe ambele cai. python3 -m pytest -qtrece.
- Verificare E2E: acoperit de US-005.
US-005: Verificare E2E browser pe ambele fluxuri
Ca lead vreau dovada in browser ca editarea e acum un singur control coerent pentru ca bug-ul raportat e de UX vizual, nu doar de logica.
- Depinde de: US-002, US-003, US-004
- Fisiere: — (doar verificare; eventuale fix-uri in fisierele de mai sus)
- Test intai (RED): —
- Acceptance criteria:
- Import preview: rand cu operatie nemapata + cod liber → modalul arata UN rand de chips (warning + cod + select), fara chenare/zone separate; screenshot atasat la raport.
- Selectarea unui cod din Sugestii transforma chip-ul warning in chip cod, instant, fara "+".
- Alegerea "Nu se declara la RAR" produce chip
Nedeclarat; salvare → rand "Nedeclarat". - Trimiteri (
/trimitere/{id}corectie): acelasi control, "salveaza ca regula" functional. - Salvarea persista chips-urile (regresie
c6e29aa) si nu reapar controale duble la re-deschidere.
- Verificare E2E: browser HTMX pe http://localhost:8010/ (import xlsx test + o trimitere
needs_mapping), conform pasilor de mai sus.
5. Riscuri
hx-disabled-eltmostenit de la form a mai rupt butoanele chips o data (5.22) — selectul unic primeste explicithx-disabled-elt="this"; test de template pentru atribut.changepe select nativ se declanseaza si la navigarea cu tastatura pe unele browsere vechi; acceptat (comportamentul modern e la confirmare), iar chip-ul gresit se sterge cu un click.- Compatibilitate stare veche: submission-uri/override-uri existente fara
chip_exclustrebuie citite caexclus=0(default la deserializare) — altfel salvarea de pe randuri vechi crapa. - Doua endpoint-uri de save (import + Trimiteri) cu acelasi contract de campuri — orice
schimbare de nume de camp se face simultan in ambele, plus
_chips_state_from_formunic partajat.
6. Intrebari deschise
Rezolvate cu utilizatorul la aprobare (2026-07-07):
×pe un chipNedeclarat→ readuce chip-ul warning al operatiei (operatia NU se sterge).- Selectul unic ramane
<select>nativ cu tot nomenclatorul — acceptat; autocomplete ramane non-goal.
7. Valuri de executie (graful de dependente)
Val 1: [US-001] ← fara dependente
Val 2: [US-002] [US-004] ← deblocate de US-001, fisiere distincte → paralel
Val 3: [US-003] ← deblocat de US-002
Val 4: [US-005] ← verificare finala E2E
Anexa /autoplan — Review CEO (Faza 1, 2026-07-07, mod SELECTIVE EXPANSION, voci: subagent-only)
NOT in scope (decizii din review)
- Autocomplete/cautare in picker — non-goal confirmat de utilizator.
- Schimbarea panoului de mapare / precedentei
resolve_prestatii— non-goal PRD. - Badge-uri sursa sugestie (GOLD/SILVER) in select — respins (P5): optgroup "Sugestii" e suficient.
- "Bulk: aplica maparea la N randuri identice" in preview — deferat TODOS (in afara blast radius).
- Metrici de baza (deschideri modal / % randuri mapate manual) — deferat TODOS.
What already exists (refolosit, nu reconstruit)
- Stare chips in hidden inputs +
/form-chipsstateless (_chips_prestatii.html,routes.py:2402). - Validare cod vs nomenclator la add si la save (
c6e29aa); mesajechips_error/chips_ok(5.22). - Sugestii:
suggest_codes+sugestie_principala(mapping.py:117,868) — aceleasi surse ca preview. EXCLUDE_SENTINEL/split_prestatii_excluse(0bc6187);apply_row_override(c6e29aa).- Empty state nomenclator lipsa;
has_r_odo/reveal odometru; buton "salveaza ca regula" (Trimiteri).
Dream state delta
Planul muta editorul de la 3 controale/4 actiuni la 1 control/2 actiuni si aduce sugestiile in modal — pas direct spre idealul 12 luni (o singura componenta de mapare peste tot). Ramase pe traiectorie: autocomplete (daca nomenclatorul creste), componenta partajata cu panoul de mapare.
Arhitectura (Sectiunea 1)
[modal Editare rand]──include──▶[_form_editare]──include──▶[_chips_prestatii (REWRITE)]
│ │ hx-post change/×
▼ ▼
POST editeaza (import) ─┐ POST /form-chips (add|remove)
POST corecteaza (Trim.) ─┴─▶ _chips_state_from_form ──▶ apply_row_override(prestatii+exclus)
│ (commit)
suggest_codes/mapping.py ◀──────┘ resolve + split_prestatii_excluse
Cuplaj NOU: /form-chips → motorul de sugestii (pana acum doar preview-ul) — justificat (reuse),
cu conditia caii NE-blocante pe request (lock embeddings non-blocking, PRD 5.21). Fara migrare DB
(exclus traieste in override_json). Rollback: git revert simplu. Fereastra de deploy: un modal
deschis peste deploy trimite campuri vechi (chips_add_cod_{i}) pe care handlerul nou le ignora
— utilizatorul redeschide editarea; acceptat (sesiune de editare scurta).
Registru erori & rescue (Sectiunea 2)
CODEPATH | CE POATE ESUA | TRATARE | USER VEDE
--------------------------|------------------------------------|--------------------------------|-----------
/form-chips add | cod gol / necunoscut | chips_error (exista) | mesaj rosu
/form-chips add | index tinta iesit din forma | chips_error (exista) | mesaj rosu
/form-chips add NED | __NEDECLARAT__ fara tinta | GAP -> chips_error nou | mesaj rosu
/form-chips render | motor sugestii rece/dezactivat | GAP -> degradare la nomenclator| select fara optgroup
/form-chips | nomenclator gol | empty state (exista) | avertisment
save (ambele) | cod necunoscut in stare | re-render cu eroare (exista) | modal + eroare
save (ambele) | stare veche fara chip_exclus | default exclus=0 (PRD risc) | nimic (compat)
save (ambele) | CSRF invalid/expirat | 403 (existent) | eroare form
enqueue | toate operatiile excluse | excluded / needs_data (exista) | stare explicita
GAP-uri de inchis in implementare: NED-fara-tinta si degradarea sugestiilor (ambele = criterii noi).
Securitate (Sectiunea 3)
Fara endpoint nou. Input nou chip_exclus: parsare stricta ("1" -> 1, orice altceva -> 0).
Sentinelul __NEDECLARAT__ nu ajunge NICIODATA in payload RAR (split inainte de enqueue —
invariant existent; test explicit). XSS: denumire in options/title — autoescape Jinja (exista).
Sugestii cross-account: politica 5.14 (suggestion-only) neschimbata. CSRF pe /form-chips: exista.
Nicio amenintare High nemitigata.
Edge cases date/interactiune (Sectiunea 4)
- Dublu
changein zbor:hx-disabled-elt="this"pe select (criteriu US-002). - Focus pierdut dupa swap
outerHTML: focusul revine pe select dupa add (criteriu nou US-002). - Navigare cu tastatura prin select declanseaza change pe unele browsere: acceptat (PRD risc), chip-ul gresit se scoate cu un click.
- Iesire din modal mid-edit: stare pierduta (comportament existent, form-local) — neschimbat.
- Dedup (operatie,cod) si cod liber duplicat: exista, se pastreaza.
- Mod plat +
has_r_odo: pastrate explicit (spec actualizat).
Calitate (Sectiunea 5)
4 actiuni -> 2 reduce ramificarea din post_form_chips (~120 linii azi). _chips_state_from_form
ramane UNICUL parser, partajat de ambele endpoint-uri de save (risc PRD; test comun).
Alternativa "un singur camp hidden JSON" in loc de 4 liste paralele — decizie de gust (vezi gate).
Teste (Sectiunea 6) — completari la RED-urile din PRD
test_add_nedeclarat_fara_tinta_da_eroare(US-001)test_sugestii_indisponibile_degradare_fara_optgroup(US-003)test_mod_plat_fara_operatii_select_doar_coduri_libere(US-002)test_has_r_odo_pastrat_dupa_actiuni(US-002)test_sentinel_nedeclarat_nu_ajunge_in_payload(US-004)- Template:
test_select_are_hx_disabled_elt_this(capcana 5.22)
Performanta (Sectiunea 7)
Sugestiile se calculeaza la FIECARE re-render /form-chips pentru operatia tinta — bounded (matvec numpy 5.21, corpus 17k, <100ms tipic); calea request NU asteapta warmup (lock non-blocking). 18 optiuni in select — trivial. Fara probleme.
Observabilitate (Sectiunea 8)
Starea randurilor e deja vizibila in dashboard (needs_mapping/excluded). Gap acceptat si deferat TODOS: metrica "deschideri modal / sugestie acceptata" (leaga de decizia de produs, nu de 5.23).
Deploy (Sectiunea 9)
Fara migrare, fara feature flag (UI inlocuit atomic in acelasi template). Worker neatins. Post-deploy: smoke = deschide un rand needs_mapping, adauga un cod, salveaza.
Traiectorie (Sectiunea 10)
Reversibilitate 4/5 (revert curat; starile cu exclus persistate raman valide — split exista
independent). Datorie REDUSA (actiuni duplicate eliminate). Comentariul de header din
_chips_prestatii.html se rescrie (diagrama noua a starii — parte din US-002).
Design/UX la nivel CEO (Sectiunea 11)
Ierarhie: chips (starea) inaintea selectului (actiunea) — corect. Stari acoperite: gol (hint), nomenclator lipsa, eroare, succes, exclus. Mobil: rand cu wrap; latimea selectului pe 390px = criteriu in faza Design. Accesibilitate: aria-labels existente se pastreaza; focus dupa swap. Riscul de mis-binding (tinta implicita + fara text permanent) — ridicat de vocea externa, decizie la gate. Detaliu complet in Faza 2 (plan-design-review).
Decision Audit Trail (/autoplan)
| # | Faza | Decizie | Clasificare | Principiu | Rationament | Respins |
|---|---|---|---|---|---|---|
| 1 | CEO | Abordare A (rescriere template + unificare actiuni) | Mecanica | P1,P5 | B pastreaza confuzia; C incalca non-goal aprobat | B, C |
| 2 | CEO | A11y tastatura + focus dupa swap → criterii US-002 | Mecanica | P1 | in blast radius, 2 fisiere | — |
| 3 | CEO | Badge sursa sugestie in select → respins | Mecanica | P5 | optgroup "Sugestii" spune deja asta | badge-uri |
| 4 | CEO | Bulk-apply mapare pe randuri identice → TODOS | Mecanica | P2,P3 | in afara blast radius (panou preview = non-goal) | — |
| 5 | CEO | Metrici deschideri-modal/sugestii → TODOS | Mecanica | P3 | produs, nu 5.23 | — |
| 6 | CEO | GAP-uri erori (NED-fara-tinta, degradare sugestii) → criterii noi | Mecanica | P1 | zero silent failures | — |
| 7 | CEO | Auto-advance tinta + fara eticheta pe select | TASTE (gate) | — | voce externa: risc mis-binding pe declaratii ireversibile | — |
| 8 | CEO | Paleta click 18 coduri vs select nativ | TASTE (gate) | — | premisa "tot nomenclatorul" e falsa (18 coduri fixe) | — |
| 9 | CEO | Stare chips: 4 liste hidden vs un camp JSON | TASTE (gate) | — | a 3-a regresie in zona; JSON = sursa unica | — |
| 10 | CEO | Test cu operator real in US-005 | Mecanica | P1 | verifica direct riscul de mis-binding; cost ~0 | — |
| 11 | Design | Scara de dominanta vizuala (tabel §3.1) | Mecanica | P1,P5 | 3 tratamente concurente fara ierarhie = confuzia initiala reambalata | — |
| 12 | Design | Stari loading/eroare/gol/complet specificate (tabel §3.1) | Mecanica | P1 | eroarea de retea lasa selectul disabled permanent altfel | — |
| 13 | Design | Tinta invarianta (exista cat sunt nemapate; click pe tinta = no-op) | Mecanica | P5 | interzice starea "cod liber cu warnings inca pe rand" tacuta | — |
| 14 | Design | Comutare tinta CLIENT-SIDE (fara round-trip) | Mecanica | P3 | round-trip pe click de highlight = lent + race cu add-ul in zbor | server-side |
| 15 | Design | Ordine chips stabila + focus pe select dupa swap | Mecanica | P1 | reflow-ul + focusul pierdut rup fluxul de tastatura pe 10 randuri | — |
| 16 | Design | Optiuni COD — denumire; chip warning ellipsis 18ch |
Mecanica | P5 | 18 coduri criptice fara denumire = memorare fortata | — |
| 17 | Design | Nedeclarat vizibil (line-through, nu mut) + mesaj cu numele operatiei | Mecanica | P1 | cea mai riscanta actiune legala nu poate fi cea mai discreta | stil mut |
| 18 | Design | Mesaje chips_ok/err raman pattern 5.22 (persista pana la actiune) | Mecanica | P4 | timer de auto-dismiss = JS nou fara valoare | timer 4s |
| 19 | Design | Auto-advance tinta: pastrat cu emfaza vs eliminat | TASTE (gate) | — | CEO-voice: elimina (mis-binding); Design-voice: pastreaza (momentum) + emfaza | — |
| 20 | Design | Touch targets × pe chips sub 44px (UI compact 11px existent) | Mecanica | P4 | consecvent cu design-ul compact existent; nota in TODOS a11y | 44px |
| 21 | Eng | exclus supravietuieste resolve_prestatii (treapta noua, non-goal amendat) |
Mecanica | P1 | P1 confirmat: it.pop("exclus") mapping.py:298 face US-004 imposibil; alternativa (regula pe cont) schimba semantica aprobata |
regula per-cont; taierea US-004 |
| 22 | Eng | Itemii exclusi raman in payload_json + exclus in toti constructorii de chips |
Mecanica | P1 | P1 confirmat: routes.py:1744 ii elimina → × pe Nedeclarat imposibil dupa salvare | — |
| 23 | Eng | chips_submission_id hidden + ecou in /form-chips ("salveaza ca regula" persistent) |
Mecanica | P1,P3 | butonul dispare azi la prima re-randare; fluxul nou trece TOT prin /form-chips | — |
| 24 | Eng | chips_pick reset dupa orice raspuns; valoarea NEaplicata la Salveaza |
Mecanica | P5 | clasa de bug c6e29aa; sentinel NED pozitional pe calea corectie | aplicare implicita |
| 25 | Eng | Validare semantica tinta + chip_exclus strict + sectiune inerta in request | Mecanica | P1 | POST fabricat / index stale / race mid-flight leaga codul de alt item | — |
| 26 | Eng | chips_present=1 — golirea listei se persista (nu no-op) |
Mecanica | P1 | _chips_state_from_form intoarce None pe form fara chips → golire imposibila |
no-op actual |
| 27 | Eng | Actualizarea testelor existente pe actiunile vechi in acelasi val | Mecanica | P6 | altfel suita e rosie intre Val 1 si Val 2 | — |
| 28 | Eng | Emfaza chip nou pe index, nu pe cod | Mecanica | P5 | doua operatii cu acelasi cod = dubla evidentiere falsa | — |
| 29 | Eng | Fara memoizare sugestii per re-render | Mecanica | P3 | rapidfuzz pe 18 randuri + k-NN gardat = bounded; memoizarea = complexitate fara castig | memoizare |
| D2 | Gate | Auto-advance pastrat + placeholder-ul selectului numeste tinta | USER | — | leaga explicit codul de operatie la momentul alegerii, fara text sub control | doar emfaza; fara auto-advance |
| D3 | Gate | Select nativ pastrat (mockup v1); paleta v2 vazuta si RESPINSA de utilizator | USER | — | directia utilizatorului; paleta ramane alternativa daca selectul se dovedeste lent (US-005 cu operator) | paleta 18 coduri |
| D4 | Gate | Stare chips = UN hidden chips_state JSON versionat + fallback tranzitoriu liste vechi |
USER | — | elimina clasa de regresii de aliniere pe index | 4 liste paralele |
| D5 | Gate | Plan revizuit APROBAT de utilizator | USER | — | — | — |
Anexa Eng (Faza 3) — diagrama de acoperire teste
CODE PATHS USER FLOWS
[+] post_form_chips (rescris, 2 actiuni) [+] Corectie rand cu N operatii nemapate
├── add cu tinta valida [RED planificat] ├── sugestie→chip instant [RED + E2E US-005]
├── add fara tinta (liber) [RED planificat] ├── comutare tinta client [E2E US-005]
├── add NED cu/fara tinta [RED planificat] ├── × pe cod → warning [RED planificat]
├── tinta semantica invalida [RED planificat] ├── NED → Nedeclarat → × [RED planificat]
├── remove index/liber [RED planificat] ├── eroare retea la add [→E2E] [GAP inchis §3.1]
└── dedup + cod necunoscut [exista, se muta] └── golire totala + salvare [RED chips_present]
[+] resolve_prestatii treapta item-exclus [RED planificat — REGRESIUNE potentiala: IRON RULE,
test obligatoriu ca exclus NU e sters si ca restul precedentei ramane identic]
[+] _chips_state_from_form (4 liste + compat vechi + liste scurte) [RED planificat]
[+] save x2 (import/corectie): exclus round-trip, NED respins, chips_pick ignorat [RED planificat]
[+] template: hx-atribute, focus, sectiune inerta, mod plat, has_r_odo [RED planificat]
COVERAGE planificata: 100% din ramurile noi au RED numit in stories. Fara eval-uri LLM (nu se
ating prompturi). Regresiune-cheie: precedenta resolve_prestatii → test dedicat blocant.
ENG DUAL VOICES — CONSENS (subagent-only):
Dimensiune Claude Codex Consens
1. Arhitectura solida? DA* N/A OK (directia 4→2 actiuni corecta; * dupa fix P1-uri)
2. Acoperire teste suficienta? NU→DA N/A FLAGGED→INCHIS (6 teste noi adaugate in stories)
3. Riscuri de performanta? NU N/A OK (18 coduri, k-NN gardat, bounded)
4. Securitate acoperita? PARTIAL→DA N/A INCHIS (validare semantica tinta, chip_exclus strict, NED respins la save)
5. Drumuri de eroare tratate? PARTIAL→DA N/A INCHIS (§3.1 + criterii noi)
6. Risc de deploy gestionabil? DA N/A OK (fara migrare; fereastra modal-peste-deploy acceptata)
Raport VERIFY
Verificator independent (subagent context curat, doar PRD + §5.6), 2026-07-08. VERDICT: PASS pe toate criteriile testabile; regresia de aur RAR live = NEPROBAT (contul QA fara creds RAR).
- Suita:
python3 -m pytest -q→ verde. La VERIFY: 1672 passed, 1 skipped. Dupa fix-urile de code-review CLOSE: 1680 passed, 1 skipped (+45 teste noi fata de baseline 1635). - US-001..US-004 PASS cu dovezi de cod + teste (chips_state JSON unic, 2 actiuni add/remove, exclus supravietuieste resolve_prestatii cu test de regresie blocant pe precedenta, sentinel respins pe ambele cai).
- US-005 E2E browser (import preview + Trimiteri corectie, Playwright): PASS pe (a) un singur rand de chips cu tinta evidentiata + placeholder-tinta + optgroup Sugestii + optiune "Nu se declara la RAR" la deschiderea initiala; (b) sugestie→chip cod instant fara "+"; (c) Nedeclarat → salvare → rand "Nedeclarat", redeschidere arata chipul, × readuce warning; (d) acelasi control la Trimiteri, "salveaza ca regula" persistent; (e) fara controale duble, zero erori JS de flux.
- Gap prins in executie (dupa US-003, reparat inainte de VERIFY): tinta implicita + sugestiile
nu se calculau la randarea initiala a modalului — helper partajat
_chips_target_si_sugestiiin toate caile de randare.
Code-review CLOSE (high, 8 unghiuri + verify) — 1 BLOCKER de siguranta + 2 findings, toate reparate
- BLOCKER (CONFIRMED, reparat): itemii exclusi (
exclus=1, cod null) ramaneau inpayload_jsonpe calea de corectie, iar worker-ul ii trimitea la RAR ca{codPrestatie: null}→ risc ORA-12899 / FINALIZATA partial ireversibil. Nimic nu faceasplit_prestatii_exclusela MOMENTUL trimiterii. Fix la chokepoint unic (worker, inainte debuild_rar_payload) — acopera toate canalele (API/import/corectie) — + filtru defensiv inbuild_rar_payload(sare itemii exclusi / fara cod) + teste care dovedesc ca itemul exclus NU apare in payload-ul RAR. - Consistenta round-trip (reparat):
commit_import/web_confirma_importpastreaza acum prestatiile complete inpayload_json(cheia idempotentei = doar declarabile, identica cu preview); bonus: bug latent de idempotenta preview↔commit in_web_compute_previewreparat. - Conventii CLAUDE.md (reparat): referinte PRD/US-xxx/decizii scoase din comentariile noi.
- Robustete tinta (reparat): un item fara
cod_op_servicenu mai poate deveni tinta invizibila; sugestiile intorc gol pe denumire goala.
GSTACK REVIEW REPORT
| Review | Trigger | Why | Runs | Status | Findings |
|---|---|---|---|---|---|
| CEO Review | /plan-ceo-review |
Scope & strategy | 1 | CLEAR (PLAN via /autoplan) | 5 proposals, 2 accepted, 3 deferred; 8 constatari voce externa |
| Codex Review | /codex review |
Independent 2nd opinion | 0 | UNAVAILABLE (usage limit pana 2026-07-18) | voci = subagent-only |
| Eng Review | /plan-eng-review |
Architecture & tests (required) | 1 | CLEAR (PLAN via /autoplan) | 8 issues (4×P1 confirmate in cod), 0 critical gaps ramase |
| Design Review | /plan-design-review |
UI/UX gaps | 1 | CLEAR (FULL via /autoplan) | score: 6/10 → 9/10, 10 decizii in §3.1 |
| DX Review | /plan-devex-review |
Developer experience gaps | 0 | SKIPPED | fara scope developer-facing |
- CROSS-MODEL: indisponibil (Codex la limita de utilizare); toate vocile externe = subagenti Claude independenti (context curat, fara review-ul anterior).
- VERDICT: CEO + ENG + DESIGN CLEARED — gata de implementare. Decizii gate aplicate: D2 placeholder-tinta, D3 select (paleta respinsa), D4 stare JSON, D5 aprobat.
NO UNRESOLVED DECISIONS