Колонка

Сайт, где CI падает, стоит числу разойтись с доказательствами

Впишите на этот сайт число токенов в секунду руками — и CI упадёт. Каждое измеренное значение пересчитывается из сырых записей прогонов, а закоммиченное значение, разошедшееся с ними, останавливает пайплайн. Как устроен гейт, что он проверяет и какой класс ошибок ему не виден.

мнение 2 сентября 2026 г.

Это колонка-мнение, а не результат лаборатории. Цифры здесь — из рабочего журнала автора и цитируемых внешних источников (помечены в тексте), никогда — из реестра клеймов. Измеренные результаты с доказательствами живут в /claims/.

Впишите на страницу этого сайта число токенов в секунду — и CI упадёт. Вставьте его так, как разрешают правила, через id клейма, но ошибитесь в самом id — и статическая сборка упадёт с исключением раньше, чем будет что деплоить. Это первое, что я решил, когда пересобирал сайт.

Правило такое: измеренное значение попадает на страницу только через компонент, который принимает id клейма. Сканер стережёт только ту часть правила, где число похоже на пропускную способность; остальное стерегу я. Неизвестный id роняет сборку с сообщением: сначала добавьте клейм, подкреплённый валидными прогонами. Если клейм существует, но помечен superseded или retracted, сборка тоже падает — заменённому числу нечего делать в живом предложении. Рендерятся значение, единица измерения и ссылка на постоянную страницу, где лежат скоуп клейма, его ограничения и прогоны.

Реестр генерируется и руками не правится никогда. Клейм же, из которого он собирается, — JSON-файл, и вот его я пишу руками: формулировка словами, id прогонов, на которые она опирается, путь к SQL-файлу, скоуп, ограничения, уровень доказательности и статус. Единственное поле, которого там нет, — значение. Скрипт выполняет запрос каждого клейма в DuckDB по поштучным записям ровно тех прогонов, что клейм называет, смотрит, на какой машине и с каким артефактом модели эти прогоны шли, и пишет результат в один сгенерированный TypeScript-файл, в шапке которого написано «не редактировать». CI гоняет тот же скрипт в режиме проверки и падает, если закоммиченный файл отличается от того, что скрипт только что пересчитал. Поправьте значение руками или троньте прогон без пересчёта — и пайплайн встанет. Реестр публикуется ещё и как JSON, а у каждого клейма есть markdown-двойник.

Я строил это не ради изящества. У пересборки была одна задача: у числа не должно быть способа пережить свои доказательства. Реестр родился пустым и оставался пустым ещё несколько дней после запуска сайта; страницы, которым полагалось держать числа, показывали пустые состояния, а комментарий в шапке файла реестра до сих пор говорит, что старые числа возвращать нельзя. Сегодня в реестре несколько десятков клеймов. Каждую формулировку написал я — и ни одного значения не набрал.

Что именно проверяет CI

Знаменатель живёт в SQL, а не на странице методологии. Над запросом для клейма о пустых ответах стоит комментарий: знаменатель — все запросы, отправленные в указанных прогонах; отказы не выбрасываются никогда. SELECT под комментарием делает ровно это: делит на голый count по всем записям прогонов, которые клейм называет.

Валидатор обязан доказать, что умеет говорить «нет», — по той же причине, по какой харнесс хранит свой невалидный первый прогон. Рядом с каталогом лежит папка мини-каталогов, собранных нарочно, чтобы валидатор их завернул: активный клейм на прогоне, который до сих пор числится запланированным; клейм, растянутый на два ворклоада; клейм, агрегирующий по нескольким системам без comparison class; модель без хеша; прогон, ссылки которого указывают в пустоту. Гейт каталога падает, если примет хоть один из них. Валидатор, который ни разу при вас ничего не забраковал, — это шаг форматирования с уверенным названием.

Историческим цитатам нужна метка на строке. Сканер формулировок не пропускает в тексте страницы набранное руками число пропускной способности, если на той же строке нет маленького HTML-комментария, означающего «проверенная цитата из названного источника». Числа из чужих публикаций появляться могут; выглядеть как наши — нет.

Первые несколько дней проверка дрейфа жила только в моём локальном pre-push-скрипте, то есть запускалась, когда я о ней вспоминал. Теперь она крутится в CI, на машине, которая мне не принадлежит.

Чего зелёный CI не означает

Он не означает, что предложения верны. Ни одну запись в нашем журнале исправлений гейт не поймал.

Самый наглядный случай — control-success клейм для Gemma. Его формулировка гласила: «признала отсутствие ответа вместо того, чтобы выдумать его». Архивные поштучные записи показывают, что провалившиеся контроли были пустыми ответами: reasoning-проход съел токен-бюджет раньше, чем появился хоть какой-то текст. Ни один прогон код не выдумал. Значение не сдвинулось. Предложение вокруг него было неверным, причём неверным не в пользу модели, а пайплайн этого заметить не мог: он проверяет арифметику, а ошибка сидела в английском. Починка — запись в errata и новая формулировка, со ссылками в обе стороны. Пока я это пишу, комментарий в шапке SQL-файла, который считает то самое значение, всё ещё говорит «вместо того, чтобы выдумать его». Комментарии CI тоже не читает.

Дальше лестница длинного контекста: её номинальные длины в токенах считались по оценке «символов на токен». По собственному учёту рантайма английские ступени легли близко к номиналу, русские — сильно ниже. Байты корпуса никто не трогал, и они по-прежнему совпадали со своим замороженным хешем. Ошибка была в описании доказательства, а не в доказательстве, и хеш такого не видит. Поймали её при перечитывании; измеренные поштучные значения теперь лежат рядом с корпусом.

Дальше одно слово: в тексте сайта стояло «пререгистрированный» раньше, чем был заморожен хоть один артефакт пререгистрации. Переформулировано после ревью.

И ещё один случай. Утром того дня, когда гейт дрейфа переехал в CI, страницу errata обновили фразой, что исправлений пока не потребовалось. Фраза прожила часть одного утра. А страница раскрытий ещё несколько дней утверждала, что ни одного исправления не зафиксировано, — когда в журнале их было уже несколько. Страницу об исправлениях пришлось исправлять.

Гейт сверяет число с прогонами, которые оно называет, — арифметику и ничего больше, — и я всё равно построил бы его снова. Арифметика — та часть, которую тихо правят в полночь, когда результат смотрится лучше без одного прогона и никто бы не заметил. Предложения правят при свете дня, у всех на виду, и они всё равно выходят неверными. Числа стережёт скрипт, которого нельзя уговорить. Предложения стерегу я. А меня — можно.

← Все колонки