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

@@ -26,22 +26,20 @@ $p = Start-Process 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe' -
$p.WaitForExit(120000); if (!$p.HasExited) { $p.Kill() }
```
- `-A` ignora config.fpw implicit, `-T` sare peste splash; **ambele obligatorii** - fara `-T`
procesul ramane pe ecranul de intampinare (simptom identic cu o eroare de compilare).
Un `-c<cale>` explicit (lipit de flag) e preluat chiar si impreuna cu `-A`.
- **SAFETY**: sub `-A` porneste ON, deci primul `STRTOFILE` peste un log existent (sau
`COMPILE` peste un `.err`/`.fxp` existent) scoate dialogul modal "overwrite?" si procesul
pare agatat. Pune `SET SAFETY OFF` ca PRIMA linie din script si/sau `SAFETY=OFF` +
`RESOURCE=OFF` intr-un config.fpw propriu pasat cu `-c`. Verificare: logheaza
`SET("SAFETY")`/`SET("RESOURCE")` la start.
procesul ramane pe ecranul de intampinare (simptom identic cu o eroare de compilare). `-c<cale>`
explicit (lipit de flag) e preluat si cu `-A`.
- **SAFETY**: sub `-A` porneste ON - primul `STRTOFILE` peste un log existent (sau `COMPILE` peste
un `.err`/`.fxp` existent) scoate dialogul modal "overwrite?" si procesul pare agatat. Pune
`SET SAFETY OFF` ca PRIMA linie din script si/sau `SAFETY=OFF`+`RESOURCE=OFF` intr-un config.fpw
propriu pasat cu `-c`. Verificare: logheaza `SET("SAFETY")`/`SET("RESOURCE")` la start.
- In script: logare cu STRTOFILE (nu WAIT WINDOW / debugger - nu exista consola);
`ON ERROR DO <handler> WITH ERROR(), MESSAGE(), PROGRAM(), LINENO()` care logheaza si
continua (mimeaza ErrorHandler); `QUIT` obligatoriu la final.
- `LINENO()` din handler e relativ la inceputul metodei: linia in `.vc2` = linia raportata +
linia `PROCEDURE`.
- Nu rula cu IDE-ul sau exe-ul aplicatiei deschis (lock pe binare); sterge `.fxp`-ul vechi
daca ai editat scriptul intre rulari. Daca nu-l stergi, VFP ruleaza codul vechi din `.fxp`
fara niciun semn - testul poate trece si raportul poate parea valid, desi modificarea nu a
fost executata; se prinde doar dupa ce lipseste din log o linie pe care o scrie doar codul nou.
- Nu rula cu IDE-ul sau exe-ul aplicatiei deschis (lock pe binare); sterge `.fxp`-ul vechi dupa
editarea scriptului - altfel VFP ruleaza codul vechi din `.fxp` fara niciun semn (testul poate
trece fals; se prinde doar cand lipseste din log o linie scrisa doar de codul nou).
- Forme modale: `Show(1)` blocheaza. Replica in script doar liniile relevante din Show, sau
seteaza `WindowType = 0`.
@@ -69,7 +67,7 @@ Cel mai ieftin test dupa o modificare: `COMPILE` headless, fara aplicatie si far
## 5. Bisectia versiunilor de clase (regresii)
Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
Cand un bug apare "de azi", compara cu clasa veche fara sa atingi SVN:
1. `git show <rev>:clase\fisier.vcx > temp\fisier.vcx` (+ `.vct`); pentru diff lizibil,
`vcx2txt.ps1 -Source temp\fisier.vcx -CacheRoot temp\txt`.
2. In harness incarca DOAR copia (`SET CLASSLIB TO temp\fisier.vcx`), **nu ADDITIVE peste cea
@@ -89,8 +87,8 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
pe copie crapa; recreeaza indexul dupa copiere. Acelasi lucru pentru cursorii creati intr-un
test: trebuie sa aiba EXACT indecsii pe care ii creeaza fluxul real inainte de instantiere,
altfel ordinea/logica difera si testul da rezultat fals.
- **Un grid isi pierde TOATE coloanele** (`ColumnCount` devine 0, fara eroare in log) daca un
ControlSource crapa la re-evaluare in timp ce coloanele sunt atinse programatic (ex. font per
- **Un grid isi pierde TOATE coloanele** (`ColumnCount` devine 0, fara eroare in log) daca
ControlSource crapa la re-evaluare cat timp coloanele sunt atinse programatic (ex. font per
coloana la Init). Simptome in aval: `attachtogrid` copiaza 0 coloane, apoi `calctotal` da
"Property <cColWithLabel> is not found". Similar, un cursor legat la grid recreat de Init
lasa grid-ul fara coloane (eroare 1925).
@@ -100,25 +98,24 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
- **Coloana de grid cu ControlSource EXPRESIE (nu camp) cere `Bound = .F.`** Fara el: eroare 9
"Data type mismatch" la `CREATEOBJECT`-ul formei (faza de constructie, raportata la linia
apelanta, Details gol).
- **Erorile de instantiere sunt raportate la linia `CREATEOBJECT`, nu la `.Init`**: daca
- **Erorile de instantiere se raporteaza la linia `CREATEOBJECT`, nu la `.Init`**: daca
`Procedure` = scriptul apelant, eroarea vine din evaluarea definitiei clasei (`ADD OBJECT ...
WITH RowSource`, ControlSource-expresie), pentru ca bind-ul controalelor native se rezolva la
WITH RowSource`, ControlSource-expresie) - bind-ul controalelor native se rezolva la
CONSTRUCTIE, inainte de `Init`.
- **Literal string > 255 caractere = eroare de COMPILARE, nu de runtime** (masurat 24.07.2026:
255 trece, 256 pica). Mesaj: `Unrecognized command verb` daca linia incepe cu un apel de
metoda, `Command contains unrecognized phrase/keyword` la o atribuire. Insidios: restul
programului ruleaza, doar linia aceea lipseste din `.fxp` si da eroare 16 cand se ajunge la
ea. De aceea SQL-ul lung se scrie cu `TEXT TO <var> [TEXTMERGE] NOSHOW ... ENDTEXT` sau
concatenat. Verificare: `awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`.
- **Linie de COD (nu doar literal string) prea lunga intr-o metoda de clasa `.vc2` poate
arunca eroarea 11 ("Function argument value, type, or count is invalid") pe PRIMA
instructiune a metodei, nu pe linia vinovata** - simptom complet derutant. Se exclude prin
diagnostic: aceeasi expresie merge normal la nivel de program, in alta clasa, intr-o
subclasa cu metoda noua, si pe instanta virgina - deci nu tine de tipul datelor, de context
sau de clasa parinte. Reper practic: linii preexistente >200 caractere intr-o clasa mare
functioneaza pana la ~250; pragul real e in jur de 255, ca la literalii de string. Remediu:
sparge expresia in pasi cu variabile locale. Verificare (comparat intre fisierul curent si
un backup anterior):
- **Literal string > 255 caractere = eroare de COMPILARE, nu runtime** (255 trece, 256 pica).
Mesaj: `Unrecognized command verb` daca linia incepe cu un apel de metoda,
`Command contains unrecognized phrase/keyword` la o atribuire. Insidios: restul programului
ruleaza, doar linia lipseste din `.fxp` si da eroare 16 cand se ajunge la ea. De aceea SQL-ul
lung se scrie cu `TEXT TO <var> [TEXTMERGE] NOSHOW ... ENDTEXT` sau concatenat. Verificare:
`awk 'length($0) > 260 {print NR": "length($0)}' fisier.prg`.
- **Linie de COD (nu doar literal string) prea lunga intr-o metoda de clasa `.vc2` poate arunca
eroarea 11 ("Function argument value, type, or count is invalid") pe PRIMA instructiune a
metodei, nu pe linia vinovata** - simptom derutant. Se exclude prin diagnostic: aceeasi
expresie merge normal la nivel de program, in alta clasa, intr-o subclasa cu metoda noua, si
pe instanta virgina - deci nu tine de tipul datelor, de context sau de clasa parinte. Reper
practic: linii preexistente >200 caractere intr-o clasa mare functioneaza pana la ~250; pragul
real e in jur de 255, ca la literalii de string. Remediu: sparge expresia in pasi cu variabile
locale. Verificare (comparat intre fisierul curent si un backup anterior):
```powershell
$l=[IO.File]::ReadAllLines($p,[Text.Encoding]::GetEncoding(28591))
for($i=0;$i -lt $l.Length;$i++){ if($l[$i].Length -gt 200){ "{0}: len={1}" -f ($i+1), $l[$i].Length } }
@@ -126,27 +123,31 @@ Cand un bug apare "de azi", compara cu clasa veche fara a atinge SVN:
- **Un UDF care citeste campul curent (`Nvl(camp,0)=1` sau similar) nu e de incredere intr-o
clauza de filtrare** (`SELECT ... WHERE`, `LOCATE FOR`, `SCAN FOR`, `DELETE FOR`) - pointerul
nu e garantat pe randul evaluat la fiecare apel, deci filtrul devine practic o valoare
constanta (fie nu se declanseaza niciodata, fie loveste tot). Simptome vazute: o comasare de
randuri care nu se mai producea deloc; un test agatat. Remediu: in clauze de filtrare
foloseste expresia INLINE pe camp (`Nvl(camp,0) <> 1`); pastreaza helper-ul doar in cod
procedural (`If`, `Replace` pe randul curent), unde pointerul e garantat pozitionat.
constanta (nu se declanseaza deloc, sau loveste tot). Simptome vazute: comasare de randuri
care nu se mai producea deloc; test agatat. Remediu: in clauze de filtrare foloseste expresia
INLINE pe camp (`Nvl(camp,0) <> 1`); pastreaza helper-ul doar in cod procedural (`If`,
`Replace` pe randul curent), unde pointerul e garantat pozitionat.
- **`SET PROCEDURE TO x.prg`**: in `.exe` se rezolva din modulele compilate (orice `.prg` din
`.pjx`), din IDE doar prin `SET PATH`. O cale lipsa din `SET PATH` se vede deci doar necompilat,
iar in `Try` trece tacut.
## 7. Capcane la SCRIEREA scriptului de test
- **`SET SAFETY OFF` in primele linii, INAINTE de orice `STRTOFILE`/`CREATE CURSOR`** (plus
`SET TALK OFF`). Fara el VFP deschide dialogul de confirmare la suprascrierea fisierului de
log, iar headless dialogul blocheaza procesul pana la timeout. Suitele existente il au deja -
capcana apare la scripturile ad-hoc, scrise repede pentru o masuratoare.
`SET TALK OFF`). Fara el VFP deschide dialogul de confirmare la suprascriere, iar headless
dialogul blocheaza procesul pana la timeout. Suitele existente il au deja - capcana apare la
scripturile ad-hoc, scrise repede pentru o masuratoare.
- **`DEFINE CLASS ... ENDDEFINE` nu poate sta la mijlocul programului principal.** Toate liniile
de DUPA `ENDDEFINE` dau "Statement is not in a procedure" (vezi `<script>.ERR`); scriptul
ruleaza doar pana acolo si se opreste silentios, fara sa ajunga la `QUIT` - simptom: vfp9.exe
pare agatat la nesfarsit. Pune orice `DEFINE CLASS` auxiliar la FINALUL fisierului.
de DUPA `ENDDEFINE` dau "Statement is not in a procedure" (vezi `<script>.ERR`); scriptul se
opreste silentios, fara sa ajunga la `QUIT` - simptom: vfp9.exe pare agatat la nesfarsit. Pune
orice `DEFINE CLASS` auxiliar la FINALUL fisierului.
- **Dummy-uri cu metode**: `CREATEOBJECT('Custom')` + `AddProperty()` adauga doar PROPRIETATI.
Daca clasa testata apeleaza `goExecutor.oExecute(...)`, dummy-ul trebuie sa fie
`DEFINE CLASS dummyexecutor AS Custom` cu `PROCEDURE oExecute` reala.
- **Diagnostic "script agatat"**, in ordine: (1) exista `<script>.ERR` langa `.prg`? => s-a
oprit la compilare; (2) CPU-ul procesului ~0 dupa cateva secunde (`Get-Process | select CPU`)
=> asteapta un dialog modal, nu proceseaza; confirma enumerand ferestrele procesului cu
=> asteapta un dialog modal; confirma enumerand ferestrele procesului cu
`EnumWindows`/`GetWindowText`/`GetWindowThreadProcessId` (`Add-Type`, user32) filtrat pe PID -
daca vezi doar fereastra principala + "Command", nu e dialog, cauta alta cauza (tipic `-T`
lipsa). Confirma mereu cauza inainte de a schimba scriptul.