From ca2056d06aa4a7152777a11798f974b60fc2e522 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Thu, 17 Sep 2026 22:36:46 +0300 Subject: [PATCH] sync SVN r18174 --- docs/PORNIRE.md | 101 ++++++++ docs/function_hooks_verificare.md | 193 +++++++++++++++ docs/handoff_activ.md | 127 ++++++++++ docs/handoff_inject.md | 57 +++++ docs/hooks_functii_context.md | 173 +++++++++++++ docs/plan_qa_factura_aviz.md | 133 ++++++++++ docs/progres_qa_factura.md | 98 ++++++++ docs/qa_factura_harta.md | 161 ++++++++++++ docs/qa_factura_hooks_ref.md | 393 ++++++++++++++++++++++++++++++ docs/qa_factura_unelte.md | 191 +++++++++++++++ docs/s0_context_hook.md | 100 ++++++++ docs/sessionstart_ref.md | 330 +++++++++++++++++++++++++ docs/vm304_acces.md | 102 ++++++++ 13 files changed, 2159 insertions(+) create mode 100644 docs/PORNIRE.md create mode 100644 docs/function_hooks_verificare.md create mode 100644 docs/handoff_activ.md create mode 100644 docs/handoff_inject.md create mode 100644 docs/hooks_functii_context.md create mode 100644 docs/plan_qa_factura_aviz.md create mode 100644 docs/progres_qa_factura.md create mode 100644 docs/qa_factura_harta.md create mode 100644 docs/qa_factura_hooks_ref.md create mode 100644 docs/qa_factura_unelte.md create mode 100644 docs/s0_context_hook.md create mode 100644 docs/sessionstart_ref.md create mode 100644 docs/vm304_acces.md diff --git a/docs/PORNIRE.md b/docs/PORNIRE.md new file mode 100644 index 0000000..60aaad9 --- /dev/null +++ b/docs/PORNIRE.md @@ -0,0 +1,101 @@ +# Pornire pe VM 304 - QA factura/aviz + +Pachet pregatit 17.09.2026 de sesiunea de pe masina principala. Contine tot ce ii trebuie unei +sesiuni Claude Code noi ca sa continue de la S1, fara sa refaca analiza. + +## Pasul 1 - copiaza fisierele + +Din acest pachet, in copia de lucru de pe VM (verifica intai care e calea reala - documentatia +spune `D:\roa\`, planul presupune `D:\ROA\ROAFACTURARE`; daca difera, calea reala castiga): + +| Din pachet | Unde pe VM | +|---|---| +| `docs\*.md` (8 fisiere) | `\docs\` | +| `utile\context_watch.ps1` | peste `\COMUN\utile\context_watch.ps1` | + +Daca pe VM nu exista checkout ROAGEST, pune `context_watch.ps1` oriunde si ajusteaza calea din +settings.json la pasul 2. + +## Pasul 2 - hook-urile (optional, dar recomandat) + +In `%USERPROFILE%\.claude\settings.json` de pe VM, adauga: + +```json +"env": { + "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "70" +}, +"hooks": { + "SubagentStop": [ + { "hooks": [ { "type": "command", + "command": "powershell -NoProfile -ExecutionPolicy Bypass -File \\context_watch.ps1 -Subagent -Json" } ] } + ] +} +``` + +Daca `settings.json` are deja `env` sau `hooks`, se completeaza, nu se inlocuieste. +Verifica dupa editare ca fisierul e JSON valid. + +Ce face: la fiecare subagent care se termina, masoara contextul ACELUI subagent (citind +`agent_transcript_path` din inputul hook-ului) si avertizeaza orchestratorul la 150k / 200k. +Tace sub prag si tace la `stop_hook_active=true`, ca sa nu intre in bucla. + +## Pasul 3 - verifica mediul inainte de orice + +Rulare rapida, inainte sa incepi lucrul: + +```powershell +Test-Path 'C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe' +Test-Path '\COMUN\utile\Teste\vfp_ui_harness.ps1' +Test-Path '\COMUN\utile\Teste\test_init_env_auto_roafacturare.prg' +Test-Path 'D:\ROA\UTIL\foxbin2prg\vfp_symbols.ps1' +``` + +Daca vreunul lipseste, **spune-i lui Marius inainte sa incepi** - planul presupune ca exista. +Conexiunea Oracle se probeaza cu: +`DO test_init_env_auto_roafacturare WITH 'CENTRAL','MARIUSM_AUTO','ROMFASTSOFT'` + +## Pasul 4 - promptul de pornire + +Da-i sesiunii noi exact textul asta: + +--- + +Continua planul din `docs\plan_qa_factura_aviz.md`. Starea curenta e in +`docs\progres_qa_factura.md` - citeste-le pe amandoua inainte de orice. + +S0 e terminat (prototipul de context/handoff). Urmeaza **S1: baseline QA**, si e primul story +care se face pe masina asta, cu UI vizibil. + +Inainte sa incepi, ruleaza verificarile de mediu din `PORNIRE.md` pasul 3 si spune-mi daca ceva +lipseste. + +Reguli care se aplica de la primul pas, nu dupa ce acumulezi context: +- Orice investigatie, editare, rulare de teste se deleaga unui subagent. Tu orchestrezi. +- Nu atinge `combosql` din `COMUN\clase\_cb_base.vc2` - e clasa de baza a tuturor produselor ROA. + Comportamentul nou de cautare se suprascrie in `combosql_cautare` din `ofacturare.vc2`. +- `.vc2` se editeaza cu script Python binar, niciodata `sed -i` (sterge CRLF-urile) si niciodata + Edit pe linii cu octeti >0x7F (diacriticele sunt cp1250, nu cp1252). +- Write-back doar `txt2vcx.ps1 -ProjectRoot `. Fara `-ProjectRoot` scrie + in alt produs. +- Dupa fiecare write-back: `MODIFY CLASS` + captura, si inchide designerul inainte de urmatorul. +- Commit dupa fiecare story, pe branch de lucru, fara push. Mandatul e dat: nu cere aprobare per + story. Exceptie: mockup-ul de la S4 se arata lui Marius inainte de implementare. +- Actualizeaza `docs\progres_qa_factura.md` dupa FIECARE story, nu la final. +- La ~250k context: opreste lucrul, scrie handoff pe disc, preda. „Mai am putin" nu e motiv de + amanare. + +S1 nu modifica niciun cod. Produce doar dovada vizuala si scenariile, in +`docs\qa_factura_baseline.md` + capturi. + +--- + +## Ce sa NU refaca sesiunea noua + +Analiza e platita deja, e in `docs\qa_factura_harta.md` (harta de cod, cu fisier:linie), +`docs\qa_factura_unelte.md` (harness UI, headless, Oracle, hook-uri) si +`docs\qa_factura_hooks_ref.md` (referinta de hook-uri). Se citesc, nu se refac. + +Doua lucruri stabilite si neredeschise: +- Pragul de 3 caractere la cautare = proprietatea `ncharcountbegin=2`, nu logica. +- Duplicatele de articol vin din Oracle (`pack_facturare.cursor_preturi`), nu din VFP. S3 e + blocat pana se citeste corpul pachetului din `ALL_SOURCE` pe MARIUSM_AUTO. diff --git a/docs/function_hooks_verificare.md b/docs/function_hooks_verificare.md new file mode 100644 index 0000000..8e8e182 --- /dev/null +++ b/docs/function_hooks_verificare.md @@ -0,0 +1,193 @@ +# Verificare "function hooks" — Claude Code 2.1.274 (nativ, win32-x64) + +Sursa de verificat: https://claudefa.st/blog/tools/hooks/function-hooks (blog tert, neoficial). +Metoda: (1) incercare de rulare reala `/plugin-types`; (2) cautare de siruri si context in +binarul nativ instalat, `C:\Users\mmari\.local\bin\claude.exe` (233691808 octeti, Bun-compiled, +comitul `1efcc1361e64`). Fiecare constatare de mai jos e marcata cu sursa ei. + +## 1. Rularea comenzii cerute + +``` +CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude -p "/plugin-types ./types" +``` + +Rezultat: **nu s-a generat niciun fisier**. Raspunsul modelului a fost text conversational +("Ready — no task given yet." / la reincercare cu `--output-format json`: `"I'm ready. What +would you like me to work on?"`). Niciun folder `types/` sau `.claude/types/` nu a aparut in +scratchpad dupa rulare (verificat cu `ls`). + +**Cauza identificata, nu specifica function hooks**: am testat control cu `claude -p "/help"` +(comanda locala cea mai de baza din tot CLI-ul, intotdeauna inregistrata, fara nicio poarta de +feature-flag). A esuat identic — modelul a primit "/help" ca text mangled si a raspuns +conversational, in loc sa afiseze ajutorul. **Concluzie: invocarea `claude -p ""` din acest +mediu nu ruteaza deloc prin dispecerul de comenzi locale ("slash commands")** — cererea merge +direct la model ca prompt text. Din `--debug-file`, header-ul de atribuire arata +`cc_entrypoint=sdk-cli`, adica sesiunea porneste prin calea SDK, nu prin REPL-ul interactiv complet; +acolo comenzile locale par sa nu fie interceptate. Deci esecul lui `/plugin-types` **nu e dovada +ca function hooks sunt dezactivate** — e o limitare a modului de invocare folosit aici, valabila +si pentru comenzi complet neutre ca `/help`. N-am putut testa varianta interactiva (fara TTY in +acest mediu). + +`claude --help` si `claude plugin --help` (rulate separat, capturate integral) **nu listeaza** +nicio comanda `plugin-types` la nivel de CLI top-level — motivul e ca `/plugin-types` e o comanda +*in-sesiune* ("slash command"), nu o subcomanda a executabilului `claude`, deci absenta ei din +`--help` e normala si nu spune nimic despre activare. + +## 2. Ce exista REAL in binar (cautare de siruri, cu offset de octet verificabil) + +Nu s-au generat `.d.ts`, deci n-am putut citi declaratii TypeScript complete ca "dovada +canonica" ceruta in sarcina. In schimb, am gasit in binar cod sursa minificat (nu doar siruri +izolate) care confirma mecanismul de facto. Tot ce urmeaza e citat verbatim din binar, cu offset. + +### 2a. Flag-ul si poarta lui reala + +La offset ~103270720 (grep -a -b), blocul de cod al flag-ului: + +``` +var kYe="tengu_plugin_hooks_modules"; +var Azt=()=>!1; +var AFe=()=>a.CLAUDE_CODE_ENABLE_FUNCTION_HOOKS??P(kYe,Azt()); +var h8=()=>AFe()&&!qb()&&!Br("hooks")&&!zm(); +``` + +Interpretare directa din cod: +- flag-ul GrowthBook real se numeste **`tengu_plugin_hooks_modules`**, default **oprit** (`Azt=()=>!1`). +- `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS` e o suprascriere locala peste acel flag (`??`) — confirma + exact ce zice blogul despre numele variabilei de mediu. +- **dar** poarta finala folosita in productie, `h8()`, cere si `!qb() && !Br("hooks") && !zm()` + — trei conditii suplimentare. Numele acestor functii sunt minificate si reciclate in zeci de + module din bundle (acelasi nume `qb`/`Br`/`zm` apare cu corpuri complet diferite in alte + scope-uri), deci **nu pot atribui cu certitudine ce verifica exact aici** fara deminificare + completa — onest: aceasta e limita cercetarii, nu o concluzie. +- Alaturi, la acelasi offset, un tabel de atribuire a sursei flag-ului pentru afisare in UI: + `{override:"from a local override", payload:"from GrowthBook (this session's payload)", + disk:"from GrowthBook (the disk cache of an earlier session)", disabled:"from the default + (GrowthBook is off ...)"}` — confirma ca e un flag GrowthBook cu override local, exact + mecanismul descris de blog. + +### 2b. Comanda `/plugin-types` — confirmata REAL, dar NEgatata de flag + +La offset 203438732, definitia completa a comenzii (citat verbatim): + +``` +var mer=Object.freeze({type:"local",name:"plugin-types", + description:"Write claude-code.d.ts, claude-code-plugins.d.ts and claude-code-mcp.d.ts: + the plugin API's TypeScript declarations, the enabled plugins' type contracts and the + inputs of the connected MCP tools, for typing a hooks module against this session", + argumentHint:"[dir]", supportsNonInteractive:!0, + load:()=>import("B:/~BUN/root/chunk-0rpsm23r.js")}); +``` + +Important: **acest obiect n-are nicio conditie `isEnabled`/gate legata de `h8()` sau de +flag** — e inregistrata neconditionat. Descrierea confirma explicit sintagma "hooks module" +din blog: comanda exista ca sa tipizeze "a hooks module against this session". Deci comanda in +sine e reala si documentata intern, indiferent de starea flag-ului; problema empirica de mai +sus (sectiunea 1) e doar despre modul de invocare `-p` din acest mediu. + +### 2c. Lista REALA de evenimente si API-uri ("scan manifest"), gasita ca date, nu ca documentatie + +La offset 223160560 exista un manifest static de tip "scan" folosit (aparent) pentru analiza +statica / sandboxing a unui modul de plugin, cu lista completa si explicita: + +```js +scan: { + hooks: ["session.start","ui.render","command.run","ui.close","ui.focus","ui.scroll", + "tool.call","prompt.submit"], + calls: ["clock.after","clock.every","clock.now","command.register","fs.list","fs.read", + "fs.stat","process.run","session.id","session.messages","store.get","store.set", + "telemetry.log","telemetry.mark","ui.close","ui.invalidate","ui.log","ui.open", + "ui.resolve","ui.status"] +} +``` + +Aceasta e cea mai tare dovada gasita — e o **lista de date**, nu un string de proza, deci +foarte probabil chiar suprafata reala (sau foarte apropiata) a API-ului de hooks module: + +- **evenimente de hook confirmate**: `session.start`, `ui.render`, `command.run`, `ui.close`, + `ui.focus`, `ui.scroll`, `tool.call`, `prompt.submit` (8 la numar). +- **`turn.complete` si `turn.start` NU sunt in lista de evenimente de hook**, desi cele doua + siruri exista in alta parte a binarului (24, respectiv 68 aparitii) — apartin mecanismului + intern de motor ("engine turn 1 start/end", vazut si in log-ul de debug la rularea reala), + nu suprafetei de hooks expuse pluginurilor. +- **`prompt.submit` e confirmat**, si separat, la offset 206959908, exista codul intern real + care implementeaza acest hook point: un pipeline `core`/`managed` cu posibilitate de a + rescrie textul promptului (`"prompt.submit: text rewritten by a hook (...)"`) sau de a-l + bloca (`"Prompt dropped by a hook: ..."`). Semnatura exacta gasita e apelul + `.prompt.submit({submission, origin, turnId, shouldWait})` — **nu am gasit litera `$` ca + alias/receiver exact** in siruri; forma `$.prompt.submit({text})` din blog e plauzibila ca + sugar-syntax peste acest mecanism, dar nu e confirmata verbatim. +- **API-uri de tip "calls" confirmate ca namespace-uri cu metode**: `fs.read/list/stat` + (deci `$.fs` probabil e un namespace, nu o valoare simpla), `store.get/set`, + `clock.after/every/now`, `session.id/messages` — coincide cu ce cerea sarcina sa verific + (`$.session.messages()`, `$.fs`, `$.store`, `$.clock.every`), dar iar, prefixul `$.` in sine + nu apare ca sir literal langa aceste nume — e o inferenta rezonabila, nu o citare directa. + +### 2d. Tokeni / context / usage / compactare — CAUTATE EXPLICIT, NU GASITE + +Am cautat explicit `token`, `usage`, `context`, `compact` in vecinatatea manifestului de mai +sus si in restul zonei de "function hooks". **Niciunul dintre cele 20 de `calls` sau 8 `hooks` +de mai sus nu are legatura cu tokeni, context window, usage sau compactare.** Sirurile +`contextWindow` (8 aparitii) si `compact` (405 aparitii) exista din abundenta in binar, dar in +alte module (afisarea usage-ului in `--output-format json`, autocompact intern al motorului +— vazut si in logul de debug: `autocompact: tokens=[REDACTED] level=ok effectiveWindow=980000`), +**nu ca hook sau call disponibil unui modul de function hooks**. Nu exista dovada in acest +binar ca un modul de hooks ar putea citi tokenii ramasi sau starea de compactare. + +### 2e. Forma `register` si `hooks/hooks.json` + +Doua descoperiri, ambele reale, dar **doua lucruri diferite**: + +1. **`hooks.json` din binar (27 aparitii) e manifestul VECHI/existent de plugin-hooks** + (PreToolUse, SessionStart etc. — cel folosit deja de pluginul `ponytail` din acest proiect, + vazut in logul de debug: `Read manifest hooks for plugin ponytail (enabled=true): + ./hooks/claude-codex-hooks.json`). Contextul din binar confirma: sirul e `"plugin + hooks.json"`, langa mesaje despre `SKILL.md` si actualizarea regulilor de auto-mode/permisiuni + — sistemul clasic de hooks pe evenimente de tool-use, nesuprapus cu "function hooks". + +2. **Forma `register` pentru "function hooks" (modulul nou)**, gasita in doua exemple interne + reale de pluginuri deja construite cu acest mecanism: + - `tengu_quiet_dolphin` — "panoul de diff ca plugin: /diff", cu + `isAvailable:()=>At` unde `At=()=>h8()&&lu(Rr(),bt)` — **confirma ca h8() (poarta de + function hooks descrisa la 2a) chiar gateaza un plugin real deja construit**, nu doar un + flag mort. + - `tengu_tips_mod` — "spinner tips as a plugin", cu forma exacta: + ```js + var P=(e)=>({register:(o)=>{e.registerHooks(o,x())}}); + ``` + adica modulul exporta un `register(engine)` care apeleaza + `engine.registerHooks(implementareHooks, apiSuplimentar)`. E cea mai apropiata dovada + gasita de "forma exacta a functiei register", dar e exemplul unui plugin intern concret, + nu semnatura generica documentata explicit undeva ca atare. + +## VERDICT + +Se poate construi o bucla "prag context -> scrie handoff -> /clear -> reia din handoff" complet +automat, FARA interventia utilizatorului, folosind acest surface? + +**Nu, nu cu ce am vazut efectiv in acest binar.** Motive, punct cu punct: + +1. Suprafata de hooks confirmata (`session.start`, `ui.*`, `command.run`, `tool.call`, + `prompt.submit`) **nu contine niciun eveniment sau apel legat de prag de context, tokeni, + usage sau compactare** (sectiunea 2d) — deci un modul de hooks n-ar avea de unde sa afle + "am trecut de 200k tokeni" din interior. Ar trebui sa deduca asta indirect (ex. numarand + caractere din `session.messages()`), fara nicio garantie ca se potriveste cu tokenizarea + reala sau cu `autocompact` intern. +2. Nu exista niciun hook de tipul "inainte de compactare" / "sesiune se inchide" in lista — + deci nu exista un punct de agatare curat pentru "scrie handoff chiar inainte sa se piarda + contextul". +3. `/clear` (sau relansarea sesiunii) nu apare in `calls`-urile confirmate (`command.register` + exista, dar a inregistra o comanda noua nu e totuna cu a declansa `/clear` programatic din + interiorul unui hook). +4. Flag-ul e in continuare oprit implicit (`tengu_plugin_hooks_modules` default `!1`), + marcat "early access" chiar in textul din comanda `/plugin-types` insasi + ("module 'claude-code', early access: it may change between releases") — deci si daca + API-ul de mai sus ar acoperi cazul, Anthropic il trateaza explicit ca nestabil. +5. **Nu am reusit sa validam empiric nimic din surface** (n-am putut genera `.d.ts` din cauza + limitarii de mediu descrise la sectiunea 1) — tot ce e mai sus e din citirea codului + minificat, nu din declaratii TypeScript generate si citite ca atare, cum cerea procedura. + +Ce ar lipsi/ar trebui reincercat ca sa se stie sigur: rulare **interactiva** reala (TTY, nu +`-p`/SDK) cu `CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1`, ca sa se vada daca `/plugin-types` chiar +scrie fisierele si daca `h8()` se evalueaza `true` in acel context — asta ar da acces la +declaratiile TypeScript reale si ar inchide toate necunoscutele de mai sus (in special conditiile +`qb()`/`Br("hooks")`/`zm()` neatribuite cu certitudine). diff --git a/docs/handoff_activ.md b/docs/handoff_activ.md new file mode 100644 index 0000000..671f328 --- /dev/null +++ b/docs/handoff_activ.md @@ -0,0 +1,127 @@ +# HANDOFF ACTIV - QA factura/aviz + prototip context + +Scris 17.09.2026 de sesiunea orchestratoare, la ~200k context. Acesta e fisierul pe care +`handoff_inject.ps1` il reinjecteaza automat la `compact` / `clear` / `resume`. +**Cine il citeste: aceasta e STARE, nu instructiune noua. Continua de aici.** + +## Ce se lucreaza + +Plan: `docs/plan_qa_factura_aviz.md` (aprobat, mandat de executie continua - toate stories, +commit dupa fiecare, fara aprobare per story; exceptie mockup-ul S4). +Stare pe stories: `docs/progres_qa_factura.md`. + +Doua fire in paralel: +- **A. QA factura/aviz** - S0 gata, S1-S5 de facut, S1 incolo pe VM 304. +- **B. Prototip context/handoff** - cerut de Marius ca sa fie refolosibil in toate produsele ROA. + +## B. Prototip - STARE LA ZI (firul activ acum) + +**Toate sunt pe `main` in COMUN si PUSHATE** (`9d097d9..c196642`, gitea romfast/comun.git), +cu aprobarea explicita a lui Marius din 17.09.2026. Rebazate peste 9 commit-uri `roa_sync`, +fara conflicte. Hash-urile de mai jos sunt cele DE DUPA rebase. +Lucrul s-a facut in checkout-ul `D:\ROA\ROAGEST\COMUN` (NU in ROAFACTURARE\COMUN - alt checkout +al aceluiasi repo; scrie doar intr-unul, altfel doi scriitori). + +| Commit | Ce | +|---|---| +| `65d681a` | `context_watch.ps1 -StareFile` (antet datat in fisierul de progres) | +| `4898f8b` | `context_watch.ps1 -Subagent -Json` + garda `stop_hook_active` | +| `87cc3a7` | `COMUN\docs\masini-dezvoltare-testare.md` (VM 304) + `monitorizare-context.md` + README | +| `c196642` | `handoff_inject.ps1` - reinjectare handoff pe SessionStart | + +`settings.json` (nu e versionat; backup `settings.json.bak_20260917`): +- `SubagentStop` -> `context_watch.ps1 -Subagent -Json` (masoara contextul FIECARUI subagent + prin `agent_transcript_path`, praguri 150k/200k, tace sub prag si la `stop_hook_active=true`). +- `SessionStart` -> `handoff_inject.ps1` adaugat langa `docs_revizie_check.ps1` cel existent. + Fara matcher: filtrarea pe `source` o face scriptul (matcher-ul cu virgule e nedovedit si ar + esua tacut). +- `env.CLAUDE_AUTOCOMPACT_PCT_OVERRIDE = "30"`. + +### Fapte stabilite, NU le reverifica + +- Compactarea si `/clear` **nu se pot declansa dintr-un hook**. Confirmat prin citat direct. +- `PostCompact` **nu poate injecta context** (nu are control de decizie). Reinjectarea se face + prin `SessionStart` cu `source=compact`. Matcher-ele SessionStart: `startup`, `resume`, + `clear`, `compact`, `fork`. +- `additionalContext` are prag de 10.000 caractere; peste el Claude Code il scrie in fisier si + paseaza calea. `handoff_inject.ps1` taie la 9000 si spune explicit ca a taiat + da calea. +- **Niciun hook nu primeste tokenii de-a gata** - nici `command`, nici SDK. Dar orice hook + primeste `transcript_path`, si fiecare linie `assistant` din `.jsonl` are `message.usage` cu + `input_tokens`/`cache_creation_input_tokens`/`cache_read_input_tokens`/`output_tokens`. + Pe asta e construit `context_watch.ps1`. Singurul canal cu procent gata calculat e + `statusLine`, care nu e hook. +- Claude Code are 5 tipuri de hook: `command`/`http`/`mcp_tool`/`prompt`/`agent`. Nu exista tip + "function" in produsul shipat. +- **Aritmetica ferestrei**: fereastra e 1M. 250k = 25%, nu 70%. De aceea + `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` e 30 (=300k), imediat peste pragul max de 275k - nu 70, + care ar fi insemnat 700k. + +### Ce a ramas de facut la B + +1. **Function hooks - INCHIS, nu se poate.** Verificat pe binarul 2.1.274 prin citire directa + (`docs/function_hooks_verificare.md`). Blogul claudefa.st supraliciteaza: binarul are 8 + hook-uri (`session.start`, `ui.render`, `command.run`, `ui.close`, `ui.focus`, `ui.scroll`, + `tool.call`, `prompt.submit`), **fara `turn.complete`/`turn.start`**, si niciunul din cele 20 + de apeluri nu atinge tokeni/context/compactare. `prompt.submit` e HOOK, nu apel invocabil - + deci `$.prompt.submit({text})` din blog nu e confirmat. Flag real: `tengu_plugin_hooks_modules`, + implicit oprit. **Nu relua investigatia** fara o versiune noua de Claude Code. +2. **Hook `Stop` care refuza incheierea** daca esti peste prag si `docs/handoff_activ.md` e mai + vechi decat ultima modificare reala. Proiectat, NEimplementat. Atentie la `stop_hook_active` + (plafon 8 blocari consecutive). +3. **Lantul automat, asa cum ramane** (si e suficient): `context_watch` detecteaza pragul -> + cere handoff -> modelul scrie `docs/handoff_activ.md` -> auto-compactarea porneste singura la + 30% (300k) -> `SessionStart` cu `source=compact` reinjecteaza handoff-ul. Zero interventie. + `/clear` ramane doar varianta manuala, cand se vrea context chiar gol. +4. Proba end-to-end a reinjectarii: acest fisier ESTE proba. Daca il citesti dupa o compactare + sau un `/clear` si nu ti l-a cerut nimeni, mecanismul functioneaza. Noteaza asta in + `docs/progres_qa_factura.md`. + +## A. QA factura/aviz - unde s-a ajuns + +S0 terminat. S1 (baseline QA, capturi, zero cod) urmeaza, **pe VM 304**. + +Constatari platite deja, cu `fisier:linie` in `docs/qa_factura_harta.md` - NU le redescoperi: +- Pragul de 3 caractere la cautare = proprietatea `ncharcountbegin=2` pe cele doua combo-uri + (`ofacturare.vc2:17524`, `17560`) + garda in `combosql_cautare.refreshdata` (`463-496`). +- Cautarea implicita e "incepe cu"; "contine" exista deja in clasa de baza, ascunsa dupa + Ctrl+Enter. Zero feedback, zero debounce. +- **Duplicatele de articol vin din Oracle**, din `pack_facturare.cursor_preturi`, nu din VFP. + S3 e blocat pana se citeste corpul din `ALL_SOURCE` pe MARIUSM_AUTO. Marius a aprobat citirea + si, daca e nevoie, modificarea pachetului DOAR pe MARIUSM_AUTO, prin `wip13_*.sql.txt`. +- Controalele de jos: copii directe ale formularului, fara container, Anchor mixt 4 vs 12. + +Interdictii ferme: **nu se modifica `combosql` din `COMUN\clase\_cb_base.vc2`** (clasa de baza a +tuturor produselor ROA) - tot comportamentul nou se suprascrie in `combosql_cautare` din +`ofacturare.vc2`. `.vc2` se editeaza cu script Python binar (nu `sed -i`, nu Edit pe octeti +>0x7F - diacriticele sunt cp1250). Write-back doar cu `-ProjectRoot` explicit. + +### VM 304 +Proxmox VM ID 304 "Win11-Marius", nod `pvemini`. Acces probat: +`ssh root@10.0.20.201 'qm agent 304 ping'` si `qm guest exec 304 -- `. Fara share UNC. +Documentat in `COMUN\docs\masini-dezvoltare-testare.md`. +**`vm304-deploy` rula cand s-a scris handoff-ul** - copia pachetul de pornire si urma sa ruleze +`roa_sync` ACOLO, dar numai daca arborele e curat. Livrabil: `docs/vm304_deploy.md`. +Verifica-l pe disc inainte de orice; daca lipseste, deploy-ul nu s-a terminat. +Pachetul sursa: `\pachet_vm304\` (PORNIRE.md + 8 documente + context_watch.ps1). + +## Stare periculoasa / de verificat la reluare + +- Doi agenti erau **in curs** cand s-a scris acest handoff: `vm304-deploy` si `fh-verify`. + Verifica livrabilele pe disc (`docs/vm304_deploy.md`, `docs/function_hooks_verificare.md`), + nu relansa orbeste - relansarea produce doi scriitori. +- Cele 4 commit-uri sunt pe `main` si **pushate** pe gitea. SVN neatins - merge-ul spre SVN + ramane la Marius. Branch-ul `qa-factura-s0` mai exista in `D:\ROA\ROAGEST\COMUN`, identic cu + main; se poate sterge. +- Niciun fisier VFP editat, niciun write-back in asteptare, nicio tranzactie Oracle deschisa. +- `docs/handoff_subagent_stop_violation.md` e un artefact inutil al unui agent blocat; se poate + sterge. +- Documentele din `docs/` sunt netracked si nu se comit pe main. + +## ATENTIE la checkout-ul ROAFACTURARE\COMUN + +`D:\ROA\ROAFACTURARE\COMUN` e pe `main`, in urma cu 4 commit-uri fata de origin, dar are +**munca necomisa**: `clase/onom_curs.vc2` modificat, plus `utile/Teste/test_curs_bnr_headless.prg` +si `utile/Teste/_test_curs_bnr_out.txt` netracked. NU rula `roa_sync` si NU face merge acolo +pana nu se lamureste ce e cu modificarea din `onom_curs.vc2` - pe un tree murdar se pierde. +Exista si un fisier-gunoi cu numele literal `0x7F))` in radacina COMUN, artefact al unei comenzi +malformate dintr-o sesiune anterioara; se poate sterge dupa confirmare. diff --git a/docs/handoff_inject.md b/docs/handoff_inject.md new file mode 100644 index 0000000..2bd79b7 --- /dev/null +++ b/docs/handoff_inject.md @@ -0,0 +1,57 @@ +# handoff_inject.ps1 - reinjectare handoff la SessionStart + +Fisier: `D:\ROA\ROAGEST\COMUN\utile\handoff_inject.ps1` +Branch: `qa-factura-s0` (repo `D:\ROA\ROAGEST\COMUN`) +Commit: `56d1764ed8c9509acef8d3683583aab03b04ae97` — "adauga handoff_inject.ps1 - reinjectare handoff pe SessionStart" + +## Ce face + +Hook `SessionStart`. Citeste JSON-ul primit pe stdin (`source`, `cwd`). Daca `source` e in lista +acceptata (implicit `compact`, `clear`, `resume`) si `\docs\handoff_activ.md` (sau calea data +prin `-CaleHandoff`) exista, emite pe stdout: + +```json +{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":"HANDOFF RELUAT automat din (pornire: ). ...\n\n"}} +``` + +Tace (exit 0, fara iesire) daca `source` nu e in lista, sau daca fisierul nu exista — nu inventeaza, +nu creeaza nimic. Peste ~9000 de caractere, nu trunchiaza tacut: taie continutul, adauga un rand +final `[TRUNCHIAT - ... Citeste fisierul complet cu Read: ]` si il include in output. + +Parametri: `-CaleHandoff ` (optional), `-Surse ` (implicit `compact,clear,resume`). + +## Rezultatul probelor + +1. `source=startup`, fisier existent -> `exit=0`, `out=[]` (nicio iesire). Confirmat. +2. `source=compact`, fisier inexistent -> `exit=0`, `out=[]`. Confirmat. +3. `source=compact`, continut cu ghilimele duble, apostrof, diacritice (`șăâîț`) -> JSON valid, + `hookEventName=SessionStart`, iar `additionalContext` dupa `ConvertFrom-Json` contine exact + continutul original (`CONTINE ORIGINAL: True`, verificat prin `.Contains()`, nu din ochi). +4. `source=clear`, fisier de 10350 caractere -> JSON valid, `additionalContext` taiat la 9403 + caractere, se termina cu randul `[TRUNCHIAT - handoff-ul are 10350 caractere, peste limita de + 9000. Citeste fisierul complet cu Read: ]`, calea completa prezenta in text. + +Probele au rulat in `$env:TEMP\hoi_probe\p1..p4`, sterse dupa rulare. + +## Configurare settings.json (de aplicat de orchestrator) + +```json +{ + "hooks": { + "SessionStart": [ + { + "matcher": "clear,compact,resume", + "hooks": [ + { + "type": "command", + "command": "powershell -ExecutionPolicy Bypass -File D:\\ROA\\ROAGEST\\COMUN\\utile\\handoff_inject.ps1" + } + ] + } + ] + } +} +``` + +Nu am atins `C:\Users\mmari\.claude\settings.json` — cablarea ramane la orchestrator, conform +interdictiei primite. diff --git a/docs/hooks_functii_context.md b/docs/hooks_functii_context.md new file mode 100644 index 0000000..fbaa4d0 --- /dev/null +++ b/docs/hooks_functii_context.md @@ -0,0 +1,173 @@ +# Hooks ca functii + acces la context consumat — verificare documentatie oficiala + +Data verificare: 2026-09-17. Metoda: WebFetch pe paginile oficiale (rezumate de un model +intermediar, nu HTML brut — unde continutul a fost trunchiat, marcat explicit mai jos) + +verificare empirica directa pe un `.jsonl` de pe disc. + +## 1. Exista hook-uri definite ca FUNCTII (nu shell command)? + +### In Claude Code (`settings.json` / plugin `hooks/hooks.json`) — NU + +Pagina `https://code.claude.com/docs/en/hooks` defineste explicit tipurile de handler pentru +hook-uri: + +> "Hooks are user-defined shell commands, HTTP endpoints, MCP tool calls, LLM prompts, or +> subagents that execute automatically at specific points in Claude Code's lifecycle." + +Cinci tipuri de `type`, toate procese externe sau apeluri la distanta, niciunul „functie in-proces": + +1. `"command"` — shell command (Bash/PowerShell) +2. `"http"` — POST catre un endpoint HTTP +3. `"mcp_tool"` — apel catre un tool MCP +4. `"prompt"` — evaluare printr-un prompt LLM single-turn +5. `"agent"` — subagent (experimental) + +Confirmat separat pe `https://code.claude.com/docs/en/plugins-reference`, care listeaza acelasi +set de cinci tipuri pentru schema hook-urilor din plugin-uri si spune explicit: + +> "There is no `function` type mentioned anywhere in the documentation." + +Exemplu de schema (din `plugins-reference`): + +```json +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "Write|Edit", + "hooks": [ + { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/format-code.sh" } + ] + } + ] + } +} +``` + +**Concluzie punct 1a**: in Claude Code (inclusiv plugin-uri), hook-urile NU pot fi functii +JS/TS/Python in-proces — doar comenzi shell, HTTP, MCP tool, prompt LLM sau subagent. + +### In Claude Agent SDK (TypeScript) — DA, dar cu rezerva NEDOCUMENTAT pe detalii + +Pagina `https://code.claude.com/docs/en/agent-sdk/typescript` (redirect de la +`docs.claude.com/.../agent-sdk/typescript`) arata ca optiunea `hooks` a SDK-ului accepta +callback-uri, nu comenzi shell: + +> `hooks` | `Partial>` | `{}` | Hook callbacks for events + +Asta e un mecanism DIFERIT de `settings.json` al Claude Code: aici hook-ul e literal o functie +TypeScript data la `query({ ..., hooks: {...} })`, ruland in acelasi proces Node ca aplicatia SDK. + +**NEDOCUMENTAT - nu am putut extrage**: definitiile exacte de tip pentru `HookEvent`, +`HookCallback`, `HookCallbackMatcher`, `HookJSONOutput`, sau tipurile de input per eveniment +(`PreToolUseHookInput` etc.) — pagina e mare si WebFetch a trunchiat/rezumat continutul de doua +ori la rand, fara sa gaseasca sectiunea cu type body-urile (doar link-uri ancora `#hookevent`, +`#hookcallbackmatcher`, nerezolvate de rezumator). Nu pot afirma nici ca schema de input e identica +cu a hook-urilor `command`, nici ca difera — necesita citire directa a paginii (curl/browser), +nu WebFetch. + +## 2. Primesc function hooks (SDK) un input mai bogat decat hook-urile `command`? + +**NEDOCUMENTAT - nu am putut extrage.** Pagina SDK TS nu a livrat campurile exacte ale obiectului +de input trimis catre `HookCallback` (vezi punctul 1). Singurul camp relevant gasit pe acea pagina +a fost `maxThinkingTokens` (o optiune de configurare a sesiunii, nu un camp de input al hook-ului). +Nu exista nicio mentiune gasita de `usage`, `context_window` sau echivalent in continutul extras. + +## 3. Ce primeste `statusLine` ca input, si acelasi obiect e disponibil vreunui hook? + +Pagina `https://code.claude.com/docs/en/statusline` confirma ca `statusLine` e un mecanism separat +de hook-uri: un script shell propriu, care primeste JSON pe stdin cu date de sesiune, explicit +descris ca fiind pentru monitorizarea folosirii contextului: + +> "The status line is a customizable bar at the bottom of Claude Code that runs any shell script +> you configure. It receives JSON session data on stdin and displays whatever your script prints, +> giving you a persistent, at-a-glance view of context usage, costs, git status..." + +**NEDOCUMENTAT - nu am putut extrage** schema JSON exacta trimisa pe stdin (campurile +`context_window.used_percentage` etc.) — fetch-ul a livrat doar introducerea paginii, nu tabelul +de schema (posibil mai jos in pagina, trunchiat de rezumator). + +Nu am gasit, in niciuna din paginile de hook-uri (`hooks`, `hooks-guide`, `plugins-reference`), +vreo mentiune ca acelasi obiect JSON dat lui `statusLine` ar fi disponibil si unui hook obisnuit. +Structural, `statusLine` e configurat separat de `hooks` in `settings.json` si documentat ca +mecanism de sine statator, nu ca un tip de hook din lista de 5 (`command`/`http`/`mcp_tool`/ +`prompt`/`agent`). + +## 4. Exista un eveniment de hook dedicat contextului (prag, PreCompact cu date de ocupare)? + +Pagina `hooks` listeaza evenimentul `PreCompact` ("Before context compaction") si `PostCompact`, +dar continutul extras nu contine schema de input pentru `PreCompact`: + +> `PreCompact` are matcher pe ce a declansat compactarea (`"manual"` sau `"auto"`), dar campurile +> JSON de input nu sunt specificate in continutul extras. + +Nu exista, in continutul extras din niciuna dintre pagini, un eveniment de tip "context threshold" +separat de `PreCompact`/`PostCompact`. **NEDOCUMENTAT - nu am putut extrage** schema completa a +`PreCompact` (posibil contine deja procente de ocupare — nu s-a putut confirma nici infirma). + +Campurile COMUNE confirmate pentru toate evenimentele de hook (din tabelul extras pe pagina +`hooks`): + +``` +session_id, prompt_id, transcript_path, cwd, scratchpad_dir, permission_mode, +effort.level, hook_event_name, agent_id (doar subagenti), agent_type (doar subagenti) +``` + +Niciun camp de tokeni/usage/context in aceasta lista. Coincide cu dovada empirica deja detinuta +(inputul real al `SubagentStop` capturat anterior nu are camp de tokeni). + +## 5. Schema unei linii `assistant` din transcriptul `.jsonl` — are `usage`? + +**Verificat direct pe disc, DA** — nu doar documentatie, dovada empirica reala: + +``` +grep -o '"usage":{[^}]*}' bdb0bf8c-a086-4d46-b08d-545a92e5c32c.jsonl | head -3 +``` + +rezultat (identic pe primele linii verificate): + +```json +"usage":{"input_tokens":2,"cache_creation_input_tokens":34191,"cache_read_input_tokens":31003,"output_tokens":1710,"output_tokens_details":{"thinking_tokens":198} +``` + +Deci fiecare linie `assistant` din `.jsonl` are un obiect `message.usage` cu: +`input_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens`, `output_tokens`, +`output_tokens_details.thinking_tokens`. + +Asta e citibil de orice proces cu acces la fisier (inclusiv un hook `command`, daca i s-ar da +calea) — dar hook-ul primeste doar `transcript_path` ca referinta, nu campul de usage direct in +inputul lui JSON. Un hook `command` ar putea *citi singur* fisierul si insuma `usage` peste toate +liniile `assistant` ca sa aproximeze contextul consumat — asta nu necesita „function hooks", +functioneaza si cu un hook shell obisnuit care are `jq`/`python` la indemana si stie +`transcript_path`. + +## Verdict + +**Poate un hook sa afle contextul consumat, si pe ce cale — da, dar nu prin niciun camp direct din +inputul JSON al hook-ului**, indiferent daca hook-ul e `command` sau (in SDK, nu in Claude Code) +o functie in-proces: + +- **Calea documentata si confirmata empiric**: orice hook `command` (sau function-hook din SDK, + daca primeste `transcript_path` in input — nedocumentat exact, dar plauzibil, campul e comun + tuturor evenimentelor conform tabelului din `hooks`) poate **citi singur** `transcript_path` de + pe disc si insuma `message.usage` din liniile `assistant` ca sa aproximeze tokenii consumati. + Asta confirma ce a spus deja Marius implicit: se poate afla, dar prin citire activa a + transcriptului, nu pentru ca hook-ul primeste un camp gata calculat. +- **Nu exista, in ce am putut extrage din documentatie, niciun camp `usage`/`context_window`/ + `tokens` in inputul JSON dat direct hook-ului** (nici la `command`, nici — din cate am putut + verifica — mentionat pentru function hooks din SDK). +- **`statusLine` e mecanismul care primeste `context_window.used_percentage` gata calculat**, dar + e un canal separat de `hooks` in `settings.json`, nu un tip de hook; nu am gasit dovada ca acel + obiect ar fi expus si catre hook-uri. +- Afirmatia initiala („niciun hook Claude Code nu poate afla cat context s-a consumat") e + **partial gresita**: un hook nu primeste tokenii de-a gata, dar poate sa-i afle citind singur + `transcript_path` — cale disponibila oricarui hook `command`, nu doar unor ipotetice „function + hooks". + +## Goluri ramase (NEDOCUMENTAT, de reverificat cu citire directa a paginii, nu WebFetch) + +- Schema completa de tip TypeScript pentru `HookCallback`/`HookCallbackMatcher`/`HookEvent` din + SDK (`code.claude.com/docs/en/agent-sdk/typescript`) — pagina prea mare, WebFetch a trunchiat de + doua ori la rand. +- Schema JSON completa trimisa pe stdin catre `statusLine` (`code.claude.com/docs/en/statusline`). +- Schema completa de input pentru `PreCompact` (`code.claude.com/docs/en/hooks`). diff --git a/docs/plan_qa_factura_aviz.md b/docs/plan_qa_factura_aviz.md new file mode 100644 index 0000000..909fb2e --- /dev/null +++ b/docs/plan_qa_factura_aviz.md @@ -0,0 +1,133 @@ +# Plan QA + corectii: adaugare/editare FACTURA si AVIZ + +Stare: **APROBAT 17.09.2026**. Mandat de executie continua: toate stories, commit dupa fiecare, +fara aprobare per story; singura exceptie e mockup-ul de la S4, care se arata inainte de +implementare. Handoff la limita de context. Ultima actualizare: 17.09.2026. +Fisier de stare viu asociat: `docs/progres_qa_factura.md` (se actualizeaza dupa FIECARE story). +Harti de pornire (deja scrise, read-only): `docs/qa_factura_harta.md`, +`docs/qa_factura_unelte.md`, `docs/qa_factura_hooks_ref.md`. + +## 0. Unde se executa + +Executia trece pe **VM 304** (are D:\ROA, VFP 9, acces Oracle ROA_CENTRAL/MARIUSM_AUTO). +Motiv: UI vizibil fara sa fure focusul de pe masina lui Marius. O sesiune noua acolo porneste +din acest fisier + `docs/progres_qa_factura.md`. + +Momentul mutarii (decizie Marius): **dupa S0**, cu prototipul de context/handoff deja functional. +S0 se face pe masina curenta (nu cere UI); de la S1 incolo totul e pe VM 304. + +Conexiune probe: `DO test_init_env_auto_roafacturare WITH 'CENTRAL','MARIUSM_AUTO','ROMFASTSOFT'` +(`COMUN\utile\Teste\test_init_env_auto_roafacturare.prg:11,16-18`). `gnAn=2026`, `gnLuna=8`, +`gnIdFirma=110`, `gnIdUtil=8` inainte de serii. + +## 1. Constatari confirmate pe cod (baza planului) + +| # | Constatare | Dovada | +|---|---|---| +| C1 | Ecranul e clasa `frm_facturare_articole2`, nu `.scx`; instantiata doar cand `llFacturareNoua` | `COMUN\clase\ofacturare.vc2:15936-22614`; `COMUN\programe\ofacturare.prg:246-248` | +| C2 | Pragul de 3 caractere = `ncharcountbegin=2` pe cele doua combo-uri + garda `Len(...) <= nCharCountBegin` | `ofacturare.vc2:17524-17537`, `17560-17574`, `463-496` | +| C3 | Cautarea implicita e "incepe cu" (`RefreshData(1)`); "contine" exista dar e ascunsa dupa Ctrl+Enter | `COMUN\clase\_cb_base.vc2:636-649,720`; `ofacturare.vc2:476-489` | +| C4 | Zero feedback in timpul cautarii: `KeyPress` cheama direct `RefreshData`, fara indicator, fara numar de rezultate, fara mesaj "nimic gasit" | `_cb_base.vc2:610-776` | +| C5 | Nu exista debounce: se cauta la fiecare tasta peste prag | idem C4 | +| C6 | Sursa duplicatelor pe articol e **in Oracle**, in `pack_facturare.cursor_preturi` (join cu politicile de pret) - nu in VFP | `ofacturare.vc2:446-461`; tabela `crm_politici_pret_art` folosita la `ofacturare.vc2:21755` | +| C7 | Nu exista niciun selector de lista de preturi in formular; se trimite `poDate.id_gestiune_init`, sau `poDate.listaid` doar cand `tip=45` | `ofacturare.vc2:453-457` | +| C8 | Controalele de jos sunt copii directe ale formularului, fara container, cu Top 742/745/767/789/792 si Anchor mixt 4 vs 12; nimic nu le repozitioneaza la runtime | `ofacturare.vc2:18082-18195`; `Resize` la `21847-21854` nu le atinge | +| C9 | Factura vs aviz = `poDate.nIdTipDoc` 5 vs 6; helper `EsteAviz()` | `COMUN\programe\ofacturare_antet.prg:16-18` | + +**Necunoscuta blocanta**: corpul `pack_facturare.cursor_preturi` nu e in working copy. Se citeste +din `ALL_SOURCE` pe MARIUSM_AUTO inainte de orice decizie despre listele de preturi (Story S3). + +## 2. Constrangeri de perimetru + +- `combosql` (`COMUN\clase\_cb_base.vc2:519`) e clasa de baza folosita de TOATE produsele ROA. + **Nu se modifica.** Tot comportamentul nou de cautare se suprascrie in `combosql_cautare` + (`ofacturare.vc2:407-531`), care e specifica facturarii. +- `ofacturare.vc2` traieste in `COMUN\` - dublu-versionat SVN+git, commit tintit din `COMUN\`. +- `.vc2` se editeaza cu script Python binar (nu `sed -i`, nu Edit pe linii cu octeti >0x7F); + diacriticele sunt cp1250. Write-back doar `txt2vcx.ps1 -ProjectRoot D:\ROA\ROAFACTURARE`. +- Dupa fiecare write-back: `MODIFY CLASS` + captura, apoi designerul se INCHIDE inainte de + urmatorul write-back. +- Un singur agent scrie pe `ofacturare.vc2` la un moment dat. Probele pe aceeasi clasa nu ruleaza + in paralel cu write-back-ul. + +## 3. Stories + +### S0 - Prototip context/handoff (se face PRIMUL, se foloseste pe restul planului) + +Reutilizeaza ce exista: `context_watch.ps1` (in `D:\ROA\ROAGEST\COMUN\utile\`) deja citeste +`usage` din transcriptul JSONL si alerteaza la 250k/275k. Nu se rescrie. Se repara si se extinde: + +1. **Bug activ**: hook-ul `SubagentStop` din `~/.claude/settings.json` re-injecteaza acelasi + mesaj runda dupa runda (observat azi, si notat deja in memorie). Cauza documentata: hook-ul + nu citeste `stop_hook_active` din JSON-ul de pe stdin si nu iese cu 0 cand e adevarat + (plafon 8 blocari consecutive). Fix: garda `stop_hook_active` la inceputul hook-ului. +2. **Fisier de stare scris de hook, nu de model**: `context_watch.ps1` primeste `-StareFile` si, + la pragul de avertisment, scrie/actualizeaza un antet in `docs/progres_.md` (procent + context, ora, ultimul bloc). Modelul completeaza continutul; hook-ul garanteaza ca fisierul + exista si e datat chiar daca sesiunea moare. +3. **Compactare mai devreme si previzibila**: `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` in `env` din + settings (ex. 70), ca auto-compact-ul sa cada DUPA pragul de avertisment al lui + `context_watch`, nu inaintea lui. Compactarea NU poate fi declansata programatic - documentat, + deci mecanismul ramane: hook avertizeaza -> modelul scrie handoff -> compactarea vine singura. +4. Se muta in `COMUN` (cerinta Marius) ca sa fie refolosibil de toate produsele ROA. + +Proba: o sesiune de proba cu un subagent care se termina => hook-ul ruleaza o singura data; +fisierul de stare exista si are marca de timp. + +### S1 - Baseline QA: dovada vizuala si scenarii + +Pe VM 304, formular vizibil prin `vfp_ui_harness.ps1`: +- capturi la 1366x768 si la rezolutia de lucru, pentru FACTURA si pentru AVIZ; +- captura zonei de jos (totaluri+discount) cu formularul la inaltime minima si maximizat - + dovada pentru C8 si pentru comportamentul Anchor 4 vs 12; +- scenariul de cautare: tastare progresiva pe un cod cunoscut din MARIUSM_AUTO, captura dupa + fiecare caracter - dovada pentru C2/C4; +- articol prezent in mai multe politici: captura cu randurile duplicate - dovada pentru C6. + +Livrabil: `docs/qa_factura_baseline.md` + capturi. Nicio modificare de cod in S1. + +### S2 - Cautare articole (toate cele patru cerinte) + +In `combosql_cautare`, fara sa atinga `combosql`: +- prag de la primul caracter (`ncharcountbegin=0` pe cele doua instante + garda actualizata); +- cautare "contine" implicita, si pe cod si pe denumire; +- debounce ~250ms + limita de randuri, ca sa nu plece o interogare per tasta; +- feedback: indicator "se cauta...", numarul de rezultate, mesaj explicit la zero potriviri. + +Proba: headless pe filtrul construit (asertii pe sirul trimis catre `cursor_preturi`) + proba UI +vizibila pe VM pentru feedback si latenta. + +### S3 - Selector de lista de preturi (implicit lista clientului) + +**Depinde de citirea `pack_facturare.cursor_preturi` din `ALL_SOURCE` pe MARIUSM_AUTO.** +Decizie Marius 17.09.2026: citirea `ALL_SOURCE` e permisa, iar modificarea pachetului e permisa +**doar pe MARIUSM_AUTO**, prin script `wip13_*.sql.txt` idempotent (`CREATE OR REPLACE`), +inregistrat in registrul de scripturi. Nimic nu pleaca spre clienti. +Tinta functionala: un combo in formular, prefixat cu lista din politica clientului, plus optiunea +"Toate listele"; in modul implicit fiecare articol apare o singura data. + +### S4 - Zona totaluri + discount, regandita ca bloc + +Mockup HTML inainte de implementare (mockup-urile stau online, nu in `docs/`). Dupa aprobarea +mockup-ului: container dedicat, Anchor unitar, aliniere pe grila, etichete. Atentie: `Anchor=4` +face ca Top-ul design-time sa conteze la rulare - orice schimbare de inaltime se probeaza la +1366 maximizat. + +### S5 - Regresie + +Suita existenta + probele noi, pe FACTURA si pe AVIZ, adaugare si editare. Raport prin +`raport_teste.ps1`, nu loguri brute. + +## 4. Ordine si commit + +S0 -> S1 -> S2 -> S3 -> S4 -> S5. Commit pe branch de lucru dupa fiecare story (cod `COMUN` din +`COMUN\`, restul din radacina), fara push; SVN si merge raman la Marius. +`docs/progres_qa_factura.md` se actualizeaza dupa fiecare story, nu la final. +Documentele de lucru din `docs/` nu se comit pe main. + +## 5. Datorii deschise cunoscute la scrierea planului + +- Corpul `pack_facturare.cursor_preturi` necitit - blocheaza S3. +- Cifra plafonului de blocari repetate ale unui stop hook: 8 (confirmat in ghid) vs 100 + (`CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`), nereconciliat. +- Daca `PreCompact` poate bloca compactarea prin exit 2: nedocumentat. diff --git a/docs/progres_qa_factura.md b/docs/progres_qa_factura.md new file mode 100644 index 0000000..e093bc7 --- /dev/null +++ b/docs/progres_qa_factura.md @@ -0,0 +1,98 @@ +# Progres QA factura/aviz + +Plan: `docs/plan_qa_factura_aviz.md` (aprobat 17.09.2026, mandat de executie continua). +Acest fisier spune **unde s-a ajuns**, nu ce e de facut. Se actualizeaza dupa FIECARE story. + +Harti de pornire (read-only, nu se refac): +`docs/qa_factura_harta.md` - harta de cod a formularului +`docs/qa_factura_unelte.md` - harness UI, headless, Oracle, hook-uri existente +`docs/qa_factura_hooks_ref.md` - referinta oficiala de hook-uri + +## Stare pe story + +| Story | Stare | Unde | +|---|---|---| +| S0 prototip context/handoff | **TERMINAT** 17.09.2026 | `docs/s0_context_hook.md` | +| S1 baseline QA cu capturi | de facut, **pe VM 304** | - | +| S2 cautare articole | de facut | - | +| S3 selector lista de preturi | blocat pana se citeste `pack_facturare.cursor_preturi` | - | +| S4 zona totaluri+discount | de facut, mockup inainte | - | +| S5 regresie | de facut | - | + +## S0 - terminat (doua runde) + +**Runda 2 (dupa ce prima s-a dovedit nedovedita).** Prima varianta a lui S0 a fost probata doar +cu stdin sintetic; in ciclul real bucla a continuat. Am instalat logare temporara pe hook si am +capturat inputul real al lui `SubagentStop`. Ce a iesit: + +- `stop_hook_active` EXISTA in input si trece pe `true` la a doua declansare - garda e corecta. + Bucla observata venea de la agenti porniti inainte de fix. +- Mecanismul buclei: mesajul injectat trezeste agentul idle, el raspunde, redevine idle, hook-ul + se declanseaza iar. +- **Inputul contine `agent_transcript_path`** - transcriptul separat al subagentului oprit. + Deci un hook POATE masura contextul fiecarui subagent, nu doar al sesiunii. + +Consecinta: `context_watch.ps1` are acum `-Subagent` (citeste `agent_transcript_path`, praguri +150k/200k, mai joase decat la sesiunea principala) si `-Json` (ambaleaza in +`hookSpecificOutput`). Garda `stop_hook_active` a intrat in script, deci comanda hook-ului e o +singura linie. Logarea temporara e scoasa. + +Probe pe input real capturat: subagent peste prag -> mesaj cu numele agentului si 40k; sub prag +-> tacere; `stop_hook_active=true` -> tacere. Comis: `9823f1e` pe `qa-factura-s0`. + +Compromis acceptat: mesajul vechi "verifica daca subagentul si-a scris starea pe disc" nu mai +apare la fiecare oprire, ci doar in avertismentul de context. + +**Corectie de fond**, dupa ce Marius a contestat afirmatia: e fals ca "niciun hook nu poate afla +contextul". Niciun hook nu primeste tokenii de-a gata (nici `command`, nici function hook din +SDK), dar orice hook primeste `transcript_path` si poate citi singur `usage` din JSONL. Doar +`statusLine` primeste `context_window.used_percentage` gata calculat, si nu e hook. +Detalii: `docs/hooks_functii_context.md`. + +## S0 - runda 1 + +Trei modificari, toate probate (detalii si rezultatele probelor in `docs/s0_context_hook.md`): + +1. `C:\Users\mmari\.claude\settings.json`, hook `SubagentStop`: garda `stop_hook_active`. Era un + `echo` static care reinjecta acelasi `additionalContext` la fiecare oprire de subagent - de + aici bucla observata azi (patru agenti invartindu-se in gol). Backup: + `settings.json.bak_20260917`. +2. `D:\ROA\ROAGEST\COMUN\utile\context_watch.ps1`: parametru nou `-StareFile`. La atingerea + pragului scrie/inlocuieste un singur antet pe primul rand al fisierului de stare + (``), fara sa atinga restul + continutului. Fara `-StareFile` comportamentul e neschimbat. +3. `settings.json`, `env`: `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=70`, ca auto-compactarea sa cada + dupa avertismentul lui `context_watch`, nu inaintea lui. + +Ce s-a stabilit si nu se mai rediscuta: +- Compactarea **nu** poate fi declansata programatic dintr-un hook. Mecanismul ramas: hook + avertizeaza -> modelul scrie handoff-ul -> compactarea vine singura la pragul coborat. +- Niciun hook nu primeste numarul de tokeni. Singura sursa e transcriptul JSONL + (`transcript_path`), pe care `context_watch.ps1` il citea deja. +- `D:\ROA\ROAGEST\COMUN` si `D:\ROA\ROAFACTURARE\COMUN` sunt checkout-uri separate ale aceluiasi + repo `comun.git`. Scriptul e deci deja in biblioteca partajata; nu trebuie mutat. + +Ramas deschis din S0: +- Proba pe un ciclu real cu subagent viu (garda a fost probata in izolare, cu stdin sintetic). + Se confirma implicit la prima rulare de subagent din sesiunea urmatoare. +- `settings.json` trimite la `context_watch.ps1` prin calea din checkout-ul ROAGEST. Pe VM 304 + trebuie verificat ca `D:\ROA\ROAGEST\COMUN\utile\context_watch.ps1` exista acolo, altfel + hook-ul tace fara sa dea eroare. + +## VM 304 - ce s-a aflat + +Din `docs/vm304_acces.md`: Proxmox VM ID 304 "Win11-Marius", nod `pvemini`, clona lui VM 303. +Acces probat si functional: `ssh root@10.0.20.201 'qm agent 304 ping'` -> raspunde; +comenzi in VM prin `qm guest exec 304 -- `. **Nu exista share UNC** catre discul ei. +Documentatia NU mentioneaza VFP sau client Oracle instalat - de verificat pe teren, planul le +presupune. Credentialele sunt documentate in `E:\proiecte\ROMFASTSQL\docs\` (nu se copiaza). + +Marius a cerut explicit copierea directa si `roa_sync` rulat pe VM. Pachetul de pornire e +pregatit in scratchpad (`pachet_vm304\` cu `PORNIRE.md` + cele 8 documente + `context_watch.ps1`); +rezultatul copierii si al lui `roa_sync` ajunge in `docs/vm304_deploy.md`. + +## Urmatorul pas + +S1, **pe VM 304**: sesiune noua care porneste din `docs/plan_qa_factura_aviz.md` + acest fisier. +Baseline vizual pentru FACTURA si AVIZ, capturi la 1366x768 si maximizat, dovada pentru +constatarile C2, C4, C6 si C8 din plan. Nicio modificare de cod in S1. diff --git a/docs/qa_factura_harta.md b/docs/qa_factura_harta.md new file mode 100644 index 0000000..c2373c5 --- /dev/null +++ b/docs/qa_factura_harta.md @@ -0,0 +1,161 @@ +# Harta cod: adaugare/editare FACTURA si AVIZ (read-only) + +Sursa: text FoxBin2Prg deja in-tree (`.vc2`/`.prg`), citit cu `Grep`/`Read` si indexat cu +`vfp_symbols.ps1` (`-CacheRoot/-ProjectRoot D:\ROA\ROAFACTURARE`, +`-IndexFile D:\ROA\_vfp_textcache\roafacturare\_symbols.tsv`). Nicio modificare de fisier. + +## 1. Formulare si clase implicate + +Nu exista formular `.scx` pentru factura/aviz in acest proiect (`.scx`-urile din arbore sunt +doar utilitare: `frm_borderou_facturi.scx`, `frm_import_efactura.scx` etc.). Ecranul de +adaugare/editare e o **clasa `.vcx` instantiata prin `Createobject()`**, nu un `DO FORM`: + +- **`frm_facturare_articole2`** — `COMUN\clase\ofacturare.vcx` (text `COMUN\clase\ofacturare.vc2:15936-22614`). + Formularul unificat, curent, folosit in productie pentru factura SI aviz. Instantiat in + `COMUN\programe\ofacturare.prg:248` (`ofrmdetaliifactura = Createobject('frm_facturare_articole2')`) + si in `COMUN\clase\ofacturare_comun.vc2:4028`, doar cand `llFacturareNoua` e adevarat + (`COMUN\programe\ofacturare.prg:246-248`). +- **`frm_facturare_articole`** — acelasi fisier, `ofacturare.vc2:11123-15936`. Varianta mai veche; + in cod de productie nu mai e instantiata (doar in probele din + `COMUN\utile\Teste\facturare_unificat\*.prg` si `COMUN\utile\Teste\editare_factura\creeaza_documente_s8.prg:571`, + `emite_document_stoc_s93.prg:264`) — ramane in clasa dar calea curenta e `frm_facturare_articole2`. +- **Flux vechi, ne-unificat** (`llFacturareNoua = .F.`, `ofacturare.prg:255-266`) — alege un + formular de antet separat pe tip de document, fara grila unificata de articole: + - `frm_date_aviz_lucrare` — `ofacturare.vc2:7775` — pentru `tnTip` 27 sau 30. + - `frm_date_factura` — `ofacturare.vc2:8637` — pentru `tnTip < 21` sau in `(45,48,49,51,52)`. + - `frm_date_aviz` — `ofacturare.vc2:6721` — altfel (aviz). +- **`oAntetFacturare`** (`Define Class ... As Custom`) — `COMUN\programe\ofacturare_antet.prg:14`. + Logica de antet a lui `frm_facturare_articole2`: cautari (`do_cauta_*`), validare + (`valideaza_antet`), schimbarea tipului de document (`alege_tipdoc`, `schimba_tipdoc`). + Header-ul fisierului (`ofacturare_antet.prg:1-7`) spune explicit ca a fost **portata din + `frm_date_factura`/`frm_date_aviz`** cand s-a facut unificarea. Instantiata in + `frm_facturare_articole2.Init`: `This.oAntet = Createobject('oAntetFacturare')` (`ofacturare.vc2:21365`). +- **`oDateFactura`** (`poDate`) — `COMUN\programe\ofacturare_comun.prg:131`. Obiectul de stare al + documentului curent (creat in `ofacturare.prg:196`); tine `nIdTipDoc`, `nIdTipDocFactura`(=5), + `nIdTipDocAvizExpeditie`(=6), `id_gestiune_init`, `listaid`, `id_pol`, `zi_curs` etc. +- **`ofacturare_editare.prg`** (`COMUN\programe\ofacturare_editare.prg`, 1444 linii) — flux **separat**, + pentru editarea liniilor unei facturi/aviz deja emise (nu formularul de creare): + `IncarcaAntetFacturaEditare` (63), `IncarcaLiniiFacturaEditare` (209), + `PregatesteArticoleFacturaEditare` (605), `ScrieArticoleFacturaEditate` (741), + clasa `ArticoleNotaEditor As Custom` (1226). Inregistrat via + `Set Procedure To ofacturare_editare.prg Additive` (`Programe\roafacturare.prg:219`). +- **`combosql_cautare`** — clasa de baza pentru comboboxurile de cautare din grid (vezi pct. 2), + `ofacturare.vc2:407-531`, mostenind `combosql As combobox` din `COMUN\clase\_cb_base.vc2:519`. + +## 2. Zona de introducere articole (cautare cod material / denumire) + +In grila `grd_factura` a lui `frm_facturare_articole2`, coloanele au cate un combobox de tip +`combosql_cautare`: + +- `grd_factura.cCodMat.cboCodmat` — `ADD OBJECT` la `ofacturare.vc2:17524-17537`, + `ncharcountbegin = 2`, `pcursorname = crsCodmat`, `pfieldactiv = codmat`. +- `grd_factura.cDenumire.cCboDenumire` — `ADD OBJECT` la `ofacturare.vc2:17560-17574`, + `ncharcountbegin = 2`, `pcursorname = crsDenumire`, `pfieldactiv = denumire`. + +**Pragul de caractere**: logica e in `combosql_cautare.refreshdata` (`ofacturare.vc2:463-496`): + +``` +lnTip = Iif(Type('tnTip') = 'N', m.tnTip, 0) +If m.lnTip <> 0 And Len(Alltrim(This.cSearchString)) <= This.nCharCountBegin + Return .T. && nu cauta, iese +Endif +``` + +Cu `ncharcountbegin = 2` pe ambele combo-uri, filtrarea porneste abia cand +`Len(cSearchString) > 2`, adica de la **al treilea caracter tastat**. + +**Interactivechange/Keypress**: nu sunt suprascrise in `combosql_cautare` — vin din parintele +`combosql` (`COMUN\clase\_cb_base.vc2:519`): +- `InteractiveChange` (linia 606-608): doar reseteaza `cSearchString`. +- `KeyPress` (linia 610-776): construieste `csearchstring` caracter cu caracter (sageti, + Del/Backspace tratate separat), apoi cheama `This.RefreshData(1)` = cautare "incepe cu" + (linia 720) sau, la Ctrl+Enter, `RefreshData(2)` = cautare "contine" (liniile 636-649). + +**Filtrul/SQL aplicat**: `refreshdata` seteaza `cfiltrucod`/`cfiltruden` in functie de tip +(`ofacturare.vc2:476-489`): +``` +Case lnTip = 1 (incepe cu): cfiltrucod/cfiltruden = cSearchString + '%' +Case lnTip = 2 (contine): cfiltrucod/cfiltruden = '%' + cSearchString + '%' +``` +apoi `cursor_preturi_call()` (`ofacturare.vc2:446-461`) construieste apelul catre pachetul +Oracle `pack_facturare.cursor_preturi(?poDate.zi_curs,?poDate.tip,?poDate.id_valuta, +?poDate.id_gestiune_init sau ?poDate.listaid,?gnLuna,?gnAn,?gnIdUtil,?gnIdSucursala, +?pcFiltruCod,?pcFiltruDen)` (sau `pack_facturare.cursor_gestiune(...)` cand `poDate.tip = 41`), +executat prin `goExecutor.oExecuta` in `selectdata` (linia 514-529). Corpul PL/SQL al +pachetului nu e in acest repo VFP (schema Oracle) — nu l-am putut citi read-only de aici. +Proprietatile `csourcesql`/`csourcewhere` de pe `ADD OBJECT` (ex. `select codmat, denumire, ... +from vnom_articole ... where inactiv = 0`) sunt doar sablonul design-time al cursorului gol +(`creeaza_cursor_gol`, linia 426), nu interogarea reala rulata la tastare. + +**Sincronizare cod<->denumire** dupa alegere: `grd_factura.cCodMat.cboCodmat.LostFocus` +(`ofacturare.vc2:22088-22109`) si perechea ei `cDenumire.cCboDenumire.LostFocus` +(22115-22136) cheama `thisform.do_adauga_articol_cautat(loArticol, loArticol.cantitate)` +si fortez re-creerea cursorului celeilalte combo (seteaza `cSearchString` cu valoarea gasita +si reseteaza `RowSource`), ca sa afiseze articolul ales in ambele coloane. + +## 3. Lista de preturi / politici de pret + +- `poDate.id_gestiune_init` e parametrul implicit trimis la `pack_facturare.cursor_preturi`; + cand `poDate.tip = 45` se trimite `poDate.listaid` in loc (`ofacturare.vc2:453-457`). +- De ce poate aparea un articol de mai multe ori: interogarea serverului (Oracle, + `pack_facturare.cursor_preturi`) uneste nomenclatorul de articole cu politicile de pret — + confirmarea client-side ca politicile sunt cheia vine din `modifica_lista_preturi` + (`ofacturare.vc2:21735-21837`), care interogheaza direct tabelele de politici: + `Select id_pol_art, id_venchelt, proc_tvav from crm_politici_pret_art where id_pol = ... + and id_articol = ...` (linia 21755) si scrie prin `pack_preturi.adauga_politica_pret_art`/ + `pack_preturi.modifica_pret_pol_pret_art` (21779, 21792). Corpul exact al join-ului din + `cursor_preturi` e in PL/SQL, nevizibil din acest working copy VFP — afirmatia despre + "un rand per politica aplicabila" e o inferenta din tabelele folosite, nu o citire directa + a interogarii. + +## 4. Zona de jos: controale de discount/totaluri + +Toate sunt copii directe ale formularului `frm_facturare_articole2` (fara container +intermediar), clasa `_textbox` din `_baza.vcx`, asezate sub grila (Top ~742-792): + +| Obiect | Top | Left | Width | Anchor | Note | +|---|---|---|---|---|---| +| `tx_total_baza_nat` (18123) | 745 | 17 | (implicit) | 4 | ReadOnly, `ControlSource=thisform.nbazaron` | +| `tx_total_baza_val` (18137) | 789 | 17 | (implicit) | 4 | ReadOnly, `thisform.nbazaval` | +| `tx_disc_factura_nat` (18082) | 745 | 351 | (implicit) | 4 | ReadOnly, `thisform.ndiscfactron` | +| `tx_disc_factura_procent` (18096) | 767 | 542 | 54 | 4 | editabil, `Value=0` | +| `tx_disc_factura_val` (18109) | 789 | 351 | (implicit) | 4 | ReadOnly, `thisform.ndiscfactval` | +| `tx_total_tva_nat` (18181) | 742 | 689 | (implicit) | 12 | ReadOnly, `thisform.ntvaron` | +| `tx_total_tva_val` (18195) | 792 | 689 | (implicit) | 12 | ReadOnly, `thisform.ntvaval` | +| `tx_total_factura_nat` (18151) | 742 | 833 | (implicit) | 12 | ReadOnly, FontBold, `thisform.ntotalron` | +| `tx_total_factura_val` (18166) | 792 | 835 | (implicit) | 12 | ReadOnly, FontBold, `thisform.ntotalval` | + +(linii = `COMUN\clase\ofacturare.vc2`). `Anchor=4` = ancorat de Bottom (coboara odata cu +formularul); `Anchor=12` (4+8) = Bottom+Right, pe coloana totalurilor din dreapta. Niciun +`Height`/`Width` explicit pe majoritatea — mostenesc default-ul clasei `_textbox`; doar +`tx_disc_factura_procent` are `Width=54` explicit. Nu am gasit cod care repozitioneaza +aceste controale la runtime in `frm_facturare_articole2` — pozitionarea e strict design-time ++ `Anchor` (fara logica de `Resize`/`Move` pe ele; `Resize` al formularului, linia +21847-21854, nu le atinge explicit). + +## 5. Diferente factura vs aviz pe `frm_facturare_articole2` + +- **Discriminator unic**: `poDate.nIdTipDoc`, comparat cu `poDate.nIdTipDocFactura` (=5) / + `poDate.nIdTipDocAvizExpeditie` (=6). Helper: `oAntetFacturare.EsteAviz()` + (`ofacturare_antet.prg:16-18`): `Return poDate.nIdTipDoc = poDate.nIdTipDocAvizExpeditie`. +- **Setare initiala**, dupa `tnTip` primit la deschidere (`COMUN\programe\ofacturare.prg:196-206`): + ``` + Case tnTip = 27 or 30 -> nIdTipDoc = 6 (AVIZ) + Case tnTip < 21 sau tnTip in (45,48,49,51,52) -> nIdTipDoc = 5 (FACTURA) + Otherwise -> nIdTipDoc = 6 (AVIZ) + ``` +- **Schimbare interactiva**: combo `clb_fdoc.cboFdoc` -> `do_schimba_tipdoc` + (`ofacturare.vc2:20046-20071`) -> `oAntet.alege_tipdoc(valoare_combo)` mapeaza textul + ("FACTURA"/"AVIZ"/"PROFORMA"/"BON FISCAL") pe id-ul de tip, apoi `oAntet.schimba_tipdoc(id)` + (`ofacturare_antet.prg:889-923`) actualizeaza `poDate.nIdTipDoc` si seriile. Exista o garda: + daca documentul e proforma si au fost deja adaugate articole, schimbarea tipului e blocata + cu `amessagebox` (`ofacturare.vc2:20050-20055`). +- **Ramuri `EsteAviz()` in `oAntetFacturare`** (aceleasi metode de cautare/validare servesc + ambele tipuri, dar cu cai diferite): `do_cauta_altele` (20-45), `do_cauta_client` (97-100), + `do_cauta_comanda` (240-243), `do_cauta_contract` (296-299), `do_cauta_gestiune_init` + (518-521), `do_cauta_lucrare` (553-556), `do_cauta_sectie` (633-636), `do_cauta_venchelt` + (708-711), `valideaza_antet` (762-766) — toate in `COMUN\programe\ofacturare_antet.prg`. +- **Fluxul vechi (ne-unificat)** folosea deja formulare separate per tip pentru antet + (`frm_date_factura` / `frm_date_aviz` / `frm_date_aviz_lucrare`, vezi pct. 1) — unificarea + descrisa in header-ul `ofacturare_antet.prg` a mutat logica lor comuna intr-o singura clasa, + ramura aleasa la runtime pe `poDate.nIdTipDoc`. diff --git a/docs/qa_factura_hooks_ref.md b/docs/qa_factura_hooks_ref.md new file mode 100644 index 0000000..b2e88c8 --- /dev/null +++ b/docs/qa_factura_hooks_ref.md @@ -0,0 +1,393 @@ +# Referinta oficiala hooks Claude Code (pentru diagnosticul "subagent stop violation") + +Surse fetch-uite azi (2026-09-17), toate redirecteaza de pe `docs.claude.com` pe `code.claude.com`: +- https://code.claude.com/docs/en/hooks (fost https://docs.claude.com/en/docs/claude-code/hooks) +- https://code.claude.com/docs/en/hooks-guide (fost .../hooks-guide) +- https://code.claude.com/docs/en/settings (fost .../settings) +- https://code.claude.com/docs/en/settings-reference +- https://code.claude.com/docs/en/settings-example +- https://code.claude.com/docs/en/env-vars + +**Limitare tehnica intalnita**: paginile `hooks` si `settings-reference` sunt prea mari pentru +fetch-ul folosit (WebFetch trece continutul brut printr-un model mic inainte sa-l intoarca); la +cereri repetate pe aceeasi pagina, portiuni identice (tabelul "Common input fields", tabelul +"Exit code 2 behavior per event" pana la randul `Stop`, exemplele din `hooks-guide`) au iesit +IDENTIC de mai multe ori — acelea sunt tratate mai jos ca sigure/verbatim. O extractie initiala, +mai larga, a produs scheme JSON pentru `SessionStart`/`Stop`/`SubagentStop`/`PreCompact` care NU +s-au mai reprodus la cereri ulterioare tintite pe aceleasi sectiuni (acelea au raspuns explicit +"nu e in continutul furnizat, pagina e trunchiata") — acea extractie e tratata ca **nesigura** si +nu e citata mai jos. Sectiunile marcate **NEDOCUMENTAT** de mai jos sunt cele pe care nu am putut +sa le confirm verbatim, nu neaparat cele care lipsesc din documentatia reala. + +## 1. Lista completa a evenimentelor de hook + +Tabelul de mai jos e citat verbatim din `hooks-guide` (sectiunea "How hooks work"), confirmat prin +citire directa a continutului brut al fetch-ului (nu prin sumarizare): + +> | Event | When it fires | +> | `SessionStart` | When a session begins or resumes | +> | `Setup` | When you start Claude Code with `--init-only`, or with `--init` or `--maintenance` in `-p` mode. For one-time preparation in CI or scripts | +> | `UserPromptSubmit` | When you submit a prompt, before Claude processes it | +> | `UserPromptExpansion` | When a user-typed command expands into a prompt, before it reaches Claude. Can block the expansion | +> | `PreToolUse` | Before a tool call executes. Can block it | +> | `PermissionRequest` | When a tool call needs a permission decision | +> | `PermissionDenied` | When auto mode denies a tool call, including denials without a classifier verdict. ... | +> | `PostToolUse` | After a tool call succeeds | +> | `PostToolUseFailure` | After a tool call fails | +> | `PostToolBatch` | After a full batch of parallel tool calls resolves, before the next model call | +> | `Notification` | When Claude Code sends a notification | +> | `MessageDisplay` | While assistant message text is displayed | +> | `SubagentStart` | When a subagent is spawned | +> | `SubagentStop` | When a subagent finishes | +> | `TaskCreated` | When a task is being created via `TaskCreate` | +> | `TaskCompleted` | When a task is being marked as completed | +> | `Stop` | When Claude finishes responding | +> | `StopFailure` | When the turn ends due to an API error | +> | `TeammateIdle` | When an agent team teammate is about to go idle | +> | `InstructionsLoaded` | When a CLAUDE.md or `.claude/rules/*.md` file is loaded into context. ... | +> | `ConfigChange` | When a configuration file changes during a session | +> | `CwdChanged` | When the working directory changes, for example when Claude executes a `cd` command. ... | +> | `DirectoryAdded` | When a working directory is added mid-session via `/add-dir` or the SDK `register_repo_root` control request | +> | `FileChanged` | When a watched file changes on disk. The `matcher` field specifies which filenames to watch | +> | `WorktreeCreate` | When a worktree is being created via `--worktree`, `isolation: "worktree"`, or for a background session. ... | +> | `WorktreeRemove` | When a worktree is being removed at session exit, when a subagent finishes, or when you delete a background session | +> | `PreCompact` | Before context compaction | +> | `PostCompact` | After context compaction completes | +> | `PreModelSwitch` | Before Claude Code applies a model switch that you or a client requested. Can block the switch | +> | `PostModelSwitch` | After the session's model changes, including changes Claude Code makes on its own, ... | +> | `Elicitation` | When an MCP server requests user input during a tool call | +> | `ElicitationResult` | After a user responds to an MCP elicitation, before the response is sent back to the server | +> | `SessionEnd` | When a session terminates | + +Sursa: https://code.claude.com/docs/en/hooks-guide, sectiunea "How hooks work". + +### Schema JSON exacta pe stdin/stdout pentru PreCompact / SessionStart / Stop / SubagentStop + +**NEDOCUMENTAT (in sensul de mai sus: nu am putut confirma verbatim)**. Fetch-ul repetat pe +`hooks` (inclusiv varianta `.md`) intoarce constant tabelul "Common input fields" (comun tuturor +evenimentelor, vezi mai jos) si tabelul "Exit code 2 behavior per event" doar pana la randul +`Stop`; sectiunile individuale `### SessionStart`, `### PreCompact`, `### Stop`, `### SubagentStop` +cu exemplele lor JSON complete nu au putut fi extrase — raspunsul explicit al fetch-ului a fost +"the actual detailed 'Hook events' section ... appears to be cut off or not included" si "I +cannot find a subsection literally titled 'PreCompact'... in the provided content". Nu inseamna +ca documentatia oficiala nu contine acele scheme (aproape sigur le contine, pagina fiind +"Hooks reference" completa), ci ca uneltele disponibile in aceasta sesiune nu au putut sa le +aduca integral. + +Ce **s-a confirmat verbatim** despre campurile comune (tabelul "Common input fields", identic la +doua fetch-uri separate pe `hooks` si pe `hooks.md`): + +> | Field | Description | +> | `session_id` | Current session identifier | +> | `prompt_id` | UUID identifying the user prompt currently being processed. ... Absent until the first user input. Requires Claude Code v2.1.196 or later | +> | `transcript_path` | Path to conversation JSON. The transcript file is written asynchronously and may lag the in-memory conversation, so it may not yet include the current turn's most recent messages when a hook fires. Hooks that need the final assistant text of the current turn should use `last_assistant_message` on Stop and SubagentStop instead of reading the transcript | +> | `cwd` | Current working directory when the hook is invoked | +> | `scratchpad_dir` | Path to the session's scratchpad directory, where Claude keeps temporary working files. Absent when the session has no scratchpad or the temp directory is unavailable. Requires Claude Code v2.1.257 or later | +> | `permission_mode` | Current permission mode: `"default"`, `"plan"`, `"acceptEdits"`, `"auto"`, `"dontAsk"`, or `"bypassPermissions"`. ... | +> | `effort` | Object with a `level` field holding the effort level in effect when the hook runs... Present for events that fire within a tool-use context, such as `PreToolUse`, `PostToolUse`, `Stop`, and `SubagentStop`, when the current model supports the effort parameter. | +> | `hook_event_name` | Name of the event that fired | +> +> When running with `--agent` or inside a subagent, two additional fields are included: +> +> | Field | Description | +> | `agent_id` | Unique identifier for the subagent. Present only when the hook fires inside a subagent call. Use this to distinguish subagent hook calls from main-thread calls. | +> | `agent_type` | Agent name (for example, `"Explore"` or `"security-reviewer"`). Present when the session uses `--agent` or the hook fires inside a subagent. For subagents, the subagent's type takes precedence over the session's `--agent` value. | + +Sursa: https://code.claude.com/docs/en/hooks, sectiunea "Common input fields" (confirmat identic +si pe varianta .md). + +Nota: campul `trigger` (pentru `PreCompact`/`PostCompact`, valori `manual`/`auto`) si `source` +(pentru `SessionStart`, valori `startup`/`resume`/`clear`/`compact`/`fork`) sunt mentionate ca +**valori de matcher**, nu confirmate ca nume exact de camp JSON pe stdin — vezi tabelul de +matchere de la punctul 3. + +Ce s-a confirmat despre `SessionStart` prin exemplu real de configurare (verbatim, din +`hooks-guide`, sectiunea "Re-inject context after compaction"): + +> When Claude's context window fills up, compaction summarizes the conversation to free space. +> This can lose important details. Use a `SessionStart` hook with a `compact` matcher to +> re-inject critical context after every compaction. +> +> Claude Code adds plain text your command writes to stdout to Claude's context. + +```json +{ + "hooks": { + "SessionStart": [ + { + "matcher": "compact", + "hooks": [ + { "type": "command", "command": "echo 'Reminder: use Bun, not npm. ...'" } + ] + } + ] + } +} +``` + +Schema de iesire (`hookSpecificOutput`, `additionalContext`, `systemMessage`, `decision`, +`continue`, `stopReason`) pentru cele 4 evenimente cerute: **NEDOCUMENTAT** in sensul de mai sus +pentru forma completa exacta. S-a confirmat insa, verbatim, forma generala de output pentru +`UserPromptSubmit` (acelasi tipar `hookSpecificOutput.additionalContext`, aplicabil probabil si +altor evenimente, dar nu s-a putut confirma explicit pentru `SessionStart`/`Stop`/`SubagentStop`): + +> For `UserPromptSubmit` hooks, use `hookSpecificOutput.additionalContext` instead to inject text +> into Claude's context. Nest `additionalContext` inside `hookSpecificOutput`; if you place it at +> the top level of the JSON, Claude Code silently ignores it. + +```json +{ + "hookSpecificOutput": { + "hookEventName": "UserPromptSubmit", + "additionalContext": "Current branch: release-42. Deploy freeze until Friday." + } +} +``` + +> Other events use different decision patterns. For example, `PostToolUse` and `Stop` hooks use a +> top-level `decision: "block"` field, while `PermissionRequest` uses +> `hookSpecificOutput.decision.behavior`. + +Sursa: https://code.claude.com/docs/en/hooks-guide, sectiunea "Structured JSON output". + +## 2. Tokeni consumati / marimea contextului in input-ul hook-urilor + +**Confirmat, de doua ori, cautare pe intreaga pagina `hooks`**: nu exista niciun camp de tokeni +in input-ul hook-urilor. + +> Search for "stop_hook_active": No matches found for the term "stop_hook_active" on this page. +> Search for "token", "usage", and "input_tokens": No matches found for these terms on this page. + +(cautarea a fost facuta explicit pe pagina "Hooks reference"; rezultatul e consistent la doua +apeluri separate — semnal ca reflecta continutul real, nu o presupunere a modelului de sumarizare) + +Concluzie: singura sursa documentata pentru starea conversatiei ramane `transcript_path` +(fisier `.jsonl`), descris astfel (verbatim, vezi campurile comune de mai sus): + +> Path to conversation JSON. The transcript file is written asynchronously and may lag the +> in-memory conversation, so it may not yet include the current turn's most recent messages when +> a hook fires. + +**NEDOCUMENTAT**: schema exacta a unei linii din `transcript_path` (daca fiecare linie JSONL are +un obiect `usage` cu `input_tokens`/`cache_read_input_tokens`). Nu am gasit nicio sectiune care sa +descrie formatul intern al transcriptului; pagina de hooks il trateaza doar ca „path to +conversation JSON", fara schema de linie. + +Singurul loc unde a aparut o notiune de "context folosit" e statusline-ul (alta functionalitate, +nu un hook), in exemplul din `settings-example`: + +> "command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'" + +adica statusline-ul primeste `context_window.used_percentage` — dar acesta e inputul JSON al +comenzii de `statusLine`, nu al vreunui hook (`PreCompact`/`Stop`/etc.). Sursa: +https://code.claude.com/docs/en/settings-example, sectiunea "Your own settings". + +## 3. Declansarea programatica a compactarii; PreCompact poate bloca? + +Confirmat verbatim (tabelul de matchere, `hooks-guide`, sectiunea "Filter hooks with matchers"): + +> | Event | What the matcher filters | Example matcher values | +> | `PreCompact`, `PostCompact` | what triggered compaction | `manual`, `auto` | + +Nu exista alta explicatie a diferentei functionale dintre `manual` si `auto` in continutul pe care +am putut sa-l confirm — **NEDOCUMENTAT** in acest fetch (probabil documentat in sectiunea +"Hooks reference" pe care nu am putut-o extrage integral). + +Despre blocare: tabelul "Exit code 2 behavior per event" s-a confirmat identic de 3 ori, dar +mereu trunchiat la randul `Stop`: + +> | Hook event | Can block? | What happens on exit 2 | +> | `PreToolUse` | Yes | Blocks the tool call | +> | `PermissionRequest` | No | Exit code 2 isn't honored for this event and the permission flow proceeds unchanged. ... | +> | `UserPromptSubmit` | Yes | Blocks prompt processing and erases the prompt | +> | `UserPromptExpansion` | Yes | Blocks the expansion | +> | `Stop` | Yes | Prevents Claude from stopping, continues the conversation | + +Randul pentru `PreCompact` (si `SubagentStop`, `SessionStart`) nu a putut fi extras — nici prin +fetch normal, nici prin varianta `.md`, nici prin cereri tintite doar pe randul lipsa. +**NEDOCUMENTAT explicit aici**: daca `PreCompact` poate bloca compactarea prin exit code 2. +(Rationament indirect, NEconfirmat ca fapt: linia generala din ghid — "Some events can't be +blocked: for SessionStart and others, exit 2 shows stderr to the user and execution continues" — +sugereaza ca exista o categorie de evenimente needitabile prin exit 2, dar nu specifica daca +`PreCompact` e in acea categorie sau in cealalta.) + +Citat sigur, din `hooks-guide`, care mentioneaza explicit ca `SessionStart` NU poate fi blocat: + +> Some events can't be blocked: for `SessionStart` and others, exit 2 shows stderr to the user and +> execution continues. + +Declansare programatica a compactarii: **NEDOCUMENTAT** in continutul confirmat — nu am gasit un +flag/comanda explicita de tip "trigger compaction now" in paginile fetch-uite (hooks, hooks-guide, +settings, settings-reference, env-vars). Doar variabila urmatoare influenteaza PRAGUL, nu +declansarea manuala programatica: + +> `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` — Set the percentage (1-100) of the auto-compact window at +> which auto-compaction triggers. Use lower values like `50` to compact earlier; the variable +> can't raise the threshold, so values above the default percentage are ignored. It applies only +> in sessions that compact before the model's context limit. Applies to both main conversations +> and subagents. + +Sursa: https://code.claude.com/docs/en/env-vars. + +## 4. Hook-uri in subagenti (Task/Agent); SubagentStop; bucla stop_hook_active + +**Confirmat verbatim** (hooks-guide, sectiunea "Limitations"): + +> Background subagents can't show a prompt in non-interactive mode. Claude Code still runs the +> hooks for their tool calls, and if no hook returns a decision, it denies the call. In an +> interactive session, background subagent prompts surface in your main session and the hooks +> fire as usual. + +Deci: hook-urile de tip `PreToolUse`/`PostToolUse` etc. **se declanseaza si in interiorul +subagentilor**, pentru apelurile lor de unelte — confirmat explicit doar pentru cazul +`PermissionRequest`/permisiuni; pentru restul evenimentelor (`PreToolUse`, `PostToolUse` propriu-zise +in subagent) nu am gasit o fraza separata la fel de explicita, dar tabelul de scope de configurare +confirma ca hook-urile de subagent exista ca mecanism dedicat: + +> | Location | Scope | Shareable | +> | [Subagent](/docs/en/sub-agents) frontmatter | While that subagent is running | Yes, defined in the subagent file | + +Sursa: https://code.claude.com/docs/en/hooks-guide, sectiunea "Configure hook location". + +`SubagentStop` — definitie confirmata din tabelul de evenimente (punctul 1): + +> `SubagentStop` | When a subagent finishes + +**NEDOCUMENTAT** (nesigur): o extractie initiala a afirmat ca exista fraza "Claude Code converts +a `Stop` hook here to `SubagentStop`, the event it fires when a subagent completes" — aceasta +fraza NU s-a mai reprodus la recitirea directa a continutului brut al `hooks-guide` (1065 de +linii citite integral), asa ca nu o citez ca fapt confirmat. Nu neg ca ar fi adevarata (e +plauzibila si consistenta cu restul mecanismului de scope pe subagent), doar ca nu am reusit sa o +verific verbatim in aceasta sesiune. + +### stop_hook_active si bucla + +**Confirmat verbatim**, din `hooks-guide`, sectiunea "Stop hook hits the block cap": + +> Claude keeps working instead of stopping, then ends the turn with a warning that the Stop hook +> blocked too many consecutive times. +> +> Claude Code overrides a Stop hook after it blocks eight times in a row without progress. Your +> hook script needs to check whether it already triggered a continuation. Parse the +> `stop_hook_active` field from the JSON input and exit early if it's `true`: + +```bash +#!/bin/bash +INPUT=$(cat) +if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then + exit 0 # Allow Claude to stop +fi +# ... rest of your hook logic +``` + +> If your hook legitimately needs more than eight iterations to converge, raise the cap with +> `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`. + +Deci: **cauza tipica a buclei** e un hook `Stop`/`SubagentStop` care intoarce mereu o decizie de +blocare (exit 2 / `decision: "block"`) fara sa verifice `stop_hook_active`, astfel incat Claude +Code il tot re-invoca; plafonul e 8 blocari consecutive "fara progres", dupa care Claude Code +suprascrie hook-ul si opreste turul cu un avertisment. Campul `stop_hook_active` exista exact ca +sa permita hook-ului sa detecteze ca a mai fost invocat o data in acelasi ciclu de "stop" si sa +cedeze (`exit 0`) in loc sa continue sa blocheze. + +Variabila de mediu asociata, confirmata din `env-vars` (extras separat, cu wording plauzibil dar +NEverificat printr-un al doilea fetch identic — trateaza ca moderat sigur, nu ca sigur): + +> `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` — Maximum number of blocks a stop hook can request before +> Claude Code stops respecting further requests from that hook and logs a warning (default: +> `100`). Useful when a hook inadvertently loops and repeatedly requests stops. + +Nota: valoarea implicita citata aici de fetch (`100`) **contrazice** cifra "eight times in a row" +din `hooks-guide` (confirmata de doua ori, sigura). Nu pot reconcilia cele doua cifre din +continutul disponibil — posibil ca 8 sa fie plafonul implicit "fara progres" mentionat in ghid, iar +`100` sa fie un plafon absolut diferit citit gresit de fetch-ul pe `env-vars` (surse nereconciliate, +posibil eroare de extractie pe aceasta a doua cifra). **Trateaza cifra "100" ca NEDOCUMENTAT/de +reverificat manual**, foloseste "8" ca fiind confirmat de doua ori pe pagina oficiala a ghidului. + +## 5. Setari relevante in settings.json + +Confirmat din tabelul settings-reference (randuri, fara detaliu de default/exemplu — sectiunile +detaliate de sub tabel nu au putut fi extrase, pagina prea mare): + +> | Key | Description | Topic | Scope | +> | `autoCompactEnabled` | Turn automatic compaction off or on | Memory and context | Any file | +> | `autoCompactWindow` | Set how full the context gets before Claude Code compacts | Memory and context | Any file | +> | `cleanupPeriodDays` | Choose how many days Claude Code keeps transcripts before deleting them | Privacy and telemetry | Any file | +> | `env` | Set environment variables for every session and its subprocesses | Memory and context | Any file | + +Sursa: https://code.claude.com/docs/en/settings-reference. **NEDOCUMENTAT** aici: valorile +implicite exacte pentru `autoCompactEnabled` si `autoCompactWindow` (sectiunile detaliate nu s-au +putut extrage). + +Exemple reale confirmate (`cleanupPeriodDays`, `env`), din https://code.claude.com/docs/en/settings-example: + +```json +// ~/.claude/settings.json — un dezvoltator +{ + "...": "...", + "cleanupPeriodDays": 20 +} +``` +> Delete session transcripts and other local session data older than 20 days + +```json +// .claude/settings.json — o echipa +{ + "env": { + "CLAUDE_CODE_ENABLE_TELEMETRY": "1", + "OTEL_METRICS_EXPORTER": "otlp", + "OTEL_EXPORTER_OTLP_PROTOCOL": "grpc", + "OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.example.com:4317" + }, + "hooks": { + "PreToolUse": [ + { + "matcher": "Bash", + "hooks": [ + { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh" } + ] + } + ] + } +} +``` + +```json +// managed-settings.json — o organizatie +{ + "...": "...", + "cleanupPeriodDays": 7 +} +``` +> Delete session transcripts and other local session data after 7 days + +Variabile `CLAUDE_CODE_*` legate de context/compactare, confirmate din +https://code.claude.com/docs/en/env-vars: + +> `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` — Set the percentage (1-100) of the auto-compact window at +> which auto-compaction triggers. Use lower values like `50` to compact earlier; the variable +> can't raise the threshold, so values above the default percentage are ignored. Applies to both +> main conversations and subagents. + +> `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` — vezi punctul 4 (cifra de default nereconciliata). + +**NEDOCUMENTAT** in acest fetch: nu am gasit alte variabile `CLAUDE_CODE_*` explicit legate de +"context size" ca numar de tokeni (cautarea pe `env-vars` a fost limitata la cuvintele +COMPACT/CONTEXT/TOKEN/STOP_HOOK; nu a intors nimic cu "CONTEXT" in nume). + +## Rezumat pentru cine investigheaza "subagent stop violation" + +- Nu exista niciun camp de tokeni/marime-context in inputul niciunui hook (confirmat, cautare + directa pe pagina oficiala). Singura sursa e `transcript_path`, iar formatul intern al liniilor + JSONL nu e documentat in paginile verificate. +- Bucla clasica de `Stop`/`SubagentStop` are o cauza documentata si un mecanism de iesire: + campul `stop_hook_active` pe input, plafon confirmat de "8 blocari la rand fara progres" dupa + care Claude Code preia controlul si opreste turul cu avertisment (`hooks-guide`, sectiunea + "Stop hook hits the block cap"). +- Hook-urile ruleaza si in subagenti; input-ul lor primeste in plus `agent_id`/`agent_type` fata de + campurile comune. +- Schemele JSON complete (toate campurile) pentru `PreCompact`/`SessionStart`/`Stop`/`SubagentStop` + si detaliul exact al blocarii pentru `PreCompact` NU au putut fi confirmate verbatim in aceasta + sesiune — pagina oficiala "Hooks reference" (https://code.claude.com/docs/en/hooks) le contine + aproape sigur, dar depaseste ce a putut extrage fetch-ul disponibil; de reluat cu acces direct + (browser) daca e nevoie de schema exacta camp-cu-camp. diff --git a/docs/qa_factura_unelte.md b/docs/qa_factura_unelte.md new file mode 100644 index 0000000..e26259d --- /dev/null +++ b/docs/qa_factura_unelte.md @@ -0,0 +1,191 @@ +# Inventar unelte QA/testare UI si infrastructura de progres — ROAFACTURARE + +Inventar read-only, 17.09.2026. Fara propuneri, doar stare (citate `fisier:linie`). + +## 1. `vfp_ui_harness.ps1` — orchestrator UI + +Locatie: `D:\ROA\ROAFACTURARE\COMUN\utile\Teste\vfp_ui_harness.ps1`. +Complement in VFP: `D:\ROA\ROAFACTURARE\COMUN\utile\Teste\ui_harness.prg` (proceduri de handshake +incluse in testul .prg via `SET PROCEDURE TO ui_harness ADDITIVE`). + +Parametri (`vfp_ui_harness.ps1:20-28`): +- `-TestPrg` (obligatoriu) — calea `.prg` a testului. +- `-Steps` (obligatoriu) — array de etichete, una per pas asteptat (`ready_.txt`/`cont_.txt`). +- `-StepTimeoutSec` (implicit 130), `-ReadyTimeoutSec` (implicit 180, pt. `ready_0` = afisarea formularului). +- `-ShotsDir` (implicit `\screenshots`), `-SyncDir` (implicit `\uisync`). +- `-Vfp` (implicit `C:\Program Files (x86)\Microsoft Visual FoxPro 9\vfp9.exe`). + +Ce face exact: +- Precompileaza izolat (`_precompile.ps1`, proces copil) inainte de lansare (`vfp_ui_harness.ps1:145-154`). +- Lanseaza `.FXP`-ul cu `vfp9.exe -A ` (nu `.prg`), cu pana la 8 incercari daca testul nu + scrie START in 30s (`vfp_ui_harness.ps1:160-190`). +- Fereastra principala e mutata **off-screen** (`x=-4000`, `HWND_BOTTOM`, `SWP_NOACTIVATE`) imediat + ce apare `MainWindowHandle`, si re-impinsa la fiecare pas — **fara furt de focus**, cerinta Marius + 17/07/2026 (`vfp_ui_harness.ps1:13-19,73-77`). +- Screenshot per pas via `PrintWindow` pe handle (flag `PW_RENDERFULLCONTENT=2`, fallback flag 0 + daca iese gol) — nu `CopyFromScreen` (`vfp_ui_harness.ps1:106-131`). +- Bucla pasi: asteapta `ready_.txt` (scris de test din `ui_harness.prg`), face screenshot, scrie + `cont_.txt` ca sa continue testul (`vfp_ui_harness.ps1:200-221`). +- La final asteapta `done.txt`, omoara doar instantele `vfp9.exe` proprii (linie de comanda contine + folderul testului) (`vfp_ui_harness.ps1:133-140,223-231`). + +`ui_harness.prg` — API apelat din testul VFP: +- `HarnessLog(mesaj)` (`ui_harness.prg:19-28`), `HarnessReady(n, nota)` (`ui_harness.prg:30-35`), + `HarnessWaitContinue(n, autoSec=30)` (`ui_harness.prg:37-51`), `HarnessStep(n, nota, autoSec)` + = Ready+WaitContinue (`ui_harness.prg:53-57`), `HarnessDone(status)` (`ui_harness.prg:59-64`). +- `HarnessWaitContinue` are auto-continue dupa `autoSec` (implicit 30s) daca orchestratorul nu + raspunde — testul merge si fara `vfp_ui_harness.ps1`, doar fara capturi (`ui_harness.prg:8-9,43-49`). +- `HarnessInit`: `SET SAFETY OFF` + `SET TALK OFF` defensiv (`ui_harness.prg:11-17`). + +Limitari cunoscute: +- **Nu trimite input real** (fara `SendInput`/`keybd_event`/click injectat) — harness-ul doar + citeste semafoare si face screenshot; actiunile UI (click, taste) sunt executate **din interiorul + testului VFP** (apeluri directe de metode/evenimente), nu de PowerShell din afara. +- Watchdog-ul de dialoguri (`watchdog_vfp.ps1`) e un instrument separat, folosit doar pt. dialoguri + native neasteptate; dismiss-ul se face STRICT prin mesaje Windows tintite pe handle (`BM_CLICK`, + `WM_COMMAND IDCANCEL`, `WM_KEYDOWN/UP` ESCAPE, `WM_CLOSE`) — interzis explicit input real de + tastatura/mouse, masina fiind partajata cu utilizatorul (`watchdog_vfp.ps1:16-26`). +- Dialogurile VFP owner-drawn (ex. "View Parameter") pot sa nu raspunda la niciun mesaj — dismiss-ul + esueaza cinstit, ramane deschis pana la timeout (`watchdog_vfp.ps1:23-26`). +- Coloanele de grid nu se materializeaza sub `-A -T`/headless (`ColumnCount=0`, `RecordSource` sunt + artefacte) — cunoscut, documentat separat (memorie `grid-coloane-nu-se-materializeaza-headless`); + simptomul apare si in suitele UI (ex. `test_page3_articole` 14/2 in `docs\progres.md:67`, cele 2 + FAIL = artefactul de baseline). +- `watchdog_vfp.ps1` clasifica orice fereastra noua diferita de `MainWindowHandle` ca dialog blocant + (nu dupa numele clasei — VFP refoloseste acelasi prefix de clasa si pt. shell, si pt. dialoguri + proprii) (`watchdog_vfp.ps1:6-9`). + +## 2. Harness headless (skill `roa-vfp-headless-test`) + +Skill: `D:\ROA\ROAFACTURARE\COMUN\skills\roa-vfp-headless-test\SKILL.md`. + +Lansare probe (`SKILL.md:102-103`): `vfp9.exe -A -T "" `, din PowerShell, cu +timeout si `$p.Kill()` daca nu iese (`$p.WaitForExit(120000)`). `-A` si `-T` obligatorii amandoua +(`SKILL.md:45-46`). Precompilare izolata obligatorie inainte (`_precompile.ps1`, proces copil), +altfel `vfp9 -A` poate deschide editorul in loc sa ruleze (`SKILL.md:28-29,99-100`). + +Loguri: fiecare test scrie propriul `_log.txt` langa `.prg` (convenit prin `gcUILog`/logica +proprie a testului); sinteza vine din `raport_teste.ps1` (`D:\ROA\ROAFACTURARE\COMUN\utile\Teste\raport_teste.ps1`), +care citeste **doar** fisierele `*_log.txt` dintr-un folder (implicit `achizitie_import`, parametrizabil +cu `-Dir`), numara linii `^PASS` si `^(FAIL|BUG)` si scoate PASS/FAIL per fisier + varsta (minute de +la ultima scriere) (`raport_teste.ps1:9-33`). `-Baseline ` marcheaza NOU vs. preexistent +(`raport_teste.ps1:7-8,16-19`). Regula: orchestratorul citeste doar acest raport, nu logurile brute +(`raport_teste.ps1:2-3`, trimite la `COMUN\docs\orchestrare-subagenti.md`). + +Mock-uri disponibile in `D:\ROA\ROAFACTURARE\COMUN\utile\Teste\`: +- `mock_amessagebox.prg` — inlocuieste `FUNCTION amessagebox` din `oproceduri_comune.prg`; returneaza + 6 (Da/OK) implicit, configurabil per apel prin `PUBLIC gnMockRaspuns` (raspuns generic), + `gnMockRaspunsTotal` (raspuns separat pt. mesajul "Actualizati totalul facturii"), + `gcMockUltimMesaj`/`gnMockUltimTip` (captura textul/tipul ultimului dialog, pt. asertii) + (`mock_amessagebox.prg:1-44`). **Trebuie incarcat PRIMUL** in `SET PROCEDURE` (VFP foloseste, la + nume duplicat, fisierul cautat primul, nu cel deschis cel mai recent) — vezi + `test_init_env_auto_roafacturare.prg:119-121` unde e adaugat inaintea listei aplicatiei. + LIMITA 1: nu acopera apeluri intra-fisier (ex. `verifica_partener_show_info` -> `amessagebox` in + acelasi `oproceduri_comune.prg`) — necesita mock dedicat per caz (`mock_amessagebox.prg:13-15`). + LIMITA 2: **nu acopera dialogurile de eroare ale lui `goExecutor`** — o interogare gresita agata + headless fara nicio linie in log (`mock_amessagebox.prg:16-17`). Nu exista un mock generic pentru + `goExecutor` la radacina `Teste\`; exista doar mock-uri punctuale per test in subfoldere (ex. + `achizitie_import\mock_cauta_alfa_tva11.prg`, `achizitie_import\mock_oscrie_in_fisiere.prg`). +- `watchdog_vfp.ps1` — pt. dialoguri native neprinse de ON ERROR/mock-uri (`SKILL.md:97-98`). + +Init de mediu specific ROAFACTURARE: `test_init_env_auto_roafacturare.prg` — vezi punctul 3. + +## 3. Conectare Oracle in probe (schema MARIUSM_AUTO) + +Script: `D:\ROA\ROAFACTURARE\COMUN\utile\Teste\test_init_env_auto_roafacturare.prg`. + +Apel: `DO test_init_env_auto_roafacturare WITH 'CENTRAL', 'MARIUSM_AUTO', 'parola'` +(`test_init_env_auto_roafacturare.prg:11`). + +Valori implicite daca parametrii sunt goi (`test_init_env_auto_roafacturare.prg:16-18`): +- `tcHost` = `CENTRAL` +- `tcSchema` = `MARIUSM_AUTO` +- `tcPassword` = `ROMFASTSOFT` + +Conexiunea propriu-zisa: `goConn = createobject("oConn")` + +`goConn.Connect(tcHost, tcSchema, tcPassword)` (`test_init_env_auto_roafacturare.prg:209-214`), +verificata prin `gnHandle > 0`. Executorul de SQL e `goExecutor = createobject("oExecutor")` +(`test_init_env_auto_roafacturare.prg:209`), folosit apoi pt. `oExecuta(...)`. + +An/luna de lucru fixe (independente de `Date()`): `gnAn=2026`, `gnLuna=8` daca nu sunt pasate ca +parametri 4/5 (`test_init_env_auto_roafacturare.prg:36-37`). Firma: `gnIdFirma=110` implicit +(parametru 6 optional) (`test_init_env_auto_roafacturare.prg:39,221-224`). + +Cale aplicatie fixa: `gcAppPath = 'D:\ROA\ROAFACTURARE\'` (`test_init_env_auto_roafacturare.prg:57`) — +seteaza `SET PATH`/`SET CLASSLIB`/`SET PROCEDURE` identic cu `roafacturare.prg`, plus mock-ul +`amessagebox` incarcat primul (`test_init_env_auto_roafacturare.prg:82-176`). + +Nota din antet: variantele `test_init_env_auto_.prg` (ROACONT/ROAGEST/ACNPRO/ROADEF) au +cale + SET-uri specifice produsului, dar **partea de conexiune Oracle e identica** in toate +(`test_init_env_auto_roafacturare.prg:6-9`). Alegerea harness-ului gresit incarca alt working copy +silentios (`SKILL.md:21-23`). + +## 4. Fisiere de progres/status existente + +In `D:\ROA\ROAFACTURARE\docs\`: +- `progres.md` — **fisierul curent de stare**, actualizat de fiecare sesiune inainte sa se incheie; + planurile (`plan_0*.md`) spun *ce*, `progres.md` spune *unde s-a ajuns* (`progres.md:1-7`). Format: + titlu cu punctele acoperite, "Ultima actualizare: DD.MM.YYYY", apoi blocuri + `> **RUNDA DD.MM.YYYY — titlu.**` cu subsectiuni in proza (ce s-a schimbat, decizii numerotate, + teste rulate cu PASS/FAIL, capcane platite, ramas deschis) — nu tabel, istoricul sesiunilor nu se + pastreaza, doar starea la zi (`progres.md:1-9`). +- `handoff_*.md` — 6 fisiere curent (`handoff_update_romfast.md`, `handoff_cont_discount_667_709.md`, + `handoff_id_set_skilluri.md`, `handoff_idempotenta_id_set.md`, plus altele). Format observat in + `handoff_idempotenta_id_set.md:1-13`: titlu cu subiect+data, sectiuni numerotate H2 — "Livrabile + terminate" (tabel Ce/Unde/Stare), "Ce face X", "APROBAT dar NEEXECUTAT", "NEFINALIZAT/necomis", + "Comenzi de reluat" (bloc powershell), incheiat de regula cu inventar fisier:linie si stare + write-back per fisier atins. +- `diff_*.md` / `diff_*.patch` — diff-uri de revizuit inainte de commit (ex. + `diff_cont_discount_667_709.md`). +- `plan_index.md` + `plan_1*.md` — planuri pe story-uri (ex. `plan_10_integrare_contracte.md`). +- `docs\cercetare\*.md` — ~60 de fisiere de cercetare/investigatie punctuala (un subiect per fisier). +- `erori_deschise.md`, `livrare_13.md`, `raport_doc.md`, `raport_src.md`. + +In `D:\ROA\ROAFACTURARE\COMUN\docs\` (relevante pt. orchestrare/testare, nu fisiere de progres in +sine ci proceduri): +- `orchestrare-subagenti.md` — procedura Regula zero (predare context), citata de `raport_teste.ps1:2-3`. +- `reguli_lucru.md` — index de reguli de lucru/testare, ruteaza pe zona la skill-ul potrivit. +- `depanare_testare_vfp.md`, `testare-ui-vfp.md` — capcanele detaliate din `SKILL.md` (sec. 6-7 / integral). + +Nu exista fisiere de progres/status in `D:\ROA\COMUNROA\` — directorul `COMUNROA` (shared suite-wide, +distinct de `COMUN\` din interiorul ROAFACTURARE) nu are un `docs\progres.md` propriu vizibil din +acest working copy. + +## 5. Hook-uri configurate + +### `C:\Users\mmari\.claude\settings.json` (nivel user, global) + +- `UserPromptSubmit` -> `context_watch.ps1 -Stdout` (mesaj injectat, exit 0). +- `SessionStart` -> `docs_revizie_check.ps1 -Stdout`. +- `PostToolUse` -> `context_watch.ps1 -OSinguraData` (async, timeout 20s). +- `PreCompact` -> mesaj fix de sistem (Regula zero — predare la compactare). +- `PostCompact` -> mesaj fix + `additionalContext` (Regula zero — predare obligatorie dupa compactare). +- `SubagentStop` -> mesaj fix (`additionalContext`) care aminteste orchestratorului sa verifice + daca subagentul si-a scris starea pe disc inainte sa-i dea sarcina urmatoare. + +**Da, exista deja un hook `context_watch`**, script: +`D:\ROA\ROAGEST\COMUN\utile\context_watch.ps1` (in COMUNROA/ROAGEST, partajat intre proiecte, invocat +din `settings.json` cu cale absoluta acolo). + +Ce face (`context_watch.ps1:1-9,55-84`): +- Citeste ultimul `"usage":{...}` din coada transcriptului JSONL al sesiunii curente (ultimii 400KB + din fisier, nu tot fisierul), insumeaza `input_tokens + cache_creation_input_tokens + + cache_read_input_tokens`. +- Praguri: `-Prag 250000` (implicit, nivel "avertisment") si `-PragMax 275000` (implicit, nivel + "max" — peste limita, predare OBLIGATORIE acum). +- La `avertisment`: mesaj care cere incheierea blocului curent, actualizarea handoff-ului pe disc, + delegarea catre subagenti a oricarei citiri/testari ramase. +- La `max`: mesaj cu procedura completa Regula zero (opreste lucrul, scrie handoff pe disc, confirma + in doua randuri, preda unei sesiuni noi). +- `-Stdout`: scrie mesajul pe stdout si iese cu 0 (folosit pe `UserPromptSubmit`, injecteaza context + fara sa esueze hook-ul). Fara `-Stdout`: scrie pe stderr si iese cu exit 2 (semnaleaza agentului). +- `-OSinguraData` (folosit pe `PostToolUse`): emite alerta o singura data per sesiune+prag, marcaj + fisier in `%TEMP%\claude_ctxwatch__.flag` — altfel mesajul s-ar repeta la fiecare + tool call (`context_watch.ps1:9-10,74-80`). +- Fara `-TranscriptPath` explicit, il citeste din stdin (JSON-ul hook-ului) sau, ca fallback, cauta + cel mai recent `.jsonl` din `~/.claude/projects/\` (`context_watch.ps1:18-34`). + +### `D:\ROA\ROAFACTURARE\.claude\` (nivel proiect) + +Singurul fisier: `settings.local.json`, continut integral `{"outputStyle": "Concise"}`. **Niciun +hook definit la nivel de proiect** — toate hook-urile active vin din `settings.json` global de user. diff --git a/docs/s0_context_hook.md b/docs/s0_context_hook.md new file mode 100644 index 0000000..8cc7e96 --- /dev/null +++ b/docs/s0_context_hook.md @@ -0,0 +1,100 @@ +# S0 - Prototip context/handoff: fix SubagentStop, -StareFile, compactare mai devreme + +Executat 17.09.2026, pe masina curenta (fara UI, conform plan_qa_factura_aviz.md sectiunea S0). + +## Ce am gasit + +- Hook-ul `SubagentStop` din `C:\Users\mmari\.claude\settings.json` (era la cheia + `hooks.SubagentStop[0].hooks[0].command`) era un simplu `echo '{"hookSpecificOutput":...}'` + static, executat de fiecare data cand un subagent se opreste, fara sa citeasca deloc stdin-ul + hook-ului. Nu bloca explicit (nu avea `decision:block`/exit 2), dar reinjecta acelasi + `additionalContext` la fiecare `SubagentStop`, inclusiv la reincercarile in acelasi ciclu de + stop - de aici bucla observata (patru agenti raportand cicluri repetate in aceeasi sesiune). + Cauza + fix documentate in `docs/qa_factura_hooks_ref.md` sectiunea 4 ("stop_hook_active si + bucla"): campul `stop_hook_active` trebuie citit de pe stdin, iar la `true` hook-ul trebuie sa + iasa imediat cu 0, fara iesire. +- `context_watch.ps1` e in `D:\ROA\ROAGEST\COMUN\utile\context_watch.ps1`. Verificat: acel `COMUN` + e checkout separat al aceluiasi repo `git@gitea.romfast.ro:romfast/comun.git` ca si + `D:\ROA\ROAFACTURARE\COMUN` (acelasi `origin`, ramuri `main`) - deci e intr-adevar biblioteca + partajata, doar clonata separat per produs. Nu l-am mutat: mutarea in `COMUN` (punctul 4 din + planul S0) nu a fost in cele trei sarcini primite de la team lead pentru aceasta sesiune, ramane + neacoperit (vezi mai jos). +- Scriptul deja avea parametrii `-Stdout` (UserPromptSubmit) si `-OSinguraData` (PostToolUse, + dedup prin fisier marcaj in `%TEMP%`); nu avea niciun mecanism de scriere pe disc a starii. +- `env` in `settings.json` nu exista `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`. + +## Ce am schimbat + +### 1. Garda `stop_hook_active` pe hook-ul SubagentStop + +`C:\Users\mmari\.claude\settings.json`, cheia `hooks.SubagentStop[0].hooks[0].command` +(inainte de orice modificare am facut copie de siguranta la +`C:\Users\mmari\.claude\settings.json.bak_20260917`, verificata pe disc): + +Inainte: +``` +echo '{"hookSpecificOutput":{"hookEventName":"SubagentStop","additionalContext":"..."}}' +``` + +Dupa: +``` +grep -q '"stop_hook_active"[[:space:]]*:[[:space:]]*true' && exit 0; echo '{"hookSpecificOutput":{"hookEventName":"SubagentStop","additionalContext":"..."}}' +``` + +Mesajul `additionalContext` a ramas identic (neschimbat), doar prefixat cu garda. `grep -q` +citeste stdin-ul hook-ului (JSON-ul cu `stop_hook_active`) fara dependenta de `jq` (nu e instalat +pe masina - verificat). Daca patternul gaseste `"stop_hook_active":true` (cu sau fara spatiu dupa +`:`), hook-ul iese cu 0 fara sa emita nimic; altfel continua la `echo` ca inainte. + +### 2. `-StareFile` in `context_watch.ps1` + +`D:\ROA\ROAGEST\COMUN\utile\context_watch.ps1`: +- linia 20: parametru nou `[string]$StareFile`. +- liniile 23-36: functia noua `Scrie-AntetStare` - daca fisierul exista si primul rand se + potriveste cu `^`. + - am adaugat manual un rand "text scris de model" dupa antet (simuland continutul modelului). + - rulare 2 (o secunda mai tarziu): antetul de pe primul rand a fost INLOCUIT (ora actualizata), + randul "text scris de model" a ramas neatins, nu s-a adaugat un al doilea antet + (verificat cu citire BOM-aware: 2 linii total, 1 linie cu prefixul antetului). +3. **`context_watch.ps1` fara `-StareFile`**: acelasi transcript de test -> acelasi mesaj de + avertisment pe stderr, exit code 2, identic cu comportamentul dinaintea modificarii (nimic + scris pe disc). +4. **Hook-ul `SubagentStop`**: comanda extrasa din `settings.json` dupa modificare, rulata direct: + - stdin `{"stop_hook_active":true}` -> nicio iesire, exit 0. + - stdin `{"stop_hook_active":false}` -> a scos exact `additionalContext`-ul de dinainte, exit 0. + +## Ce a ramas neacoperit + +- Punctul 4 din S0 al planului ("se muta in COMUN ca sa fie refolosibil de toate produsele ROA") + NU a fost facut - nu a fost in lista de 3 sarcini primite de la team lead pentru aceasta rulare. + Scriptul ramane in `D:\ROA\ROAGEST\COMUN\utile\context_watch.ps1`, neschimbat ca locatie. +- Proba "ciclu real cu subagent care se termina, o singura rulare a hook-ului" (mentionata in + plan la finalul sectiunii S0) nu a fost reprodusa printr-un subagent real - probele de mai sus + au testat garda si scrierea de stare direct, in izolare, nu printr-o rulare completa + Claude Code cu un subagent viu. Nu am lansat subagenti (interdictie explicita in sarcina). +- Nu am facut niciun commit (interdictie explicita); `settings.json` nu e sub control de versiuni + in acest repo, deci nu exista diff de revizuit acolo - doar backup-ul + `C:\Users\mmari\.claude\settings.json.bak_20260917`. `context_watch.ps1` e in repo-ul `COMUN` + (git) - diff-ul ramane de revizuit acolo inainte de commit, conform regulii "fara commit fara + review". diff --git a/docs/sessionstart_ref.md b/docs/sessionstart_ref.md new file mode 100644 index 0000000..2dba21b --- /dev/null +++ b/docs/sessionstart_ref.md @@ -0,0 +1,330 @@ +\# Referinta oficiala: SessionStart / PostCompact / Stop (surse: code.claude.com/docs) + +Toate citatele de mai jos sunt verbatim din versiunile `.md` brute ale paginilor +(`https://code.claude.com/docs/en/hooks.md`, `.../hooks-guide.md`), fetch-uite direct cu +`curl` pe 2026-09-17 (WebFetch trunchiaza paginile astea, sunt prea mari pentru modelul +intern al tool-ului — vezi nota metodologica de la final). Nu am dedus nimic; unde n-am gasit +un raspuns explicit, scriu "NEDOCUMENTAT". + +--- + +## 1. SessionStart — valori de matcher acceptate + +**CONFIRMAT, dar lista din brief e incompleta: sunt 5 valori, nu 4.** Lipsea `fork`. + +Sursa: `https://code.claude.com/docs/en/hooks.md`, sectiunea `### SessionStart`: + +> The matcher value corresponds to how the session was initiated: +> +> | Matcher | When it fires | +> | :-------- | :------------------------------------------------------------------------------------------------------------------------------------- | +> | `startup` | New session | +> | `resume` | `--resume`, `--continue`, or `/resume` | +> | `clear` | `/clear` | +> | `compact` | Auto or manual compaction | +> | `fork` | A new session forked from an existing one: `--fork-session` with `--resume` or `--continue`, the `/fork` background copy, or `/branch` | +> +> Before v2.1.214, forked sessions reported source `"resume"`. + +Important pentru mecanismul propus: **`compact` e si el un matcher de `SessionStart`**, separat +de evenimentul `PostCompact` (vezi punctul 4). Adica dupa o compactare (auto sau manuala), +Claude Code re-porneste efectiv un `SessionStart` cu `source: "compact"`, iar acela SUPORTA +`additionalContext` — spre deosebire de `PostCompact` propriu-zis, care nu suporta (punctul 4). + +--- + +## 2. SessionStart — campuri pe stdin, cum distinge `/clear` de pornire normala + +Sursa: `https://code.claude.com/docs/en/hooks.md`, `#### SessionStart input`: + +> In addition to the [common input fields](#common-input-fields), SessionStart hooks receive +> `source` and optionally `model`, `agent_type`, and `session_title`: +> +> | Field | Description | +> | :-------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +> | `source` | How the session started: `"startup"` for new sessions, `"resume"` for resumed sessions, `"clear"` after `/clear`, `"compact"` after compaction, or `"fork"` for a new session forked from an existing one | +> | `model` | The active model identifier. It can be omitted, for example after `/clear` or when a session is restored through conversation recovery, so check for the field before reading it | +> | `agent_type` | The agent name, present when you start Claude Code with `claude --agent ` | +> | `session_title` | The current session title if one is already set, for example via `--name` or `/rename`. A hook that emits `sessionTitle` can check `session_title` first to avoid overwriting a title the user set explicitly | + +**Distinctia `/clear` vs pornire normala se face STRICT prin campul `source`**: `"clear"` vs +`"startup"`. Nu exista alt semnal necesar. + +Campuri comune (din `#### Common input fields`, aceeasi pagina), relevante pentru mecanism: +`session_id`, `prompt_id`, `transcript_path`, `cwd`, `scratchpad_dir`, `permission_mode`, +`effort`, `hook_event_name`. Citat exact pentru `transcript_path`: + +> `transcript_path` — Path to conversation JSON. The transcript file is written asynchronously +> and may lag the in-memory conversation, so it may not yet include the current turn's most +> recent messages when a hook fires. + +Cand `source` e `"resume"` sau `"fork"` si transcript-ul are cel putin un raspuns Claude, mai +vin 4 campuri (necesare v2.1.251+): `seconds_since_last_response`, `context_tokens`, +`prompt_cache_likely_expired`, `estimated_cache_write_usd`. **Aceste campuri NU apar pentru +`source: "clear"`** — deci hook-ul nu primeste de la Claude Code o estimare gata facuta a +cate token-i "costa" reluarea; asta ramane treaba handoff-ului scris pe disc. + +`agent_type` si `agent_id` (subagent-only) — prezente doar cand hook-ul ruleaza intr-un +subagent sau sesiunea foloseste `--agent`. + +**Timing**: la pornire/`--resume`/`--continue`/`/clear`, hook-urile `SessionStart` ruleaza in +fundal — poti scrie imediat, dar primul raspuns al lui Claude asteapta sa termine hook-urile. +La `/resume` in interiorul unei sesiuni, switch-ul asteapta hook-urile. Citat: + +> When you start an interactive session, resume a conversation at launch with `--continue` or +> `--resume`, or run `/clear`, SessionStart hooks run in the background. You can type right +> away, and a conversation you resumed appears without waiting for the hooks. Claude's first +> response still waits for the hooks to finish, so their context reaches Claude. + +--- + +## 3. SessionStart — cum returneaza context, forma exacta, limita de marime + +Sursa: `https://code.claude.com/docs/en/hooks.md`, `#### SessionStart decision control` + +exemplu JSON: + +> In addition to the [JSON output fields](#json-output) available to all hooks, you can return +> these event-specific fields: +> +> | Field | Description | +> | :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +> | `additionalContext` | String added to Claude's context at the start of the conversation, before the first prompt. | +> | `initialUserMessage` | String used as the first user message of the session. Applies in non-interactive mode with `-p`... | +> | `sessionTitle` | Sets the session title, with the same effect as `/rename`... Applies when `source` is `"startup"`, `"resume"`, or `"fork"`; ignored on `"clear"` and `"compact"` | +> | `watchPaths` | Array of absolute paths to watch for FileChanged events during this session | +> | `reloadSkills` | Boolean. When `true`, re-scans skill/command dirs after SessionStart hooks complete... | +> +> ```json +> { +> "hookSpecificOutput": { +> "hookEventName": "SessionStart", +> "additionalContext": "Current branch: feat/auth-refactor\nUncommitted changes: src/auth.ts, src/login.tsx\nActive issue: #4211 Migrate to OAuth2", +> "sessionTitle": "auth-refactor" +> } +> } +> ``` + +Confirmat: e `hookSpecificOutput` cu `hookEventName: "SessionStart"` si `additionalContext` +imbricat inauntru — exact forma presupusa in brief. + +**Limita de marime (generala, se aplica la SessionStart la fel ca la toate evenimentele)**, +sursa: `https://code.claude.com/docs/en/hooks.md`, `#### Add context for Claude`: + +> The `additionalContext` field passes a string from your hook into Claude's context window. +> Claude Code wraps the string in a system reminder and inserts it into the conversation at the +> point where the hook fired. +> +> [...] +> +> If a value exceeds 10,000 characters, Claude Code writes the text to a file in the session +> directory and passes Claude the file path with a short preview instead. + +Deci: **10.000 de caractere** e pragul. Peste el, Claude Code NU trunchiaza si NU refuza — +scrie continutul intr-un fisier in directorul sesiunii si trimite lui Claude calea + un preview +scurt. Pentru un handoff mare, asta e de fapt convenabil: hook-ul poate trimite tot textul, iar +peste prag Claude Code il redirectioneaza singur spre fisier. + +Unde ajunge textul pentru `SessionStart` specific, din acelasi paragraf: + +> * [SessionStart](#sessionstart) and [SubagentStart](#subagentstart): at the start of the +> conversation, before the first prompt + +Nota despre re-rulare la resume, aceeasi sectiune: + +> `SessionStart` hooks run again on resume with `source` set to `"resume"`, or `"fork"` if you +> added `--fork-session`, so they can refresh their context. + +(Nu mentioneaza explicit re-rularea la `/clear`, dar tabelul de matchere de la punctul 1 o +confirma separat: `clear` e chiar unul dintre matcherele native ale evenimentului.) + +Exit code: stdout simplu (fara JSON) e tratat ca text simplu si ajunge in context, la fel ca +`additionalContext` — nu trebuie neaparat JSON daca hook-ul nu seteaza si alte campuri. Citat: + +> Claude Code adds stdout it treats as plain text to Claude's context. [...] Since plain stdout +> already reaches Claude for this event, a hook that only loads context can print to stdout +> directly without building JSON. Use the JSON form when you need to combine context with other +> fields such as `sessionTitle`. + +--- + +## 4. PostCompact — aceleasi intrebari, plus `manual` vs `auto` + +Sursa: `https://code.claude.com/docs/en/hooks.md`, `### PostCompact`: + +> Runs after Claude Code completes a compact operation. Use this event to react to the new +> compacted state, for example to log the generated summary or update external state. Claude +> Code discards a PostCompact hook's `systemMessage` and `continue` fields. +> +> The same matcher values apply as for `PreCompact`: +> +> | Matcher | When it fires | +> | :------- | :----------------------------------------------------------------------------------------------------------------------- | +> | `manual` | After `/compact` | +> | `auto` | After auto-compact when the conversation reaches the auto-compact window | +> +> #### PostCompact input +> +> In addition to the common input fields, PostCompact hooks receive `trigger` and +> `compact_summary`. The `compact_summary` field contains the conversation summary generated by +> the compact operation. +> +> ```json +> { +> "session_id": "abc123", +> "transcript_path": "...", +> "cwd": "...", +> "hook_event_name": "PostCompact", +> "trigger": "manual", +> "compact_summary": "Summary of the compacted conversation..." +> } +> ``` +> +> **PostCompact hooks have no decision control. They can't affect the compaction result but can +> perform follow-up tasks.** + +**Constatare critica pentru mecanismul propus: `PostCompact` NU poate injecta +`additionalContext` si nu poate influenta rezultatul compactarii — e strict pentru efecte +secundare (log, notificare externa etc.).** Daca planul se baza pe "PostCompact reinjecteaza +handoff-ul", premisa e falsa. Calea care CHIAR functioneaza pentru compactare e +`SessionStart` cu matcher `compact` (punctul 1 si 3) — un eveniment diferit, care ruleaza dupa +`PostCompact` si care are `additionalContext`. Exemplul oficial de "re-inject context after +compaction" din `hooks-guide.md` confirma asta explicit: + +> When Claude's context window fills up, compaction summarizes the conversation to free space. +> This can lose important details. Use a `SessionStart` hook with a `compact` matcher to +> re-inject critical context after every compaction. + +Pentru `PreCompact` (nu a fost cerut explicit, dar e relevant ca sa nu confundati): poate bloca +(`decision: "block"` sau exit 2) si primeste `trigger` + `custom_instructions`, dar la fel +"discards `systemMessage` and `continue`". `PreCompact` nu e mecanismul de reinjectare — ruleaza +INAINTE de compactare. + +--- + +## 5. Poate un hook sa declanseze `/clear` sau `/compact`? + +**NU exista niciun mecanism. Confirmat explicit, nu doar prin absenta.** + +Sursa: `https://code.claude.com/docs/en/hooks-guide.md`, linia 952: + +> Command hooks communicate through stdout, stderr, and exit codes only. **They can't trigger +> `/` commands or tool calls.** Text returned via `additionalContext` is injected as a system +> reminder that Claude reads as plain text. HTTP hooks communicate through the response body +> instead. + +Am cautat explicit orice camp de tip `"command"` sau mecanism de rulare a unei comenzi slash +din output-ul unui hook, in tot `hooks.md` (3840 linii) si `hooks-guide.md` (1064 linii) — nu +exista. Singurele cai care declanseaza efectiv o compactare/clear raman actiunile native ale +utilizatorului (`/clear`, `/compact`) sau host-ul/SDK-ul care porneste sesiunea. + +--- + +## 6. Stop hook — poate bloca oprirea si injecta o instructiune? + +**Da, in doua moduri diferite**, sursa `https://code.claude.com/docs/en/hooks.md`, +`### Stop` + `#### Stop input` + `#### Stop decision control`: + +Input: + +> In addition to the common input fields, Stop hooks receive `stop_hook_active`, +> `last_assistant_message`, `background_tasks`, and `session_crons`. The `stop_hook_active` +> field is `true` when Claude Code is already continuing as a result of a stop hook. Check this +> value or process the transcript to avoid blocking on a condition that will never resolve. +> Claude Code overrides the hook and ends the turn after 8 consecutive blocks. + +Decision control: + +> `Stop` and `SubagentStop` hooks can control whether Claude continues. In addition to the JSON +> output fields available to all hooks, your hook script can return these event-specific +> fields: +> +> | Field | Description | +> | :-------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +> | `decision` | `"block"` prevents Claude from stopping. Omit to allow Claude to stop | +> | `reason` | Required when `decision` is `"block"`. Tells Claude why it should continue | +> | `hookSpecificOutput.additionalContext` | Non-error feedback for Claude. The conversation continues so Claude can act on it, but unlike `decision: "block"` it is shown in the transcript as hook feedback rather than a hook error | +> +> A hook that blocks by exiting 2 routes the same way as `reason`: Claude receives the stderr +> message as the explanation for why it should continue. +> +> ```json +> { +> "decision": "block", +> "reason": "Must be provided when Claude is blocked from stopping" +> } +> ``` +> +> Use `additionalContext` when the hook is working as designed and giving Claude guidance, such +> as "run the test suite before finishing". It keeps the conversation going through the same +> loop protections as `decision: "block"`, namely the `stop_hook_active` input and the +> 8-consecutive-continuation cap, but the transcript labels it `Stop hook feedback` and no hook +> error notification is shown. + +Deci: `decision: "block"` + `reason` (top-level, NU in `hookSpecificOutput`) forteaza +continuarea si arata `reason` ca eroare de hook; `hookSpecificOutput.additionalContext` face +acelasi lucru dar apare ca "Stop hook feedback", nu ca eroare. **Ambele variante trec prin +aceleasi limite de bucla**: campul `stop_hook_active` (hook-ul trebuie sa verifice singur ca sa +nu se blocheze la infinit) si plafonul intern de **8 blocari consecutive fara progres**, dupa +care Claude Code forteaza oprirea oricum. + +Exit code 2 pe `Stop`: din tabelul citat separat in `hooks.md`, poate bloca (spre deosebire de +`SessionStart`, unde exit 2 doar arata mesajul utilizatorului si continua executia). + +**Aplicabil direct la ideea "Stop scrie handoff-ul acum": da, se poate implementa** — +hook-ul `Stop` verifica o conditie (context mare, sarcina neterminata etc.), daca handoff-ul nu +exista inca pe disc raspunde cu `decision: "block"` + `reason: "scrie handoff-ul pe disc inainte +de oprire"`, Claude continua turul, scrie handoff-ul, iar hook-ul (cand ruleaza din nou la +urmatoarea incercare de Stop) vede handoff-ul pe disc si lasa oprirea sa treaca. Trebuie +verificat `stop_hook_active` ca sa nu intre in bucla si respectat plafonul de 8. + +--- + +## VERDICT PRACTIC + +**Lantul complet "handoff pe disc -> /clear -> reinjectare automata" se poate construi, cu doua +completari fata de premisa initiala:** + +1. **Partea automata, confirmata**: + - `SessionStart` cu matcher `clear` (sau, pentru compactare, matcher `compact`) fireste + dupa `/clear`/compactare, primeste `source` explicit (`"clear"` / `"compact"`) — hook-ul + poate citi handoff-ul de pe disc si il injecta prin + `hookSpecificOutput.additionalContext`, INAINTE de primul prompt al sesiunii noi. Asta + merge din prima, fara nicio interventie manuala suplimentara, pentru ambele declansatoare + (`/clear` SI compactare — nu doar `/clear`). + - Nu exista limita blocanta de marime: sub 10.000 caractere textul intra direct in context; + peste, Claude Code il scrie singur intr-un fisier si trimite calea — deci un handoff mare + nu se pierde, doar se livreaza indirect. + - `Stop` poate fi folosit ca plasa de siguranta care FORTEAZA scrierea handoff-ului inainte + de oprire (`decision: "block"` + `reason`), cu conditia sa respecte `stop_hook_active` si + plafonul de 8 blocari. + +2. **Ce ramane obligatoriu manual / in afara hook-urilor**: + - **Niciun hook nu poate declansa `/clear` sau `/compact` singur** — confirmat explicit in + documentatie ("can't trigger `/` commands or tool calls"). Utilizatorul (sau orchestrator-ul, + daca ruleaza in headless/SDK cu control asupra sesiunii) trebuie sa emita el actiunea. + - **Niciun hook nu anunta "am ajuns la ~50% context"** — nu exista un eveniment de tip + "context threshold reached". Campurile `context_tokens` etc. apar DOAR pe `SessionStart` cu + `source: "resume"/"fork"`, dupa fapt — nu in timp real, in timpul sesiunii curente. Decizia + de "e timpul sa scriu handoff-ul" ramane a modelului/sesiunii, exact cum descrie deja + regula din `CLAUDE.md` — hook-urile nu o pot automatiza. + - **Premisa gresita de reparat**: daca planul se baza pe `PostCompact` pentru reinjectare, + nu functioneaza — `PostCompact` n-are `decision control` deloc. Mecanismul corect pentru + compactare e `SessionStart` cu matcher `compact`, nu `PostCompact`. + +**Pe scurt**: partea "citeste handoff de pe disc si baga-l inapoi in context la (re)pornire" e +100% automata prin `SessionStart`. Partea "declanseaza tu insuti /clear" ramane 100% manuala — +nu exista ocolire documentata. `Stop` poate automatiza doar "nu te opri pana nu ai scris +handoff-ul pe disc", nu si declansarea lui `/clear` dupa aceea. + +--- + +## Nota metodologica + +`WebFetch` (tool-ul standard) trunchiaza/rezuma paginile `hooks` si `hooks-guide` inainte sa +ajunga la sectiunile per-eveniment (confirmat empiric: trei incercari diferite de prompt au +esuat sa extraga `### SessionStart`, `### Stop`, `### PostCompact` din pagina `hooks`, desi +tabelele de sus ale paginii ies corect). Documentatia Mintlify expune si varianta bruta: +`https://code.claude.com/docs/en/hooks.md` si `.../hooks-guide.md` (mentionate chiar de pagina: +"Fetch the complete documentation index at: https://code.claude.com/docs/llms.txt"). Am fetch-uit +acele `.md`-uri direct prin `curl` (citire read-only, fara nicio scriere in afara acestui +livrabil) si am citat din ele. Toate citatele de mai sus sunt verbatim din acele fisiere. diff --git a/docs/vm304_acces.md b/docs/vm304_acces.md new file mode 100644 index 0000000..bffa2f6 --- /dev/null +++ b/docs/vm304_acces.md @@ -0,0 +1,102 @@ +# VM 304 — ce este si cum se acceseaza + +## Ce este + +VM 304 = masina virtuala Proxmox cu ID **304**, nume **Win11-Marius**, pe nodul **pvemini** +din clusterul Proxmox ROA. Nu e in HA (`noha`). + +Surse: +- `E:\proiecte\ROMFASTSQL\proxmox\cluster\docs\oprire-planificata-cluster.md:293` + `| 2 | pvemini | VM 304 Win11-Marius | Nu | Shutdown |` +- `E:\proiecte\ROMFASTSQL\proxmox\cluster\docs\oprire-planificata-cluster.md:479` + `Guest-uri in afara HA: CT 102, CT 301, VM 302, VM 303, **VM 304**, VM 310.` +- `E:\proiecte\ROMFASTSQL\proxmox\cluster\scripts\cluster-startup.sh:53` `304 # Win11-Marius` +- `E:\proiecte\ROMFASTSQL\proxmox\cluster\scripts\cluster-shutdown.sh:41` + `304 # Win11-Marius — desktop, fara dependente` +- `E:\proiecte\ROMFASTSQL\proxmox\cluster\scripts\.cluster-state.txt:13` `vm pvemini 304 running noha` + +E clona lui **VM 303 (Win11-Adina)**: +- `E:\proiecte\ROMFASTSQL\docs\acces-ssh-chei-angajati.md:251` + `| docs/chei-publice/vm304.pub | ... | angajat, romfast@VM-304 (clona lui 303) |` +- `E:\proiecte\ROMFASTSQL\docs\acces-ssh-chei-angajati.md:256-260` — clona a pornit cu aceeasi + cheie privata ca VM 303; a fost regenerata separat (`ssh-keygen -t ed25519 -C "romfast@VM-304"`), + cu stergerea keypair-ului mostenit din Bitvise User keypair manager si regenerarea cheilor de + host `ssh_host_*`, altfel clona continua sa se autentifice cu identitatea VM 303 in loguri. + +Nu am gasit un nume de retea/hostname DNS sau un IP direct alocat lui VM 304 in documentatia +cautata (nu e in tabelul de IP-uri interne `10.0.20.x` de la +`E:\proiecte\ROMFASTSQL\docs\acces-ssh-chei-angajati.md:388-394`, care listeaza doar nodurile +Proxmox). Accesul documentat trece prin host-ul Proxmox, nu prin IP propriu al VM-ului (vezi mai jos). + +## Cum se acceseaza + +**Nu prin RDP** — nu am gasit nicio mentiune de RDP catre VM 304 in fisierele cautate. Accesul +documentat e **headless, prin QEMU guest agent**, de pe LXC 171 (sau orice masina cu acces SSH la +host-ul Proxmox), catre host-ul nodului `pvemini` la `root@10.0.20.201`: + +```bash +# ping guest agent, ca sa confirmi ca VM-ul raspunde: +ssh root@10.0.20.201 "qm agent 304 ping" + +# executie de comanda Windows in interiorul VM 304: +ssh root@10.0.20.201 "qm guest exec 304 -- " +``` + +Sursa: `E:\proiecte\ROMFASTSQL\docs\drepturi-utilizatori-roa-firme.md:14-19` (documentat generic +pentru ``, cu exemplul explicit "304 = Win11-Marius" la linia 14). + +Acelasi tipar (guest agent prin `qm agent`/`qm guest exec` de pe host `root@10.0.20.201`) e +folosit si pentru celelalte VM-uri Windows non-HA ale clusterului — vezi si +`E:\proiecte\ROMFASTSQL\proxmox\cluster\docs\oprire-planificata-cluster.md:15` (guest agent +necesar pentru shutdown controlat). + +## Cale de retea catre discul ei + +Nu am gasit o cale UNC (`\\server\share`) documentata catre VM 304. Ce e documentat e o cale +**locala, in interiorul VM-ului** — `D:\roa\BITVISE\.tlp` (profilele Bitvise) si +`D:\roa\\...` (working copy ROA, folosita ca sursa pentru scripturi SQL) — accesibila doar +prin comenzi rulate cu `qm guest exec`, nu prin share de retea: + +- `E:\proiecte\ROMFASTSQL\docs\drepturi-utilizatori-roa-firme.md:17` + `# Profilul Bitvise al clientului e in D:\roa\BITVISE\.tlp pe VM.` +- `E:\proiecte\ROMFASTSQL\docs\drepturi-utilizatori-roa-firme.md:62` + `Sursa: D:\roa\\COMUN\Drepturi utilizatori\drepturi_utilizatori.sql din orice working copy ROA` +- `E:\proiecte\ROMFASTSQL\docs\acces-ssh-chei-angajati.md:371-372` + `astea sunt fisierele care pleaca pe VM 303 / VM 304 (pe VM 304 stau in D:\roa\BITVISE\)` + +## Ce are instalat (documentat) + +- **Bitvise SSH Client**, cale `C:\Program Files (x86)\Bitvise SSH Client\sexec.exe` + (`E:\proiecte\ROMFASTSQL\docs\drepturi-utilizatori-roa-firme.md:19`), cu profile de clienti in + `D:\roa\BITVISE\*.tlp` si cheia globala `C:/Users/romfast/.ssh/id_ed25519`. +- **O copie/working copy ROA** sub `D:\roa\\...` (produsul e generic in text, nu apare + explicit "ROAFACTURARE" — vezi `drepturi-utilizatori-roa-firme.md:62`). +- Nu am gasit mentiune explicita despre VFP 9 sau Oracle client instalate pe VM 304 in fisierele + cautate (spre deosebire de VM 302, documentat separat ca `oracle-test`, + `E:\proiecte\ROMFASTSQL\proxmox\vm302-oracle-test\`). + +## Credentiale — unde sunt documentate (nu le-am copiat) + +- Cheia publica SSH pentru angajat pe VM 304: `E:\proiecte\ROMFASTSQL\docs\chei-publice\vm304.pub`, + amprenta SHA-256 listata la `E:\proiecte\ROMFASTSQL\docs\acces-ssh-chei-angajati.md:251`. +- Cheia globala folosita de `sexec.exe` in `qm guest exec`: + `C:/Users/romfast/.ssh/id_ed25519` (in interiorul VM 304 — vezi + `drepturi-utilizatori-roa-firme.md:19`). +- Lista completa a serverelor pe care sunt copiate cheile: `scripts/bitvise-chei.ps1`, variabila + `$Servere` (`E:\proiecte\ROMFASTSQL\docs\acces-ssh-chei-angajati.md:264`). +- Nu am gasit parola sau alta credentiala pentru autentificare directa (RDP/consola) pe VM 304 in + fisierele cautate. + +## Unde am cautat + +1. `D:\ROA\ROAFACTURARE\COMUN\docs\` (grep `304`, `vm304`, `masina virtuala`, `server de test`, + `infrastructur`) — potriviri gasite pentru `304` erau toate numere de linie in cod PL/SQL + (`PACK_UTILS` linia 304, `PLS-00304`) sau text irelevant, nicio mentiune de VM 304. +2. `D:\ROA\COMUNROA\` — grep pe `304` a expirat (timeout la 20s pe arborele intreg, prea mare); + nu am reluat cautarea pentru ca raspunsul complet a fost deja gasit la pasul 3, conform + instructiunii de oprire la primul raspuns gasit. +3. `E:\proiecte\ROMFASTSQL\` — gasit direct: `docs/chei-publice/vm304.pub`, + `docs/acces-ssh-chei-angajati.md`, `docs/drepturi-utilizatori-roa-firme.md`, + `proxmox/cluster/docs/oprire-planificata-cluster.md`, + `proxmox/cluster/scripts/cluster-{startup,shutdown}.{sh,ps1}`, + `proxmox/cluster/scripts/.cluster-state.txt`.