Стандарт и языковые модели

Last updated: 2026-09-05Почему модель нарушает стандарт в пользу стиля, на котором её обучали, почему полный свод ей давать не стоит, и Small GRAIN — двенадцать законов, которые копируются в промт.

Стандарт и языковые модели

Отдельная глава, потому что это отдельная проблема: стандарт, написанный против «кода без автора», приходится применять к тому, кто этот код и производит.

Почему модель ломает стандарт

Языковая модель выбирает наиболее вероятное продолжение. Самое вероятное имя обработчика в мире — handleSubmit. Самый вероятный файл для функции, которой не нашлось места, — utils.ts. Самый вероятный комментарий — пересказ следующей строки. Самая вероятная защита — try/catch вокруг чистой функции.

Стандарт запрещает ровно эти варианты. То есть требует от модели идти против собственного распределения — на каждой строке, а не один раз. На коротком фрагменте это получается. На длинном тянет обратно: чем дальше от начала ответа, тем ближе к середине распределения, к тому стилю, на котором модель обучали.

Как выглядит поломка

  • Половинчатое соблюдение. Экспортируемые функции переименованы по словарю, а колбэк тремя строками ниже остался handleClick. Формально файл «переписан по стандарту».
  • Изобретённые правила. Модель дописывает правила, которых в стандарте нет: суффикс Service, префикс I у интерфейсов, Async в имени. Они выглядят правдоподобно, потому что взяты из соседних конвенций.
  • Имитация формы. Комментарий получает тег why:, но за тегом — пересказ кода. Тег есть, «почему» нет: линтер доволен, читатель обманут.
  • Ложная уверенность. На вопрос «это соответствует стандарту?» модель отвечает «да» — потому что похоже, а не потому что проверила.
  • Внимание уходит на запятые. Чем длиннее свод в контексте, тем больше бюджета уходит на его соблюдение и тем меньше — на саму задачу. Код получается идеально названным и неправильным.

Полный стандарт модели давать не стоит

Прямая рекомендация: не подключайте полный стандарт к ассистенту. Не потому, что модель недостаточно хороша, а потому что полный свод и модель решают разные задачи. Стандарт написан для человека, который прочитает его один раз и будет держать в голове годами, и для линтера, который проверяет буквально и не устаёт. Модель не делает ни того, ни другого: она держит правила ровно столько, сколько они помещаются в активное внимание, и тем хуже, чем длиннее ответ.

Полный свод в промте даёт не более строгий код, а более уверенные нарушения: модель ссылается на правила, выполняет половину и защищает результат. Это дороже, чем если бы она просто писала обычный код, который потом поправит линтер.

Small GRAIN

Двенадцать законов, которые переживают любую модель. Копируется в промт целиком и собирается из тех же словарей, что читает линтер, поэтому не разъезжается со стандартом.

GRAIN — минимальный свод правил кода. Соблюдай буквально. Если правило не покрывает
случай, действуй по смыслу правила, а не по своей привычке. Новых правил не выдумывай.

1. ИМЯ ФУНКЦИИ — ДЕЙСТВИЕ. Начинается с глагола из списка:
   find get list count read write load save make derive resolve parse format encode decode normalize sign verify hash create delete archive restore ensure assert apply set emit send start stop use with render
   Предикат называется префиксом: is has can should was will must.
   ЗАПРЕЩЕНО: handle process manage do perform execute check init update fetch retrieve calculate compute generate build setup validate transform convert prepare determine deal run trigger
2. КОНТРАКТ В ИМЕНИ. find* может вернуть null и никогда не бросает. get* гарантирует
   значение. list* — всегда коллекция. count* — число.
3. ЧИСЛО НЕСЁТ ЕДИНИЦУ: At Ms Sec Min Hours Days Bytes Kb Mb Gb Cents Ratio Pct Count Index Px Deg Hz Bpm Db (refreshTtlSec, priceCents,
   sizeBytes). Без единицы допустимо только безразмерное: x y z id width height depth port page limit offset version priority.
4. БУЛЕВО — только с префиксом: is has can should was will must.
5. СЛОВА-ПУСТЫШКИ ЗАПРЕЩЕНЫ В ИМЕНАХ: data info obj object temp tmp stuff misc thing things res ret arr str num flag val result helper handler manager wrapper util utils.
   Сокращения пишутся целиком: request, response, message, error, index, config.
6. КОММЕНТАРИЙ ОТВЕЧАЕТ «ПОЧЕМУ» и начинается с тега: why: perf: safety: spec: ref:.
   Пересказ кода, TODO, эмодзи, ASCII-разделители, «шаг 1» — не писать.
7. ФАЙЛ = ОДНА РОЛЬ, роль в имени: <домен>.entry.ts <домен>.route.ts <домен>.rpc.ts <домен>.store.ts <домен>.wire.ts <домен>.policy.ts <домен>.shape.ts <домен>.event.ts <домен>.job.ts <домен>.pure.ts.
   store — единственное место с SQL. pure — ноль I/O. Запрещены: utils util helpers helper common shared misc lib main types constants service manager handler index.
8. CATCH ОБЯЗАН ДЕЙСТВОВАТЬ: пробросить дальше или вернуть типизированный отказ.
   Записать в лог и продолжить — нельзя.
9. НЕДЕТЕРМИНИЗМ ТОЛЬКО НА ГРАНИЦЕ: Date.now Math.random crypto.randomUUID process.env performance.now — только в
   ролях entry route rpc job wire. В домен приходят аргументом.
10. НЕЗАВИСИМЫЕ AWAIT — ЧЕРЕЗ Promise.all. Последовательность только там, где второй
    вызов использует результат первого.
11. ТОЛЬКО ИМЕНОВАННЫЕ ЭКСПОРТЫ. any не существует: внешнее приходит как unknown и
    разбирается схемой.
12. СОБЫТИЕ — СВЕРШИВШИЙСЯ ФАКТ: v1.{домен}.{предмет}.{что произошло} (verified,
    granted, paid), не команда (не payInvoice).

Если сомневаешься в имени — возьми ближайший глагол из списка. Не изобретай синоним,
не добавляй «улучшений» к правилам и не объясняй правила в коде.

В Small GRAIN намеренно не вошли пределы вложенности и длины, глубина каталогов, воронка guard → acquire → derive → effect, направление импортов, форма кода отказа. Не потому что они неважны, а потому что их проверяет линтер, и проверяет лучше: это ровно те правила, где машина точна, а модель угадывает. Осталось то, что машина проверить не может или проверяет поздно: словарь глаголов, контракт find/get, единица у числа, смысл комментария, catch, который не молчит.

Арбитр — линтер, а не модель

Не спрашивайте у ассистента, соответствует ли код стандарту. Спросите у линтера: он читает те же словари, отвечает списком строк и не умеет быть уверенным без причины. Долг, зафиксированный числами, устроен так, что новый код обязан быть чистым независимо от того, кто его написал, — и это единственная гарантия, которая работает одинаково для человека и для модели.

Стандарт и языковые модели | AS Docs