Sari la conținut
Braincap
← Toate articolele

Controlul care trece testul și nu face nimic

de Claudiu Hulea · IT Management Consultant

Ilustrație: un lacăt închis, cu bifa de test trecut, pe o ușă care stă deja deschisă; controlul se blochează, dar nu securizează nimic

O regulă de securitate scrisă corect, aplicată pe nouă site-uri, validată cu testul de configurație al serverului, citită de două ori în fișier, reîncărcată fără eroare. Și complet inertă.

Nu era o greșeală de sintaxă. Nu era o greșeală de logică. Regula bloca extensiile de arhivă și le bloca exact așa cum fusese scrisă. Problema era că serverul rescria calea cerută înainte ca regula să ajungă să o vadă, iar rescrierea se întâmpla doar pentru fișierele care există pe disc. Pentru o cale inventată, regula funcționa impecabil. Pentru fișierul real pe care trebuia să îl protejeze, nu se declanșa niciodată.

O încuietoare care se blochează doar când ușa e deja deschisă trece orice test pe care te-ai gândi să îl faci.

Am prins-o pentru că am aplicat schimbarea pe un singur site întâi și am verificat împotriva unui fișier care există. Dacă aș fi verificat pe o cale inventată, cum se face de obicei, aș fi văzut codul 404 așteptat și aș fi declarat succes pe toate nouă. Regula ar fi rămas acolo luni de zile, decorativă, într-un raport de conformitate care ar fi spus că endpointul e blocat.

Clasa de eșec, nu incidentul

Cazul de mai sus e mic. Interesantă e clasa din care face parte, pentru că ea nu are legătură cu nginx.

Există o categorie de defecte care nu produc niciun semnal. Comanda iese cu cod zero. Fișierul se citește corect. Testul de configurație trece. Serviciul repornește. Și efectul promis nu se produce. Într-un registru de schimbări, o astfel de intervenție arată identic cu una reușită, iar în raportarea către un auditor arată chiar mai bine, pentru că nu a generat nicio excepție de explicat.

Din propria noastră evidență operațională, într-o singură zi de aplicare a șapte schimbări pregătite anterior, fiecare conținea cel puțin un defect în comenzi sau în verificare. Șase în total. Niciunul nu era o eroare de raționament. Toate erau comenzi plauzibile, scrise de oameni competenți, care se uitau în locul greșit: o comandă de listare care pagina implicit la 50 de intrări pe o listă de 180, o verificare care căuta în jurnalul serverului de aplicație blocajele făcute de proxy-ul din fața lui, o buclă scrisă pentru un shell și rulată cu altul, care nu muta niciun fișier și raporta că a terminat.

Cel mai periculos din serie: patru fișiere șterse dintr-un director web, confirmate ca inexistente pe disc, dintre care două continuau să fie servite public cu conținutul lor exact, din memoria cache a proxy-ului. Modul de eșec care costă nu e să vezi că fișierul se servește încă. E să verifici o cale care se întâmpla să nu fie în cache, să primești 404, să declari închisă expunerea și să lași restul public. Ai stins toate luminile, te uiți pe o singură fereastră, o vezi întunecată și declari clădirea goală.

De ce revizuirea umană nu prinde asta

Un om care revizuiește un artefact caută o greșeală. Aici nu există o greșeală de găsit, ci o absență: ceva ce nimeni nu a cerut, pentru că toată lumea presupunea că e acolo.

Oamenii sunt buni la a găsi ceva greșit într-un text și slabi la a observa ce lipsește dintr-un text care arată complet. Asta nu e o problemă de competență sau de atenție. E o proprietate a sarcinii. Cu cât materialul e mai bine scris, cu atât e mai greu de contestat, iar cine ar vrea să spună „stați puțin” trebuie să articuleze rapid o intuiție pe care nu o poate încă demonstra, împotriva unui document coerent.

Adăugarea de oameni nu rezolvă problema. Patru revizori care citesc același artefact cu același model mental despre sistem produc patru confirmări, nu patru verificări independente. Dacă modelul mental are o gaură, toți patru trec pe lângă ea. Iar dacă înaintea revizuirii s-a produs un document de evaluare a impactului, situația se înrăutățește: ceilalți verifică artefactul față de document, nu față de sistemul real. Documentul devine ancora.

Ce schimbă codul generat

Un revizor experimentat nu citește doar logica. Citește și urmele: locul unde autorul a ezitat, comentariul defensiv adăugat lângă o linie delicată, funcția scrisă altfel decât restul pentru că acolo era ceva ce nu se rezolva la fel. Sunt semnale despre unde a fost incertitudine, iar atenția se duce acolo.

Codul produs de un model nu are urmele astea. E uniform, idiomatic, comentat consecvent. Arată la fel de îngrijit acolo unde problema a fost înțeleasă și acolo unde a fost completat un tipar. Suprafața e netedă peste tot, inclusiv peste gaură. Revizorul își pierde substitutul pe care îl folosea pentru a-și aloca atenția, fără ca nimic să îl anunțe.

A doua schimbare e mai simplă și mai brutală: volumul de artefact produs per unitate de atenție umană a crescut cu un ordin de mărime, iar atenția a rămas la fel. O modificare pe care o echipă ar fi purtat-o în cap două săptămâni se produce în două zile. Nu e doar mai mult de citit. E mai puțin trăit, iar înțelegerea vine în bună măsură din a fi construit lucrul, nu din a-l fi citit.

A treia, și cea care contează cel mai mult: constrângerile neexprimate în cod nu apar nicăieri. Izolarea între clienți pe o infrastructură partajată, de exemplu, nu apare în semnătura unei funcții, nu apare în tipuri, nu apare în schema unei tabele. Trăiește în capul echipei. Un model generează cod corect față de ce i s-a cerut; ce nu i s-a cerut nu apare nici ca lipsă, nici ca întrebare. Iar oamenii care revizuiesc au constrângerea atât de adânc internalizată încât nu observă că nu e nicăieri în text. O presupui prezentă tocmai pentru că ție ți-e evidentă.

