Чему можно доверять
Какие части руководства — разобранные парсером факты, какие — вывод модели, что покидает вашу машину и что инструмент отказывается делать.
Коротко
| Утверждение | Источник | Может ли быть неверным? |
|---|---|---|
| Этот файл существует по этому пути | парсер | Нет |
| Эта функция находится на строках 88–104 | парсер | Нет |
Эта сигнатура — send(self, url, data) | парсер | Нет |
| Эта функция вызывает ту | парсер | Нет для полного уровня; по мере возможностей для универсального |
| Эти вызовы не удалось разрешить | парсер | Нет — они перечислены, а не угаданы |
| Эти файлы не удалось прочитать или разобрать | парсер | Нет — они перечислены, а не зачтены как покрытые |
| Этот файл относится к этому этапу | LLM, механически валидировано | В части суждений — да. Структурно — нет |
| Назначение этого файла — «…» | LLM | Да — это проза |
| Эта подсистема работает так: «…» | LLM | Да — это проза |
| Это состояние проходит через эти этапы | LLM, поверх настоящих id этапов | Да, хотя id этапов настоящие |
Правило, которому следует весь дизайн: агент маршрутизируется по верхней половине этой
таблицы и читает настоящие исходники, прежде чем действовать. SKILL-пакет говорит об этом
в первой же строке, а его протокол маршрутизации заканчивается словами «read_file
настоящий исходник по каждому упомянутому пути, прежде чем предлагать или вносить
изменения».
Что покидает вашу машину
Phase 1 — ничего. Статический анализ полностью локален. Ни одного сетевого вызова.
Phase 2 и Phase 3 отправляют содержимое исходных файлов на конечную точку, которую настроили вы. Это может быть модель, работающая на вашей собственной машине (vLLM, Ollama, LiteLLM). У Handbooks нет телеметрии, нет аналитики и нет конечной точки по умолчанию, кроме OpenAI, для которой вы сами должны предоставить ключ.
--max-chars-per-file <n> ограничивает, сколько из любого отдельного файла вообще
может быть отправлено.
Рендеринг, упаковка и валидация никогда не касаются сети. Как и apply с
rollback.
Планировщик читает ваши исходники локально и отправляет выдержки из прочитанного на конечную точку — так же, как генерация.
Что намеренно отклоняется
Отказы — несущая часть этого инструмента. В порядке приоритета:
Патчер
- Якорь, совпавший ноль раз → отказ. Код ушёл вперёд.
- Якорь, совпавший два и более раз → отказ. Это неоднозначно.
- Никогда не «брать первое совпадение». Именно так патч ложится не в ту функцию.
- Один сбой прерывает применение целиком, до записи первого байта.
- Путь, выходящий за корень исходников — в том числе через родительский каталог-симлинк, когда файла ещё не существует, — отклоняется.
- Откат отказывается трогать любой файл, изменённый после патча, если не передан
--force.
Планировщик
- Инструмента записи не существует. Не отключён — не реализован.
- Ответ, выдумывающий секции
## Tool result, отклоняется целиком, включая любой план в его конце, потому что этот план выведен из вымысла. - Запуск, который сдался, завершается ненулевым кодом, вместо того чтобы записать
извинение в
plan.md. - Катастрофические регулярные выражения (
(a+)+,(.*)*) отклоняются до того, как успеют подвесить запуск.
Конвейер
- Вызов, который анализатор не может разрешить, попадает в
dropped-calls.json. Он никогда не угадывается. - Файл, который анализатор не может прочитать или разобрать, попадает в
scan-coverage.jsonс указанием причины и не попадает вscannedFiles. Его никогда не описывают как пустой файл. Файл, разобравшийся лишь частично, остаётся — и всё равно перечисляется: его факты настоящие, но неполные, и вам стоит знать, какие страницы на них опираются. - Файл, для которого не удалась генерация карточки, получает пустое описание, никогда
не выдуманное, и перечисляется в
_coverage.json. - Структурное изменение, предложенное циклом-доктором, которое называет несуществующий этап или оставило бы файлы сиротами, отклоняется до того, как коснётся скелета.
- Критик, чей ответ не удалось распарсить, считается за
REJECT.
Конфигурация
- Секрет никогда не бывает флагом командной строки и отклоняется, если появляется
в файле конфигурации, — потому что файлы конфигурации попадают в коммиты. Секретами
объявлены две настройки:
llmApiKey/OPENAI_API_KEYиllmExtraBody/OPENAI_EXTRA_BODY— у второй форма произвольная, подмешивается она в тело каждого запроса, а шлюзы аутентификацию там принимают, так что ничто не отличит поле тонкой настройки от учётных данных. llmBaseUrlнамеренно не объявлен секретом целиком: если вся команда направляет каждый свой клон на один общий шлюз, закоммитить его — законное желание. В файле конфигурации отклоняется только URL со встроенными учётными данными (https://user:pass@host/v1).- Переданное, но невалидное значение никогда не проваливается к значению по умолчанию. Опечатка — это ошибка.
- Пустое значение читается как неустановленное, поэтому
HANDBOOK_TITLE=не может породить руководство без заголовка.
Обнаружение дрейфа
coverage.json в SKILL-пакете несёт хеш содержимого для каждого файла, снятый в
момент упаковки.
handbook validate --skill skills/myrepo --source ~/code/myrepoзаново хеширует живые исходники и сообщает о каждом файле, чьё содержимое с тех пор
сдвинулось. Так агент узнаёт, что «эта страница может отставать от кода», прежде чем
действовать на основе устаревшего утверждения, — и именно поэтому --work и --source
стоит передавать в handbook skill.
Канал исправлений
Когда утверждение руководства противоречит настоящим исходникам, агент-потребитель
добавляет одну строку JSON в corrections.jsonl в корне skill:
{
"file": "src/engine.py",
"page": "references/stages/stage-2.md",
"claim": "spin() is defined in src/main.py",
"actual": "spin() is defined in src/engine.py"
}handbook resync --corrections <file> затем обновляет ровно те файлы, что в нём
названы — даже если их байты не менялись, потому что утверждение, которому противоречат
исходники, само по себе повод описать этот файл заново.
Файл живёт в корне skill и никогда — под references/, потому что планировщики монтируют
это дерево только на чтение. Пересборка сохраняет накопленные исправления при очистке.
Позиция Studio по безопасности
Studio — локальный инструмент и не делает вид, что это не так.
- По умолчанию привязывается к
127.0.0.1. - CSRF-защита проверяет заголовок запроса
Host, а не сокет, поэтому проходят только loopback-имена хостов. POSTтребуетapplication/json, что блокирует классическую кросс-доменную атаку через форму.- Раздача файлов исходников и руководства ограничена песочницей зарегистрированных корней.
В контейнере он должен привязаться к 0.0.0.0, чтобы опубликованный порт вообще был
достижим, но это не расширяет круг тех, кто может с ним говорить: запрос с LAN-IP или
именем хоста контейнера всё равно получает 403. Удалённый доступ — намеренно
нереализованная, отдельная функция: ей понадобился бы явный список разрешённых.
Чего Handbooks не претендует знать
Граф вызовов не может сказать, почему было принято решение, для чего продукт или каковы соглашения вашей команды. Handbooks не выводит их и не делает вид, что выводит. Он документирует структуру и поведение; замысел по-прежнему записывать вам.
Достоверность анализа
Два уровня анализа производят внешне одинаковый результат. Это ловушка, поэтому каждый адаптер объявляет, что он способен выдать, а руководство это раскрывает.
Генерация handbook
Выбор детализации, режима синтеза и стратегии; запуск фаз по отдельности; возобновление; и что делать, когда результат неверен.