починены находки финальной сверки: закрытие задачи переехало за коммит

- sprint.md прямо запрещал шаг, который пайплайн теперь делает: раздел «кто и
  когда закрывает» переписан под снятую границу приёмки
- закрытие задачи стало шагом 11, после коммита: раньше упавший коммит оставил
  бы задачу закрытой без следа работы
- контракт close --implemented больше не обещает состоявшуюся приёмку
- слот «куда копируются критерии приёмки» убран из session: на него отвечает
  пайплайн, а канон его не заводил
- research/ в таблице ролей вернул adversary; журнал версий поднимает CLAUDE.md
  целиком, а не тремя пунктами из восьми
- TODO и REMAINING перестали занижать: коммитов одиннадцать, переписок три
This commit is contained in:
av
2026-08-03 14:48:01 +03:00
parent 0eab075f84
commit 68218208b7
8 changed files with 70 additions and 55 deletions
+10 -10
View File
@@ -1,7 +1,7 @@
# Остатки, открытые вопросы и принятые пределы
Состояние на 2026-08-03, после разбора восьми тем и первых двух коммитов
реализации (`ad1779b`, `9cef452`).
Состояние на 2026-08-03, после разбора восьми тем и 11 коммитов реализации
(`ad1779b` `HEAD`).
План работ — [TODO.md](TODO.md). Решения с причинами — [DECISIONS.md](DECISIONS.md).
Здесь то, что **не** является работой из плана: незакрытые риски, честно принятые
@@ -9,16 +9,17 @@
## Главный незакрытый риск
**Калибровка не сделана, а charter'ы переписаны второй раз.**
**Калибровка не сделана, а charter'ы переписаны трижды.**
Первый раз девять charter'ов правили при выносе в плагин: предмет проверки
заменили ссылкой на раздел брифа. `references/calibration.md` требует при такой
правке замерить, помогла ли она, — **замера не было**. Второй раз их переписали
сейчас, коммитом `9cef452`: ссылка на раздел брифа заменена путём документа
канона.
коммитом `9cef452`: ссылка на раздел брифа заменена путём документа канона.
Третий — коммитами `0eab075` и следующим, по находкам ревью: `adversary`, `ops`,
`reimpl`, `rubric` и `triage` правились ещё раз.
Два неизмеренных изменения подряд **в том самом месте, где присваивается
severity**. Пробы готовы и синтетических не нужно — четыре реальные находки
**Три неизмеренных изменения подряд** в том самом месте, где присваивается
severity. Пробы готовы и синтетических не нужно — четыре реальные находки
прошедшей сессии healthlog:
- скелет из `null` затирает маршрут тренировки молча и необратимо;
@@ -41,9 +42,8 @@ severity**. Пробы готовы и синтетических не нужн
Список работ — в [TODO.md](TODO.md). Здесь только то, что стоит держать в голове
отдельно:
- **`git push`.** Четыре коммита с `av-dev-pm` и `av-dev-pipeline` не отправлены
на origin, поэтому установленный маркетплейс их не видит и до сих пор стоит на
`092d07c`. Это буквальное объяснение фразы «плагины ни к одному проекту не
- **`git push`.** 11 коммитов не отправлены на origin, поэтому установленный
маркетплейс их не видит и до сих пор стоит на `092d07c`. Это буквальное объяснение фразы «плагины ни к одному проекту не
подключены»: подключать пока нечего.
- **Ни один скилл не прогонялся на живом проекте.** `docs.py` прогнан на
healthlog и jellybit в режиме `check` и находит осмысленный дрейф; `init`,
+2 -2
View File
@@ -8,8 +8,8 @@
## 0. Предусловие
- [ ] `git push`четыре коммита с `av-dev-tasks` и `av-dev-pipeline` не
отправлены на origin, поэтому маркетплейс их не видит (37)
- [ ] `git push`11 коммитов не отправлены на origin, поэтому маркетплейс их
не видит и стоит на `092d07c` без единого нового плагина (37)
- [ ] `claude plugin marketplace update av-dev-skills` — повторно, после push
## 1. Репозиторий плагинов
+18 -17
View File
@@ -288,20 +288,6 @@ description: Автономно проводит одну задачу чере
и пройди по разделам его раскладки: каждый документ канона получает строку.
Канона в проекте тоже нет — назови это исходом и предложи `av-dev-pm:canon`.
### 9а. Закрыть задачу
**Вызови Skill `av-dev-pm:tasks`** и попроси закрыть задачу как реализованную —
он владеет форматом и двигает строку между индексами сам. Путь к его скрипту не
выясняй и индексы руками не правь: мост между плагинами — вызов скилла, а не
путь.
Плагина в проекте нет — вызов не разрешится. Тогда **ничего не выдумывай**:
скажи в докладе, что учёт задач остаётся за владельцем, и назови исход.
**Приёмщик и исполнитель здесь совпадают**, и закрытие не окончательно: человек
на сессии может вернуть задачу (`reopen` с причиной). Поэтому доклад по критериям
приёмки — не формальность, а единственное, по чему приёмка вообще возможна.
### 10. Коммит
Коммить **в текущую ветку** (`git rev-parse --abbrev-ref HEAD`), сам ветку не
@@ -313,9 +299,24 @@ description: Автономно проводит одну задачу чере
сделано», тело списком 1–3 пункта, без трейлеров). Одна задача — один осмысленный
коммит.
Готово — доложи кратко. Задача к этому моменту **закрыта шагом 9а** (или учёт
явно оставлен владельцу, если плагина нет). Доклад — то, по чему человек проводит
приёмку и решает, не вернуть ли задачу `reopen`.
### 11. Закрыть задачу — **после коммита, не раньше**
**Вызови Skill `av-dev-pm:tasks`** и попроси закрыть задачу как реализованную —
он владеет форматом и двигает строку из `SPRINT.md` сам. Путь к его скрипту не
выясняй и индексы руками не правь: мост между плагинами — вызов скилла, а не
путь.
**Порядок обязателен.** Закрытие удаляет файл задачи; сделанное до коммита оно
оставило бы задачу закрытой без единого следа работы, если шаг 10 упадёт.
Плагина в проекте нет — вызов не разрешится. Тогда **ничего не выдумывай**:
скажи в докладе, что учёт задач остаётся за владельцем, и назови исход.
**Приёмщик и исполнитель здесь совпадают**, и закрытие не окончательно: человек
на сессии может вернуть задачу (`reopen` с причиной). Поэтому доклад по критериям
приёмки — не формальность, а единственное, по чему приёмка вообще возможна.
Готово — доложи кратко.
- **исход** задачи одним из трёх слов и, если не «сделана», чем ограничен
результат;
+1 -1
View File
@@ -62,7 +62,7 @@ kebab-case.
| `database.md` | что лежит в хранилище и какими настройками | `ops`, `adversary`, `reimpl` |
| `security.md` | против кого защищаемся и что вне модели | `adversary` |
| `conventions/` | как мы пишем код | `code` |
| `research/` | что показала реальность, а не документация | `specs`, `reimpl`, `ops` |
| `research/` | что показала реальность, а не документация | `specs`, `reimpl`, `ops`, `adversary` |
| `adr/` | почему решено именно так | `architecture` |
| `review.md` | как настроен конвейер и что уже проскакивало | `triage`, каждый проход — свою часть |
| `openspec/specs/` | что система делает — нормативно | `specs` |
@@ -38,7 +38,10 @@ upgrade` идёт по записям снизу вверх от версии п
документам канона.
10. `conventions.md``conventions/`, `local-research.md``research/`.
11. Завести `docs/security.md` с периметром первой строкой и `docs/adr/`.
12. В `CLAUDE.md`: severity рядом с каждым инвариантом, семантика гейта,
запреты с путями; убрать раздел «Процесс», если он пересказывает пайплайн.
12. В `CLAUDE.md`: severity рядом с каждым инвариантом; семантика гейта (чем
краснеет безусловно, где логи, чего в нём нет и кто тогда гоняет дорогое);
**имя основной ветки**; запреты с путями; где `testdata` и куда писать
временное; **что считается необратимым**; общий станок; ориентир по размеру
спринта. Убрать раздел «Процесс», если он пересказывает пайплайн.
13. В `openspec/config.yaml` оставить только нужды генерации и ссылки.
14. Добавить шаг `docs.py check` в гейт проекта.
+5 -5
View File
@@ -208,13 +208,13 @@ python3 $tk reopen <слаг> --dir D --reason … # приёмка не со
спринт.
3. **Необратимое** — что спрашивается у человека всегда (тот же слот, что у
скилла `tasks`; дом один).
4. **Как критерии приёмки переживают удаление файла задачи** — файл удаляется
при закрытии, поэтому критерии копируются туда, где их увидит приёмщик
(предложение об изменении, описание ветки, тело коммита). Куда именно —
решает проект.
5. **Ориентир по размеру спринта**, если он замерялся. Умолчание — 5–8 задач, и
4. **Ориентир по размеру спринта**, если он замерялся. Умолчание — 5–8 задач, и
это **ориентир, а не закон**.
Слота «куда копируются критерии приёмки» здесь нет намеренно: на него отвечает
**пайплайн проекта**, перенося их в описание изменения при его заведении. Проект
без пайплайна называет своё место сам, в слоте 1.
Числа проекта (сколько задач в спринте, сколько времени на задачу, каков прирост
беклога) — предмет шага 2, а не константы этого скилла.
+28 -17
View File
@@ -61,19 +61,27 @@
### Кто и когда закрывает
**Задачу закрывает не пайплайн, а владелец спринта — после приёмки.** Порядок:
**Задачу закрывает агент-оркестратор — тот же, кто её и сделал**, последним шагом
пайплайна, после коммита. Порядок:
1. пайплайн доводит задачу до коммита и **докладывает исход**; файл задачи он не
трогает — своей процедуры закрытия у него нет;
2. приёмщик (не исполнитель) сверяет критерии поимённо и выносит вердикт;
3. вердикт сошёлся — владелец спринта зовёт `close <slug> --implemented`
командой учёта задач из `CLAUDE.md` проекта.
1. пайплайн доводит задачу до коммита;
2. **после коммита** зовёт `Skill av-dev-pm:tasks` и закрывает задачу
(`close <slug> --implemented`); строка уходит из `SPRINT.md`;
3. **докладывает исход и по каждому критерию — оракул и наблюдаемый исход.**
Это доклад приёмщику, а не отметка «принято».
Обратный порядок ломает приёмку физически: закрытие **удаляет файл**, и
приёмщику, нашедшему расхождение, возвращать нечего.
**Приёмщик и исполнитель здесь совпадают, и это принято сознательно** — цена
названа в `SKILL.md`, раздел «Стимулы». Поэтому закрытие **не окончательно**, а
доклад по критериям — не формальность: он единственное, по чему приёмка вообще
возможна.
**Дорога назад существует и обязана быть названа.** Закрыли раньше вердикта, а
приёмка не сошлась — `tasks.py reopen <slug> --reason "приёмка не сошлась: …"`:
**Порядок «коммит, потом закрытие» обязателен.** Закрытие удаляет файл задачи;
упавший коммит после закрытия оставил бы задачу закрытой без единого следа
работы.
**Дорога назад существует и обязана быть названа.** Человек на сессии сверил
критерии, и приёмка не сошлась — `tasks.py reopen <slug> --reason "приёмка не
сошлась: …"`:
файл восстанавливается из истории git, строка возвращается в набор идущего
спринта (или в беклог, если спринта нет), строка кладбища снимается. Тело
восстанавливается **на момент удаления** — всё, что было дописано позже, живёт
@@ -84,13 +92,16 @@
Три условия, без которых пункт про критерии не исполняется никем:
1. **Критерии переживают файл задачи.** Файл удаляется при закрытии, поэтому
критерии копируются туда, где их увидит приёмщик — в предложение об
изменении, описание ветки, тело коммита. Куда именно, называет `CLAUDE.md`
проекта. Иначе приёмка проверяет критерии из файла, которого больше нет.
2. **Принимает не исполнитель.** Отдельный контекст — сабагент или человек, —
которому дают изменение, отчёт исполнителя и отчёты ревью. Тот же принцип
декорреляции, на котором стоит любой конвейер проверки: занизивший и
проверяющий не должны быть одним контекстом.
критерии копируются туда, где их увидит приёмщик. Куда именно — **отвечает
пайплайн проекта, а не слот в `CLAUDE.md`**: он переносит их в `tasks.md`
изменения на шаге заведения change. Проект без пайплайна называет своё место
сам.
2. **Принимает человек на сессии, а не отдельный агент.** Декорреляция
исполнителя и приёмщика в момент закрытия **снята** (решение о снятии и его
цена — в `SKILL.md`, «Стимулы»). Опоры остались три: сохранённый отчёт триажа
в `openspec/changes/<id>/review/` — независимый артефакт, `SPRINT.md` под git
и `reopen`. Переоценка на сессии и есть момент, когда критерии видит не
исполнитель.
3. **Расхождение — дефект критериев.** Приёмщик правит критерии и возвращает
задачу исполнителю **в этом же спринте**: ответ есть, остаток есть, по тесту
про остаток это не выход из спринта.
+1 -1
View File
@@ -116,7 +116,7 @@ python3 $tk add --dir D --slug S --title T [--type goal|idea|epic] [--section S]
python3 $tk edit S --dir D [--title T] [--hook H] [--type T] [--goal G] [--add-tag a,b] [--rm-tag c]
python3 $tk move S --dir D --section S [--reason R] [--after S | --first]
python3 $tk close S --dir D --reason R # в REJECTED.md + удалить (ушла без реализации)
python3 $tk close S --dir D --implemented # просто удалить (реализована, приёмка сошлась)
python3 $tk close S --dir D --implemented # просто удалить (реализована и закоммичена)
python3 $tk reopen S --dir D --reason R # вернуть закрытую: приёмка не сошлась
python3 $tk sprint start --goal S --dir D | take S… | drop S… --reason R | close [--dissolve --reason R]
python3 $tk init --dir D [--sections …] [--plan-sections …] [--items …] [--backlog …] …