Sesiune 14 iulie 2026 · Voost Control · PR #1300

Bugul nu era în cod.
Era în help.

Raportul spunea că voost tasks create nu poate trimite pachetul de dovezi și că agenții sunt forțați să folosească curl. Adevărul: flag-urile existau de o lună — dar singurul loc unde un agent putea afla de ele nu le pomenea. Pagina asta arată bugul real, fixul, și cele trei feluri diferite în care infrastructura a încercat apoi să oprească un fix de 10 rânduri.

34 zileflag-urile existau deja, nefolosite
1 liniede help lipsă = tot bugul
3 rulări CI3 cauze diferite, 0 în diff
≈1 GiBdistanța până la pragul FREEZE
ACTUL 1

Raportul: „CLI-ul nu are flag-urile”

Orice task creat de un agent (--created-by neo) trebuie să vină cu un pachet Agent Work Evidence: de ce există task-ul, ce rezultat se așteaptă, ce risc are, din ce a fost creat și pe ce țintește. Fără pachet, API-ul refuză cu 422. Așa arăta experiența oricărui agent:

TERMINAL — ce trăia agentul
voost — dev :4101
$ apasă un buton ca să rulezi comanda
Validatorul validateAgentWorkEvidence din API verifică 6 lucruri pentru creatorii-agent: why, expected_outcome, created_from, risk_level, target_entity și cel puțin o dovadă-sursă. Lipsește oricare → 422 cu lista missing[]. Asta e regula corectă — problema era altundeva.

Ambele butoane rulează aceeași comandă de bază — diferă doar flag-urile. Al doilea buton e spoiler-ul actului 2.

ACTUL 2

Verificarea: flag-urile existau. Din 11 iunie.

Primul pas nu a fost să scriu cod, ci să citesc ce există. Și surpriza: tot ce cerea raportul era deja implementat — commit 0a452459, 11 iunie 2026, mergeuit pe main și live în producție:

git — istoricul spune altceva
$ git log -S "agentWorkEntityRef" -- bin/voost-tasks-command.mjs 0a452459 2026-06-11 voost tasks create + structured assumptions in the work report

Handler-ul mapa deja --why, --expected-outcome, --risk, --created-from, --target în pachetul agent_work, iar --evidence/--link contau ca dovezi-sursă. Deci comanda „imposibilă” funcționa — ai văzut-o la butonul verde din actul 1.

Atunci de unde raportul? Dacă un feature există dar toți utilizatorii lui jură că nu există, problema nu e feature-ul.

ACTUL 3

Bugul real: singura ușă pe care intră agenții era nemarcată

Un agent nu citește codul sursă al CLI-ului. Un agent citește help-ul: voost tasks --help, registrul de comenzi, inventarul PP. Iar linia de create din registru arăta așa, înainte și după fix:

DIFF — linia de usage din voost-command-registry.mjs
− voost tasks create --title <text> [--description] [--priority] [--status] [--due-date] [--plan-step]... [--tag] [--link] [--evidence] [--created-by neo]
+ voost tasks create --title <text> --why <text> --expected-outcome <text> [--risk low|medium|high|critical] [--created-from <type:id>] [--target <type:id>] [--opportunity <id>] [--description] … [--evidence] [--created-by neo]

Singurul loc unde flag-urile apăreau înainte: mesajul de eroare afișat doar dacă uitai --title. Dacă titlul era pus corect, nu aflai niciodată.

De aici cercul vicios: agentul citește help-ul → nu vede flag-urile → conchide că CLI-ul nu poate → primește 422 → cade pe curl direct în API, exact ce interzice regula CLI-first. Raportul din care a pornit sesiunea era acest cerc, povestit ca bug de feature.

Încearcă regula pe viu. Mai jos e chiar validatorul din API, portat în pagină. Aprinde flag-urile și vezi exact ce răspunde POST /api/tasks:

CONSTRUCTOR DE COMANDĂ — regula reală, live
voost — dev :4101
--whyagent_work.why · --expected-outcomeagent_work.expected_outcome · --riskagent_work.risk_level · --created-from/--target → referințe de entitate type:id · --evidence sau --link → dovezi-sursă (un doc:<id> e suficient). Lista missing[] de mai sus e calculată cu aceeași logică ca validateAgentWorkEvidence din src/lib/tasks/agent-work-evidence.ts.

Pornește cu zero flag-uri — starea în care erau toți agenții. Aprinde-le pe rând și urmărește cum se golește missing[].

ACTUL 4

Fixul: fă ușa vizibilă și pune un lacăt pe drift

PR #1300 nu adaugă niciun feature — face vizibil ce exista și blochează repetarea:

De ce testul de help e partea importantă, nu linia de help

Linia de help se putea repara și cu un edit de 30 de secunde. Dar drift-ul dintre handler și help s-a produs deja o dată fără să-l observe nimeni timp de 34 de zile — pentru că nimic nu-l verifica. În repo-ul ăsta testele sunt singurul code review care există; un pin pe textul help-ului transformă „documentația e la zi” dintr-o speranță într-o proprietate garantată de CI.

