
У 256 годзе да нашай эры губернатар па імені Лі Бін сутыкнуўся з ракой, якая кожную вясну выходзіла з берагоў і губіла ўраджай. Відавочным рашэннем была плаціна. Ён яе не пабудаваў.
Ён падзяліў раку Мін каменнай дамбай у форме рыбінага рота і дазволіў падзелу самому рабіць работу — большая частка цячэння на палі ў сухія месяцы, лішак адводзіцца назад у паводку, іл ідзе разам з ім. Ніякіх шлюзаў, ніякага персаналу. Рака рэгулявала сябе сама і да гэтага часу арашае раўніну Чэнду — дваццаць тры стагоддзі праз.
Гэты месяц я шмат думаў пра Лі Біна. Мой найцяжэйшы тэст меў хваробу ракі: ён выходзіў з берагоў пры кожным запуску.
Цячэнне, якое нельга падрабіць
OwlMeans — гэта AI-пайплайн распрацоўкі: апісваеш прадукт у выглядзе гісторый карыстальніка, а спецыялізаваныя AI-ролі ператвараюць іх у паўнавартасны прадукт, які належыць табе. Каб пратэставаць гэта end-to-end, нельга выкарыстоўваць мокі — запускаеш сапраўднае.
Тэст рэгіструе карыстальніка, уводзіць промпт, чакае спецыфікацыі, пацвярджае яе — і тады пачынаецца самая цяжкая частка: для гэтага праекта падымаецца новы sandbox Kubernetes, агент распрацоўвае першую гісторыю ўнутры яго, і тэст чакае, пакуль гісторыя не будзе завершана. Ад дзесяці да сарака хвілін, усе магчымыя асінхронныя аперацыі паміж — і ўсе магчымыя прычыны для нестабільнасці. Рэшткавы стан, напалову разгорнуты sandbox, агент, які завіс, інтэрфейс, які мяняецца на вачах. Наіўная версія — гэта васьмідзесяціхвіліны таймаут і малітва.
Палавіна, якую я не пісаў
Першая частка хітрасці: большасць гэтага я не будаваў.
Браўзерная частка працуе на нашым уласным харнесе, @owlmeans/test-ui — адной са агульных бібліятэк OwlMeans, на якіх пабудаваны кожны праект тут. Ён запускае браўзер, уваходзіць праз нашы ключы-суперваізеры замест сапраўднага ўваходу праз Google і абгортвае Playwright-сантэхніку так, каб мой тэст чытаўся як апісанне намераў.
Sandbox таксама не патрабаваў маёй удзелу. Эфемерны Kubernetes-слот — namespace, storage, deployment, сеткавая палітыка — прэвізіануецца і падтрымліваецца жывым іншай агульнай бібліятэкай, @owlmeans/kephemeral: яна сочыць за podам і лечыць яго, калі ён упадзе. Яна ўжо ведала, як трымацца.
Засталося адно: як залежаць ад цячэння, якое рэальна займае сорак хвілін, не сочачы за ім?
Рыбін рот
Нельга выкарыстоўваць кароткі таймаут — агент рэальна можа думаць сорак хвілін, і гэта нармальна. Таксама нельга чакаць восемдзесят хвілін, каб даведацца, што ён загінуў на трэцяй. Фіксаваны таймер — гэта плаціна: занадта нізкі — затапляе, занадта высокі — бескарысны.
Таму я перастаў вымяраць час цячэння і пачаў чытаць яго пульс. Агент расходвае токены ў час работы — гэта не проксі прогрэсу, гэта і ёсць прагрэс. Тэст сочыць за балансам токенаў. Кожныя дваццаць секунд: яшчэ зніжаецца? Калі так — агент жывы, чакай колькі трэба. Калі спынілася на дзесяць хвілін — агент завіс, і тэст падае прама цяпер, а не глядзіць у сцяну яшчэ гадзіну.
Вось і ўся ідэя: уласныя паводзіны цячэння кажуць мне, ці яно здаровае, гэтак жа як цячэнне кажа дамбе Лі Біна, колькі прапусціць. Трыццаць радкоў кода ператварылі мой самы нестабільны тэст у самы надзейны.
Чысты ліст на ўваход, чысты ліст на выхад
Яшчэ адна ўцечка. Запуск, перарваны ў самым разгары, пакідае за сабой цэлы sandbox — deployment, storage, сертыфікаты, маршруты, namespace — і наступны запуск спатыкаецца аб гэты смецце і не хоча стартаваць.
Выпраўленне сумнае і татальнае: перад кожным запускам і пасля яго тэст знішчае кожны праект на адным шматразовым профілі. Як бы папярэдні запуск не скончыўся — чысты выхад, крэш, закрыты ноўтбук — наступны стартуе з вядомага, пустога стану. Ніякай ручной уборкі, ніколі — чысты ліст на кожны запуск — гэта лепшае, што можна зрабіць супраць нестабільных тэстаў, і тут гэта бясплатна.
Акведук

