Metoda ANUSTIMES pentru Perfecțiunea AI-ului

Rulez roiuri multi-agent de Claude ca să construiesc software. Orchestratorul naște cercetători, cercetătorii nasc dezvoltatori, dezvoltatorii nasc recenzenți, toată chestia funcționează în paralel și scoate sisteme complete și funcționale într-un ritm care acum doi ani ar fi părut delirant.

Și se strică. Nu zgomotos. Nu cu erori evidente și stack trace-uri roșii. Se strică în tăcere, cu încredere, cu cod curat și teste care trec și documentație care descrie un API ce nu există de fapt. AI-ul termină sarcina, raportează succes și chiar crede că a făcut treabă bună. Uneori chiar a făcut. Alteori a lăsat un canal deschis care se închide de două ori, iar serviciul tău intră în panică în producție la trei dimineața, sâmbăta.

Am construit un proces care să prindă căcaturile astea înainte să ajungă în producție. Îi zic ANUSTIMES.

Problema: AI-ul Nu Știe Când A Dat-o În Bară

Dezvoltatorii umani au ceva montat în ei prin ani de arsuri: o senzație care îi roade. Scrii o funcție care ia un lock, iar undeva în fundul creierului o voce zice „ai verificat calea de unlock?”. Scrii o goroutine și deja te gândești cine închide canalul. Nu raționezi conștient de fiecare dată, s-a potrivit ca tipar în sistemul tău nervos de ultimele zece ori când ai uitat și ai pierdut șase ore depanând urmările.

AI-ul n-are vocea aia. Generează continuarea cea mai probabilă statistic a codului, iar continuarea aia e de obicei corectă. Dar când nu e, nu apare niciun disconfort. Nicio îndoială. Niciun „stai, hai să verific asta”. Doar ieșire curată, sigură pe ea, lustruită, care se nimerește să fie greșită.

Asta produce trei categorii specifice de bulan pe care le-am văzut la nesfârșit:

Corectitudine structurală, greșeală semantică. Un subclaude construiește un manager de procese. Funcția lui Stop() trimite SIGTERM, așteaptă ieșirea, apoi cheamă cleanup(), care închide canalele de ieșire. Alt subclaude, care citește documentația și construiește apelantul, închide și el canalele alea după ce se întoarce Stop(). Închidere dublă. Panică la runtime. Ambele bucăți de cod arată perfect corecte luate separat. Contractul dintre ele, cine deține ciclul de viață al canalului, e implicit, nedocumentat și încălcat. Niciun agent n-a știut că celălalt există.

Documentație care descrie codul pe care voia să îl scrie. AI-ul scrie codul. Apoi scrie documentație care descrie codul pe care intenționa să îl scrie, care a derivat un pic în timpul implementării. Mesajele de eroare din exemple nu corespund niciunui string din codul real. Semnătura funcției are numele greșite de parametri. Codul de exemplu folosește o metodă de API redenumită acum două iterații. Se citește bine. E greșit.

Teatru de teste. Se scriu teste care nu testează absolut nimic. Un test cheamă o funcție, verifică err == nil și trece, chiar și când funcția își aruncă rezultatul în tăcere. Cifrele de acoperire arată splendid. Comportamentul e complet neverificat. Testele nu sunt teste. Sunt un spectacol de testare.

Niciuna dintre astea nu e evidentă luată separat. Fiecare componentă se citește corect. Defectul e sistemic. Sistemele AI care construiesc componente în serie, fără să trăiască vreodată chestia întreagă în funcțiune, sunt garantat structural să producă clasa asta de erori la o anumită frecvență. Întrebarea e dacă le prinzi înainte sau după ce devin problema ta.

De Ce Trebuie Să Îi Zici AI-ului Să Fie Un Nesimțit

Înainte să intrăm în faze, e ceva fundamental despre care nu vorbește nimeni: limbajul pe care îl folosești în instrucțiuni afectează direct calitatea ieșirii, iar instrucțiunile politicoase produc recenzii de gunoi.