Ce funcționează

Concluzia practică nu e „mai puțină automatizare”. E că verificarea trebuie să se mute de la citit la executat, iar invariantele trebuie să existe ca artefact separat de cod.

Invariantul se scrie înainte și rulează singur. Nu ca test al implementării curente, ci ca afirmație despre sistem care se evaluează indiferent ce s-a schimbat și cine a scris schimbarea. „Niciun rând nu trece frontiera de client” e o interogare care întoarce zero sau nu. Nu depinde de cât de bine arată modificarea care tocmai a intrat.

Agregat, nu eșantion. O verificare pe o mie de rânduri corecte nu spune nimic despre existența undeva a unui rând greșit. Proprietățile de izolare sunt relaționale: se văd din perspectiva celuilalt, nu din a ta. Un număr calculat pe toată mulțimea e ieftin pe un index și e singurul care înseamnă ceva.

Verificarea se face din alt punct decât execuția, și mai târziu. Verificarea rulată la câteva secunde după schimbare, din același context care a produs-o, se lovește de aceleași straturi care au mințit prima dată: memoria cache nu a expirat, filtrul greșit întoarce gol la fel de convingător, paginarea arată la fel. O reevaluare la 24 de ore, pornită din altă parte, rupe toate trei și nu cere nimic de la operator.

Un rezultat gol nu e un rezultat. Înainte de a cita un zero ca dovadă, filtrul se validează pe un caz despre care știi că trebuie să întoarcă ceva. Dacă nu îl găsește nici pe acela, zeroul de lângă nu valorează nimic.

Măsoară în două locuri. Stratul de configurație și stratul care aplică efectiv. Când cele două nu sunt de acord, cel care aplică are dreptate. Adresele pot fi în baza de date a uneltei și absente din setul care filtrează, iar unealta va raporta succes.

Ce ar contrazice teza

Argumentul de mai sus ar fi greșit dacă ar exista dovezi că revizuirea umană prinde constant constrângeri care nu sunt exprimate în artefact. Nu cunosc astfel de dovezi, dar afirmația e verificabilă și merită contrazisă cu date, nu cu impresii.

Ar fi greșit și dacă defectele descrise ar fi rare. Din evidența noastră nu sunt: pe un eșantion de șapte schimbări pregătite cu atenție, șase defecte de verificare. E un eșantion mic și dintr-un singur mediu, deci nu susține o rată generală, dar e suficient ca să justifice întrebarea.

Întrebarea de luni dimineață

Câte dintre invariantele voastre de izolare, de retenție și de acces există ca aserțiune executabilă, și câte trăiesc în capul echipei?

Pentru fiecare din ele, a doua întrebare: când a rulat ultima dată, împotriva a ce, și de unde știți că nu a întors gol pentru că se uita în locul greșit?

Ce nu rezolvă asta

Verificarea automată a efectului nu spune dacă schimbarea era o idee bună. Nu înlocuiește verificarea de integritate: faptul că un endpoint de atac e blocat nu spune nimic despre un fișier deja pus pe disc. Și nu acoperă precondițiile umane, cele de tipul „a fost anunțat proprietarul”, care nu se pot verifica tehnic. Dacă una din ele se sare, singura soluție e să scrie în registrul de schimbări că s-a sărit și cine a decis.

Iar partea care rămâne integral la om nu e mică: ce documentează rândul pe care îl ștergi, dacă cifra din raport a fost măsurată azi pe sistemul ăsta, și dacă al nouăsprezecelea fișier găsit acolo unde inventarul spunea optsprezece e gunoi sau e o piesă activă.

Întrebări frecvente

Ce este un control care trece testul dar nu face nimic?

Un defect care nu produce niciun semnal: comanda iese cu cod zero, fișierul se citește corect, testul de configurație trece, serviciul repornește, dar efectul promis nu se produce. Într-un registru de schimbări arată identic cu o intervenție reușită, iar în raportul de conformitate arată chiar mai bine, fiindcă nu a generat nicio excepție de explicat.

De ce nu prinde revizuirea umană astfel de defecte?

Fiindcă nu e o greșeală de găsit, ci o absență: ceva ce nimeni nu a cerut, presupus prezent. Oamenii găsesc ușor ce e greșit într-un text, dar greu ce lipsește dintr-unul care arată complet. Mai mulți revizori cu același model mental produc confirmări, nu verificări independente, iar un document de evaluare a impactului devine ancora față de care se verifică artefactul, nu sistemul real.

Ce schimbă codul generat de AI?

Trei lucruri: dispar urmele prin care un revizor își aloca atenția (codul e uniform, la fel de îngrijit și unde a fost înțeles, și unde a fost completat un tipar); volumul per unitate de atenție umană crește cu un ordin de mărime, iar înțelegerea vine din a construi, nu din a citi; și constrângerile neexprimate în cod, cum e izolarea între clienți, nu apar nici ca lipsă, nici ca întrebare.

Ce funcționează în locul revizuirii prin citire?

Mutarea verificării de la citit la executat, cu invariantele ca artefact separat de cod: invariantul se scrie înainte și rulează singur; se măsoară agregat, nu pe eșantion; verificarea se face din alt punct decât execuția și mai târziu (o reevaluare la 24 de ore, din altă parte); un rezultat gol se validează întâi pe un caz care trebuie să întoarcă ceva; și se măsoară în două locuri (configurația și stratul care aplică efectiv), iar când nu sunt de acord, cel care aplică are dreptate.

Articole similare