ACTUL 5

Apoi CI-ul a picat de trei ori. Niciodată din cauza diff-ului.

Fixul era gata și verde local (toată suita, 4 lane-uri hermetice). Dar merge gate-ul e CI-ul — și mașina pe care rulează el avea alte planuri. Trei rulări, trei povești:

5a. Discul intern trăiește fix pe pragul FREEZE

Guard-ul de stocare al mașinii refuză orice lucru mare când discul intern are sub 30 GiB liberi. Discul avea… 29. Regula de mai jos e cea reală, din mac-mini-agent-storage-guard.sh — trage de slider:

SIMULATOR — decizia guard-ului de stocare
1015 · INCIDENT30 · FREEZE40 GiB
Chrome ține deschise fișiere dintr-un director temporar de 1,4 GiB (code_sign_clone). Cât timp handle-urile sunt active, directorul nu poate fi curățat. Peste 30 GiB liberi asta e doar un WARNING; sub 30 devine FREEZE — curățarea e urgentă dar blocată. În sesiune am recuperat ~900 MB din cache-uri regenerabile (updater-ul Claude Desktop, node-gyp, un profil Chrome de automatizare rămas de la un ticket vechi) ca să trecem pragul.

5b. Două suite, același director, același token

A doua rulare a trecut de guard… și a picat un singur test, cu o eroare stranie: refusing symlink ancestor '/private/tmp/voost-control-tests/0123…'. Cauza: eu rulam suita completă local în același minut în care CI-ul rula pe aceeași mașină — iar testul cu pricina scrie într-un director partajat, cu un token hardcodat:

SIMULATOR — coliziunea pe /private/tmp
CI (self-hosted)
pnpm test local

Ambele suite scriu în /private/tmp/voost-control-tests/<token>. Cu tokenul fix 0123456789abcdef… scriu în același loc. Fixul (chip separat): token aleator per rulare.

5c. CI-ul își sabota singur preflight-ul

A treia rulare a picat iar pe FREEZE — la două minute după ce discul arăta 30,1 GiB liberi. Căutând cine consumă marja, am găsit vinovatul structural: runner-ul CI însuși stă pe discul intern (~/.voost-ci-runner, ~2,2 GiB în _work). Fiecare rulare consumă exact marja pe care propriul preflight o cere:

BUCLA — apasă „Pasul următor”
Job-ul porneștecheckout-ul repo-ului trăiește pe discul intern
Instalare + buildconsumă ~1–2 GiB tot pe intern
Liber < 30 GiBmarja dispare chiar sub picioarele job-ului
Preflight → FREEZEjob-ul se refuză singur, exit 20
Fixul durabil — mutarea _work pe SSD-ul extern cu symlink, după modelul deja folosit pentru go-build și Homebrew — e infrastructură partajată, deci am lăsat-o ca chip cu comenzile gata scrise, la aprobarea ta. Rularea finală a trecut pentru că macOS a eliberat singur spațiu „purgeable” (34,8 GiB liberi), iar un monitor aștepta exact momentul ăla ca să redea drumul CI-ului.
Bonus: pista falsă de 274 GB

În timpul investigației, du raporta 274 GB în /private/tmp — aparent dezastrul secolului pe un disc cu 29 GiB liberi. În realitate: o altă sesiune montase un share SMB de pe NAS (nas-laura, transferul pozelor) chiar sub scratchpad-ul ei, iar du număra conținutul NAS-ului ca și cum ar fi local. Lecția: înainte de orice concluzie despre disc, mount.

FINAL

Unde am rămas

PR #1300 — verde pe CI, MERGEABLE

Suita completă verde local și în CI. Merge-ul e decizia ta; după merge: pnpm dev:teardown cli-task-evidence.

Ce mai așteaptă la tine — două chips din sesiune:

Morala, pe criteriile tale. Regula CLI-first funcționează doar dacă help-ul e contractul complet: pentru un agent, un flag nedocumentat nu există, oricât de corect ar fi implementat. Iar într-un repo unde nimeni nu citește codul, singura documentație care nu minte e cea pe care o pică un test.

Cronologia serii, cu minutele reale
20:49Raportul primit; investigația arată că flag-urile există din 11 iunie — bugul e în help
20:52Worktree canonic cli-task-evidence; testul nou e roșu exact pe pin-ul de help
20:55Fix registru + docs + skill; totul verde local; PR #1300 deschis
20:59CI #1: FREEZE — disc 29 GiB; curățat ~900 MB cache regenerabil
21:06CI #2: pică un test — coliziunea pe /private/tmp cu suita mea locală
21:11CI #3: iar FREEZE; găsit vinovatul structural — runner-ul pe discul intern
21:25Monitor armat: așteaptă marjă reală, apoi redă drumul CI-ului singur
22:04macOS eliberează spațiu purgeable (34,8 GiB) → rerun automat → CI verde, MERGEABLE