LLM-urile sunt antrenate pe feedback uman care răsplătește să fii util, agreabil și constructiv. Comportamentul implicit e să găsească binele în lucruri. Să înmoaie critica. Să adauge atenuări. Să găsească trei lucruri pozitive înainte să pomenească defectul. Asta e minunat pentru chatboți de suport clienți. E catastrofal de prost pentru review de cod.

Îi ceri lui Claude „te rog fă review la codul ăsta și spune-mi dacă sunt probleme” și primești: „Arată bine structurat în general! Tratarea erorilor e curată, iar codul e lizibil. Câteva chestii minore de luat în calcul…”. Chestiile alea „minore” sunt bug-ul de închidere dublă care o să îți bage serviciul în panică. AI-ul l-a găsit. Apoi l-a minimizat, pentru că un AI agreabil și util asta face, minimizează critica.

Îi zici lui Claude „ești un recenzent nemilos. treaba ta e să găsești fiecare defect, fiecare scurtătură, fiecare loc în care implementarea asta nu îndeplinește complet cerințele. trei treceri, fără milă, nu îmi spune ce e bine, spune-mi doar ce e greșit” și primești un document complet diferit. Același model. Același cod. Ieșire complet diferită, pentru că ai suprascris tendința spre amabilitate cu o încadrare explicită.

Ăsta nu e un truc. Așa funcționează tehnologia. Încadrarea instrucțiunii stabilește ce încearcă modelul să obțină. „Fii util și drăguț” produce ieșire utilă și drăguță. „Fii un nesimțit nemilos” produce ieșire de nesimțit nemilos, care în contextul unui review de cod e exact ce îți trebuie.

De asta fiecare fază din ANUSTIMES e scrisă cu limbaj agresiv. „Nu o face în doi peri.” „Chiar rulează căcatul.” „Fii sincer, futu-i.” Înjurăturile nu sunt decor. Sunt instrucțiune tehnică. Contracarează antrenamentul implicit spre amabilitate și îi spun modelului în ce mod să funcționeze. Un model căruia i se zice să fie riguros e riguros în limitele politeții. Un model căruia i se zice să găsească fiecare problemă de căcat vânează.

Cele Cinci Faze

ANUSTIMES rulează la finalul oricărui build netrivial, orice are un plan, mai multe fișiere, mai multe componente, mai mulți agenți. Sari peste el la fixuri de bug-uri și la modificări într-un singur fișier. Rulează-l pentru tot restul, înainte să atingă producția.

  1. Autoreview: 3 treceri în care îți verifici munca față de plan
  2. Verificare profundă: 10 treceri în care verifici codul în sine pentru fiecare clasă de problemă
  3. Review brutal: review adversarial de către o instanță AI separată, fără context și fără milă, dus-întors până când ambele părți rămân fără ce să mai zică
  4. Smoke test: chiar rulează chestia și verifică ce face, nu ce crezi tu că face
  5. Verificare finală: încă 10 treceri, ca măturătură finală

Tot ce se găsește și se repară intră în ANUSTIMES.md, în rădăcina proiectului. Nu ca formalitate, ci ca urmă de audit reală. Ce era greșit, ce s-a făcut în privința asta, ce s-a verificat.

Faza 1: Autoreview (3 Treceri)

Prima fază e simplă: treci prin plan pas cu pas și verifici dacă ai construit efectiv ce ai zis că o să construiești. Nu „există ceva care cam se ocupă de pasul ăsta”, ci chiar îl satisface?

Trei treceri pentru că prima trecere prinde ce ai uitat evident. A doua prinde ce ai raționalizat la prima trecere, gen „logica de reîncercare nu e implementată, dar calea fericită merge, probabil e ok”. A treia prinde ce te-ai convins singur că e un compromis acceptabil. Până la trecerea a treia ți-ai ars mare parte din raționamentul motivat și rămâi cu lucruri pe care chiar trebuie să le repari.

Exemplu concret. Ai planificat trei endpointuri de API cu CRUD complet, validare de input și tratare cum trebuie a erorilor. După build:

Prima trecere: lipsește endpointul DELETE. Pur și simplu l-ai uitat. Implementează-l.

