Každé selhání migrace, jaké jsme kdy v jiném softwaru viděli, pramení ze stejného místa: brát “nejdřív si vyčistěte data” jako problém zákazníka místo problému produktu. Tohle jsme stavět nechtěli. Takže jsme brzy sami narazili na skutečný případ a naučil nás něco, co jsme nečekali: někdy je správná odpověď na “má se toho ujmout AI” prostě ne.
Migrace, která nás naučila ten rozdíl
Měli jsme přinést skutečný export ze starého CRM: 349 firem, 491 poznámek, většinou historii hovorů psanou slovinsky, 393 kontaktů. Zjevným krokem by bylo pustit to přes Neo, náš AI-asistovaný import, ten samý, co čte neuspořádanou tabulku a navrhuje z ní čisté záznamy.
Rozhodli jsme se, že ne. Zdrojová data už byla strukturovaná, už vyřešená, už správná. Protažení AI průchodem by nepřidalo nic než riziko: model, který parafrázuje nebo shrnuje skutečné slovinské poznámky z hovorů, přičemž tiše ztrácí přesnost v textu, který musel zůstat přesně tak, jak byl napsán. Postavili jsme tedy druhou, oddělenou, záměrně AI-prostou cestu: přesné, deterministické kopírování, párované podle ID starého záznamu, se zachováním původních časových razítek, bez jazykového modelu kdekoliv v tom.
Stavba té cesty odhalila skutečné mezery, které bychom jinak nenašli: pole formuláře, které backend kdovíjak dlouho potichu zahazoval, protože sloupec v databázi za ním nikdy neexistoval, kontakty, které se cpaly do poznámek s volným textem, protože neměly správné místo, kde být. Obě věci jsme opravili natrvalo, ne jen pro tuhle jednu migraci.
Takhle teď skutečně vypadá Migration Engine: Neo pro poctivý nepořádek, hoďte nám svou nejhorší tabulku a my vám na rovinu řekneme, čemu jsme rozuměli a čemu ne, a tichá, přesná kopírovací cesta pro data, která jsou už důvěryhodná a jen potřebují dorazit neporušená. Dva různé problémy. Přestali jsme předstírat, že jsou jeden.
Dostat se vůbec k něčemu, co stojí za testování
Nic z testování níže nemá smysl, pokud pod tím nic skutečného není. Upřímně, část toho, jak jsme se sem dostali, začala náhodou. Nahrávání obrazovky se pořád odkládalo, hlavně z obyčejné neochoty si sednout a něco pořádně nahrát, takže skutečným obchvatem bylo prostě sledovat, jak AI naživo proklikává aplikací, a zapisovat si, co se děje. To se ukázalo jako jedna z nejlepších metod ladění, na jakou jsme za celý projekt narazili, ne chytrý plán, ale vedlejší produkt neochoty dělat něco jiného. Pár skutečných funkcí dnes existuje proto, že se přesně takhle chytil bug.
Větší stavba se ubírala podobným směrem, méně podle velkého plánu, víc podle nutnosti: jeden skutečný kus po druhém, každý otestovaný od začátku do konce, než začal další, protože projekt téhle velikosti jinak zdravý rozum neudrží. Co nás fakt překvapilo, je, že základní testovací sada nakonec předvídala věci, o které ji nikdo nežádal. Přidáte novou funkci o měsíce později, a Velvet občas odhalil, že nějaký sousední kus tam celou tu dobu tiše ležel z poloviny hotový a čekal, až si ho někdo všimne. Ne proto, že by byl kdokoli zapojený nějak zvlášť bystrý. Test, který skutečně klikne na tlačítko a zkontroluje skutečný výsledek, má prostě svůj způsob, jak najít věci, které by člověk přelétávající kód nenašel.
Velvet
Někde po cestě dostala naše vlastní end-to-end testovací sada jméno místo toho, aby zůstala jen “testy”. Říkáme jí Velvet. Zhruba pět tisíc řádků Playwrightu, rozdělených do dvanácti pojmenovaných sad, smoke, regrese, Trezor, AI Village, action-bus toky, tvrdé okrajové případy, stres, mimo jiné, spouštěných proti pěti oddělených syntetickým, osazeným testovacím firmám. Řídí skutečnou, běžící aplikaci, backend i frontend oba naživo, žádnou mockovanou náhradu za ani jeden z nich.
Uvnitř pojmenovaných regresních sad jsou volání AI mockovaná na deterministické odpovědi, záměrně, ne jako zkratka. Při skutečném objemu narážejí opravdová volání AI na limity připojení prohlížeče a produkují selhání, která nemají nic společného s tím, jestli produkt skutečně funguje. Mockování tam odděluje jednu poctivou otázku, funguje instalatérství, od jiné, je skutečná odpověď AI dobrá, což se testuje odděleně, doopravdy.
Disciplína pod každou vrstvou
Pět pravidel platí všude, kde se v tomto projektu testuje, ne jen ve Velvet:
Zapsat předpověď písemně před spuštěním testu, aby se úspěch nemohl potichu zpětně předefinovat na to, co se náhodou stalo. Test, který jen potvrzuje, že tlačítko existuje, není test; musí na tlačítko kliknout, počkat na skutečnou odpověď, včetně skutečné latence AI, a zkontrolovat skutečný výsledný stav. Každá funkce se zkouší tak, jak má fungovat, a zkouší se tak, jak by ji skutečně špatně použil skutečný, občas nedbalý, občas nepřátelský člověk. Když se “selhání” ukáže být bugem v testovacím skriptu, a ne v produktu, i to se nahlásí, ne se potichu opraví a zapomene. A oprava není hotová, když se kód zkompiluje; je hotová, když je přesně ten scénář, který se rozbil, doopravdy znovu spuštěn a projde.
Za Velvet: sedm vrstev, ne jedna
Velvet je jedna vrstva ze sedmi. Skutečné, nemockované ověření AI běží odděleně, jednorázový skript proti živé aplikaci se skutečnými voláními modelu, poté uklizený, konkrétně proto, aby zachytil ten druh bugu, který se objeví jen proto, že se odpověď skutečného modelu liší běh od běhu. Simulace na dlouhém horizontu pouští simulované firemní historie, měsíc, rok, pět let, proti skutečným tenantům se živými voláními AI po celou dobu, přičemž pokládá stejné kanonické otázky na více místech, aby ověřila, jestli odpovědi skutečně zesílily, jak se historie hromadila, ne jen jestli se vůbec vrátily. Záměrná adversariální vrstva, osm nepřátelských testů, kterým říkáme Překážková dráha, se přímo snaží prolomit tvrzení produktu o poctivosti a bezpečnosti: prompt injection, únik dat mezi tenanty, protichůdné instrukce, odolnost vůči smazání, skutečné finanční odsouhlasení, zacházení s duplicitními účty. Backendové jednotkové a integrační testy pokrývají Sacred Spine a příjem dokumentů od začátku do konce. Vedené průchody testují skutečné uživatelské rozhraní při skutečných velikostech obrazovky, desktop a opravdový mobilní viewport, se screenshoty jako důkazem, ne pouhým zaškrtnutím na seznamu. Dokonce i prezentační propagační videa posloužila jako testovací vrstva: každé je skutečný scénář narážející na skutečnou, živou aplikaci, a každý okamžik, který při revizi vypadal trochu divně, byl jednotlivě dosledován buď ke skutečnému bugu, nebo k problému s časováním skriptu, nikdy se bez ověření nepředpokládalo, o co jde.
Napříč tím vším, zhruba dvacet pět simulovaných let firemní aktivity, několik odvětví, přes devět tisíc skutečných záznamů v Trezoru vygenerovaných po cestě, jedenáct skutečných bugů nalezených a opravených. Celkové skutečné API výdaje za celý program: 9,57 dolaru.
Co nebudeme tvrdit
Netestovali jsme podnikovou škálu, tisíce souběžných tenantů najednou. Nezátěžově jsme netestovali, co se stane s cenou AI při opravdu intenzivním, otevřeném denním chatu, na rozdíl od scénářové firemní aktivity, kolem které byla postavena většina tohoto testování. Během výše popsané práce jsme v našem vlastním zpětném doplňování embeddingů našli skutečné riziko škálování, jednorázové dohánění velkého Trezoru se nepříjemně blížilo k timeoutu požadavku, a říkáme vám to, místo abychom to potichu opravili a nic neřekli.
Nic tady není dokonalé, protože nic dokonalé není. Za čím si můžeme skutečně stát, je, že jsme se pořádně podívali na vlastní tvrzení, než jsme vám je předložili, a že vám říkáme, co jsme zjistili, tak nebo tak. To je celá disciplína. Budeme v ní pokračovat.