Плагин владел двумя разными вещами сразу — документацией проекта и учётом работ, — и это мешало обеим. Канон нельзя было поставить без задач, задачи без канона, а язык проектных текстов лежал внутри скилла canon и потому принадлежал половине. Теперь плагина два, каждый ставится сам по себе. av-dev-docs: скиллы canon, docs, init; агенты doc-consistency, doc-code-drift, doc-wording; скрипт docs.py. av-dev-tasks: скиллы tasks, session; агенты task-form, task-wording; скрипт tasks.py. Между собой они зовутся через пространство имён, а не по пути в чужое дерево. Все относительные ссылки, пересекшие границу плагина, сняты: tasks больше не указывает в canon, canon не указывает в tasks. Вместо ссылки — имя скилла и оговорка, что вызов может не разрешиться, и это исход, а не поломка. То, что нужно обоим дословно, стало вторым общим домом. Словарь «Сопровождение и эксплуатация» назван в трёх местах трёх плагинов — секция роадмапа, раздел «Эксплуатация» в architecture.md, тема ревью operations — и ни один из трёх им не владеет; он уехал в shared/operations.md, а canon.md и скилл задач везут копии. Три перечня «чем держат проект» уже разъезжались на «метриках и логах» против «мониторинга», так что ссылка тут не годится: плагин, поставленный в одиночку, получил бы указатель в никуда. Тем же способом язык: у av-dev-tasks появилась своя копия language.md. Копий стало 18 при 8 домах. Переименования разведены по смыслу, а не заменой строки: где речь о каноне — av-dev-docs, где об учёте задач — av-dev-tasks. В пайплайне таких мест одиннадцать, и оба адресата там встречаются вперемешку. Журналы (DECISIONS, TODO, HISTORY) намеренно не тронуты: они описывают состояние на момент записи. По той же причине оставлена наблюдённая строка в комментарии docs.py — она цитирует конфиг живого проекта, а не называет плагин. Не входит в этот заход и названо отдельно: слияние canon и docs в один скилл, разделение docs/.pm.json на два конфига и переезд openspec в пайплайн. Гейт зелёный: копии, фронтматтеры, диаграммы, json. Оба скрипта прогнаны после переезда — docs.py version и tasks.py check на фикстуре. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
10 KiB
Задачи из аудита и ревью
Ревью и аудиты — код-ревью, архитектурный проход, аудит безопасности, любой разбор другим агентом — порождают находки, часть которых становится задачами. Это отдельный интейк со своей опасностью, зеркальной интейку из диалога.
- Интейк из диалога грешит переполнением: из одной мысли рождается пять файлов.
- Интейк из ревью грешит сваливанием: сорок сырых находок превращаются в сорок файлов. Беклог раздувается, а следующая переоценка склеивает их обратно.
Защита от сваливания — та же, что в самом ревью: кластеризация по причине, а не файл-на-находку. Если у ревью был триаж — половина работы уже сделана, бери его выход. Если нет — триажируй сам, прежде чем заводить.
Находка агента — не задача
Мнение агента — гипотеза, пока у неё нет свидетельства (падающий тест, воспроизводимый шаг, положение руководства). Согласие нескольких находок само по себе достоверность не повышает: это один источник, высказавшийся несколько раз.
Отсюда фильтр входа, поверх обычного «не делаем сейчас + пожалеем о потере»:
- Находка со свидетельством, отложенная к исполнению → задача. Свидетельство и последствие переносим в тело — это её «почему», то самое, что переживает запись.
- Находка без свидетельства / низкой уверенности → сырьё:
research, у которого раздел «Вопрос» и есть недостающее свидетельство («при каких условиях это воспроизводится»). Неfix: безВоспроизведенияего в спринт не возьмут, и правильно — чинить нечего, пока непонятно, что ломается. Судьба сырья — штурм, где либо найдётся подтверждение, либо оно уедет вREJECTED.md. - Уже починено по ходу ревью → ничего. Починенное не заводим.
- Развилка, решённая при ревью → ничего; решённая «потом» → задача с
вопросом в разделе «Вопросы» и тегом
question.
Порядок
-
Возьми выход триажа, а не сырые находки. Сырой отчёт — это симптомы до дедупликации; в нём одна причина размазана по нескольким строкам.
-
Кластеризуй по причине. Пять находок об одном отсутствующем инварианте — одна задача, а не пять. Класс мелочи (nits, косметика) — один пакетный файл со списком пунктов, а не файл на каждую запятую.
-
Дедуп против живых задач и
REJECTED.md. Аудит переоткрывает уже заведённое и уже выкинутое. Нашлось среди живых — дописываем находку в существующий файл. Нашлось вREJECTED.md— это сигнал: причина отказа могла устареть, выноси пользователю, а не заводи молча заново. -
Разложи по целям — там, где цель нужна. Большинство находок ревью это
fixиchore, и цель им не требуется: они служат работоспособности, а не направлению, и в спринт входят помимо его цели. Придуманная им цель — ровно то враньё, от которого спасает тип.Цель обязательна у находки, которая оказалась новой возможностью (
feature): нашлось поведение, которого никто не заказывал, и его надо либо заказать целью, либо убрать. Подходящей цели нет — заведи её (add --type goal --section Направления) в том же проходе. -
Покажи карту до создания файлов. Кластер → задача / сырьё / строка в пакетный файл / уже заведено / отброшено, и под какую цель — пачкой через
AskUserQuestion. Это тот же барьер, что и «три кандидата» в интейке из диалога: массовое заведение файлов без подтверждения — ровно тот отказ, ради которого интейк из ревью и выделен. Дешёвая мелочь по явному согласию может заводиться и без поштучного вопроса — но карта пользователю предъявляется всё равно. -
Заводи утверждённое через
tasks.py add, с тремя добавками:- тег партии —
--tag review-ГГГГ-ММ-ДД(илиaudit-<slug>), чтобы весь заход разбора поднимался одной командойlist --tag …; - тип —
--type, и он не по умолчаниюfix: починкой считается расхождение с заявленным поведением, а находка «этого свойства никто не заказывал» — этоfeature, находка «не знаем, как поведёт себя драйвер» —research. Тип, розданный оптом, врёт ровно там, где по нему потом отбирают, и требует не тех разделов: каждомуfixпридётся заполнитьВоспроизведение, а у находки без свидетельства его нет; - провенанс в теле — кто нашёл, каким проходом, с каким свидетельством. Без него через месяц не отличить проверенную находку от догадки.
- тег партии —
-
tasks.py check.
Куда девается серьёзность, если приоритетов нет
Приоритетов нет, и отображать серьёзность некуда — но выкидывать её нельзя. Правило замены:
- тяжёлая находка со свидетельством → задача под ту цель, которой она
угрожает, и кандидат в ближайший набор: серьёзность здесь превращается в
довод при выборе цели следующего спринта, а не в уровень в файле. Довод
записывается причиной в мете (
--reason), иначе к моменту набора его никто не вспомнит; - находка, ломающая уже идущий спринт, — не интейк вовсе: см. правило
вторжения в скилле
session. В беклог она падает, только если врываться не положено; - низкая уверенность или нет свидетельства → сырьё (
researchс пустым разделом «Вопрос»); - мелочь → строка в пакетный файл;
- уже починено / развилка решена сейчас → ничего.
Словарей серьёзности много, и отображать их механически не на что: при сомнении — вопрос пользователю, а не догадка.
Поимённая сверка
Интейк считается выполненным, только если каждая находка триажа получила исход: слаг заведённой задачи, ссылку на существующую, строку пакетного файла или запись «не заведена: причина». Нулевой урожай при непустом отчёте триажа виден сразу — и это единственный способ отличить «находок не было» от «не стал заводить». Список составляет не тот, кто отчитывается о заведении.
Границы покрытия отчёта — то, что ревью проверить не смогло, — не находки и в задачи не идут: у них нет предмета. Их место в докладе, не в беклоге.
Доклад
- Источник (какое ревью/аудит, сколько находок на входе).
- Свёрнуто в задачи: N кластеров из M находок, со слагами, целями и тегом партии.
- Что не заведено и почему: починено инлайн, уже заведено, стало сырьём, ушло в
REJECTED.md. - Поимённая сверка: находок на входе N, исход есть у N.
tasks.py check.