Vsak polom migracije, ki smo ga kdaj videli pri drugi programski opremi, izvira z istega mesta: obravnava “najprej počistite podatke” kot problem stranke namesto proizvoda. Tega nismo hoteli graditi. Zato smo zgodaj naleteli na resničen primer in ta nas je naučil nekaj, česar nismo pričakovali: včasih je pravi odgovor na “naj to naredi AI” - ne.
Migracija, ki nas je naučila razliko
Imeli smo resničen izvoz iz starega CRM-ja za uvoz: 349 podjetij, 491 beležk, večinoma zgodovina klicev, napisana v slovenščini, 393 kontaktov. Očitna poteza bi bila, da to spustimo skozi Neo, naš AI-podprt uvoz, tistega, ki prebere neurejeno preglednico in iz nje predlaga čiste zapise.
Odločili smo se, da ne. Izvorni podatki so bili že strukturirani, že razrešeni, že pravilni. Prehod skozi AI ne bi dodal ničesar razen tveganja: model, ki parafrazira ali povzema resnične slovenske zabeležke klicev, tiho izgublja natančnost v besedilu, ki je moralo ostati točno takšno, kot je bilo zapisano. Zato smo zgradili drugo, ločeno, namenoma AI-prosto pot: natančno, deterministično kopiranje, ujemanje po ID-ju starega zapisa, ohranjanje izvirnih časovnih žigov, brez jezikovnega modela kjerkoli v tem.
Gradnja te poti je razkrila resnične vrzeli, ki jih drugače ne bi našli: polje v obrazcu, ki ga je zaledje tiho izpuščalo kdo ve kako dolgo, ker stolpec v podatkovni bazi za njim nikoli ni obstajal, kontakti, ki so se tlačili v prosto besedilo beležk, ker niso imeli pravega mesta za bivanje. Oboje smo popravili za stalno, ne le za to eno migracijo.
To je zdaj dejanska oblika Migration Enginea: Neo za pošten nered, vrzite nam vašo najbolj razmetano preglednico in vam bomo naravnost povedali, kaj smo razumeli in česa ne, ter tiha, natančna pot kopiranja za podatke, ki so že zaupanja vredni in morajo le prispeti nepoškodovani. Dva različna problema. Nehali smo se pretvarjati, da sta eden.
Kako sploh priti do nečesa, vrednega testiranja
Nič od spodnjega testiranja ni pomembno, če pod tem ni ničesar resničnega. Iskreno, del tega, kako smo prišli sem, se je začel po naključju. Snemanje zaslona se je stalno odlašalo, večinoma zaradi navadne nevoljnosti, da bi sedli in nekaj pošteno posneli, zato je bila dejanska rešitev preprosto opazovati, kako AI v živo klika po aplikaciji, in si zapisovati, kaj se dogaja. To se je izkazalo za eno najboljših metod odpravljanja napak, na katero smo naleteli v celotnem projektu, ne kot pameten načrt, temveč kot stranski produkt nevoljnosti, da bi počeli kaj drugega. Nekaj resničnih funkcij obstaja danes prav zato, ker je bil hrošč ujet točno na ta način.
Večja gradnja je sledila podobni obliki, manj po velikem načrtu, bolj po nuji: en resničen kos naenkrat, vsak testiran od začetka do konca, preden se je začel naslednji, ker projekt te velikosti drugače ne ostane pri pameti. Kar nas je res presenetilo, je, da je osnovni testni paket na koncu napovedoval stvari, ki jih od njega nihče ni zahteval. Dodajte novo funkcijo mesece kasneje, in Velvet bi včasih ujel, da je nek sosednji del ves čas tiho ležal napol dokončan in čakal, da ga kdo opazi. Ne zato, ker bi bil kdo od vpletenih posebej bister. Test, ki dejansko klikne gumb in preveri resničen rezultat, ima preprosto način, kako najti stvari, ki jih oseba, ki preleti kodo, ne bi.
Velvet
Nekje po poti je naš lastni end-to-end testni paket dobil ime namesto da bi ostal zgolj “testi”. Kličemo jo Velvet. Približno pet tisoč vrstic Playwrighta, v dvanajstih poimenovanih skupinah, dimni testi, regresija, Trezor, AI Vas, tokovi action-busa, trdi robni primeri, stres, med drugim, izvedenih proti petim ločenim sintetičnim zasejanim podjetjem. Upravlja resnično, delujočo aplikacijo, zaledje in uporabniški vmesnik oba v živo, ne lažne nadomestne različice za nobenega od njiju.
Znotraj poimenovanih regresijskih skupin so klici AI lažirani na deterministične odgovore, namenoma, ne kot bližnjica. Pri resničnem obsegu pravi klici AI trčijo ob omejitve povezav brskalnika in povzročajo polome, ki nimajo veze s tem, ali proizvod dejansko deluje. Lažiranje tam ločuje eno pošteno vprašanje, ali napeljava deluje, od drugega, ali je dejanski odgovor AI dober, kar se testira ločeno, zares.
Disciplina, ki je pod vsako plastjo
Pet pravil velja povsod, kjer se v tem projektu testira, ne le v Velvet:
Zapišite napoved, preden zaženete test, tako da se izid kasneje ne more tiho na novo opredeliti kot to, kar se je naključno zgodilo. Test, ki le potrdi, da gumb obstaja, ni test; klikniti mora gumb, počakati na resničen odgovor, vključno z resnično zakasnitvijo AI, in preveriti dejansko končno stanje. Vsaka funkcija se preizkusi tako, kot bi morala delovati, in tako, kot bi jo dejansko, včasih malomarna, včasih sovražno nastrojena oseba dejansko napačno uporabila. Kadar se “polom” izkaže za hrošča v testnem skriptu in ne v izdelku, se tudi to prijavi, ne tiho zakrpa in pozabi. Popravek pa ni dokončan, ko se koda prevede; dokončan je, ko je natanko tisti scenarij, ki se je polomil, ponovno pognan zares in uspešen.
Onkraj Velveta: sedem plasti, ne ena
Velvet je ena plast od sedmih. Resnično, nelažirano preverjanje AI teče ločeno, enkratna skripta proti živi aplikaciji z dejanskimi klici modela, ki se nato pobriše, posebej zato, da ujame vrsto hrošča, ki se pojavi samo zato, ker se odgovor resničnega modela razlikuje od zagona do zagona. Simulacija dolgega horizonta poganja simulirane poslovne zgodovine, mesec, leto, pet let, proti resničnim najemnikom z živimi klici AI ves čas, in ob več točkah postavlja ista kanonična vprašanja, da preveri, ali so odgovori dejansko postali ostrejši, kolikor se je zgodovina kopičila, ne le ali so sploh prišli nazaj. Namerna nasprotniška plast, osem sovražnih testov, ki jih imenujemo Tekmovalna proga, poskuša neposredno zlomiti trditve izdelka o poštenosti in varnosti: vbrizgavanje pozivov (prompt injection), uhajanje podatkov med najemniki, nasprotujoča si navodila, odpornost na brisanje, resnično finančno usklajevanje, ravnanje s podvojenimi računi. Backend enotni in integracijski testi pokrivajo Sveto hrbtenico in vnos dokumentov od začetka do konca. Vodeni ogledi testirajo dejanski uporabniški vmesnik pri resničnih velikostih zaslona, namizni in pristen mobilni pogled, s posnetki zaslona kot dokazom, ne s kljukico na seznamu. Celo predstavitveni promocijski videi so služili kot plast testiranja: vsak je resničen scenarij, ki udari ob pravo, živo aplikacijo, in vsak trenutek, ki je bil ob pregledu videti malce narobe, je bil posamično izsleden bodisi do resničnega hrošča bodisi do težave s časovno usklajenostjo posnetka, nikoli predpostavljen brez preverjanja.
Skozi vse to, približno petindvajset simuliranih let poslovne dejavnosti, več panog, čez devet tisoč resničnih vnosov v Trezor, ustvarjenih po poti, enajst resničnih hroščev najdenih in odpravljenih. Skupna resnična poraba za API za celoten program: 9,57 dolarja.
Česa ne bomo trdili
Nismo testirali podjetniške razsežnosti, tisočev hkratnih najemnikov naenkrat. Nismo obremenitveno testirali, kaj se zgodi s stroškom AI pri resnično intenzivnem, odprtem dnevnem klepetu, v nasprotju s skriptirano poslovno dejavnostjo, okoli katere je bilo zgrajeno večina tega testiranja. Med zgornjim delom smo v lastnem naknadnem polnjenju embeddingov odkrili resnično tveganje pri skaliranju, enkratno dohitevanje velikega Trezorja, ki se je neprijetno približalo časovni omejitvi zahteve, in to vam povemo, namesto da bi to tiho zakrpali in ne rekli ničesar.
Nič tu ni popolno, ker ni nič. Kar lahko dejansko zagovarjamo, je, da smo temeljito pogledali svoje lastne trditve, preden smo vam jih predstavili, in da vam povemo, kaj smo našli, ne glede na izid. To je celotna disciplina. To bomo počeli še naprej.