chimera-list-exemptions-not-obligations
Проверка, перечисляющая, что проверять, работает как fail-open — ломается именно тот сайт, который никто не вспомнил добавить. Перечисляйте вместо этого исключения, каждое с записанной причиной, и поведением по умолчанию станет отказ.
Присвоено человеком, который прочитал карточку, а не заявлено файлом о самом себе. Карточка, которую агент выводит во время запуска, поглотившего недоверенное содержимое, рождается заражённой и удерживается на разбор, прежде чем её вообще извлекут.
Когда это вспоминается
- пишу гейт сборки
- распространяю правило на весь пакет
- список проверяемых файлов ведётся руками
- раздел лишился гарантии
- добавляю новую точку входа
Ценность обычно лежит в разделах «Избегать» и «Проверить». «Делать» — это раздел, который пишут все.
Текст карточки выше — перевод. Английский оригинал — это то, что импортирует командная строка, что читает агент во время работы и что подтверждает хеш ниже.
Повод
Вы обеспечиваете свойство, которое должно выполняться в каждой точке определённого рода: каждая поверхность без присмотра проходит через профиль governance, каждый писатель проходит gate, каждый маршрут API перегенерирует свою схему. Правило — одно предложение, но точки написаны в разное время разными руками, и ни одна из них не называет вещь так, как её называют остальные.
Это не относится к случаю, когда совокупность замкнута по построению: правило о трёх записях таблицы диспетчеризации уже перечислено самой таблицей. Приём окупается только тогда, когда новая точка может появиться в файле, которого ещё не существует.
Делать
- Перечисляйте совокупность механически. Обходите каждый
*.pyвнутри пакета (PACKAGE.rglob("*.py")), а не написанный вручную список файлов, о которых вы случайно знаете. - Определяйте точку структурно. Разбирайте и обходите AST в поисках нужного вызова;
grepне отличит собранный реестр от тех же слов внутри docstring, а такой docstring появится, потому что кто-нибудь напишет комментарий про это исправление. - Обходите вложенные области видимости и ключуйте по цепочке охватывающих имён —
chimera/cli/main.py:solve._run_solve. Единственная поверхность, которую Chimera потеряла, строила свой реестр внутри замыканияfactory()(chimera/server/manager.py:_gateway_on_message.factory) и была невидима для обхода, смотревшего только на функции верхнего уровня. - Сделайте поведением по умолчанию ОТКАЗ. Держите один
EXEMPT: dict[str, str]из ключа точки в записанную причину, и пусть проверка перечисляет все найденные точки, которых нет среди ключей. - Пишите причину как предложение об этой конкретной точке и разделяйте виды причин. «attended: interactive REPL» (человек может нажать Ctrl-C) — куда более сильное утверждение, чем «собирает эквивалентный стек из собственных флагов»: второе помечает дублирующую реализацию, которую надо консолидировать, а не решённый вопрос.
- Добавьте второй тест, проверяющий, что каждый ключ
EXEMPTпо-прежнему называет живую точку, чтобы список не пережил код, который он оправдывает, и не сгнил в формальность.
Избегать
Список обязанностей:
SURFACES = ["serve", "cron", "mcp", "a2a", "platform"] # fails OPEN
for name in SURFACES:
assert_governed(name)
против списка исключений:
EXEMPT = {"chimera/cli/main.py:chat": "attended: interactive REPL"} # fails CLOSED
assert not [s for s in every_site_in_the_package() if s not in EXEMPT]
Первая версия governance-gate в Chimera была верхней: она разбирала один файл и называла пять
поверхностей. chimera/server/manager.py — Discord-бот, который запускает переключатель Messaging в
десктопном приложении, тот же самый бот, что поднимает serve --discord, — строил свой реестр без
governance ещё три недели после зачистки, которая должна была его покрыть. Он не проваливал gate.
Он вообще не попадал в поле зрения.
Также избегайте исключения без причины. Голый EXEMPT: set[str] — это список проверок, которые надо
пропустить, и через год его никто не сможет отревьюить; одно предложение — вся цена такой записи и
вся её ценность.
Проверить
Скормите gate исходник, нарушающий правило, и убедитесь, что он пойман, в том числе изнутри вложенной функции, — иначе ошибка в разборе AST заставит gate проходить вечно, а гарантия тихо перестанет существовать:
src = "def serve():\n def factory():\n r = default_registry(ws)\n"
assert _bare_registry_calls(ast.parse(src), "m.py") == [("m.py:serve.factory", 3)]
Затем вторая половина: вызов, уже обёрнутый в соответствующую правилу форму, не должен помечаться, иначе каждой соответствующей точке потребовалось бы исключение и список перестал бы что-либо значить.
Двоичный вопрос: удалите одну запись из EXEMPT и перезапустите. Набор тестов краснеет с указанием
именно этой точки? Если нет — gate читает не тот список, о котором вы думаете.
Риск
Инверсия списка перекладывает издержки на того, кто добавит законную новую точку: посторонний PR краснеет с ошибкой про governance, о котором автор не думал. Это и есть задуманный размен, но только если в сообщении об ошибке названы оба способа соответствовать — провести через профиль или добавить исключение с причиной. Gate, срабатывающий на работе, которую он не защищал, заспорят до состояния, в котором он не срабатывает ни на чём.
Структурное распознавание к тому же уже, чем кажется. Оно ловит единственную форму, которую знает; поверхность, собирающая инструменты другим вызовом или импортирующая уже готовый реестр из другого места, лежит за пределами обхода, и зелёная сборка о ней не говорит ничего. Закрепите покрытие того файла, который дал регресс, поимённо в отдельном тесте, чтобы обход, тихо переставший его покрывать, падал, а не проходил.
Как применить
Карточка — это данные. Склонируйте репозиторий и импортируйте её по пути: всё, что приходит по сети, считается заражённым и удерживается до одобрения — это и есть желаемое поведение, и поэтому здесь нет установщика в одну строку.
git clone https://github.com/brcampidelli/chimera-agent.gitchimera skills-import chimera-agent/skills/chimera-list-exemptions-not-obligations/SKILL.mdЦелостность
SHA-256 файла в опубликованном виде. Импортёр может проверить, что полученное совпадает с показанным на этой странице.
243034feb6f9a9a06be65cfb2bf4db159e4fbcc0e7210475dffe540600227ef7