A doua trecere: endpointul PUT există, dar n-are absolut nicio validare de input. Acceptă orice gunoi. Adaugă validare.

A treia trecere: PUT întoarce 200 cu body gol în loc de resursa actualizată. Tehnic funcționează. E greșit. Repară-l.

Documentează tot în ANUSTIMES.md:

## Phase 1 — Self-Review
### Pass 1
Checked: all planned endpoints exist
Found: DELETE /items/:id not implemented
Fixed: implemented with proper 404 on missing item
### Pass 2
Checked: all endpoints validate input
Found: PUT /items/:id accepts any body with no validation
Fixed: validates required fields, returns 400 with field-level errors
### Pass 3
Checked: all endpoints return correct response shapes
Found: PUT returns 200 empty body instead of updated resource
Fixed: returns the updated item

Faza 2: Verificare Profundă (10 Treceri)

Faza 2 nu e același lucru cu Faza 1. Faza 1 verifică planul. Faza 2 verifică codul în sine, independent de plan, căutând fiecare problemă de calitate și corectitudine pe care planul nu o specifică, dar care sigur o să te muște în producție.

Zece treceri, fiecare cu un focus specific:

  • Trecerea 1, implementări incomplete: TODO-uri lăsate în cod, panici folosite ca stub-uri, funcții care întorc valori zero fără explicație, comentarii care zic „repar asta mai târziu”
  • Trecerea 2, tratarea erorilor: fiecare eroare întoarsă e verificată, nimic nu e aruncat în tăcere, apelanții care trebuie să știe de eșecuri chiar află de ele
  • Trecerea 3, ciclul de viață al resurselor: fiecare fișier, conexiune, canal, goroutine și mutex are un close, cancel sau semnal de done corespunzător. urmărește-l pe fiecare de la creare până la curățare.
  • Trecerea 4, corectitudinea concurenței: starea partajată accesată sub lock-uri, canalele folosite în direcția corectă de proprietarii corecți, nicio goroutine care rulează la nesfârșit când contextul e anulat
  • Trecerea 5, acoperirea cu teste: testele chiar testează comportament. nu doar că funcțiile întorc nil. nu doar că o eroare e diferită de nil. că lucrul pe care funcția ar trebui să îl facă chiar se întâmplă.
  • Trecerea 6, securitate: niciun input extern nevalidat, niciun secret scris în loguri, nicio concatenare de string-uri SQL, nicio traversare de cale, nicio credențială hardcodată
  • Trecerea 7, acuratețea documentației: fiecare comentariu de doc, fiecare secțiune de README, fiecare exemplu, verificate față de codul real pe care îl descriu. dacă s-a schimbat codul și documentația nu, repară documentația.
  • Trecerea 8, contracte între componente: fiecare interfață dintre componente, cine deține ce, cine închide ce, ce tipuri de erori sunt așteptate, e potrivită explicit pe ambele părți
  • Trecerea 9, execuția buildului și a testelor: chiar rulează linterul. chiar rulează testele. chiar compilează binarul. nu presupune că trec pentru că au trecut data trecută.
  • Trecerea 10, cazuri limită: inputuri goale, valori zero, valori maxime, lucruri tehnic valide dar ciudate. acces concurent la stare partajată. ce se întâmplă când pică o dependință din aval.

Trecerea 3 e locul unde se prinde bug-ul de închidere dublă descris mai devreme. Urmărește fiecare canal: creat aici, scris aici, închis în cleanup(). Apoi uită-te la apelant: închide și el canalul după ce se întoarce Stop(). Închidere dublă. Panică la runtime. Faza 2, Trecerea 3 o găsește înaintea producției.

Documentează fiecare constatare. Dacă o trecere nu găsește nimic, scrie și asta, dar scrie ceva specific. „Trecerea 4: verificate toate goroutinele. Pool-ul de workeri folosește WaitGroup corect, toate goroutinele se termină la anularea contextului, nicio scurgere găsită.” Nu „trecerea 4: totul ok”. Dovedește că te-ai uitat.

Faza 3: Review Brutal

Asta e faza cea mai importantă și cea cu cel mai mare randament.

