Вчера я прогнал свой цикл черновиков по 16 утверждённым темам и прочитал отчёты. Черновик статьи про то, как состояние живёт в файлах, вернулся с оценкой критика 2 из 10. В этом цикле такая оценка значит, что текст не пахнет моделью и идёт ко мне на чтение. Механические проверки на том же файле насчитали 10 срабатываний, 8 из них это запятая перед and.
Эту запятую критику не надо выводить из моего стиля. Она стоит в его собственном промпте жёсткой проверкой номер 3, записанной как Comma before and / or → 0. Правило было у него перед глазами, а оценка вышла 2. Фраза, которой я объясняю этот цикл, говорит, что механика решает то, у чего есть однозначный ответ, а суждение критик оставляет себе. Я вписал её в README этого репозитория и повторяю всякий раз, когда спрашивают, как устроена генерация. Числом я её ни разу не проверял.
Цикл и обстановка
Черновик сначала идёт через src/lib/tells.ts. Там 19 проверок. Почти каждая это регулярка, появившаяся после правки, которую я сделал руками: никакого тире в английском, никакой запятой перед and, счёт цифрами. Дальше черновик уходит к критику из prompts/_critic.md, который возвращает замечания и оценку от 0 до 10, где меньше значит лучше. На 3 и ниже он останавливается и ждёт меня. Выше 3 идёт переписывание, до 2 раундов.
Всё, что ниже, прогнано моделью claude-opus-5 через claude CLI 2.1.235 на node 22.23.1, против tells.ts на коммите 0f0b511. Прогоны идут внутри этого репозитория намеренно. Чистая папка нужна там, где меряется сама модель. В августе я насчитал 0 тире в 30 машинных текстах и записал это как свойство модели. На деле это выполнялся запрет из моего же CLAUDE.md. Та же модель из пустой папки дала 6.10 тире на 1000 слов. Здесь меряется цикл вместе с CLAUDE.md этого репозитория в контексте, потому что так он и работает каждый день.
16 черновиков через настоящий конвейер
16 утверждённых тем, 12 для X и 4 статьи для блога. Механика сработала на всех 16: 125 срабатываний, от 1 до 20 на черновик. Критик поставил от 2 до 5 со средней 2.9, то есть 13 из 16 лежат на пороге или ниже. Цикл остановился бы там и отдал файл мне.
Это число пришлось чинить, прежде чем оно стало что-то значить. Один черновик вернулся завёрнутым в один огороженный блок от начала до конца. Проверка на сращение дефисом вырезает такие блоки, прежде чем смотреть, поэтому в том черновике она увидела 0 слов прозы. Снятая обёртка это разница между 123 срабатываниями и 125.
62 срабатывания из 125 это та самая запятая. Корреляция оценки с числом срабатываний выглядит обнадёживающе, r = 0.51 на 16 точках. На 1000 слов она уже r = -0.21. Срабатывания идут вместе с длиной черновика, r = 0.77. Оценка против длины даёт r = 0.41, то есть первое число говорит мне в основном о том, что длинные черновики длинные.
Подсадка нарушений
Тогда я закрепил текст и стал менять одно. Чистый кусок на 857 слов, который не даёт ни одного срабатывания. Внутрь подсажены k нарушений одного правила, k удваивается от 1 до 8. Каждая версия ушла к критику 3 раза, вместе с чистой базой.
Указатели ведут себя так, как я надеялся. На 8 подсадках оценка доходит до 6.0, заметно выше порога, а правило названо в каждом прогоне. Тире доходит до 4.0. Моё правило про запятую заканчивает на 2.7 при 8 таких запятых в тексте. Это внутри проходной полосы, против 2.3 у базы, куда не подсажено ничего. При 8 запятых все 3 прогона правило в замечаниях называют, а число остаётся там, где черновик уходит ко мне.
Считать, как часто критик называет правило, это место, где я споткнулся. Первый заход искал символ тире внутри его замечаний. Ответ вышел лестный, пока я не посмотрел, что именно он ловит. Критик сам пишет тире, в 42 замечаниях из 90, в репозитории, где первое английское правило говорит, что тире нет. Поиск по слову dash уронил ответ до 1 черновика из 4, где тире было.
Тот же текст, 12 раз
Средняя 2.9 чего-то стоит только тогда, когда число повторяется. Я прогнал критика 12 раз на одном тексте, потом 12 раз на том же тексте с 2 подсаженными тире.
Чистый текст разбрасывается от 1 до 3 со средней 2.2. Версия с подсадкой все 12 раз отвечает 3. Критик шатается на чистой прозе и залипает на грязной. Это обратно тому, что я думал, но 1 текст и 1 правило это тонкое доказательство.
Какой отчёт подавать в переписывание
Здесь вопрос превращается в решение. Принудительный раунд переписывания на 15 черновиках, 2 плеча, модель в обоих одна. Плечо A получает замечания критика. Плечо B получает машинный отчёт, то есть имена правил и счёт. Оба плеча стартуют с текста в том виде, в каком его оставил цикл, поэтому стартовые числа у них ниже, чем в таблице выше.
Плечо B ответило на 8 черновиках из 15 и увело 4 из этих 8 в 0 срабатываний, не внеся нового правила нигде. Плечо A ответило на 9 и не увело в 0 ни одного. В 4 случаях из 9 оно внесло правило, которого в черновике до этого не было. Одна статья ушла с 4 срабатываний на 8, делая ровно то, что просил критик. Пустые клетки это ответ CLI HTTP 429 про лимит расхода. Десятая клетка плеча A досчиталась и пропала, потому что скрипт пишет файл после обоих плеч, а процесс умер между ними.
Где падает механика, на списке, который я набрал сам
Проверка spelled-number срабатывает на счёте, написанном словами. Правило это фраза в описании голоса. Проверка, которая его держит, это список из 15 слов.
От thirteen до nineteen в списке нет ничего, как нет sixty, seventy, eighty и ninety. На 22 статьях, которые лежали на сайте до этой, а это 22578 слов прозы, spelled-number не срабатывает ни разу. При этом 8 чисел, написанных словами, лежат в опубликованном тексте. 6 из 8 в одной статье про умножение, которого не происходит, где я написал sixteen словом 5 раз и fifteen один раз.
Что я поменял и чего не проверял
Раунд переписывания теперь получает машинный отчёт вместе с замечаниями критика, на основании плеча B. Оба сразу это третий случай, которого никто не мерил. Я взял его потому, что раунд вообще запускается только когда критик поставил выше 3. Выбросить его замечания значит оставить без ответа причину раунда. Фраза из README выживает в более узком виде. Механика отвечает за то, что кто-то уже набрал в список. Критик отвечает за остальное. Ему можно положить жёсткую проверку прямо в промпт, а он всё равно пропустит черновик, который нарушает её 8 раз. Гейтом друг для друга они не работают. Вот эту часть я понимал неправильно.
Я не проверял, имеет ли число критика хоть какое-то отношение к тому, приятно ли текст читать. Человеческих оценок здесь нет нигде. 3 прогона на клетку это мало. Это один промпт на одной модели.
У счёта есть ещё одна дыра, которую я не закрыл. Черновики здесь судились целыми файлами, а критик судит пост внутри них. На 10 черновиках для X, где пост лежит в огороженном блоке, половины с постом дают 25 срабатываний против 47 в приписках. Приписки не уходят никуда. 2 половины при этом не складываются в число по целому файлу, потому что одна из проверок вырезает огороженные блоки, прежде чем смотреть.