Засталася адна праблема — тая, якую большасць так і не вырашае чыста: кластар працуе на серверы дома — без публічнага IP, за правайдэрам, які не прымае ўваходны трафік. Каб тэставаць яго адусюль і паставіць наперадзе Cloudflare, мне трэба было вынесці цячэнне з дому.
Гэта асобны маленькі праект, flt-pf-tnl: танная хмарная VM з адным зарэзерваваным статычным IP, якая запускае WireGuard і Nginx-проксі. Шлях просты — Cloudflare → relay → зашыфраваны тунэль → хатні сервер → sandbox Kubernetes. Дзве каманды яго запускаюць — толькі Terraform, Ansible і некалькі shell-скрыптаў. Watchdog кожныя шэсцьдзесят секунд правярае файрвол і выпраўляе дрэйф; статычны IP выжывае пасля знясення, таму публічны адрас ніколі не мяняецца.
Наладжана аднойчы. Трымаецца. Акведук: пабудаваны аднойчы, працуе на гравітацыі.
Можна проста гэта мець
Адступіся. Нічога з гэтага не з’яўляецца экзатычным — самалечачы sandbox, зваротная сувязь, якая чытае ўласны пульс цячэння, тунэль, які выносіць прыватны кластар у свет. Некалькі дзён правільнай структуры вакол цячэння, якое з’ядала мае вечары. Гэтая структура і ёсць прадуктам — тое самае абяцанне, якое OwlMeans дае кожнаму прадукту, які адпраўляе: тыпізаваны манарэпо і інфраструктура вакол яго, твае назаўсёды.
Таму вось сумленны піч.
Калі ты будуеш нешта сапраўднае — ты натрапіш на гэтую сцяну: павольныя цячэнні, знешнія залежнасці, sandbox, які трэба падняць і знесці, тэсты, якія праходзяць у панядзелак і падаюць у аўторак. Можна рабіць тое, што рабіў я: спаліць тыдні, даведаўшыся, што больш доўгі таймаут ніколі не лечыць нестабільнае цячэнне, што трэба чытаць яго пульс, што доступ да ўласнага кластара патрабуе акведука. Для мяне гэта было варта; гэта мая работа.
Гэта не твая работа.
Гэта частка OwlMeans Services: мы бяром гэты харнес, sandbox і тунэль, адаптуем іх да твайго стэка і разгортваем за некалькі дзён. Усё належыць табе — код, інфраструктура, ніякага vendor lock-in, падтрымліваецца любым агентам для кадавання.
Цячэнне, якое запускае сябе само, — так само як рака цячэ ўжо дваццаць тры стагоддзі. Прапусці месяц, які патраціў я — можна проста гэта мець.
OwlMeans будуе поўнастэкавыя TypeScript SaaS-прадукты з вашых гісторый — тыпізаваныя, гатовыя да SSO, вашы для далейшага развіцця з любым агентам. Глядзіце, на што ён здольны →