10 added, 2 removed. Audit A to A.
# Точки входа для агента
## Порядок источников истины
Когда меняете Unica, разрешайте противоречия в таком порядке:
1. код и тесты;
2. `plugins/unica/.mcp.json`, `plugins/unica/.codex-plugin/plugin.json`,
`plugins/unica/.claude-plugin/plugin.json` и
`plugins/unica/third-party/tools.lock.json` — это источники контракта пакета,
а не фоновые заметки;
3. `plugins/unica/references/specs/` — источник контракта форматов XML 1С и
JSON-DSL. Когда вопрос в том, как должен выглядеть порождённый `.xml`, `.mxl`
или полезная нагрузка DSL, эти спецификации старше `spec/`, скиллов и прозы.
Они не старше поведения эмиттера, доказанного фикстурой или официальным
дампом платформы; при расхождении с ним правится спецификация;
4. `spec/` — действующий архитектурный слой; при противоречии с источниками из
пунктов 1–3 исправляется `spec/`, а не более высокий источник. Архитектурным
выбором владеет раздел `Решение` записи из `spec/decisions/`, а выведенным
проверяемым обязательством — поле `Rule` записи в
`spec/architecture/invariants.md` или
`spec/architecture/quality-requirements.md`. Происхождение адаптированных
апстримов нормирует `spec/provenance/skill-upstreams.json`: полнота
`plugins/unica/ATTRIBUTIONS.md` проверяется против него;
5. `README.md` и проза скиллов.
## Куда смотреть, где менять
Пути в обоих столбцах даны от корня репозитория, кроме двух сокращений, которые
названы прямо здесь: `architecture/` и `acceptance/` во втором столбце читаются
от `spec/`, а ADR цитируются номером и лежат в `spec/decisions/`. `<группа>` и
`<имя>` подставляются по имени домена инструмента. Сокращать путь до хвоста
нельзя: `rg` по такому хвосту ничего не находит, и строка перестаёт быть
маршрутом.
| Задача | Что читать сначала | Где менять код |
| --- | --- | --- |
| Новый или изменённый публичный инструмент `unica.*` | `architecture/invariants.md` (`INV-MCP-NAMESPACE`, `INV-MCP-SURFACE-SYNC`), `architecture/tool-surface.md` (ведомость поверхности), `architecture/change-checklist.md` | `crates/unica-coder/src/application/mod.rs` (`tools()`), `crates/unica-coder/src/application/tool_contracts.rs`, `crates/unica-coder/src/application/operation_descriptors.rs`, `crates/unica-coder/src/infrastructure/native_operations/<группа>.rs`, `plugins/unica/skills/<имя>/SKILL.md` |
| Изменение формата XML 1С или DSL | ADR-0016, `acceptance/format-profile-8-3-27.md` и `plugins/unica/references/specs/` | `crates/unica-coder/src/infrastructure/native_operations/` |
| Кеш, состояние рабочего пространства, доменные события | ADR-0003, область `CACHE` реестра | `crates/unica-coder/src/domain/events.rs`, `crates/unica-coder/src/domain/cache.rs`, `crates/unica-coder/src/infrastructure/workspace_state.rs`, `crates/unica-coder/src/infrastructure/workspace.rs` |
| Скрытый сервис рабочего пространства или задание runtime | ADR-0006, `architecture/runtime.md`, `INV-APP-LAZY-HIDDEN-SERVICES` | `crates/unica-coder/src/infrastructure/workspace_services.rs`, `crates/unica-coder/src/infrastructure/runtime_jobs.rs` |
| Упаковка или релиз | ADR-0008, ADR-0012, область `PKG` реестра, а также `docs/release-runbook.md` | `scripts/ci/package-unica-plugin.py`, `crates/unica-bootstrap/src/`, `.github/workflows/unica-plugin-release.yml` |
| Поведение, зависящее от ОС | ADR-0009, область `PLATFORM` реестра | `crates/unica-coder/src/infrastructure/platform/`, `crates/unica-bootstrap/src/platform/`, страж `scripts/ci/check-rust-platform-boundary.py` |
| Само архитектурное правило | `architecture/invariants.md` или `architecture/quality-requirements.md` плюс запись в `spec/decisions/` | проверка, названная в поле `Check` этой записи |
**Строки комбинируются.** Одна задача обычно попадает сразу в несколько:
инструмент, который пишет платформенный XML, — это первая строка вместе со
второй; инструмент, который меняет файлы и обязан сообщить о влиянии на кеш, —
первая вместе с третьей; новый инструмент, запускающий долгую работу, — первая
вместе с четвёртой. Читайте объединение подходящих строк, а не одну самую
похожую.
Отдельно про `native_operations`. Реестр инструментов, контракты и дескрипторы в
слое application описывают вызов: имя, схему аргументов, форму результата. Саму
работу делает нативный обработчик в
`crates/unica-coder/src/infrastructure/native_operations/`, где на каждый домен
приходится свой файл — `form.rs`, `meta.rs`, `dcs.rs`, `code.rs`, `cfe.rs`,
`mxl.rs` и остальные. Там же лежит разбор аргументов, чтение и запись
источников. Это самая крупная часть кодовой базы: четыре самых больших файла
рабочего пространства Cargo — из этого каталога, и суммарно он на порядок больше
всего слоя application. Изменение поведения инструмента почти всегда происходит
там, а правка в `application/` только объявляет это поведение наружу.
## Релизы
Публикация версии в публичный маркетплейс выполняется по
`docs/release-runbook.md`. Прочитайте его прежде, чем действовать по любой
просьбе выпустить, отгрузить, продвинуть или доделать релиз: порядок шагов несёт
гарантию ADR-0008 о том, что каталог никогда не указывает на неокончательные
байты, и импровизация в нём отдаёт потребителям непроверенный пакет.
## Гигиена поиска
Не сканируйте локальные игнорируемые корпуса при обычном изучении репозитория:
- `target`
- `.build`
- `dist`
- `docs-local` (локальный исследовательский материал; в поставку не входит и
источником справки платформы не является — её отдаёт `unica.documentation.search`)
Датированные деревья планов и проектных записок отслеживаются гитом, но они
описывают, как было сделано прошлое изменение, а не как система ведёт себя
сейчас. Их тоже не сканируйте:
- `docs/design/**`
- `docs/plans/**`
- `docs/provenance/reviews/**`
Открывайте их только чтобы восстановить историю одного конкретного изменения, и
никогда не выводите из их текста действующее архитектурное правило. CI-тест
может закрепить архивный файл по пути как живой тестовый вход:
`tests/ci/test_format_profile_contract.py` читает
`docs/design/2026-07-23-platform-8-3-27-format-2-20-design.md`. Это не делает
прозу файла нормативной, но запрещает считать сам файл неиспользуемым; перед
удалением проверяйте `rg <path> tests/ scripts/`.
Начинайте с `rg` и `git ls-files`. В вопросах об упаковке предпочитайте
отслеживаемые файлы и сгенерированные артефакты пакета обходу файловой системы.
## Проектные документы и решения
Эти правила связывают скиллы мозгового штурма и планирования. Они старше
умолчаний самого скилла.
**Куда кладутся артефакты.** Проектные записки — в
`docs/design/YYYY-MM-DD-<topic>-design.md`, планы реализации — в
`docs/plans/YYYY-MM-DD-<feature-name>.md`. Это переопределяет каталоги по
умолчанию в скиллах `brainstorming` и `writing-plans`. Черновики сессии остаются
в игнорируемом `.superpowers/`; никогда не делайте `git add -f` для пути, который
репозиторий игнорирует.
**`spec/` — единственный слой нормативной архитектурной документации, но не
единственный источник истины репозитория.** Код, тесты, контрактные метаданные
пакета и спецификации форматов остаются выше него согласно порядку в начале
файла. Внутри `spec/` архитектурным выбором владеет раздел `Решение` записи ADR,
а выведенным проверяемым обязательством — поле `Rule` одного из двух реестров.
Описание системы, чек-лист и приёмка ссылаются на владельца по ID. Проектная
записка фиксирует путь к выбору и нормативной не становится.
**Прочитайте правила прежде, чем предлагать проект.** Изучая контекст проекта,
начните с `spec/architecture/invariants.md` и `spec/decisions/README.md`.
Подход, который противоречит принятому решению или записи реестра, либо
отбрасывается, либо предлагается вместе с записью, заменяющей прежнюю; скажите
прямо, что именно из двух, а не оставляйте противоречие на откуп ревью.
**Выделите решение, когда сдвинулся контракт.** Написав проектную записку и до
того, как звать пользователя её смотреть, решите, меняет ли работа архитектурный
контракт. Меняет, если затронуто хоть одно из:
- набор публичных инструментов `unica.*`, их аргументы или полезная нагрузка
результата;
- идентичность MCP-сервера или граница «единственный публичный сервер»;
- владение кешем или состоянием рабочего пространства, либо контракт доменных
событий;
- контракт упаковки, хоста или релиза;
- граница слоя или любое правило, которое несёт реестр инвариантов;
- создаётся политика, которой обязан следовать более чем один потребитель —
существующий или будущий (общее ядро, разделяемый writer, единый формат
вывода).
Если меняет — запись решения пишется в `spec/decisions/` тем же коммитом. Запись
короткая и нормативная; проектная записка остаётся её происхождением и
упоминается в разделе Context. Если не меняет — так и напишите в шапке.
**Каждая проектная записка открывается тремя полями:**
```markdown
- Date: `YYYY-MM-DD`
- Status: `draft` | `approved` | `superseded`
- Decision: `ADR-NNNN` | `none — no architectural contract changed`
```
`Decision: none` — это утверждение, которое ревью может отклонить, а не значение
по умолчанию. Формат проверяет `tests/ci/test_design_documents.py`.
## Именование записей
Идентификатор записи — это устойчивая ручка: его цитируют в описаниях PR, в
коммитах и в ветках обсуждений. Поэтому он не переименовывается вслед за
формулировкой и не переиспользуется после удаления записи.
Схемы у реестра и у решений разные, и различает их один признак: **номер уместен
там, где порядок несёт смысл, и вреден там, где не несёт.**
### Записи реестра — смысловой код без цифр
Формат: `INV-<ОБЛАСТЬ>-<КОД>` для инвариантов и `REQ-<ОБЛАСТЬ>-<КОД>` для
требований к качеству. Например `INV-MCP-NAMESPACE`, `REQ-PERF-DEADLINE`.
- Код — от одного до трёх слов заглавными через дефис, не длиннее 24 символов.
- Код называет **то, что правило защищает**, а не то, как оно реализовано.
Реализация меняется, защищаемое свойство — нет: `INV-MCP-DATA-DRIVEN-SCHEMA`
переживёт переезд дескрипторов в другой модуль, а `INV-MCP-TOOL-CONTRACTS-RS`
не переживёт.
- Цифр в коде нет. Реестр — это множество, а не последовательность: порядок
записей внутри области не значит ничего, и номер сообщал бы читателю
несуществующий приоритет.
- Код уникален во всём корпусе спецификаций и после вывода записи из обращения
другому правилу не достаётся.
- Смена смысла правила — это новая запись, а не переименование прежней. Иначе
цитата из старого обсуждения начнёт указывать на правило, которого автор
ссылки не имел в виду.
Шаблон, длину и уникальность проверяет
`tests/ci/test_architecture_registry.py`.
### Записи решений — номер и слаг
Формат: файл `NNNN-<слаг>.md`, цитирование — `ADR-NNNN`.
- Номер остаётся, потому что каталог решений — это хроника: по номеру видно, что
одно решение принято после другого, и цепочки замещения читаются в порядке.
- Смысл несёт слаг в имени файла, а не номер.
- Номера монотонны, израсходованный номер не выдаётся повторно, а решение,
переставшее действовать, получает статус `superseded` и остаётся на месте.
### Записи решений — граница неизменяемости
Запись становится историей в момент попадания в целевую ветку — для обычного
потока это `main`, — а не в момент, когда в шапке появилось `accepted`
(`INV-DOC-SUPERSEDE-NOT-EDIT`). Отсюда два разных режима работы с записью, и
ревью не смешивает их:
- Записи, которой в целевой ветке ещё нет, правки не запрещены: её содержание,
дату, номер и статус меняют внутри pull request, а потерявшую актуальность
запись удаляют, переписывают или объединяют с актуальной. Требовать здесь
новую запись вместо правки — ложное срабатывание правила.
- Запись, уже существующую в целевой ветке, не переписывают: изменение
оформляется новой записью, а прежняя получает `superseded` и разрешимую ссылку
на заменяющую.
- Статус `superseded` не выдают записи, которой в целевой ветке никогда не было
как `accepted`: замещать нечего, а в каталоге появилась бы история решения,
которого репозиторий не принимал.
- Номер, живущий только в параллельном pull request, окончательно не занят.
Перед слиянием обновитесь от целевой ветки и перенумеруйте свои записи по
фактическому порядку слияния.
Подробности жизненного цикла решений — в
[`spec/decisions/README.md`](spec/decisions/README.md).
## Обязательные навыки разработки MCP
При любой задаче, которая проектирует, создаёт или развивает MCP-сервер Unica,
до проектирования и реализации обязательно используйте `build-mcp-server`.
После выбора ветки работы применяйте специализированные навыки:
- `build-mcp-app` обязателен для MCP Apps, UI-ресурсов и интерактивных виджетов;
- `build-mcpb` обязателен для MCPB, локальной упаковки и поставки MCP-сервера;
- работа, совмещающая интерактивный интерфейс и MCPB-поставку, использует
навыки в порядке `build-mcp-server` → `build-mcp-app` → `build-mcpb`.
Не применяйте `build-mcp-app` или `build-mcpb` к работе, которая не затрагивает
их контур. Канонический источник комплекта — официальный пакет Anthropic
[`mcp-server-dev`](https://github.com/anthropics/claude-plugins-official/tree/main/plugins/mcp-server-dev).
Если хотя бы один обязательный навык недоступен, не начинайте MCP-работу, пока
- не установлен весь комплект. В Codex используйте системный `skill-installer`
- с repository `anthropics/claude-plugins-official`, ref `main` и путями:
+ не доступен весь комплект. В Codex явно вызовите `$skill-installer` и установите
+ только отсутствующие навыки из repository
+ `anthropics/claude-plugins-official`, ref `main`, передав соответствующие пути:
- `plugins/mcp-server-dev/skills/build-mcp-server`;
- `plugins/mcp-server-dev/skills/build-mcp-app`;
- `plugins/mcp-server-dev/skills/build-mcpb`.
+
+ Не передавайте установщику путь уже установленного навыка: он не перезаписывает
+ существующий каталог. Ожидаемое назначение каждого навыка —
+ `$CODEX_HOME/skills/<имя>/SKILL.md`. После установки завершите текущий ход. На
+ следующем ходе проверьте, что все три навыка доступны для явного вызова и их
+ `SKILL.md` читаются. Если навык не появился, перезапустите Codex и повторите
+ проверку; до успешной проверки MCP-работу не продолжайте.
В Claude Code установите официальный плагин:
```text
/plugin marketplace add anthropics/claude-plugins-official
/plugin install mcp-server-dev
```
Для другого совместимого агента скопируйте каждый каталог навыка целиком —
`SKILL.md` вместе с `references/` — в каталог skills этого агента. Официальное
руководство: [Build with Agent Skills](https://modelcontextprotocol.io/docs/2026-07-28/develop/build-with-agent-skills).
## Правила разработки
- Устраняйте причины, а не симптомы.
- Сначала падающий тест, потом исправление. На любой найденный дефект — кем бы
он ни был найден: вами, ревью, CI или пользователем — пишется тест,
воспроизводящий его на текущем коде; запустите тест, убедитесь, что он падает
и падает именно по причине дефекта, и только после этого правьте код. Тест,
написанный после правки, не падал ни разу: он закрепляет текущее поведение,
но не доказывает ни того, что дефект воспроизводился, ни того, что устранена
именно его причина. Дефект, который тестом не воспроизводится, — утверждение,
которое ревью может отклонить, а не обходной путь: назовите причину и то, чем
проверено исправление вместо теста.
- Выносите наружу противоречия между допущениями, документацией, тестами и
поведением в runtime.
- Держите публичную границу MCP как один сервер с именем `unica` и инструментами
`unica.*`, пока запись решения не изменит этот контракт.
- Видимые модели скиллов остаются MCP-first. Пути прямого запуска упакованных
скриптов не должны возвращаться там, где уже есть нативный инструмент
`unica.*`, кроме описанных утилитарных исключений.
- Один каталог плагина обслуживает Codex и Claude Code. Держите оба манифеста на
одной версии, держите `.mcp.json` независимым от хоста и не добавляйте
необязательные ключи манифеста или каталога, не проверив, что их принимает
самый старый поддерживаемый клиент: там нераспознанный ключ — ошибка загрузки,
а не предупреждение.
- Изменение публичной поверхности — инструментов `unica.*`, идентичности
MCP-сервера, маршрутизации скиллов, упаковки или границ слоёв — правит
`spec/architecture/invariants.md` и запись-владельца из `spec/decisions/` тем
же набором изменений. Отгрузить код и отложить документацию значит оставить
реестр утверждать то, что сборка опровергает.
- Ссылайтесь на инвариант или решение по ID, а не копируйте его нормативную
формулировку. Если нужно пояснить применение правила, ставьте ID владельца
рядом и не выдавайте пояснение за независимую норму.
## Топология pull request
- По умолчанию — один самостоятельно проверяемый PR на одно связное изменение, с
базой `main` или явно названной релизной веткой.
- Не открывайте PR, базой которого является head-ветка другого открытого PR. Не
используйте дочерние PR как очередь правок по ревью: коммитьте и пушьте такие
правки в head-ветку существующего PR.
- Перед открытием PR посмотрите предполагаемую базу на GitHub. Если она
принадлежит открытому PR, остановитесь и либо возьмите его head-ветку, либо
спросите пользователя, как поступить; имя ветки само по себе не доказывает
независимость базы.
- Стек из PR допустим, только если пользователь явно попросил именованный стек и
задал порядок слияния и перебазирования. Каждый участник стека объясняет в
описании своего PR, кто его родитель, где проходит граница самостоятельного
ревью и как он будет закрыт.
- Если агент не может пушить в head существующего PR, он обязан предоставить
патч или попросить доступ; создавать дочерний PR в обход нельзя.
- Дефект, найденный во время ревью, разбирается по его происхождению.
- **Привнесённый этим же PR** — правится в нём же, коммитом в его head-ветку.
Отдельный PR на собственную регрессию оставляет в истории заведомо сломанный
коммит и делит ревью одного изменения на два.
- **Существовавший до него** — идёт независимым PR с базой `main` или
заводится задачей. В текущий PR он не втягивается: это расширяет его границу,
смешивает несвязанные изменения в одном ревью и задерживает то, что уже
готово.
- Когда происхождение неочевидно, решает `git log -S` или `git blame` по
строке дефекта, а не ощущение. Если и после этого неясно — дефект считается
существовавшим ранее и выносится наружу.
- Ни в одном из двух случаев дефект не превращается в неявный стек PR.