Files
solduri2roa/docs/handoff_etapa2_convertor.md
Marius Mutu 15bb26ac15 Etapa 2: plan v3, rapoarte de cercetare si etalonul de regresie
Cercetare: ambele formate SAGA (VFP xls/xlsx si Firebird .FDB), cu dovezi
fisier:linie in docs/raport_sursa_saga_xlsx.md si raport_exporturi_saga_noua.md.

Plan v3 dupa review de strategie si arhitectura: contract intern + trei
cititoare, mapare in doua fisiere cu proprietari diferiti, lane-uri.

Etalon de regresie anonimizat in tests/golden/ (sume si structura neatinse,
zero IBAN si zero cod fiscal real). Tabela de corespondenta ramane ignorata.

Iesirile de productie ies din git (raman pe disc); .gitignore acopera si
copiile de baze de client si iesirile intermediare ale convertorului.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYeAtVxeS8m4oXekjX8Am2
2026-09-21 15:44:57 +03:00

168 lines
9.2 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Handoff - etapa 2, convertorul reutilizabil SAGA -> ROA
Scris 21.09.2026. Sesiunea urmatoare este **orchestrator**, nu executant: imparte pe lane-uri,
trimite sarcinile la agenti opencode, verifica portile. Nu scrie ea codul.
**Stare: planul e gata si aprobat pe decizii; nu s-a scris nicio linie de cod pentru etapa 2.**
Marius nu a dat inca "porneste" pe lane-uri. Intreaba-l inainte sa lansezi primul lane.
---
## 1. Ce sa citesti, in ordine, si de ce
| fisier | de ce |
|---|---|
| `docs/plan_etapa2_convertor.md` | **contractul de lucru, v3.** Tot ce urmeaza se masoara fata de el |
| `docs/raport_sursa_saga_xlsx.md` | SAGA veche (VFP); conventiile `conturi_roa.dbf` (`.TOATE`, `.RESTUL`) |
| `docs/raport_exporturi_saga_noua.md` | SAGA noua (Firebird); structura exporturilor si a bazei |
| `docs/decizii_import.md` | regulile de mapare, **validate in productie - nu se redeschid** |
| `docs/review_ceo_etapa2.md`, `docs/review_eng_etapa2.md` | de unde vin corectiile din v3; reciteste doar daca vrei sa redeschizi o decizie |
Nu reface cercetarea. Cele doua rapoarte au costat doua lane-uri si contin dovezi cu fisier si linie.
## 2. Ce e gata
- Etapele 1-6 din `docs/plan_solduri2roa.md`: cele doua xlsx au fost **importate in ROACONT si au
trecut**; scripturile `sql/update_cod_fiscal_*.sql` au fost **executate** de Marius.
- Cercetarea pe ambele formate SAGA + conectarea la Firebird, verificata live.
- Planul v3, dupa review de strategie si de arhitectura.
- `.gitignore` + `git rm --cached` pe iesirile de productie (fisierele raman pe disc).
- **Etalonul de regresie este facut si pus in git** (21.09.2026): `tests/golden/` cu
`golden_FUNDATIA_2025_12.xlsx` si `golden_MASTER_2025_12.xlsx`, produse de
`tests/anonimizeaza_etalon.py`. Verificat: structura, numarul de randuri si sumele sunt
identice cu originalele (`SUM(totdeb) = SUM(totcred)` neatins), au fost schimbate doar
coloanele 10-14 pe randurile FACTURA plus IBAN-urile; zero IBAN si zero cod fiscal real
ramase. Tabela de corespondenta (`tests/_corespondenta_anonimizare.json`) e ignorata de git -
nu o comite, cu ea anonimizarea se desface.
## 3. Ce NU e facut
Tot ce e in tabelul de lane-uri din plan, mai putin etalonul. Niciun fisier de cod nou pentru
conversie, niciun test, niciun `config/conturi_parteneri.csv`.
## 4. Deciziile deja luate - nu le redeschide
1. **Conturile cu parteneri**: setul validat din `genereaza_xlsx.py:46-50` este autoritatea, tinut
in `config/conturi_parteneri.csv`. `CONFIG_CONT_IREG` e consultativ; unealta **raporteaza**
divergentele, nu le aplica. Motivul, cu dovada, e in plan - Oracle nu listeaza 5121/5124/5311.
2. **`acont` pentru conturi cu parteneri** ramane decis de `genereaza_xlsx.py`; maparea doar
suprascrie explicit. Randurile de diferenta raman calculate in cod.
3. **Maparea = doua fisiere**: `mapare_<FIRMA>.xlsx` scris doar de unealta (regenerat complet),
`corectii_<FIRMA>.xlsx` scris doar de Marius.
4. **Cititorul FDB se face acum**, marcat explicit "verificat doar pe cazul sintetic".
5. **Etalonul de regresie**: xlsx-uri intregi, **anonimizate** (sume si structura neatinse), in
`tests/golden/`. Tabela de corespondenta nume real -> nume fals **nu se comite**.
6. **Teste**: `unittest` din stdlib. Fara dependinte noi de test.
7. Sursa: PDF, foaie de calcul SAGA si Firebird, toate trei, egale.
## 5. Ordinea lane-urilor
`contract` singur, primul -> apoi `citire-xlsx` si `mapare` in paralel -> `citire-fdb` ->
`integrare` -> `regresie`. Criteriile de terminare sunt in plan, in tabelul de lane-uri si in cel de
testare. Etalonul din `tests/golden/` a fost fixat **inainte** sa se schimbe vreo linie de cod -
asta e tot rostul ordinii. Daca vreun lane modifica `genereaza_xlsx.py` si regresia incepe sa pice,
etalonul are dreptate, nu codul nou.
## 6. Cum lansezi un lane (verificat azi, functioneaza)
Ghidul complet: `D:\ROA\ROACONT\COMUN\docs\opencode_agenti_orchestrare.md`.
- **Port pentru acest proiect: 4296.** Nu-l folosi pe 4196 (ROACONT) sau 4096 (ROAFACTURARE) -
oprirea serverului dintr-un proiect omoara lane-urile celuilalt. Portul 4296 **nu e inca trecut in
tabelul din ghid** - adauga-l acolo (COMUN are nevoie de aprobare inainte de commit).
- Pornire, din directorul proiectului: `opencode serve --port 4296`
- Model: `{"providerID":"opencode-go","modelID":"deepseek-v4.1-flash"}`
- Promptul de sistem, obligatoriu la fiecare sesiune, in campul `system`:
`D:\ROA\ROACONT\COMUN\docs\opencode_prompt_initial.md`
- Sesiune noua: `POST /session {title}` -> `id`;
sarcina: `POST /session/:id/prompt_async?directory=D:\ROA\IMPORT2ROA\solduri2roa`
- Stare: `GET /session/status` - sesiunea lipseste cand e libera, `{}` = toate libere.
- Oprire la final:
`Stop-Process -Id (Get-NetTCPConnection -LocalPort 4296 -State Listen).OwningProcess`
Sablon PowerShell pentru trimitere (JSON pe UTF-8, altfel se strica diacriticele si ghilimelele):
```powershell
$u='http://127.0.0.1:4296'
$sys = [IO.File]::ReadAllText('D:\ROA\ROACONT\COMUN\docs\opencode_prompt_initial.md')
$m = @{providerID='opencode-go'; modelID='deepseek-v4.1-flash'}
$sid = (Invoke-RestMethod -Method Post "$u/session" -ContentType 'application/json' -Body '{"title":"lane-X"}').id
$b = @{model=$m; system=$sys; parts=@(@{type='text';text=$task})} | ConvertTo-Json -Depth 5
Invoke-RestMethod -Method Post "$u/session/$sid/prompt_async?directory=D:\ROA\IMPORT2ROA\solduri2roa" `
-ContentType 'application/json; charset=utf-8' -Body ([Text.Encoding]::UTF8.GetBytes($b))
```
Asteptarea: nu face `Start-Sleep` lung in foreground (harness-ul il blocheaza). Foloseste Bash in
fundal: `until curl -s http://127.0.0.1:4296/session/status | grep -qv busy; do sleep 20; done`.
**Ce trebuie sa contina fiecare sarcina de lane**: numele lane-ului, fisierele exacte de atins,
criteriul de terminare luat din plan, interdictiile (fara commit, fara `sed -i`, fara modificari in
`D:\ROA\ROACONT`, `D:\SAGA250909`, `saga2roa*`), unde scrie raportul, si ultimul mesaj
`GATA <lane>` / `BLOCAT <lane>: motiv`. Agentii respecta asta; doi lane-uri au mers azi asa.
## 7. Capcane deja platite - nu le redescoperi
- `openpyxl` **nu** citeste `.xls` (BIFF). Pentru `.xls`: `xlrd` (instalat, 2.0.2) sau conversie
`soffice --headless --convert-to xlsx`. Ambele verificate.
- Firebird: **numai embedded**. `firebird-driver` (instalat, 2.0.3) + `fdb.load_api` catre
`C:\Program Files\Firebird\Firebird30_Saga\fbclient.dll`, SYSDBA/masterkey, charset `WIN1250`,
`access_mode=READ`, `no_gc=True`. Pe TCP 3060 parola implicita **nu** merge.
- In `CONTURI` **soldurile stocate sunt 0**; balanta se obtine agregand `REGISTRU`. Cine citeste
`CONTURI.DEB_PREC` scoate o balanta goala fara nicio eroare.
- Coloanele `_1` din export (S..AF) seamana cu cele principale. Potrivirea numelor de coloana se
face **exact**, niciodata pe substring: `TOTAL_DEB` vs `TOTAL_DEB_1`.
- Numele foii difera intre surse (`balanta` / `xl` / `Sheet1`) - ia prima foaie, nu cauta dupa nume.
- `CONT` se citeste ca text. `401.00002` citit ca numar se strica.
- Heredoc-urile lungi in Bash au esuat pe fisierele mari de documentatie; scrie-le cu tool-ul de
scriere de fisiere.
- `python` direct din Bash e stub Windows Store si nu scrie nimic (iese 0 si fisierul ramane
neatins). Foloseste `py`, sau PowerShell.
## 8. Starea pe disc - nimic periculos, dar necomis
`git status` la predare (HEAD = `ceab089`, branch `main`):
```
M .gitignore
D balanta_FUNDATIA.csv
D balanta_MASTERJOB.csv
M docs/parteneri_cui_gasite.md
M docs/plan_solduri2roa.md
D export_balanta_fundatia_12_2025.xlsx
D init_FUNDATIA_2025_12.xlsx
D init_MASTER_2025_12.xlsx
M sql/update_cod_fiscal_FUNDATIA.sql
M sql/update_cod_fiscal_MASTER.sql
A tests/anonimizeaza_etalon.py
A tests/golden/golden_FUNDATIA_2025_12.xlsx
A tests/golden/golden_MASTER_2025_12.xlsx
?? docs/handoff_etapa2_convertor.md
?? docs/plan_etapa2_convertor.md
?? docs/raport_exporturi_saga_noua.md
?? docs/raport_sursa_saga_xlsx.md
?? docs/review_ceo_etapa2.md
?? docs/review_eng_etapa2.md
?? exemple/
```
Verificari inainte de orice altceva:
- `init_FUNDATIA_2025_12.xlsx` si `init_MASTER_2025_12.xlsx` sunt pe disc dar nu mai sunt in git.
Etalonul anonimizat e deja generat din ele si comis, deci poarta de regresie nu mai depinde de
ele. Sunt necesare doar daca vrei sa **regenerezi** etalonul (`py testsnonimizeaza_etalon.py`).
- Nu se da commit fara ca Marius sa vada diff-ul (regula proiectului).
- Niciun proces ramas viu: serverul opencode de pe 4296 a fost oprit la predare. Il pornesti tu,
cu comanda din sectiunea 6.
- `D:\ROA\ROACONT`, `D:\SAGA250909` si `saga2roa*` nu au fost modificate si nu se modifica.
## 9. Primul lucru de facut in sesiunea noua
1. Citeste planul v3.
2. Intreaba-l pe Marius daca pornesti (nu a dat inca "da" pe lansarea lane-urilor).
3. La "da": lanseaza **doar** lane-ul `contract`. Etalonul exista deja, deci lane-ul are de facut
`config/conturi_parteneri.csv` + scriptul de divergenta Oracle, si de scris testul de regresie
care compara iesirea codului de azi cu `tests/golden/`, pe valori de celula (nu pe hash: un
xlsx rescris de alta versiune de openpyxl are alti octeti cu acelasi continut). Testul trebuie
sa treaca **cu codul de conversie neschimbat**. Daca nu trece, e bug in test sau in etalon, nu
in cod, si restul lane-urilor nu au voie sa porneasca.