
Наш найважчий наскрізний тест міг сорок хвилин чекати на агента. У першій версії він мав тайм-аут на вісімдесят хвилин. Коли прогін переставав робити щось корисне, я часто дізнавався про це, лише відсидівши більшу частину цього часу.
Я весь час думав про Дуцзянʼянь. За описом ЮНЕСКО, це зрошувальна система, яку почали будувати в III столітті до н. е. Вона регулює течію річки без греблі. Її досі використовують і доглядають.
Для одного рішення в моєму тесті це порівняння виявилося корисним. Мені потрібен був сигнал від запущеного процесу, а не чергова здогадка про те, скільки він мав би тривати.
Тест керує OwlMeans через браузер. Він реєструє користувача, надсилає промпт, чекає на специфікацію й підтверджує її. Для проєкту запускається нова пісочниця Kubernetes. Потім агент розробляє першу користувацьку історію.
У прогонах, на яких ґрунтується ця червнева стаття, останній крок тривав від десяти до сорока хвилин.
Якби я підмінив модель заглушкою, тест відповідав би на інше питання. Тут я хотів знати, чи пройдуть увесь процес разом браузер, конвеєр і середовище проєкту.
Браузерна обвʼязка побудована на @owlmeans/test-ui поверх Playwright. Для тестового входу вона використовує наш механізм супервізора, тож саме цей тест не доводить, що працює справжній вхід через Google.
Пісочницю дає @owlmeans/kephemeral. Цей пакет створює тимчасовий простір імен, сховище, робоче навантаження й мережеву політику. А ще стежить за робочим навантаженням і може відновити под, що впав.
Таке відновлення допомагає середовищу лишатися доступним. Але чи правильно відповів агент, тест із цього не дізнається.
Цикл очікування
Поки агент працює, він витрачає токени. Зміни зафіксованого балансу я вважав ознакою того, що прогін ще активний.
Тест перевіряв цей баланс кожні двадцять секунд. Поки баланс змінювався, детектор дозволяв чекати далі. Якщо ж він десять хвилин стояв на місці, детектор вважав прогін, можливо, завислим і завершував його з помилкою.
Це була евристика активності для нашого конвеєра. Баланс, що змінюється, може означати й непродуктивну роботу. А незмінний баланс так само може означати цілком виправдане очікування, затримку в обліку або проблему поза моделлю.
Мені все одно були потрібні перевірки очікуваного стану історії й поведінки браузера. Самою лише витратою токенів ці перевірки не пройти.
Ці пороги я обрав для червневого процесу, і навʼязувати їх іншій команді як типові значення не став би. Зафіксуй, які сигнали насправді подає твоя довга операція, а тоді вирішуй, яка тривалість тиші вже заслуговує на розслідування.
Настанови Playwright щодо тестування теж наголошують на ізоляції тестів. Наше повільне очікування було лише одним із джерел ненадійних прогонів.
Покинута пісочниця
Якщо перервати тест, коли пісочницю вже створено, він може лишити по собі проєкт. Тоді наступний прогін натрапляє на середовище, якого тест створювати не збирався.
Ми щоразу брали той самий тестовий профіль. Перед кожним прогоном і після нього обвʼязка знищувала тестові проєкти цього профілю. Прибирання перед прогоном було важливим, бо попередній процес міг так і не дійти до згортання.
Межі видалення мають лишатися вузькими. Процедура прибирання, яка дотягується до сторонніх проєктів, була б значно гіршою проблемою, ніж нестабільний тест.
Повідомляй про збої прибирання. Якщо ресурси лишилися, а наступний тест стартує так, ніби прибирання вдалося, корисні докази зникають із поля зору. Перш ніж іти далі, перевір фактичний стартовий стан.
У такій конфігурації це усунуло джерело перешкод, яке весь час поверталося. Пізніші збої все ж доводилося розслідувати.
Дорога додому

Кластер працював на домашньому сервері за підключенням від інтернет-провайдера, яке не мало придатної публічної адреси для вхідних зʼєднань.
Маршрут ми побудували на хмарній віртуальній машині із зарезервованою публічною IP-адресою, проксі Nginx і WireGuard. Трафік ішов від Cloudflare до ретранслятора, далі зашифрованим тунелем до домашнього сервера, а звідти — до сервісу Kubernetes.
Це була наша схема з ретранслятором. Її не слід плутати з варіантом, де весь транспорт тримається на конекторі Cloudflare Tunnel.
Маршрут налаштовували Terraform, Ansible і shell-скрипти. Сторожовий процес кожні шістдесят секунд перевіряв правила брандмауера й виправляв відхилення, які розпізнавав. Він умів відновлювати окремі правила. Але впасти могла й сама мережа.
Зарезервована адреса мала лишатися незмінною й після згортань, передбачених цією схемою. Стан ресурсів у провайдера, облікові дані й конфігурацію все одно треба було підтримувати.
Тепер збій мережі має показувати мені саме збій мережі, який можна дослідити. Довше чекання на агента не полагодить зламаний маршрут до його середовища.
Завдяки цій роботі тест стало легше діагностувати. Я міг відрізнити мовчазного агента, покинуту пісочницю й розірваний шлях до кластера, а не давати всім трьом ще годину.
Обхідний вхід, бібліотека для створення пісочниць, дозволи на прибирання, облік токенів і мережева конфігурація й надалі потребують підтримки. Зміна в будь-чому з цього може зробити хибним одне з припущень тесту.
Послуги OwlMeans можуть охоплювати й таку інфраструктуру для доставки й тестування. Робота має відповідати реальному стеку й реальним сценаріям збоїв; червневе налаштування — не обіцянка розгорнути будь-яку систему за кілька днів.
Я обміняв час очікування на час, який тепер іде на підтримку обвʼязки. Для цього процесу це було того варте.
Уперше опубліковано 23 червня 2026 року. Переглянуто 15 жовтня 2026 року, щоб відокремити детектор активності від перевірок правильності й додати застереження до тверджень про інфраструктуру.