Коротка відповідь. Код від AI перевіряється так само, як pull request джуна: уважно, за списком і без довіри до впевненого тону. Різниця в акцентах – моделі роблять специфічні помилки: пропускають edge cases, вигадують API, тягнуть застарілі патерни й повторюють небезпечні приклади зі свого навчання. Нижче – чекліст із поясненнями і готовий markdown-варіант для копіювання у свій процес.

Чому це не паранойя

Згенерований код має підступну властивість: він завжди виглядає завершеним. Акуратні назви, коментарі, впевнена структура. Людський недописаний код видно одразу; недописаний AI-код виглядає як готовий. Тому перевірка за списком тут важливіша, ніж для власного коду, де ти хоча б пам'ятаєш, що зрізав кути.

1. Коректність: edge cases, які моделі люблять пропускати

Happy path майже завжди правильний. Перевіряй краї:

  • Порожні значення: [], '', null, undefined, 0. Класика:
// Згенеровано: працює, поки items не порожній
function averagePrice(items: Product[]): number {
  const total = items.reduce((sum, item) => sum + item.price, 0);
  return total / items.length; // [] → 0/0 → NaN, тихо попливе далі по коду
}

NaN не кидає помилку – він мандрує обчисленнями і випливає десь в UI як «₴NaN». Модель цей випадок пропускає стабільно.

  • Межі діапазонів: перший/останній елемент, off-by-one в індексах і слайсах.
  • Асинхронні краї: що буде, якщо запит впаде? Якщо два запити завершаться не в тому порядку? Якщо компонент розмонтується до відповіді?
  • Дублікати й повтори: повторний клік, повторний виклик, той самий id двічі.

Прийом: спитай модель «які edge cases цей код не обробляє?» – вона часто чесно перелічить власні пропуски. Потім перевір сам, бо перелік теж буває неповний.

2. Безпека: модель вчилась і на поганих прикладах

  • Ін'єкції. Конкатенація рядків у SQL, dangerouslySetInnerHTML з даними користувача, eval. Якщо дані користувача склеюються з кодом чи запитом без параметризації/екранування – стоп.
  • Секрети в коді. Ключі й токени, вписані literal-ом «для прикладу». Всі секрети – лише зі змінних середовища.
  • Вигадані залежності. Модель може імпортувати пакет, якого не існує, або з назвою, схожою на популярний (а зловмисники реєструють такі назви – це називається typosquatting). Правило: кожен новий пакет із згенерованого коду перевіряй руками на npm – хто автор, скільки завантажень, коли оновлювався.
  • Надмірні права й довіра до вводу. Валідація на клієнті без валідації на сервері, відсутність перевірки власника ресурсу.

3. Відповідність кодовій базі

Модель без контексту пише «середньостатистичний» код, а не твій:

  • Дублювання утиліт. Згенерований formatDate при живому lib/dates.ts – класика. Перед комітом: чи не існує вже функція/компонент для цього?
  • Стиль і конвенції. Іменування, структура папок, підхід до стилів. Чужорідний шматок ускладнить життя всім наступним читачам.
  • Патерни актуальної версії. Класові компоненти замість хуків, застарілі API бібліотек. Звіряй із документацією поточної версії, а не з упевненістю моделі.

Агентні інструменти, які бачать репозиторій, помиляються тут рідше – про це в розборі агентного workflow.

4. Тести як контракт

Найнадійніший спосіб перевірити згенерований код – тест, який ти написав або хоча б уважно прочитав сам:

  • тест фіксує очікувану поведінку до того, як ти повірив реалізації;
  • згенеровані тести читай прискіпливіше, ніж код: модель схильна писати тести, які проходять, а не тести, які перевіряють;
  • один тест на головний edge case (порожній ввід, помилка запиту) цінніший за п'ять тестів happy path.

5. Приватні дані й ліцензії в промптах

Перевірка працює в обидва боки – дивись не лише на те, що виходить, а й на те, що ти відправляєш:

  • не встав в промпт секрети, персональні дані користувачів, приватний код, який заборонено виносити (NDA);
  • для робочих проєктів з'ясуй політику компанії щодо AI-інструментів до того, як вставив туди половину репозиторію.

Приклад: та сама помилка до і після перевірки

Ін'єкція – найдорожча з типових помилок, тому окремо. Згенерований варіант, який «працює»:

// ❌ Дані користувача склеєні із запитом – SQL-ін'єкція
async function findUser(email: string) {
  return db.query(`SELECT * FROM users WHERE email = '${email}'`);
}

Введи в поле ' OR '1'='1 – і запит поверне всіх користувачів. Виправлення завжди одне – параметризація:

// ✅ Дані передаються окремо від коду запиту
async function findUser(email: string) {
  return db.query('SELECT * FROM users WHERE email = $1', [email]);
}

Модель знає правильний варіант і згенерує його, якщо попросити. Проблема в тому, що вона згенерує і неправильний – із тією ж упевненістю. Тому пункт чекліста, а не сподівання.

Як вбудувати чекліст у процес

Чекліст, який лежить у нотатках, не працює. Що працює:

  • PR-темплейт. Додай пункти в шаблон pull request – тоді перевірка відбувається там, де ти й так дивишся diff.
  • Питання моделі наприкінці генерації. Стандартне завершальне повідомлення: «пройдись по цьому коду за чеклістом: edge cases, безпека, дублювання з кодовою базою». Модель – непоганий перший фільтр власних помилок; ти – другий і вирішальний.
  • Правило двох читань. Перше читання – «що цей код робить», друге – «як його зламати». Друге читання і є рев'ю; без нього перше – просто ознайомлення.

Готовий чекліст для копіювання

## AI-код: перевірка перед комітом
- [ ] Порожні значення: [], '', null, undefined, 0 – поведінка визначена
- [ ] Межі: перший/останній елемент, off-by-one
- [ ] Асинхронність: помилка запиту, гонки, розмонтування
- [ ] Немає конкатенації даних користувача в SQL/HTML/команди
- [ ] Немає секретів у коді – лише env
- [ ] Кожен новий пакет перевірено на npm (автор, завантаження, свіжість)
- [ ] Не дублює наявні утиліти/компоненти проєкту
- [ ] Відповідає конвенціям кодової бази
- [ ] API звірено з документацією поточної версії
- [ ] Є тест на головний edge case, і я його прочитав
- [ ] У промпт не потрапили секрети/приватні дані
- [ ] Я можу пояснити кожен рядок цього коду

Останній пункт – найважливіший

«Можу пояснити кожен рядок» – це фільтр, який ловить усе, що пропустили попередні. Якщо рядок незрозумілий, у тебе два чесні варіанти: розібратися або викинути. Третього – «закомітити і сподіватися» – у професійній роботі немає. Ширший контекст, де AI допомагає, а де заважає, – у базовій статті AI для програміста; а системно ставити навичку читання чужого коду найшвидше через регулярні code review з ментором.