Дифф показує, що патч обіцяє зробити. Він не показує, чи справді бага більше немає, чи виконується колись нова гілка if і чи не ламає оновлення залежності імпорт на чистому встановленні. Рев'юери це знають, тому стільки рев'ю закінчуються словами «LGTM, якщо тести пройдуть».
З патчами від ШІ цей розрив росте. Модель швидко видає правдоподібний код, а правдоподібний — саме той, що прослизає повз утомленого рев'юера. Дешеве рішення — запускати зміну до того, як хтось її схвалить, там, де вона нічому не зашкодить.
Перевірка: base, head, тести
Найпереконливіший доказ, який може пред'явити патч, — відтворення, що падає на старому коді й проходить на новому. Пісочниця перетворює це на скрипт на 20 рядків. Це мікро-VM Firecracker з Python 3.12, Node.js 22, git і curl, яка стартує приблизно за секунду:
import os
from eqvps import Sandbox
REPO, BASE, HEAD = os.environ["REPO_URL"], os.environ["BASE_SHA"], os.environ["HEAD_SHA"]
def repro(sb, ref):
sb.exec(f"cd /root/app && git checkout -q {ref}", timeout=55)
return sb.exec("cd /root/app && python3 /root/repro.py", timeout=55).exit_code
with Sandbox.create(tariff="standard", ttl=1800) as sb:
sb.exec(f"git clone -q {REPO} /root/app", timeout=55)
sb.exec("cd /root/app && pip install -q -r requirements.txt", timeout=55)
sb.upload("/root/repro.py", open("repro.py").read())
before, after = repro(sb, BASE), repro(sb, HEAD)
tests = sb.exec("cd /root/app && python3 -m pytest -q", background=True).wait()
print(f"repro on base: {before}, on head: {after}; tests: {tests.state}, exit {tests.exit_code}")
repro.py — це сніпет із баг-репорту. Якщо він завершується з ненульовим кодом на base і з нулем на head, патч виправляє те, що заявляє. Опублікуйте цей рядок і зведення тестів коментарем до пул-реквесту, і рев'юер почне з фактів.
Набір тестів працює фоновим завданням, бо одна синхронна команда зупиняється на 55 секундах. TTL у 30 хвилин обмежує, скільки може коштувати завислий прогін.
Рев'ю-агенти, які запускають код
Та сама ідея працює для ШІ-рев'юера. Під'єднаний через MCP-сервер, агент отримує інструменти пісочниць: створити пісочницю, виконати команду, завантажити й вивантажити файли. Замість «це може зламати сумісність із Python 3.8» він викачує гілку, запускає код і цитує traceback — або повідомляє, що все гаразд.
Дайте такому агенту ліміт витрат і токен лише на читання та вирішіть, які інструменти він може викликати без запиту. У розділі захист MCP усі інструменти розкладено за рівнем ризику.
Який тариф
| Репозиторій | Тариф | Типовий прохід | Приблизна вартість |
|---|---|---|---|
| Маленька бібліотека, чистий Python або JS | small (0.5 vCPU, 1 GB) | 2 хв | $0.0011 |
| Вебзастосунок із набором тестів | standard (1 vCPU, 2 GB) | 5 хв | $0.0055 |
| Нативні розширення, компільовані залежності | plus (2 vCPU, 4 GB) | 15 хв | $0.033 |
Тимчасові пісочниці оплачуються посекундно з мінімумом 60 секунд. Якщо рев'юер хоче повертатися до того самого середовища кілька днів, створіть його як persistent: воно зберігає диск до 30 днів і оплачується за кожну розпочату годину, тож пісочниця standard на дводенне рев'ю коштує близько $3.17. Видаліть її, коли пул-реквест змерджено.
Ліміти, які варто знати
- Дві команди одночасно на акаунт. Для рев'ю, що йдуть одне за одним, цього досить. Якщо перевіряти десятки пул-реквестів разом, вони стануть у чергу.
- Немає вхідних портів. Відкрити застосунок у браузері не вийде. Запустіть його всередині й перевірте через
curl localhostз другої команди. - Немає Docker усередині. Тести, що піднімають контейнери, місце на раннері на VPS.
- Вихідний інтернет відкритий. Саме завдяки цьому працює
pip install. Не кладіть у пісочницю нічого, чого не віддали б авторові патча.
З чого почати
Нові акаунти отримують $1 часу пісочниць — цього вистачить більш ніж на сотню проходів рев'ю на тарифі standard. На сторінці пісочниць — тарифи, у довіднику SDK — усі методи з прикладу, а Python SDK за 5 хвилин покаже налаштування.
За темою: ізольовані прогони тестів у CI для всього пайплайна й пісочниця для ШІ-агентів для агентів, які пишуть цей код.
Коментарі
Поки немає коментарів. Будьте першим.