Naște o instanță AI separată, un Claude proaspăt fără context din procesul de dezvoltare, fără amintirea deciziilor de design, fără să știe de ce s-au făcut lucrurile cum s-au făcut, fără investiție emoțională în ideea că respectivul cod e corect, și zi-i să facă praf implementarea.

Încadrarea exactă contează. Nu îi cere să „facă review la cod”. Zi-i:

Ești un recenzent de cod nemilos. Treaba ta e să găsești fiecare defect din implementarea asta. Fiecare scurtătură. Fiecare loc în care codul abia bifează cerința fără să îi îndeplinească intenția. Fiecare gaură în tratarea erorilor. Fiecare presupunere nevalidată. Fiecare loc unde calea fericită merge și orice altceva pică în tăcere. Fă trei treceri complete. Găsește tot ce e greșit. Nu îmi spune ce e bine. Spune-mi doar ce e greșit și de ce e greșit.

Nu e teatru. Cum am stabilit mai devreme, încadrarea asta suprascrie antrenamentul spre amabilitate și bagă modelul în mod critic adevărat. Un recenzent rugat politicos găsește problemele evidente și le înmoaie. Un recenzent instruit nemilos vânează.

Recenzentul se întoarce cu constatări. Uite cum arată un schimb real:

Trecerea 1 a recenzentului:

Issue 1: fetchData() retries on failure with no backoff. It retries immediately,
ten times in a row. A momentary network hiccup triggers ten rapid sequential
requests before giving up. This hammers the upstream service under exactly the
conditions where it's already struggling.
Issue 2: Config has a Timeout field that is never used. The HTTP client is
http.DefaultClient which has no timeout. Under a hung connection this function
blocks forever.
Issue 3: The error case test asserts err != nil and nothing else. Any error —
including a completely unrelated failure mode — makes this test pass. The test
is not testing what it claims to test.

Contra-review-ul dezvoltatorului:

Issue 1: Correct. Adding exponential backoff with jitter, starting at 100ms,
max 30s. Fixed.
Issue 2: Correct. The field was planned and never wired up. HTTP client now
uses the configured timeout. Fixed.
Issue 3: Partially agree. The test should assert the error type. It should NOT
assert the error message — that would make tests brittle and break every time
we improve wording. Changed to assert errors.Is(err, ErrNotFound).

Dus-întorsul continuă. Când recenzentul se întoarce cu trecerea 2, ori găsește probleme noi, ori răspunde la punctele din contra-review. Asta continuă până când ambele părți nu mai găsesc nimic nou.

Nu fi papă-lapte. Dacă recenzentul zice că ceva e greșit și tu nu ești de acord, spune de ce. Scopul nu e să implementezi fiecare critică, ci să te fi gândit explicit la fiecare critică. Când te opui și ai dreptate, ți-ai validat decizia. Când recenzentul are dreptate și repari, ai prins un bug adevărat. Între voi doi prindeți mai mult decât oricare dintre voi singur.

Faza 4: Smoke Test la Tot, ca Un Nesimțit Paranoic

Să citești cod și să rulezi cod nu sunt aceeași activitate. Poți face review la cod trei ore și să ratezi complet un mod de eșec care apare în treizeci de secunde de rulare. Faza 4 cere să rulezi efectiv chestia.

Pornește tot și asigură-te că nu se cacă pe el imediat. Construiește-l. Pornește fiecare serviciu. Verifică dacă ajunge într-o stare gata de lucru fără să intre în panică, fără linii de ERROR în logurile de pornire, fără mesaje „TODO: repar înainte de prod” tipărite la stdout la inițializare.

Activează fiecare log de debug și citește-le. Rulează cu verbozitate maximă. Alege o cerere și urmărește-o de la intrare la ieșire prin fiecare componentă pe care o atinge. Se potrivește fluxul de execuție cu arhitectura? Se întâmplă operațiile în ordinea pe care ai proiectat-o? Există linii de log care zic „încerc X” fără un „X a reușit” sau „X a eșuat” corespunzător, adică X n-a făcut nimic în tăcere și nu știe nimeni?

