«Разработка» называла слишком много: роадмап весь про разработку, и
секция с таким именем не отличалась от остальных ничем. Стало
Сопровождение | Operations.
Смысл расширен вместе с именем: было «инструмент и процесс», стало «чем
держат проект: инструмент, процесс, эксплуатация». Расширение не
косметическое — английское Operations при узком смысле обещало бы
эксплуатацию, а внутри лежал бы линтер. Метрики, логи, инфраструктура и
выкладка в эту секцию просятся и так.
Заодно синхронизирован словарь трёх мест канона, которые про одну тему.
Сопровождение — всё, чем держат проект; эксплуатация — его часть, работа
системы на проде. ROADMAP.md, секция Сопровождение — план работ;
architecture.md, раздел «Эксплуатация» — как устроено сейчас;
эксплуатационный проход ревью — оптика проверки. Сливать их в одно слово
было бы ошибкой: они отвечают на разные вопросы. Синхронизирован
словарь, а не границы; дом — canon.md. Слово «поддержка» запрещено
вовсе: в нём слышится помощь пользователю.
Граница с возможностями проходит по тому, кто наблюдает: «приложение
сообщает о своём состоянии» — возможность, «дежурный видит состояние на
одном экране» — сопровождение.
Версия канона не менялась, и это законно: ни один проект на каноне 3 не
стоит, оба держат канон 2. Запись версии 3 правится как черновик, а не
как история — версия отделяет одно состояние проектов от другого, а не
одну редакцию текста от другой.
DECISIONS тема 25 (ЧЧЧ, ШШШ, ЩЩЩ, следствия 96–97).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
В уставе стоял заголовок «Форма записи — только для docs/tasks/items/»:
условная половина, которая на документе канона молчит, а на задаче
включается. Условное правило агент применяет по своему усмотрению, а
усмотрение и есть то, чего от него не ждут. Два коротких устава без
условий надёжнее одного длинного с ними.
Разделены не по охвату — по глубине. Язык проверяется по словам и
фразам, поштучно: залог, оценки, стоп-слова, англицизмы, жаргон. Форма
записи требует понять, что задача делает, и открыть файл цели, на
которую она ссылается, чтобы сверить, какую строку «Завершения» задача
двигает. Слитый проход одну половину делает дорогой, а вторую —
поверхностной. Отсюда и разные модели: doc-wording на sonnet,
task-form на opus. Первый подметает, второй судит смысл, и ровно на
суждении обкатка показала провал.
Каждый устав отказывается от чужой половины прямо: увиденное не по своей
части идёт строкой в границах покрытия, а не находкой. Две проверки
одного места расходятся и начинают спорить. Исключение ровно одно и
названо: неудачное слово в заголовке судит task-form, потому что
заголовок целиком его.
У task-form появилось шестое правило, которого не было ни у кого: связь
задачи со строкой «Завершения» её цели. Оно единственное читает больше
одного файла и единственное смотрит набор, а не запись — строка
«Завершения», к которой не относится ни одна поданная задача,
докладывается отдельным блоком. Это граница между вычиткой и разбором,
проведённая внутри правила.
Порог правки переехал в language.md помеченным домом «порог-правки» и
копируется в оба устава: правка без нарушенного правила не делается,
систематичность нарушения — не довод в его пользу. Дублировать его
руками значило бы получить два разных порога через месяц. Копий стало
шесть при пяти домах.
Порядок вызова — сперва task-form: его находки меняют решение «брать или
не брать», а язык меняет только цену чтения.
DECISIONS тема 23 (ССС–ФФФ, следствия 91–93).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Имя пришло из задач, но правила языка относятся ко всем проектным
текстам: документам канона, решениям ADR, запискам разведки. Форма
записи — вторая половина устава — верна только для файлов
docs/tasks/items/, и теперь это сказано заголовком раздела, а не
подразумевается. Вход расширен: список файлов или каталог, вперемешку
тоже.
Обкатка на тестовом наборе из 13 записей показала дыру в пороге
вмешательства. Агент нашёл, что раздел «Затрагивает» в нескольких
записях называет не только границу, но и её будущее состояние, — и
промолчал, объяснив это принятым стилем каталога. Записи писал один
агент за один заход: систематичность здесь значит ровно обратное —
правило не применялось вовсе. В устав добавлено: одна и та же ошибка в
пяти файлах даёт одну находку на весь набор с перечнем, но не даёт права
промолчать. Принятым стилем считается только то, что назвал зовущий или
что записано в конвенциях проекта.
Единственная находка агента попала в слово из собственного скилла. «Цель
про станок, а не про игру» — метафора, перенесённая в тестовую запись из
tasks/SKILL.md. Проверка показала худшее: «станок» в каноне уже занят,
«общий станок» это красная проверка, врывающаяся в замороженный спринт
(canon.md, session/SKILL.md). Одно слово в двух смыслах, тот же класс,
что и «окружение» в теме 19. Заменено на «работа над инструментом и
процессом» — как названа и секция роадмапа.
DECISIONS тема 22 (ППП, РРР, следствия 89–90).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Обкатка скилла tasks на выдуманном проекте — консольные крестики-нолики
на JavaScript, каталог заведён с нуля тем же скриптом. Форма вылезла
раньше содержания, и правки все про неё.
Заголовок отвечает на вопрос типа записи, и форм три: цель —
утверждение о возможности, задача — глагол в неопределённой форме
(допускается «не» перед ним), идея — назывное, без обещания. Причина не
стилистическая: описательный заголовок называет состояние, а из
состояния не видно, чего от работы ждут — «Ничья объявляется, пока
клетки есть» одинаково читается как жалоба и как задание. Отсюда же
разница индексов: роадмап — список возможностей, беклог — список работ,
и перепутанные формы делают каждый похожим на другой.
Механизировано ровно то, что механизируется: check считает заголовки,
где первое слово не на -ть/-ти/-чь, и печатает число в блоке здоровья.
Замечанием на файл нельзя — эвристика грубая, а на 97 записях двух живых
проектов это поток одинаковых строк, после которого пропускают весь блок.
Годность формулировки судит отдельный агент task-wording, а не чек-лист
в скилле: сейчас формулировку пишет и проверяет один агент в одном
контексте, а самопроверка текста слабее всего там, где формулировка
казалась удачной при написании. Он ничего не правит — возвращает готовые
формулировки, и заголовок с «зачем» показываются человеку, потому что
по ним задачу выбирают. Ничего из того, что ловит tasks.py check, он не
трогает намеренно: это был бы второй дом для правила.
Заголовки секций — с прописной, после заголовка пустая строка, во всех
индексах. Канонические имена стали Готово | Запланировано | Направления
| Разработка (англ. Done | Planned | Directions | Tooling), сверка везде
по нижнему регистру, так что старые индексы читаются по-прежнему.
Отбивка живёт на записи, а не на вставке: через Plan.index проходит
каждая правка индекса, а мест вставки три.
Имя секции принадлежит заголовку индекса, файл на неё только ссылается.
Это разрешает единственную неоднозначность починки — расхождение в одном
регистре правится в пользу заголовка. Без него переезд на канон оставил
бы «Готово» в роадмапе и «готово» в каждом файле цели, и свести это было
бы некому. Регистр правится только у канонических секций: имена секций
беклога выбирает проект.
Обкатка нашла два дефекта, которых не находили ни линтеры, ни свои
проверки. Вставка в пустую секцию съедала отбивку перед следующим
заголовком — пропуск пустых строк теперь идёт только до первой непустой.
Мета, разорванная пустой строкой, теряла поля молча: check видел лишь
следствие («без рода работы») и советовал edit --kind, который дописывал
второе такое же поле. Поле меты в теле стало ошибкой с названной
причиной, и --fix её намеренно не чинит — какое из двух значений верное,
знает человек.
DECISIONS тема 20 (ЕЕЕ–ККК, следствия 82–85), changelog канона v3
пополнен двумя пунктами и двумя шагами переезда, TODO — два шага для
healthlog и jellybit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
готово | запланировано | направления | разработка, англ. done | planned |
directions | tooling. Из четырёх предложенных имён отвергнуто одно, и по
проверяемой причине: «окружение» уже занято — в architecture.md это боевое
окружение приложения, «где работает, что рядом, кто перезапускает», и одно
слово в двух смыслах развело бы документы канона.
Секции роадмапа стали каноническими, в отличие от секций беклога, и разница
выведена, а не назначена: у каждой секции роадмапа своя семантика, в первую
пишет сам close, и роадмап, названный по-своему, читался бы только своим
автором. Секции беклога — полки, смысла не несут, остаются делом проекта.
check проверяет три вещи: состав закреплён (чужая секция — ошибка), все четыре
обязаны быть, язык один на весь индекс. Проверено на том случае, ради которого
правило и заводилось: «Что уже пройдено», которую healthlog вёл руками, теперь
называется ошибкой поимённо. Оба языка прогнаны вживую, включая close в
английский роадмап.
Ключа tasks.achieved_section не появилось — секция достигнутого опознаётся по
каноническому имени в любом из языков; --roadmap-sections у init упразднён,
выбирать больше нечего.
Названные вслух компромиссы: «готово» слегка тянет в трекерную рамку
«состояние работы», тогда как секция про возможность — перевесила читаемость;
цель в «запланировано» может быть уже наполовину построена, это очередь, а не
«не начато», «в работе» живёт в SPRINT.md.
DECISIONS 19: ГГГ переписан, добавлен ДДД, следствие 78 заменено. TODO 7 закрыт.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Основной инструмент владельца отвечал на половину своего вопроса. Оценка идёт
по поведению: что приложение уже может и чего ещё не может, — а close
--implemented удалял у достигнутой цели и файл, и строку, так что роадмап по
построению показывал только «что осталось». Свидетельство лежало в самом
роадмапе healthlog: секция «Что уже пройдено» на двадцать строк прозы, руками,
с припиской «Эти звенья целями не заведены: закрытая цель записи не оставляет».
Теперь строка с датой переезжает в секцию достигнутого, файл удаляется
по-прежнему. Вторым домом поведения это не делает: нормативное поведение живёт
в openspec/specs, роадмап отвечает, когда и в каком порядке оно появилось.
Ссылки на файл в строке нет — файла больше нет, форма как в REJECTED.md.
Цель стала возможностью приложения, задача — шагом к ней:
- заголовок цели отвечает на «что приложение будет уметь»; свойство поведения
(«сообщает о своём состоянии», «исход не зависит от порядка») — тоже
возможность и переформулировки не требует;
- «Завершение» — списком, а не абзацем: задача ссылается на его строку, и это
новая защита от «отрефакторить X» вместо прежнего «наблюдаемо снаружи».
Заодно видно обратное: строка, к которой не относится ни одна задача, —
незакрытая часть возможности;
- работа над инструментом и процессом на этот вопрос не отвечает и живёт в
отдельной секции.
Цель обязательна не у всякой задачи. Прежнее «иначе она не попадёт ни в один
спринт» было угрозой, а не аргументом, и заставляло операционную работу
выдумывать себе направление. Граница по роду: feature без цели не бывает, fix,
chore и research живут без неё и входят в набор помимо цели спринта.
Тип [epic] упразднён: зонтиком стала цель, а слишком крупный шаг дробится под
ней. Ноль употреблений на 97 записей двух живых проектов.
Секции роадмапа — умеет / строим / направления / станок, четыре вместо двух;
имена приняты как временные и запаркованы (TODO 7). Имя секции достигнутого
знает скрипт — docs/.pm.json, ключ tasks.achieved_section. reopen цели снимает
строку достигнутого, круг проверен вживую.
Всё дописано в версию 3 канона: она ещё нигде не выкачена. DECISIONS 19,
YYY–ГГГ и следствия 78–81.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Три изменения одной версией, потому что все три про одно — можно ли
оценить задачу, не открывая код.
PLAN.md → ROADMAP.md. Слово «план» значило в репозитории три разных вещи:
оглавление целей, план реализации внутри задачи и PLAN.json разовой
адаптации. Переименовано целиком — ключ конфига tasks.plan → tasks.roadmap,
--index roadmap, --roadmap-sections, --roadmap. Старый ключ в docs/.pm.json
не игнорируется молча: скрипт останавливается кодом 3 и называет
переименование, иначе проект искал бы опечатку там, где на самом деле
версия канона.
Род работы — тег kind:feature|fix|chore|research, вторая ось поверх типа
записи. В один префикс их не свести: идея бывает про функцию, эпик функцией
и является. Дом — тег, потому что теги здесь единственный механизм
разметки, а list --kind работает даром; цена принята — в строку индекса род
не попадает. Словарь закрыт, иначе он разъедется на bug/bugfix/fix/defect.
Отдельно легализован chore: у него «что станет наблюдаемо иначе» отвечается
разработчику, а раньше такие задачи либо не заводились, либо придумывали
себе пользовательскую пользу — и это второе хуже, оно проходит проверку.
Раздел «Затрагивает» — границы, которых изменение касается: эндпоинт,
таблица и миграция, формат на диске, публичный тип пакета. Без него задача
оценивается по объёму текста, а не по объёму поверхности. Механизируется
только наличие непустого раздела: полноту перечня машина не видит.
Род и границы требуются к взятию в спринт, а не к заведению — тот же приём,
что уже работает для критериев приёмки, и по той же причине. check о
пропаже только напоминает: иначе два живых проекта покраснели бы на 98
задачах, заведённых до этого решения.
Плюс правила языка задач: англицизм, у которого есть русское слово,
заменяется; термин не из паспорта, архитектуры или конвенций вводится
строкой или не употребляется; задача, которую не удаётся сказать просто,
чаще всего не одна задача.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Последнее место, где поля писались одной строкой через ·: цель, дата начала и
слаг спринта. После переезда меты задачи в блок эта строка осталась
единственным исключением, а объяснять два формата дороже, чем иметь один.
Старая шапка читается по-прежнему — GOAL_LINE берёт строку и с ведущим «- »,
SPRINT_SLUG_LINE и раньше искала по всей строке. Починки для неё нет и не
нужно: SPRINT.md переписывается целиком на sprint start и очищается на sprint
close, так что старая форма живёт не дольше идущего спринта.
Форма заодно описана в task-format.md — до сих пор она жила только в коде,
и человек, читавший документ формата, о ней не узнавал.
Проверено на временном проекте: start → take → check → подсунутая старая
шапка → drop → close; цель и слаг читаются в обеих формах.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Строкой через · мета уезжала за экран уже на трёх полях, а сам разделитель
приходилось запрещать в тексте причины и «зачем». Списком поле занимает свою
строку, запрещать нечего, и проверка длины схлопнулась до одной строки.
«Хук» переименован в «Зачем» — поле отвечает на вопрос «зачем нужна эта
задача». Слово «цель» под это не годится: оно уже занято [goal]-файлами и
тегом goal:<слаг>, и в одном блоке значило бы две разные вещи.
Хирург мета-строки — самая мутная функция скрипта, резавшая строку на куски с
запоминанием пробелов каждого, — заменён на «прочитать поля и собрать блок
заново». Тем же ходом старая форма переезжает в новую: check называет её
дрейфом, check --fix переписывает списком, Хук становится Зачем. Чужие
нераспознанные поля пересборку переживают.
Проверено на восьми сценариях: add, edit, move с причиной, sprint take/drop,
close --reason + reopen (мета собирается из текста, поднятого из git),
миграция старой формы вместе с чужим полем, отказ на мете без секции.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Метафора требовала расшифровки при каждом употреблении, и в текстах она и
расшифровывалась: «звено упорядоченной линии продукта», «тематический куст —
цель, в последовательность не встающая». Если название приходится объяснять
рядом с каждым употреблением, объясняет не название.
Новые имена называют ровно то свойство, которым секции различаются: в первой
очередь значима и обоснована прозой, во второй порядка нет вовсе.
Заголовки строчные, как ядро/инфра в беклоге: имя секции одновременно значение
для --section, и проза приведена к тому же виду, чтобы «--section Порядок» не
выглядело правильным написанием.
Версия канона не меняется: canon.md называет файл PLAN.md и о его секциях не
говорит — их дом заголовки ## индекса, умолчание живёт в tasks.py.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Два независимых сабагента на av-dev-pm и av-dev-pipeline. Две находки нашли оба.
Главная — моя же перестановка закрытия за коммит сломала reopen и батч. close
печатал «дорога назад из git», а reopen искал коммит удаления, которого в новом
порядке ещё нет: шаг 11 последний, учёт остаётся незакоммиченным. Проверено
прогоном — отказ кодом 2 на свежезакрытой задаче. Тем же грязным деревом
ломались rebase и worktree remove в батче: каждая закрывшая задачу ветка уехала
бы в провалившиеся.
Починено с обеих сторон: reopen берёт текст из HEAD, если коммита удаления нет,
а шаг 11 коммитит учёт вторым коммитом.
Вторая — канонический пример docs/.pm.json убивал tasks.py. Четыре документа
показывали ключ tasks.sections, которого скрипт не знает: неизвестный ключ это
код 3 на любой команде. Проект, заведённый по канону дословно, остался бы без
работы с задачами, а docs.py при этом печатал «канон соблюдён». Секции живут в
заголовках индекса и второго дома не получают.
Остальные восемнадцать: init писал конфиг в упразднённый .tasks.json;
looks_like_tasks не видел переименованный индекс; урожай спринта терял автотег
после sprint close; ответ на вопрос по инструкции оставлял задачу незабираемой;
adopt требовал недостижимого зелёного; путь отчёта триажа не переживал archive;
review-specs не имел режима для стыка после слияния; три остатка «шаг 9а» несли
предкоммитную позицию закрытия; sprint.md отрицал сам себя в пункте «Сделана».
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- av-dev-tasks → av-dev-pm; канон определён единственным reference-файлом,
который читают все три новых скилла
- canon: check/adopt/upgrade плюс docs.py — раскладка, битые ссылки, версия,
маркеры долга, сверки миграций и capability с документацией
- tasks и session: путь docs/tasks жёсткий, конфиг переехал в docs/.pm.json,
слот «Команда учёта задач» убран в пользу вызова скилла, раздел «Стимулы»
переписан под совпавших приёмщика и исполнителя