Ratchet Loop
Оптимизационная петля-храповик поверх одной измеримой метрики. Идея взята из
autoresearch Карпатого и перенесена на brownfield: ты не «дорабатываешь фичу до
готовности» (это goal-pipeline), ты тянешь одно число — p95 latency, число
SQL-запросов на странице, размер бандла, pass-rate промпта, mutation score — и
оставляешь только то, что реально его сдвинуло в нужную сторону. Всё остальное
откатывается. История ветки = trail исследования.
Главный механизм — храповик: попробовал → измерил замороженным оценщиком →
если лучше, коммит остаётся (зубец защёлкнулся); если нет, git reset к
последнему «keep». Петля сама не заканчивается — крутится до бюджета, до плато
или до прерывания. Это отличает её от любой gate-петли с булевым «done».
Два предохранителя, без которых храповик вырождается в reward hacking, вшиты в контракт: замороженный оценщик (агент не имеет права его трогать; целостность проверяется хешем) и независимый verifier-проход (свежий суд по артефактам, а не по самоотчёту петли).
Чем НЕ является (анти-коллизия)
| Похоже на | Разница |
|---|---|
goal-pipeline |
Coverage-пайплайн под хостовый /goal: разные фазы, терминируется на «все фазы done + аудит». ratchet-loop крутит ОДНУ задачу-вариацию на одном артефакте ради скаляра и сам не терминируется. /goal проверяет условие, а не «лучше ли число, иначе откат» — храповик в его модель не ложится. |
ralph-loop |
Общая in-session петля без хостового оценщика и без контракта оптимизации. ratchet-loop — её специализация: добавляет скаляр + направление, frozen eval, keep-or-revert и verifier. Если оптимизируемого скаляра нет — бери ralph-loop. |
gate-loop (паттерн, не навык) / /goal "done when зелёное" |
Булев гейт: «чини пока тесты/CI зелёные», терминируется когда щёлкнуло. ratchet тянет непрерывный скаляр и после «зелёного» продолжает жать. Для «до зелёного» отдельный скилл не нужен — это голый /goal или одна фаза goal-pipeline. |
spec-writer |
Только пишет документ, ничего не исполняет и не меряет. |
Когда брать / когда не брать
Брать: есть одно число, которое надо двигать, и детерминированный (или почти) способ его померить на одном артефакте — оптимизация запроса/функции, снижение latency/памяти/запросов, ужатие бандла, подъём pass-rate промпта или few-shot-набора, рост mutation score. Изменения обратимы через git (чистый код, без сайд-эффектов).
Не брать:
- Нет скаляра, есть «довести фичу до готового» →
goal-pipeline. - Метрику нельзя померить автоматически и воспроизводимо → петле нечего тянуть; сперва сделай оценщик, потом возвращайся.
- Цель — булев гейт «до зелёного» → голый
/goal "done when ...". - Оптимизируемый артефакт сам по себе сайд-эффектный (миграция, деплой-скрипт,
рассылка) → откат через git не спасёт; это не задача для ratchet-loop, откажись
и эскалируй (
RL_HALT).
Предусловия
- Git-репозиторий, чистое рабочее дерево — храповик стоит на
git reset. Грязное дерево на старте → попроси закоммитить/стешить. Нет git → откажись (предложиgit init+ baseline-коммит, без него петля небезопасна). - Замороженный оценщик — команда (
make-цель или прямая), которая печатает скаляр в распознаваемой строке и не зависит от оптимизируемого артефакта как от источника правды.python eval.py→metric: 0.873, илиpytest tests/bench_test.py -qсо строкой метрики, илиmake bench. - Понятные команды проекта. Все прогоны — командами в терминале твоей среды; не заводи под это скрипты-файлы.
Профили автономности
Выбирается в этапе 0 (дефолт — checkpoint-on-verify). Пишется в STATE.md.
| Профиль | Поведение | Когда |
|---|---|---|
| checkpoint-on-verify (дефолт) | Гонит попытки автономно; на каждом verifier-чекпоинте (каждые K keep-ов и финал) печатает RL_HALT и возвращает управление — ты глянул, ре-диспатчнул. |
Дефолт. Рутина сама, «лучшее» проверяется глазами по чекпоинтам. |
| full-auto | Руки прочь до бюджета/плато; стоп только на RL_HALT от блока (eval сломан / 3-strike crash / попытка сайд-эффекта). |
Низкорисковая чистая оптимизация под git (один файл, тесты зелёные). |
| per-keep | RL_HALT после каждого принятого улучшения. |
Хрупкий/незнакомый код, где хочешь видеть каждый зубец. |
Этап 0 — Контекст
- Профиль автономности — спроси одним
AskUserQuestion, если не задан (дефолт checkpoint-on-verify). Запиши вSTATE.md. - Git baseline —
git rev-parse HEADи проверка чистоты дерева (git status --porcelain). ЗапишиBaseline ref:вSTATE.md. Грязно → стоп, попроси привести дерево в порядок. - Память — подгрузи memory-индекс (
MEMORY.md), выборочно подними релевантное (предпочтения по стеку, прошлые прогоны по этому артефакту). Применённое вынеси в контракт как «Из памяти: …».
Этап 1 — Контракт оптимизации (программа петли)
Это самая важная часть: пока контракт не зафиксирован, петлю не запускай. Эхо задачи в одно предложение, затем определи и покажи пользователю контракт:
- Мутируемая цель — РОВНО один файл (по умолчанию) или явный малый набор. Только он редактируется. Всё прочее — заморожено.
- Замороженный оценщик — точная команда измерения + строка-якорь метрики
(например
^metric:или^val_bpb:). Оценщик и любые его данные-эталоны входят в frozen-set и не редактируются (этап 2). - Метрика и направление — один скаляр,
minimizeилиmaximize. Не «качество», не «быстрее» — конкретное число. - Порог шума (epsilon) — насколько метрика должна сдвинуться, чтобы считать это улучшением, а не дрожанием замера. Если замер шумный — оцени epsilon по 2–3 прогонам baseline.
- Бюджет на попытку — wall-clock таймаут (например 5 мин). Превышение → kill, попытка = crash/discard.
- Условие останова петли —
until-interrupted(дефолт), либоN trials, либоplateau:K(K попыток подряд без улучшения сверх epsilon).
Уточняющие вопросы — только истинные пробелы (что за метрика, чем мерить, что правим). Микро-детали — в показ контракта как предположения для правки в один клик.
Напечатай RL_CONTRACT со всеми полями и AskUserQuestion «Старт?» с режимами
правки (Старт · Поправить цель/оценщик · Сменить метрику/направление ·
Сменить бюджет/останов). Молчание ≠ подтверждение.
Пример заполненного контракта, заморозки оценщика, results.tsv и финала —
references/contract-example.md (снижение числа SQL-запросов на странице Django).
Этап 2 — Заморозка оценщика (anti-Goodhart core)
Без этого петля сжульничает в первую же ночь. После «Старт»:
- Перечисли все файлы frozen-set: скрипт оценщика, его данные/эталоны, конфиг замера, фикстуры бенча. Всё, что мутируемая цель не должна трогать.
- Зафиксируй их целостность:
git hash-object <file>по каждому (или хеш дерева подкаталога). Запиши в.ratchetrun/EVAL.lock. - Напечатай
RL_EVAL_LOCKEDсо списком файлов и хешей.
Жёсткое правило: мутируемая цель ≠ ни один файл frozen-set; их пересечение пусто. Если пользователь назвал оценщиком тот же файл, что и цель — стоп, объясни: агент, который и правит, и судит один файл, измеряет собственную выдумку.
Этап 3 — Baseline
Первая «попытка» — без правок: прогони оценщик как есть, чтобы получить отправную
точку. <eval-cmd> > .ratchetrun/run.log 2>&1, затем достань метрику
(Select-String '^metric:' .ratchetrun/run.log). Не давай выводу затопить
контекст — только строка метрики (redirect + grep, не tee).
Запиши как best в STATE.md и первой строкой в results.tsv. Напечатай
RL_BASELINE: <metric>.
Если метрика это позволяет, на baseline сними и профиль (что доминирует в числе: какой запрос, какая функция, какой кусок бандла) — чтобы гипотезы целили в горячую точку, а не угадывали. Профиль — в лог, не в контекст.
Этап 4 — Ratchet-петля
Артефакты — в .ratchetrun/ (напомни добавить в .gitignore). results.tsv
не коммить (untracked), как и весь .ratchetrun/. Колонки (tab-separated):
trial commit metric status eval_ok description
Цикл (до условия останова, RL_HALT, или прерывания):
- Eval-integrity guard. Пере-сверь хеши frozen-set против
EVAL.lock. Любое расхождение →RL_HALT,STATE.md → Status: EVAL_TAMPERED, стоп. Прогон недействителен — оценщик изменился. - Гипотеза. Одно изменение мутируемой цели (что и зачем, 1 строка), нацеленное на горячую точку из профиля, а не наугад. Один рычаг за попытку — иначе непонятно, что именно сдвинуло метрику.
- Правка. Внеси её только в мутируемую цель.
- Прогон.
<eval-cmd> > .ratchetrun/run.log 2>&1с таймаутом бюджета. Превышение → kill процесса. - Считай метрику.
Select-String '<якорь>' .ratchetrun/run.log. Пусто → crash. - Решение храповика:
- crash (пусто/таймаут/ненулевой код) →
RL_CRASH; если причина тупая (опечатка, импорт) — почини и переран один раз; иначе discard. - улучшение (метрика лучше
bestпо направлению сверх epsilon) → keep:git commit, обновиbest,RL_KEEP: <metric>. - равно/хуже → revert:
git reset --hard <last-keep-commit>(илиgit restore),RL_REVERT. - критерий простоты: метрика в пределах epsilon, но код проще (меньше строк, убрали хак) → keep как упрощение. Крошечный выигрыш ценой уродливой сложности → discard.
- crash (пусто/таймаут/ненулевой код) →
- Лог. Допиши строку в
results.tsv(eval_ok= да/нет из шага 1). - Чекпоинт. Профиль
per-keepи был keep, ИЛИ накопилосьKkeep-ов (checkpoint-on-verify) → перейди в этап 5 (verifier), затемRL_HALT. - Прерывание. Пришло сообщение пользователя → пауза на границе попытки, разберись, спроси перед продолжением.
3-strike на crash
Три подряд crash без единого keep по одной линии идей → RL_HALT с историей попыток;
STATE.md → Status: BLOCKED. Не долби стену — смени направление гипотез или верни руль.
Если идеи кончились
Не останавливайся молча (профиль full-auto/until-interrupted). Перечитай контракт и
прошлые near-miss из results.tsv, скомбинируй частичные улучшения, попробуй более
радикальную правит цели. Плато объявляй только по условию plateau:K, не на глаз.
Этап 5 — Независимый verifier-проход
Per-trial решения — самоотчёт петли; «лучшее» нужно судить с чистого листа.
Рекомендуемая форма (истинная независимость) — свежая сессия/суб-агент без доступа
к транскрипту петли, судящая только по best-коммиту + контракту. Минимум —
отдельный проход в текущей сессии. Проверь:
- Целостность оценщика. Хеши frozen-set ==
EVAL.lock. Расхождение → провал, весь прогон под подозрением. - Воспроизводимость. Чистый чекаут
best-коммита → прогони оценщик заново → метрика воспроизводится в пределах epsilon. Ловит выдумку из транскрипта, кеш-фейк и недетерминизм. - Анти-хак скан диффа против baseline ref (см. «Жульничество» ниже).
- Без сайд-эффектов. Дифф трогает только мутируемую цель: нет новых миграций,
push, деплоя, сетевых вызовов, destructive ops, правок вне цели.
Напечатай RL_VERIFY с результатом каждого пункта. Провал любого → RL_HALT,
STATE.md → Status: VERIFY_FAILED, верни руль с диагнозом.
Этап 6 — Завершение (Definition of Done)
«Done» здесь — не «метрика красивая», а прогнанные проверки (стиль harness-engineering: DoD = гейт, а не пожелание):
-
RL_VERIFYзелёный: целостность оценщика + воспроизводимостьbestиз чистого чекаута + анти-хак скан чисто + ноль сайд-эффектов вне цели. -
HEAD==best-коммит; метрикаHEAD== записаннаяbest. -
results.tsvкогерентен: по строке на попытку, статусы согласованы с git-историей. - Memory writeback сделан (что сработало/не сработало по этому артефакту).
Затем RL_RUN_COMPLETE с 5-строчным резюме: метрика baseline→best (дельта), число
попыток (keep/discard/crash), какие идеи сработали, путь к results.tsv, остался ли
запас. Если доля недетерминированно-проверенного в verifier высока — баннер «⚠ метрика
шумная, перед мержем подтверди дельту на нескольких прогонах».
Что считается жульничеством (reward hacking)
Анти-хак скан в этапе 5 ищет в диффе мутируемой цели:
- правка/перезапись любого файла frozen-set (главное и тягчайшее);
- хардкод ожидаемого ответа, чтение файла-эталона оценщика из цели, кеш результата под ключ теста;
if <тест/бенч>: return <ответ>и прочие ветки «распознал оценщик → подыграл»;try/except, глотающий падение, чтобы оценщик увидел «успех»;- сетевые вызовы / внешнее состояние, дающие метрике подсмотреть ответ;
- оверфит под eval-set, когда он совпадает с тюнингующим сигналом (нужен holdout);
- сайд-эффект ради метрики (правка вне цели, глобальное состояние).
Любое срабатывание → keep недействителен, откат, RL_HALT.
Маркеры транскрипта и память
Полная таблица маркеров (RL_CONTRACT, RL_KEEP, RL_HALT, RL_RUN_COMPLETE, …)
и правила memory-writeback (ratchet_<artifact-slug>.md) — в
references/loop-protocol.md. Читай его перед этапом 1
и перед завершением прогона.
Связанные навыки
ralph-loop— родитель: общая in-session петля без контракта оптимизации. Нет скаляра — бери её, не ratchet-loop.goal-pipeline— когда задача не «тяни число», а «доведи фичу/рефакторинг до готового по фазам».harness-engineering— независимый verifier-проход и DoD здесь — те же гейты, что харнесс кладёт в Definition of Done проекта. ratchet-loop исполняет «оптимизация под замороженным оценщиком» как один из них.test-coverage-auditor/migration-safety-auditor— могут быть оценщиком или гейтом, если оптимизируешь именно покрытие/безопасность миграций.