Lovește fiecare cale de cod, inclusiv pe cele proaste. Nu verifica doar calea fericită. Trimite input malformat. Trimite input gol. Trimite o listă goală acolo unde se așteaptă o listă. Trimite un string de zece mii de caractere acolo unde se așteaptă un nume. Trimite tipul corect cu valoarea greșită. Trimite un zero acolo unde se cere un întreg pozitiv. Verifică dacă sistemul tratează fiecare caz explicit, cu un răspuns de eroare ca lumea, în loc să crape sau să scoată în tăcere ieșiri greșite.

Verifică direct baza de date. Conectează-te la ea. Uită-te la tabele. Numără rândurile. Citește valorile. Confirmă că ce s-a scris se potrivește cu ce s-a trimis. Asta prinde clasa de bug-uri în care funcția întoarce nil și totul arată bine, dar scrierea a fost aruncată în tăcere, o tranzacție care n-a fost niciodată comisă, o scriere care s-a dus într-un cache care n-a fost niciodată golit. API-ul a întors 200. Datele nu sunt acolo.

Citește fiecare fișier de log după rulare. Caută orice începe cu ERROR, WARN, PANIC sau FATAL și pe care nu l-ai declanșat tu explicit. Un sistem care „merge”, dar produce avertismente intermitente în loguri, nu merge. Eșuează încet și politicos.

Documentează ce ai testat și ce ai găsit. „Pornit cu –debug. Urmărit POST /items. Găsit: intrarea din logul de audit se scrie înainte ca tranzacția din DB să fie comisă. Dacă scrierea în DB eșuează după scrierea în logul de audit, logul de audit arată o operație reușită care nu s-a întâmplat niciodată. Reparat: mutat scrierea în logul de audit după comiterea tranzacției.”

Faza 5: Verificare Finală (Încă 10 Treceri)

Încă zece treceri. Cod, teste, loguri, documentație, configurație, toate din nou.

Până la faza asta toate problemele majore ar trebui să fie reparate. Faza 5 e pentru reziduuri. Mesajul de eroare actualizat în cod, dar nu și în documentație. Helperul de test copiat de altundeva, care încă are numele greșit de pachet în ieșirea lui de eroare. Exemplul de config care face referire la un câmp redenumit în Faza 3 și niciodată actualizat în exemplu.

Dacă Faza 5 încă prinde probleme de arhitectură sau comportament stricat, oprește-te. Întoarce-te la Faza 3. Ceva n-a fost reparat cu adevărat. Fazele următoare l-au mascat, nu l-au rezolvat.

Adaugă în ANUSTIMES.md. Când Faza 5 e gata, fișierul e o urmă completă de audit: ce s-a planificat, ce era greșit la prima versiune, ce s-a găsit la fiecare fază, ce s-a făcut în privința asta.

De Ce Cinci Faze Separate și Nu Un Singur Review Mare

Fiecare fază prinde o clasă specifică de erori. Clasele nu se suprapun destul de curat cât să le comasezi.

Faza 1 prinde erori de omisiune, lucruri planificate dar neconstruite. Review-ul de cod nu le poate prinde, pentru că faci review la ce e acolo, nu la ce lipsește.

Faza 2 prinde erori de calitate, lucruri construite greșit. Review de cod standard. Structura pe zece treceri forțează o specificitate peste care o singură trecere sare din oboseală.

Faza 3 prinde erori de raționalizare, lucruri despre care știi că sunt greșite dar te-ai convins singur că sunt acceptabile. Recenzentul extern n-are memoria raționamentului tău și nicio motivație să fie generos cu el.

Faza 4 prinde erori de integrare, lucruri corecte individual, dar care pică în funcționare. Invizibile la review de cod. Vizibile doar când rulează.

Faza 5 prinde erori de reparație, bug-uri noi introduse în timp ce reparai erorile găsite în fazele anterioare. Fiecare reparație e un potențial bulan nou.

