AI Фактор

Як ловити типові поломки коду з v0 і Bolt

Прийом 29.10.2026
Як ловити типові поломки коду з v0 і Bolt

Автор на note.com описав конвеєр перевірок для коду з v0, Bolt і Lovable. Він ловить три збої. Перший: TSX, обрізаний на ліміті токенів (`Unexpected EOF`). Другий: `useEffect`, що оновлює стан зі свого ж масиву залежностей (`Too many re-renders`). Третій: вгадані типи API, наприклад `userId` замість `user_id`, звідки беруться 422 і `TypeError`.

Python-скрипт рахує дужки й шукає `export`, а також шукає сетер стану в `useEffect`. `tsc` звіряє код з `api.d.ts`, згенерованим з OpenAPI-схеми. Знайдені помилки стають промптом на перегенерацію. Синтаксис скрипт перевіряє лише підрахунком `{}`, `()` і `[]`, тому дужки всередині рядків дадуть хибні спрацювання.

Системний промпт, який зменшує поломки ще до перевірки

Окрім скрипта, автор дає правила для поля System Prompt / Custom Instructions у v0, Bolt чи Lovable. Кожне правило спрямоване на одну з трьох поломок:

  • Обрізаний TSX: один файл має бути не довшим за 200 рядків, а складні UI, форми й діалоги винесено в окремі файли (наприклад, ./components/ui/). Скорочення на кшталт // ... existing code ... заборонені, а в кінці файлу обов'язковий export default ComponentName;.
  • Нескінченний рендер: стан, який оновлюється в useEffect, не можна класти в його масив залежностей. Похідні дані рахуються через useMemo або прямо у функції, а не зберігаються в state.
  • Вгадані типи: any заборонено, типи API імпортуються з @/types/api.ts, а відповіді відповідають інтерфейсу ApiResponse<T> з полями success, data і необов'язковим error.

Ліміт рядків допомагає й із першою проблемою: за словами автора, обрізання частіше трапляється тоді, коли модель пхає UI, стан і логіку в один файл.

Синхронізація типів покроково

Типовий симптом: POST /api/v1/users повертає 422, а в тілі відповіді є "loc": ["body", "user_id"] і "field required". Інша форма тієї ж проблеми: обов'язкове поле позначене як user?, і UI падає на undefined. Потрібен бекенд з OpenAPI 3.0+ (FastAPI, DRF, NestJS).

  • Забрати схему: curl http://localhost:8000/openapi.json -o openapi.json
  • Згенерувати типи: npx openapi-typescript openapi.json -o src/types/api.ts
  • Вставити вміст src/types/api.ts у чат і попросити переписати код під ці типи.
  • Прогнати tsc, щоб він звірив згенерований код із цим файлом.

У статті файл типів називається по-різному: api.d.ts у схемі конвеєра і src/types/api.ts у кроках. Оберіть один шлях і пропишіть той самий у системному промпті.

Pre-commit хук

Збережіть скрипт у .git/hooks/pre-commit і виконайте chmod +x .git/hooks/pre-commit. Хук бере staged-файли .ts/.tsx через git diff --cached --name-only --diff-filter=ACM, проганяє кожен через python3 vibe_guardrail.py і відхиляє коміт, якщо скрипт повернув ненульовий код. Брак export вважається лише попередженням і коміт не блокує.

Хук викликає скрипт за відносним шляхом, тому vibe_guardrail.py має лежати в корені репозиторію. Перевіряється файл на диску, а не версія в індексі: якщо частина змін не додана через git add, результат стосуватиметься робочої копії.

Де скрипт помиляється і що перевірити

Лог у статті показує прапорці --openapi, --auto-fix і рядок про автоматичне виправлення тегів. В опублікованому vibe_guardrail.py цього немає: скрипт приймає один файл і лише звітує.

  • Обрізання між компонентами зі збалансованими дужками не дає помилки. Якщо при цьому зник export, буде лише попередження.
  • Детектор циклу — це регулярний вираз під useEffect(() => {. Він пропускає async-колбеки та function, а на вкладених блоках може обрізати тіло ефекту.
  • Сетер і залежність зіставляються лише за назвою (setData ↔ data). Залежність data.length скрипт не впізнає.
  • Ефекти з порожнім масивом залежностей або без масиву пропускаються. При цьому setState в ефекті без масиву теж може зациклити рендер.
  • Перш ніж довіряти хуку, закомітьте навмисно обрізаний файл і ефект із setData у [data] та переконайтеся, що коміт відхилено.
Раніше в теміAgents CLI: зламаний промпт ловить eval, а не тести
Читати в ТелеграміПрактика ШІ в бізнесі — щодня, без хайпу