From bff3c9e1180a34a2a0dcf49d2172a637674ca5ac Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Mon, 3 Aug 2026 14:31:41 +0300 Subject: [PATCH] =?UTF-8?q?README,=20HISTORY=20=D0=B8=20REMAINING=20=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D0=B5=D1=81=D0=BE=D0=B1=D1=80=D0=B0=D0=BD=D1=8B=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=B4=20=D0=BD=D0=BE=D0=B2=D1=83=D1=8E=20=D0=BA?= =?UTF-8?q?=D0=B0=D1=80=D1=82=D0=B8=D0=BD=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - README: три плагина, канон документов, явное обновление маркетплейса - HISTORY: сжатый AGENTIC-TASKS — что отвергнуто и почему, числа первого замера - REMAINING: главным риском названа несделанная калибровка при двух подряд переписываниях charter'ов; закрытые разбором вопросы убраны --- HISTORY.md | 85 ++++++++++++++++++++++++ README.md | 141 ++++++++++++++++++++++++--------------- REMAINING.md | 181 +++++++++++++++++++++------------------------------ 3 files changed, 248 insertions(+), 159 deletions(-) create mode 100644 HISTORY.md diff --git a/HISTORY.md b/HISTORY.md new file mode 100644 index 0000000..ab53ac1 --- /dev/null +++ b/HISTORY.md @@ -0,0 +1,85 @@ +# Как процесс дошёл до текущей формы + +Сжатие черновика `AGENTIC-TASKS.md` (497 строк), лежавшего незакоммиченным в +корне healthlog. Правила процесса из него переехали в плагины и здесь **не +повторяются** — второй дом для тех же правил ровно то, против чего документ и +был написан. Остаётся то, чего в плагинах нет и быть не должно: **что отвергнуто +и почему, и числа первого замера**. + +Решения текущего круга разбора — [DECISIONS.md](DECISIONS.md). + +## Что отвергнуто и почему + +### Scrum целиком + +Терминология близка — спринт, груминг, определение готовности, ретроспектива, — +и она удобна: не нужно изобретать слова. Но добрая половина Scrum существует ради +синхронизации людей, которых здесь нет: исполнителей двое, человек и агент. + +**Не взято:** тайм-бокс (спринт ограничен объёмом, а не временем), velocity и +оценки в очках, ежедневный стендап (стендап — это и есть диалог), планирование +отдельно от груминга (владелец беклога один), роль скрам-мастера. + +**Взято:** цель спринта, заморозка набора, определение готовности, груминг — +каждое потому, что снимает решение, которое иначе принимается заново каждый раз. +**Ретроспектива взята содержанием, но не отдельным ритуалом**: она шаг той же +сессии. Отдельная встреча ради трёх вопросов — плата ритуалом без выгоды. + +### Приоритеты у задач + +Заменены целью. Ни секциями, ни списком: «что делать дальше» отвечает набор +спринта, а между спринтами порядок не нужен никому — брать задачи вне спринта +запрещает заморозка. Отсюда нет ни «повысить», ни «встать раньше»: вместо +повышения — смена цели или включение в набор. + +### Секция «блокеры» в беклоге + +Блокер — **состояние** (спринт не может продолжаться ни одной задачей), а не +полка: он живёт ровно до ответа человека, и записи в такой секции не успевают +жить. Основание измерено: **два «блокера» из двух ничего не блокировали** — в +обоих файлах записано «что заблокировано: ничего». Отсюда разделение вопроса и +блокера. + +### Запись о сделанной задаче + +У сделанной задачи записи не остаётся: файл и строка удаляются. Ей хватает +коммита и документации; вторая запись была бы вторым домом для того же факта. +Вопрос «что было в спринте N» отвечается даром — `SPRINT.md` лежит под git. + +## Числа первого замера + +Одна сессия, шесть закрытых задач. **Выборка нетипичная, статус — первый +замер.** Приведены не как константы, а чтобы следующий замер было с чем +сравнить. + +- **Беклог вырос с 29 до 38**: заведено 15, закрыто 6 (две родились и умерли + внутри сессии). Прирост **2,5 задачи на одну закрытую** — ревью и + эксплуатационные проходы производят работу быстрее, чем мы её потребляем. +- **Одна из шести задач была внеплановой** — дозакрытие находок, вставленное в + ход работы, потому что дефект затирал маршрут тренировки необратимо, а + пересборка журнала повторяла то же поражение. Отсюда класс «необратимый + ущерб» как единственное, что врывается в замороженный спринт: правило не + придумано, оно уже применялось. +- **15 часов на шесть задач**: пять заняли от 1 ч 16 мин до 2 ч 14 мин (медиана + ≈ 1 ч 55 мин), шестая — 5 ч 42 мин в два захода. Мерилось **до** сужения + конвейера ревью; замер устарел и подлежит повторению. +- **Шесть задач за сессию** — предел одного контекста, а не спринта. Спринт + сессией не ограничен, перенос числа условен. + +Умолчание «5–8 задач в спринте» выведено отсюда и остаётся **ориентиром, а не +законом**. Пересматривается на разборе прошедшего спринта — шаг 2 сессии, и ничей +другой. + +## Что из черновика было не решено и решено позже + +| Вопрос черновика | Где решён | +| --- | --- | +| название процесса | решение Z: имени нет, процесс это `av-dev` | +| «Ближайшая цель» прозой в `docs/plan.md` как второй дом цели спринта | решение E: `plan.md` растворяется в `PLAN.md` целей | + +## Судьба самого черновика + +Документ описывал процесс, а процесс живёт в плагинах этого репозитория, не в +healthlog. Содержимое разошлось: правила — в `av-dev-pm:tasks` и +`av-dev-pm:session`, обоснования и числа — сюда. Оригинал в git не коммитился и +удаляется при переезде healthlog на канон. diff --git a/README.md b/README.md index 5fdbf62..0ab7fa8 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,116 @@ # av-dev-skills -Личный маркетплейс плагинов и скилов для разработки — чтобы подключать их к -проектам по мере необходимости, а не держать в глобальном `~/.claude`. +Личный маркетплейс плагинов для разработки. Процесс имени не имеет — он и есть +`av-dev`. + +Что решено и почему — [DECISIONS.md](DECISIONS.md). Что осталось сделать — +[TODO.md](TODO.md) и [REMAINING.md](REMAINING.md). Как процесс дошёл до текущей +формы — [HISTORY.md](HISTORY.md). + +## Плагины + +- **av-dev-pm** — управление продуктом. Владеет всем `docs/`. + - `init` — новый проект: интервью по свободному описанию замысла → первичная + документация; + - `canon` — привести проект к канону документов: `check` / `adopt` / + `upgrade`, плюс скрипт `docs.py`; + - `docs` — содержимое канона по ходу разработки: ADR из архивного + `design.md`, промоут конвенций, запись в разведку и журнал ревью, чистка + архитектуры; + - `tasks` — задачи и цели каталогом markdown-файлов; + - `session` — ритуал между спринтами и ведение спринта. +- **av-dev-pipeline** — исполнение. **Требует OpenSpec.** + - `task-pipeline` — задача через полный цикл SDD, от постановки до коммита; + - `task-batch` — несколько задач разом, каждая в своём worktree; + - `review-pipeline` — конвейер ревью: гейт, сверка со спеками, враждебные + постановки, эксплуатационный постмортем, независимая реализация, + архитектура, обязательный триаж. Девять агентов-проходов. +- **av-dev-git** — `commit`: сообщения в личном стиле. +- **av-dev-backlog** — **устарел**, заменён `av-dev-pm`. Живёт до перевода + последнего проекта. + +Соглашение об именах: имя **плагина** длинное с префиксом `av-dev-`, имена +**скилов** внутри — короткие. Вызов выходит вида `/av-dev-<плагин>:<скилл>`. + +## Канон документов проекта + +Все проекты приводятся к одной раскладке — так проще ориентироваться, когда +проектов много, и рядом OpenSpec тоже держит строгую структуру. Определение — +[av-dev-pm/skills/canon/references/canon.md](av-dev-pm/skills/canon/references/canon.md). + +``` +CLAUDE.md инварианты с severity, команды, семантика гейта +docs/ + .pm.json версия канона и пути для проверок + passport.md зачем и для кого; чем НЕ является + architecture.md как сложено — обзор; окружение и эксплуатация + database.md схема хранилища; настройки с числовым значением + security.md периметр; недоверенный вход; что вне модели + conventions/ как пишем код + что уже механизировано + research/ что показала реальность; числа с провенансом + adr/ почему — промоут поверх архивных design.md + review.md настройка конвейера + журнал дефектов + tasks/ цели, беклог, спринт, отклонённое +openspec/ + specs//spec.md что система делает — нормативно + changes/archive/ архив изменений с design.md +``` + +**Отдельного файла-брифа для ревью нет.** Проходы читают эти документы напрямую; +карта «что нужно проходу → где лежит» — +[project-facts.md](av-dev-pipeline/skills/review-pipeline/references/project-facts.md). + +Прийти в старый проект и перевести его на канон — `/av-dev-pm:canon`. Канон +версионируется, и проекты повышаются по [журналу +версий](av-dev-pm/skills/canon/references/changelog.md). ## Подключение -Типичный способ — подключить плагин **на уровне проекта**, чтобы он был активен у -всех, кто открывает репозиторий. Флаг `--scope project` пишет прямо в -`.claude/settings.json` проекта (коммитится в репозиторий) — из интерактивной -сессии Claude Code: +Плагин подключается **на уровне проекта**, чтобы был активен у всех, кто +открывает репозиторий: ``` /plugin marketplace add https://git.vakhrushev.me/av/dev-skills.git --scope project -/plugin install av-dev-backlog@av-dev-skills --scope project +/plugin install av-dev-pm@av-dev-skills --scope project +/plugin install av-dev-pipeline@av-dev-skills --scope project +/plugin install av-dev-git@av-dev-skills --scope project ``` -…или те же команды из терминала: - -``` -claude plugin marketplace add https://git.vakhrushev.me/av/dev-skills.git --scope project -claude plugin install av-dev-backlog@av-dev-skills --scope project -``` - -Обе формы дописывают в `.claude/settings.json` ровно то, что можно внести и -руками — маркетплейс в `extraKnownMarketplaces`, плагин в `enabledPlugins`: +…или те же команды из терминала через `claude plugin …`. Обе формы дописывают в +`.claude/settings.json` проекта то, что можно внести и руками: ```json { "extraKnownMarketplaces": { "av-dev-skills": { - "source": { - "source": "git", - "url": "https://git.vakhrushev.me/av/dev-skills.git" - } + "source": { "source": "git", "url": "https://git.vakhrushev.me/av/dev-skills.git" } } }, "enabledPlugins": { - "av-dev-backlog@av-dev-skills": true + "av-dev-pm@av-dev-skills": true, + "av-dev-pipeline@av-dev-skills": true, + "av-dev-git@av-dev-skills": true } } ``` -При первом открытии проекта Claude Code попросит доверять воркспейсу; после -подтверждения маркетплейс и включённые плагины подгружаются автоматически. Ключ -включения — `"<плагин>@<маркетплейс>": true`. +**Маркетплейс — git-клон удалённого репозитория, и он обновляется явно:** +`claude plugin marketplace update av-dev-skills`. Локальные коммиты, не +отправленные на origin, до него не доедут — это уже однажды выглядело как +«плагин не работает». -Без `--scope project` те же команды пишут в user-конфиг — разовая установка -только себе, настройки проекта не трогаются: +**При установке в проект, где лежали проектные копии** скиллов и агентов +(`.claude/skills/{task-pipeline,review-pipeline,task-batch}`, +`.claude/agents/<проект>-review-*.md`) — снеси их. Две копии одного скилла +расходятся, и побеждает та, что короче названа. + +## Структура репозитория ``` -/plugin marketplace add https://git.vakhrushev.me/av/dev-skills.git -/plugin install av-dev-backlog@av-dev-skills -``` - -## Плагины - -- **av-dev-backlog** — ведение беклога задач как каталога markdown-файлов (одна - задача = один файл `.md` + строка в индексе `README.md`). Скилл - `backlog`: заведение задачи из диалога, разбор находок аудита/ревью, груминг, - приоритизация, декомпозиция, штурм идей. Реализацией не занимается. Вызов: - `/av-dev-backlog:backlog`. -- **av-dev-git** — git-обвязка для личных проектов. Скилл `commit`: сообщения - коммитов в личном стиле (русский, опциональный scope-префикс, первая строка - «что сделано», тело 1–3 пункта, без co-authored). Вызов: `/av-dev-git:commit`. - -Соглашение об именах: имя **плагина** длинное с префиксом `av-dev-` (уникально в -маркетплейсе), имена **скилов** внутри — короткие. Вызов выходит вида -`/av-dev-<плагин>:<скилл>`. - -## Структура - -``` -.claude-plugin/marketplace.json — манифест маркетплейса -/.claude-plugin/plugin.json — манифест плагина -/skills//SKILL.md — скилы плагина (авто-обнаружение) +.claude-plugin/marketplace.json манифест маркетплейса +/.claude-plugin/plugin.json манифест плагина +/skills//SKILL.md скилы (авто-обнаружение) +/skills//references/ что читается по ссылке из скилла +/skills//scripts/ tasks.py, docs.py +/agents/ charter'ы сабагентов ``` diff --git a/REMAINING.md b/REMAINING.md index 8a7a116..a345b66 100644 --- a/REMAINING.md +++ b/REMAINING.md @@ -1,137 +1,102 @@ -# Остатки и открытые вопросы +# Остатки, открытые вопросы и принятые пределы -Состояние на 2026-08-03, после ввода `av-dev-tasks` и `av-dev-pipeline` -(коммиты `9219f4a` → `20dca29` → `0eca206`). +Состояние на 2026-08-03, после разбора восьми тем и первых двух коммитов +реализации (`ad1779b`, `9cef452`). -Плагины написаны, проверены тремя проходами ревью и починены по находкам. Но -**ни один из них ещё не подключён ни к одному проекту**, а часть работы -осознанно отложена. Здесь то, что осталось, — с причинами, потому что через -месяц причина забывается раньше факта. +План работ — [TODO.md](TODO.md). Решения с причинами — [DECISIONS.md](DECISIONS.md). +Здесь то, что **не** является работой из плана: незакрытые риски, честно принятые +пределы и вопросы, у которых пока нет ответа. -## Что осталось сделать +## Главный незакрытый риск -Порядок примерно соответствует зависимостям: верхнее мешает нижнему. +**Калибровка не сделана, а charter'ы переписаны второй раз.** -### 1. Калибровка переписанных проходов +Первый раз девять charter'ов правили при выносе в плагин: предмет проверки +заменили ссылкой на раздел брифа. `references/calibration.md` требует при такой +правке замерить, помогла ли она, — **замера не было**. Второй раз их переписали +сейчас, коммитом `9cef452`: ссылка на раздел брифа заменена путём документа +канона. -Все девять charter'ов ревью переписаны при выносе в плагин: предмет проверки -заменён ссылкой на раздел брифа. `references/calibration.md` самого плагина -требует при такой правке замерить, помогла ли она, — **замера нет ни одного**. - -Оценка «проход всё ещё нашёл бы находку» получена рассуждением по текстам, и -ревьюер честно пометил её `Confidence: medium`. По правилам плагина такая -оценка не поднимается выше `major`. - -Пробы готовые, синтетических не нужно — четыре реальные находки прошедшей -сессии healthlog: +Два неизмеренных изменения подряд **в том самом месте, где присваивается +severity**. Пробы готовы и синтетических не нужно — четыре реальные находки +прошедшей сессии healthlog: - скелет из `null` затирает маршрут тренировки молча и необратимо; - откат бинаря поверх новой схемы стартует без единого слова; - канонизация внутри транзакции — 768 МиБ пика, 5.019 с удержания блокировки; - `-1 >= -1` читается как «журнал разобран целиком». -Ожидаемый результат замера известен и его стоит проверить в первую очередь: -метод переносится, а **severity деградирует** — третья находка без слота под -представление данных и настройки хранилища превращается из `critical` с -прогнанным оракулом в условное наблюдение. Оркестратор реагирует на severity, -поэтому цена обобщения — не «не найдём», а «найдём и не почините». +Ожидаемый исход известен и его стоит проверить первым: метод переносится, а +**severity деградирует**. Третья находка без слота под представление данных и +настройки хранилища превращалась из `critical` с прогнанным оракулом в условное +наблюдение. Ровно ради этого случая канон развёл числа (`docs/research/`) и +настройки (`docs/database.md`) по разным домам и **обязал проход их сшивать** — +но работает ли обязанность, не проверено. Оркестратор реагирует на severity, +поэтому цена — не «не найдём», а **«найдём и не починим»**. -### 2. Завести брифы +Замер стоит перед переездом jellybit и блокирует его (решение 39). -Скилл `av-dev-pipeline:project-brief` написан и собирает бриф из `CLAUDE.md`, -архитектуры, Taskfile и конвенций. Но брифов нет ни у healthlog, ни у jellybit, -а без них конвейер идёт в деградированном режиме: `critical` по основанию -«нарушен инвариант проекта» не присваивается. +## Что ещё не сделано -При починке бриф заполнялся на обоих проектах для проверки контракта (841 и -734 строки) — эти заполнения были **черновыми, в скретчпаде**, и в проекты не -попали. Повторить и положить в репозитории. +Список работ — в [TODO.md](TODO.md). Здесь только то, что стоит держать в голове +отдельно: -### 3. Переезд healthlog на новый формат - -`docs/backlog/` → `docs/tasks/` с `items/`, `PLAN.md`, `BACKLOG.md`, -`SPRINT.md`, `REJECTED.md`. Скилл `av-dev-tasks:adopt` для этого написан и -прогнан на **копии** живого беклога: 12 целей, 38 задач, 36 переименований -слагов из транслита в английские, 86 ссылок поправлено в 36 файлах, `check` -зелёный. - -Переходное состояние после переезда известно числом: задач без цели — 0, без -двух критериев приёмки — 29. `check` при этом зелёный, но `sprint take` такие -задачи не возьмёт; закрывается порциями переоценки на сессиях. - -Вместе с переездом придётся переписать то, что противоречит новой семантике: -раздел «Процесс» в `CLAUDE.md`, преамбулу `docs/plan.md` («свой приоритет», -«беклог — что брать следующим») и строку «блокеры разбираются пачками» — по -новому определению блокер эскалируется немедленно, пачками разбираются вопросы. - -### 4. Удалить проектные копии - -После подключения плагинов в healthlog остаются два источника правды: -`.claude/skills/healthlog-task-pipeline/`, `healthlog-review-pipeline/` и девять -`.claude/agents/healthlog-review-*.md`. Проектные факты из них уезжают в бриф, -сами файлы удаляются. - -У jellybit хуже: его скиллы называются `task-pipeline`, `review-pipeline`, -`task-batch` — **ровно как в плагине**. Claude Code не переопределяет их, а -держит обе пары, так что короткое имя может увести в устаревшую проектную -копию, и молча. Тексты плагина зовут своё через пространство имён -(`av-dev-pipeline:review-pipeline`), но проектные копии всё равно надо удалять -при установке. - -### 5. Перевод jellybit - -Отложен сознательно: сперва обкатать на healthlog один-два спринта, потом -переносить. Иначе мы одновременно вводим непроверенный процесс и ломаем -работающий проект. - -Объём: беклог с приоритетами `высокий/средний/низкий` без целей и спринтов, -одиннадцать ревью-агентов старого поколения (включая `idiom` и `negative`, -упразднённые в healthlog), три скилла с коллизией имён. Часть `capability-map` -живёт в памяти агента, а не в файле, — при переводе это надо материализовать. +- **`git push`.** Четыре коммита с `av-dev-pm` и `av-dev-pipeline` не отправлены + на origin, поэтому установленный маркетплейс их не видит и до сих пор стоит на + `092d07c`. Это буквальное объяснение фразы «плагины ни к одному проекту не + подключены»: подключать пока нечего. +- **Ни один скилл не прогонялся на живом проекте.** `docs.py` прогнан на + healthlog и jellybit в режиме `check` и находит осмысленный дрейф; `init`, + `canon adopt`, `canon upgrade` и скилл `docs` не исполнялись ни разу. +- **Проектные копии в healthlog и jellybit.** Два `.claude/skills/` и одиннадцать + `.claude/agents/` старого поколения. У jellybit хуже: его скиллы названы + `task-pipeline`, `review-pipeline`, `task-batch` — **ровно как в плагине**. + Claude Code не переопределяет их, а держит обе пары, так что короткое имя может + увести в устаревшую копию, и молча. ## Открытые вопросы -**Что делать с `av-dev-backlog`.** В маркетплейсе сейчас оба плагина, и их -описания ловят один и тот же триггер («добавь задачу в беклог») — агент выберет -случайный. Пометить устаревшим, удалить из маркетплейса или оставить до -перевода jellybit, который пока на нём и живёт. +**Как проверять, что канон не разошёлся с проектами после `upgrade`.** `canon +check` сверяет версию, но не то, что миграционные записи journal'а применены +верно. Проект может нести `"canon": 2` и не иметь того, что версия 2 требовала. -**Оставлять ли раздел `## Триггеры` в контракте брифа.** Он задумывался как -проектная конкретизация правила выбора профиля ревью, но при заполнении на -обоих проектах выродился в пересказ таблицы профилей самого скилла. Контракт не -запрещает скопировать общее правило, а слот, который заполняется копированием, -пользы не несёт. +**Форма ADR при пересмотре решения.** Правило «старая запись получает статус +`заменено на`» требует, чтобы кто-то заметил, что новое решение отменяет старое. +Механической проверки нет, а принуждённое отрицание на шаге синка спрашивает про +`adr/` вообще, а не «не отменяет ли это что-то из существующего». -**Название процесса.** Плагины названы, процесс — нет. Обсуждались кодовое имя -из Средиземья (`fellowship` / `council`, под стать `rivendell` и `umbar`), -нейтральная «каденция» и описательные варианты. Для плагинов выбрана функция -(`av-dev-tasks`, `av-dev-pipeline`), но у процесса как целого имени нет. - -**Судьба `AGENTIC-TASKS.md`.** Черновик дизайна лежит в корне healthlog и не -закоммичен. Содержимое переехало в плагины, значит документ стал вторым домом -для тех же правил — а расхождение двух домов ровно то, против чего он сам и -написан. Либо удалить, либо сжать до истории решений («почему не Scrum», числа -первого замера, что и почему отвергнуто). +**Что делать с `av-dev-backlog` после перевода jellybit.** Помечен устаревшим и +переписан так, чтобы не ловить триггер. Удалять его из маркетплейса или оставить +как есть — решится, когда jellybit переедет. ## Известные пределы — приняты, чинить не планируется -**Транзакции на несколько файлов нет.** POSIX её не даёт без журнала. Окно -сжато до цепочки `rename` без ввода-вывода, а всё, что в окне может разъехаться, +**Транзакций на несколько файлов нет.** POSIX её не даёт без журнала. Окно сжато +до цепочки `rename` без ввода-вывода, а всё, что в окне может разъехаться, сделано производным и восстанавливается `check --fix` без потерь. -**Оракул в критериях приёмки проверяется эвристикой.** Число пунктов -проверяется жёстко, наличие оракула — по слову, и это **только замечание**. -В тексте прямо сказано, что проверено меньше, чем требуется, — притворяться тут -дороже, чем признаться. +**Оракул в критериях приёмки проверяется эвристикой.** Число пунктов проверяется +жёстко, наличие оракула — по слову, и это **только замечание**. В тексте прямо +сказано, что проверено меньше, чем требуется. -**Recall прохода по конвенциям равен качеству конвенций проекта.** Своего -списка у него больше нет: критерий берётся из файла проекта. На проекте с -тонкими конвенциями проход почти пуст, и charter это признаёт вслух. +**Recall прохода по конвенциям равен качеству конвенций проекта.** Своего списка +у него нет: критерий берётся из `docs/conventions/`. На проекте с тонкими +конвенциями проход почти пуст, и charter это признаёт вслух. -**Доменного словаря в брифе нет.** Charter'ы получают факты, но не термины; -словарь проход строит каждый раз заново из спек и архитектуры. Цена не -измерена. +**Доменного словаря в каноне нет.** Проходы получают факты, но не термины; +словарь строится каждый раз заново из спек и архитектуры. Цена не измерена. -**`adopt` не удаляет источники и не правит подписи ссылок.** Удалять чужое -молча нельзя, а подпись вида `[docs/backlog](docs/tasks/BACKLOG.md)` правится -глазами. И то и другое печатается в отчёте, а не проглатывается. +**Смысловые дубли ловит только агент.** `docs.py` видит раскладку, но не то, что +`docs/specs/recognition.md` описывает то же, что capability `recognition`. +Граница объявляется вслух в каждом отчёте — это единственная защита от +«соблюдено» на проекте с тремя лишними файлами. + +**Приёмщик и исполнитель совпали.** Граница «пайплайн не закрывает задачу» снята +сознательно (решение P); три защиты из раздела «Стимулы» держатся теперь текстом, +а не механикой. Реальные опоры — сохранённый отчёт триажа, `SPRINT.md` под git и +`reopen`. Это записано в самом скилле, а не спрятано. + +**Копия правила в шаблонах проекта.** `adr/README.md` и `review.md` уезжают в +репозиторий и обязаны там что-то говорить, поэтому правило канона в них +копируется намеренно. Цена: правка такого правила обязана тянуть запись в журнал +версий, иначе копия в проекте останется старой молча.