verificare partener: garda pe cont NULL, hook-uri de disciplina, docs compactate

- ooperatii_comune: verific_partener nu mai construieste SQL NULL cand contul
  primit e NULL (EMPTY(.NULL.) e .F. in VFP)
- utile\context_watch.ps1 si utile\docs_revizie_check.ps1: masurarea contextului
  sesiunii si cadenta reviziei de documentatie, prin hook-uri Claude Code
  (instalare in docs\monitorizare-context.md)
- reguli_lucru: delegare la subagenti, modificari minime si scoped, scrierea si
  revizuirea documentatiei, changelog strictul necesar (regulile 3, 6, 9, 11, 12)
- scripturi-migrare-db: continutul unui script (scoped, fara select, idempotent)
- teste noi pentru cele doua erori din achizitia de import
- restul documentatiei compactata, fara pierdere de reguli

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RYbiinqXxdEqXi53x4Ro7K
This commit is contained in:
2026-08-02 22:30:44 +03:00
parent 20323d22b3
commit c4d869921d
28 changed files with 1788 additions and 867 deletions

View File

@@ -11,11 +11,11 @@ Fisiere in `COMUN\utile\Teste\`: `vfp_ui_harness.ps1` (orchestrator generic, par
`mock_amessagebox.prg` (mock dialog) — infrastructura sta in radacina `Teste\`; suitele stau in
subfoldere pe subiect. Exemplu complet: `achizitie_import\test_import_nota_ui.prg` + `.ps1`.
**REGULA (Marius, 17/07/2026): testele pe aplicatii frontend exerseaza fluxul REAL al
**REGULA (Marius): testele pe aplicatii frontend exerseaza fluxul REAL al
utilizatorului** — formularul/butonul/metoda pe care o apeleaza aplicatia, NU introducerea
directa a randurilor in cursoare/tabele. Popularea directa sare peste validari/filtre/efecte
laterale si da PASS fals (caz real: un articol "adaugat" direct in cursor trecea testul, dar
prin fluxul real nu se adauga deloc). Mock-urile raman permise doar pe INFRASTRUCTURA (Oracle,
laterale si da PASS fals (caz real: articol "adaugat" direct in cursor trecea testul, dar prin
fluxul real nu se adauga deloc). Mock-urile raman permise doar pe INFRASTRUCTURA (Oracle,
dialoguri modale), nu pe pasii fluxului testat.
## Test UI nou in 5 pasi
@@ -33,7 +33,7 @@ dialoguri modale), nu pe pasii fluxului testat.
5. `powershell -File vfp_ui_harness.ps1 -TestPrg <test.prg> -Steps @('pas0',...)`.
PNG-uri in `screenshots\step_<n>_<eticheta>.png`; log in `<test>_log.txt`.
## Capcane / deblocari (toate confirmate in sesiune)
## Capcane / deblocari
a. **`SET SAFETY OFF` + `SET TALK OFF` inaintea primului `STRTOFILE`.** Cu SAFETY ON, scrierea
log-ului existent scoate un dialog modal care blocheaza rularea (proces viu, "instanta
@@ -51,22 +51,20 @@ d. **`vfp9 -A test.prg` deschide INTERMITENT editorul** in loc sa ruleze (log go
`.fxp`-ul PRECOMPILAT. Precompilarea (`COMPILE`+`QUIT`) atarna dupa COMPILE si, rulata in
ACEEASI sesiune powershell, otraveste lansarile ulterioare - ruleaza-o intr-un proces copil
izolat (`Start-Process -Wait _precompile.ps1`).
e. **Suitele NU se ruleaza in paralel** intre ele: harness-ul isi omoara instantele `vfp9`
ramase inainte de fiecare lansare, deci un al doilea test pornit peste primul il ucide.
Omorarea e INSA filtrata pe linia de comanda (`Win32_Process.CommandLine` care contine
folderul de teste): instantele `vfp9` straine sesiunea IDE a utilizatorului sau teste
dintr-un ALT proiect VFP — nu sunt atinse si nu blocheaza rularea. Nu reintroduce
`Get-Process vfp9 | Stop-Process -Force` fara filtru.
f. **FARA FURT DE FOCUS (17/07/2026)**: `Graphics.CopyFromScreen` fura focus si se corupe daca
utilizatorul lucreaza in paralel - nu se mai foloseste. Capturile se fac cu `PrintWindow`
(user32, P/Invoke) pe `Process.MainWindowHandle`, flag `2` = `PW_RENDERFULLCONTENT`
(fallback `0` daca iese goala); merge cu fereastra acoperita, dar NU minimizata. Fereastra
se muta OFF-SCREEN (`SetWindowPos`, `HWND_BOTTOM`, x=-4000, `SWP_NOACTIVATE`) imediat ce
apare handle-ul si SE RE-IMPINGE la fiecare pas (VFP se reactiveaza singur la
`Show()`/dialoguri). Consolele powershell copil sunt `-WindowStyle Hidden` (sigur pentru
consola, NU pentru GUI VFP - ascunsa, `PrintWindow` poate reda gol). Implementat in
`vfp_ui_harness.ps1` (Take-Screenshot, Push-Offscreen, Wait-MainWindowHandle) si
`_precompile.ps1`.
e. **Suitele NU se ruleaza in paralel**: harness-ul omoara instantele `vfp9` ramase inainte de
fiecare lansare, deci un al doilea test pornit peste primul il ucide. Omorarea e filtrata pe
linia de comanda (`Win32_Process.CommandLine` contine folderul de teste): instantele `vfp9`
straine (sesiunea IDE a utilizatorului, teste dintr-un ALT proiect VFP) nu sunt atinse. Nu
reintroduce `Get-Process vfp9 | Stop-Process -Force` fara filtru.
f. **FARA FURT DE FOCUS**: `Graphics.CopyFromScreen` fura focus si se corupe daca
utilizatorul lucreaza in paralel - nu se mai foloseste. Capturile: `PrintWindow` (user32,
P/Invoke) pe `Process.MainWindowHandle`, flag `2` = `PW_RENDERFULLCONTENT` (fallback `0` daca
iese goala); merge cu fereastra acoperita, NU minimizata. Fereastra se muta OFF-SCREEN
(`SetWindowPos`, `HWND_BOTTOM`, x=-4000, `SWP_NOACTIVATE`) la aparitia handle-ului si SE
RE-IMPINGE la fiecare pas (VFP se reactiveaza singur la `Show()`/dialoguri). Consolele
powershell copil: `-WindowStyle Hidden` (sigur pentru consola, NU pentru GUI VFP ascunsa -
`PrintWindow` poate reda gol). Implementat in `vfp_ui_harness.ps1` (Take-Screenshot,
Push-Offscreen, Wait-MainWindowHandle) si `_precompile.ps1`.
g. **Mock de messagebox**: `FUNCTION amessagebox` care returneaza direct valoarea butonului
(6=Da), incarcat cu `SET PROCEDURE ... ADDITIVE` **PRIMUL**, inaintea fisierelor aplicatiei:
la nume duplicat de procedura VFP foloseste fisierul cautat PRIMUL (verificat empiric).
@@ -83,25 +81,23 @@ i. **Cursorii trebuie sa aiba EXACT indecsii creati de fluxul real** inainte de
uneori in cascada la apeluri repetate. Verifica in codul apelant ce indecsi se creeaza si
replica-i identic.
j. **Mock-urile de date trebuie sa reproduca structura si semantica REALA a sursei** (view
Oracle: toate coloanele; relatii intre randuri: toate randurile implicate, nu unul singur cu
valori "compuse" manual in test). Un mock incomplet lasa campuri mereu NULL sau ascunde
pasul care se testeaza. Cand un flag global activeaza cod suplimentar (ex. `gl406`), acel
cod cere mock-uri in plus - verifica ce apeleaza si adauga metodele lipsa din dummy.
Cu `gl406=.T.` (SAFT), `GetTaxCodeIdPart`/`GetTaxCode` cer: `goApp.ReadIni`/`WriteIni`
(proprietate simpla nu ajunge, clasa `dummyapp` are nevoie de METODE), `goExecutor.oReset`
(no-op e suficient), si un cursor `saft_taxtable` real (nu doar mock pe `goExecutor` -
`update_jtva_coloane` face `USE saft_taxtable` direct pe alias). Fara ele, simptomul e un
dialog nativ Windows "Open" (cauta `saft_taxtable.dbf`) care blocheaza headless la nesfarsit,
fara nicio linie noua in log si CPU 0% - vezi `depanare_testare_vfp.md` pentru diagnosticul
cu `EnumWindows`/`PrintWindow` pe fereastra ascunsa cand simptomul e "ecran gol, fara eroare".
Oracle: toate coloanele; relatii intre randuri: toate randurile implicate, nu una singura cu
valori "compuse" manual). Un mock incomplet lasa campuri NULL sau ascunde pasul testat. Cand
un flag global activeaza cod suplimentar (ex. `gl406`), acel cod cere mock-uri in plus -
verifica ce apeleaza si adauga metodele lipsa din dummy. Cu `gl406=.T.` (SAFT),
`GetTaxCodeIdPart`/`GetTaxCode` cer: `goApp.ReadIni`/`WriteIni` (clasa `dummyapp` are nevoie
de METODE, nu doar proprietate), `goExecutor.oReset` (no-op e suficient), si cursor
`saft_taxtable` real (nu doar mock pe `goExecutor` - `update_jtva_coloane` face
`USE saft_taxtable` direct pe alias). Fara ele, simptomul e dialog nativ Windows "Open" (cauta
`saft_taxtable.dbf`) care blocheaza headless la nesfarsit, fara linie noua in log si CPU 0% -
vezi `depanare_testare_vfp.md` pentru diagnostic cu `EnumWindows`/`PrintWindow`.
k. **`LOCATE FOR camp == 'literal'` pe camp `C(n)` padded nu gaseste nimic** (`==` e exact) -
foloseste `ALLTRIM(camp) == 'literal'`.
l. **`CREATEOBJECT`/`ADDPROPERTY` se comporta gresit apelate DINTR-O PROCEDURA in acest runtime
headless** (obiect returnat ca string de 30 spatii; `ADDPROPERTY` da eroare 11). Din
programul PRINCIPAL merg. Construieste obiectele-parametru INLINE in main, nu intr-un helper.
Cauza confirmata intr-un caz concret: linie de cod prea lunga in ACEEASI metoda de clasa -
vezi `depanare_testare_vfp.md` sectiunea 6. Remediul (constructie inline) ramane valabil
oricum, indiferent de cauza exacta dintr-un caz punctual.
headless** (obiect returnat ca string de 30 spatii; `ADDPROPERTY` da eroare 11). Din programul
PRINCIPAL merg. Construieste obiectele-parametru INLINE in main, nu intr-un helper. Cauza
confirmata intr-un caz concret: linie de cod prea lunga in ACEEASI metoda de clasa - vezi
`depanare_testare_vfp.md` sectiunea 6; remediul (constructie inline) ramane valabil oricum.
m. **Fara `SELECT-SQL` pe cursorul legat de grid**: `SELECT ... FROM <cursor> INTO CURSOR` cat
timp cursorul e RecordSource-ul unui grid viu poate omori procesul vfp9 silentios (fara
eroare catchabila, fara semafor). Foloseste xBase nativ (`COUNT FOR ... TO`, `CALCULATE`,
@@ -113,9 +109,9 @@ n. **Wrapper-ul `.ps1` trebuie sa paseze `-SyncDir` daca `.prg`-ul isi seteaza p
asteapta un fisier care nu vine). Timeout minim: ~30s x numarul de pasi din `-Steps`
(auto-continue per checkpoint din `HarnessWaitContinue`), plus marja de pornire.
o. **Formularul resincronizeaza singur dupa o alegere din grid** (`lSyncPending` + `tmrSync`,
ex. `do_modifica_explicatie_tva` din `ointroduceri.vcx`): starea de imediat dupa actiune NU e
ex. `do_modifica_explicatie_tva` din `ointroduceri.vcx`): starea imediat dupa actiune NU e
observabila - `DOEVENTS FORCE` lasa timer-ul sa porneasca, iar resincronizarea rescrie ce
tocmai s-a aplicat (la explicatia TVA: randul S revine la familia documentului si randurile T
se realiniaza dupa el). Scrie assert-urile pe starea de DUPA resincronizare si alege un efect
pe care resincronizarea NU il repara (acolo: `scc`-ul randului T, atins doar cand se schimba
explicatia). Altfel testul pica fara sa fie ceva gresit in cod.
tocmai s-a aplicat (la explicatia TVA: randul S revine la familia documentului, randurile T se
realiniaza dupa el). Scrie assert-urile pe starea de DUPA resincronizare, pe un efect pe care
resincronizarea NU il repara (acolo: `scc`-ul randului T, atins doar la schimbarea explicatiei)
- altfel testul pica fara sa fie ceva gresit in cod.