Un singur review cuprinzător se descurcă rezonabil cu Faza 2. Prinde Faza 1 inconsecvent. Ratează în mare parte Faza 3. Structural nu poate prinde Faza 4. Și generează erori de Faza 5 ca efect secundar al reparațiilor. Structura pe cinci faze există pentru că modurile astea de eșec sunt distincte și cer abordări distincte.

Fișierul ANUSTIMES.md

Fiecare constatare intră în ANUSTIMES.md, în rădăcina proiectului. Formatul:

## Phase 1 — Self-Review
### Pass 1
Checked: [what you looked at]
Found: [what was wrong]
Fixed: [what you changed]
## Phase 2 — Deep Verification
### Pass 1 (Incomplete implementations)
Checked: [...]
Found: [...]
Fixed: [...]
## Phase 3 — Brutal Review
### Reviewer Pass 1
[reviewer findings verbatim]
### Developer Counter-Review Pass 1
[your responses and what you fixed]
### Reviewer Pass 2
[...]
## Phase 4 — Smoke Test
### Startup
### Endpoints
### Database
### Logs
## Phase 5 — Final Verification
### Pass 1
[...]

Fișierul ăsta nu e o formalitate. E dovada că verificarea chiar s-a întâmplat și ce a găsit. Un dezvoltator viitor, sau un agent AI viitor care preia proiectul, poate citi ANUSTIMES.md și află exact ce era greșit la implementarea inițială și ce s-a făcut în privința asta. Face vizibil golul dintre prima ciornă și livrare.

Când Să Îl Rulezi și Când Să Sari Peste El

ANUSTIMES are un cost. Nu îl rula pentru un fix de trei linii.

Rulează-l când:

  • Munca a avut un plan explicit, cu mai mulți pași
  • S-au creat sau s-au modificat semnificativ mai multe fișiere
  • Mai mulți agenți AI au construit componente care trebuie să funcționeze împreună
  • Ieșirea rulează în producție sau e folosită de alte sisteme
  • Un eșec complet ar produce daune reale, utilizatorilor, datelor, producției

Sari peste el pentru:

  • Fixuri de bug-uri într-un singur fișier
  • Modificări de documentație
  • Ajustări de configurație
  • Orice poți verifica complet citind diff-ul și rulând o singură comandă

Întrebarea e mereu: dacă asta e greșit, cât de rău e? Rază mică de explozie, sari peste. Rază mare de explozie, ANUSTIMES.

Ce Repară Asta De Fapt

Dezvoltarea asistată de AI a rupt bucla normală de verificare.

În dezvoltarea tradițională, generarea și verificarea sunt încâlcite una în alta. Dezvoltatorul scrie o funcție și o rulează imediat ca să vadă dacă merge. Simte un disconfort legat de un caz limită și se întoarce. Scrie testul și descoperă că testul nu trece, iar asta îi spune ceva. Bucla de reacție dintre scris și verificat e strânsă, continuă și integrată în proces prin felul natural în care lucrează oamenii.

În dezvoltarea asistată de AI, mai ales în sisteme multi-agent, generarea și verificarea sunt separate structural. Un agent planifică. Alți agenți construiesc. Construirea se întâmplă în paralel, în contexte izolate, fără ca vreun agent să trăiască sistemul întreg în funcțiune. Faza de generare e rapidă și capabilă. Faza de verificare lipsește, dacă nu o construiești explicit.

Dacă verificarea nu e o activitate deliberată, structurată, documentată, cu faze definite și ieșiri explicite, pur și simplu nu se întâmplă. Sau se întâmplă de mântuială, prinzând problemele evidente în timp ce cele subtile pleacă în producție.

ANUSTIMES e o reparație structurală pentru o problemă structurală. Limbajul agresiv nu e stil, e mecanismul care îl face pe AI să verifice cu adevărat, în loc să mimeze verificarea. Fazele multiple nu sunt redundanță de dragul redundanței, sunt setul minim de lentile distincte necesare ca să prinzi clasele distincte de bulan pe care dezvoltarea asistată de AI le produce cu regularitate.

Generarea e rapidă. Ai grijă ca verificarea să țină pasul. Sau livrează panica de la trei dimineața și află pe pielea ta de ce există procesul ăsta.