142659bfd1aa4d3ea223433195b5f159539f2f51
106
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
142659bfd1
|
язык: чекпоинт и синк вошли в словарь, опиниативный снят
Три слова жили в текстах, не входя в закрытый словарь правила 6, — то есть выглядели словарём, не будучи им. Решение по каждому своё. Чекпоинт и синк внесены с определением: первый называет плановый стоп, на котором ждут ответа, второй — сверку каждого документа канона с работой, с обязательным отрицанием по нетронутым. Русские замены обоих называют либо исход, либо обряд, но не саму работу. Опиниативный заменён на «проход с мнением» в 13 местах и добавлен к снятому рядом с конфляцией и гайдом. Копии правил пересобраны resync.py; версию канона это не двигает — в репозиторий проекта отсюда ничего не уезжает. |
||
|
|
96dafc9011
|
вычитка обслуживания: план называет глубину, уставы знают прогон без метки
Проходы берут вход, потолки и состав половин из метки, а на прогоне обслуживания метки нет — оба взяли бы их наугад и молча по-разному. План сценария теперь называет глубину прямо: basics — сверка с потолком 2, code — вход small, потолки 3 и 2 и включённая третья половина. Третья половина code включена не для полноты: без неё security и architecture не смотрит вообще никто. Границы покрытия переписаны честно — requirements не смотрел никто, две другие темы сверены только против записанных инвариантов и только если проход по коду шёл. Уставы review-code и review-basics знают прогон без метки, их описания тоже; триаж знает, что план сценария встаёт на место плана разметки. В скилле задач уточнено: тип не выбирает метку, но предлагает сценарий, а меняется он командой edit --type, а не исполнителем по ходу. Плюс язык: заголовок, два оборота и right-size на русском. |
||
|
|
95fed623e7
|
обслуживание: найденная дельта останавливает работу предложением, а не отказом
Стоп по найденной дельта-спеке говорил только «поведение меняется, дальше идёт решение». Классификация при этом падала на человека в момент, когда весь материал для неё у исполнителя, а задача выглядела сломанной, хотя она просто оказалась шире своего типа. Порядок теперь из трёх шагов: назвать тип, которым задача оказалась (fix — расходится с заявленным, feature — снаружи появляется то, чего не было), объяснить простым языком, что нашлось, и дать два решения — переформулировать запись и решать процессом того типа следующим прогоном либо прекратить работу. Третьего решения, «доделать как обслуживание», нет. Тип исполнитель предлагает, меняет его av-dev-tasks:tasks и только после ответа: переклеенный на ходу тип назначает себе другой процесс и другую глубину проверки. Сделанное при любом решении остаётся в рабочем дереве незакоммиченным. |
||
|
|
42849c13eb
|
resolve: третий сценарий — обслуживание, у цикла SDD там нет входа
Задача, не меняющая поведения (тулчейн, зависимости, сборка, гит-хуки, перенос, чистка), шла полным циклом решения. Все его шаги стоят на дельта-спеках, а у chore их нет по построению: цикл не урезан ради дешевизны, он остаётся без входа. Признак — связка: тип записи предлагает, отсутствие дельт подтверждает, а расхождение признаков это стоп. Размер признаком не стал намеренно: «мелкое — коротким путём» и есть самая дешёвая лазейка. Планового стопа у сценария нет вовсе — объяснять человеку нечего, выбора там не делают; правило необратимого поэтому действует жёстче, чем в двух других. Ревью идёт фиксированным планом без метки и без разметчика — autotests и operations, плюс conventions с техническим разбором, когда дифф трогает код. Конвейер получил раздел «Прогон без change»: он написан вокруг change, и без этой строки вызов упирался бы в предпосылку OpenSpec. Главный шаг сценария — синк документации, а триггеры ADR работают стоп-признаком: своего источника у обслуживания нет, и решение с ценой уходит в разведку. |
||
|
|
f22e7ed829
|
вычитку зовёт тот, кто правил, а не тот, кто синкал
Вычитка документов была привязана к синку, а разведка синком себя не считает — и не доставалась ей вовсе. Условие вызова теперь правка: правил документы — зови doc-wording, трогал записи — task-form и task-wording. У разведки вычитка стала шагом 6, между записью и гейтом: пачка собирается из шагов 4 и 5, раньше она не полна, после коммита правила бы уже историю. Гейт с коммитом стал седьмым шагом, закрытие — восьмым. Запрет остался, но только на судей канона: doc-consistency и doc-code-drift идут на весь канон разом и зовутся через healthcheck. |
||
|
|
b3479776a4
|
канон: «промоут» уступает место русскому глаголу | ||
|
|
b8120d3271
|
resolve: два сценария вместо одной цепочки — разведка и решение
Разведка была прологом к коду: три шага, чекпоинт вариантов — и вливание в общую ветку. Своего исхода у неё не было, поэтому и писать в документы проекта ей было незачем: ответ оседал в design.md будущего change. - у разведки появился исход: ответ уезжает в документы канона, задачи заводятся и уточняются, написанное коммитится, запись закрывается. Кода сценарий не пишет вовсе, OpenSpec ему не нужен - точка входа осталась одна, и сценарий выбирает скилл, прочитав постановку: «есть ли очевидный способ решения» видно после чтения записи, и требовать этого суждения от вызывающего значит требовать его раньше, чем оно возможно - оба сценария лежат справочниками и одинаково — solve.md и research.md, — а в SKILL.md остались вход, развилка и правила, не зависящие от сценария. Асимметрия читалась бы как старшинство: сценарий в теле скилла выглядит основным, а в справочнике — оговоркой - переход между сценариями — событие с названным исходом: решение, упёршееся в незнание способа, останавливается; разведка, выбравшая способ, доводится до конца, а код идёт следующим прогоном, который запускает человек - канон 14: у ADR два законных источника. У решения, принятого разведкой, design.md нет по построению, и такое решение либо не попадало в adr/ вовсе, либо попадало сочинённым заново Правки по своему же ревью, до коммита: - версия 14 была неполной — разрез проверки, вход и устав doc-consistency, скелеты adr/README.md и template.md по-прежнему требовали ссылку на design.md. Агент краснел бы на законной записи; скелеты уезжают в проекты, поэтому запись журнала называет их поимённо - canon.md объявлял себя двенадцатым, пережив версию 13. Литерал был третьим домом числа при двух исправных — убран, а не поправлен - сценарий разведки был недостижим там, где обещал работать: ready требует у research оба раздела, включая «Куда ляжет ответ», а сценарий брался назначить адрес сам. Адрес назначает автор записи; сценарий — только когда записи нет - разведка коммитила без гейта, хотя правит документы канона и индексы задач - при переносе выпало предупреждение про закрытие разведки без записанного ответа — возвращено |
||
|
|
863769406f
|
канон 13: файл версии зовётся по владельцу, у задач появилась своя версия формата
Имя `.pm.json` пережило плагин `av-dev-pm` на два месяца и указывало в пустоту. Правило, которое из этого вынуто: имя служебного файла — имя плагина, который его завёл, и по нему же владельца узнают. - `docs/.pm.json` → `docs/.docs.json`, запись 13 журнала. Прежнее имя docs.py не читает намеренно: по этому числу upgrade решает, какие записи применять, и два дома разъехались бы молча ровно там, где это дороже всего. Вместо совместимости — узнавание: check видит старый файл и печатает готовую git mv - у каталога задач появилась своя версия формата — ключ `tasks` в `.tasks.json`, свой журнал версий и своё повышение. До сих пор её не было вовсе, хотя docs.py в комментарии уверенно на неё ссылался: описание опережало механику ровно так, как сказано в решении 195 - число своё, а не копия канонического: плагин ставится в одиночку, и у проекта без docs/ версии канона нет — сверять было бы не с чем - конфиг задач стал обязательным (init и adopt apply пишут его всегда), check сверяет число, `check --fix` его не приписывает: приписанное объявляло бы каталог приведённым к формату, шагов которого никто не делал - переезды 11 и 12 в новый журнал задним числом не переписаны — версия 1 велит догнать формат по журналу канона, называя признаки отставания поимённо (каталог в docs/tasks/, живой SPRINT.md) - запись 60 в DECISIONS со следствиями 200–203; отдельно разведено с решением F, где `.docs.json` отвергался как указатель путей: отвергнут был указатель, а не имя |
||
|
|
12b77c3393
|
итог аудита: запись 59, карта домов про конвенции, план
- дом «что механизировано» называл conventions/README.md, хотя документ канона живёт файлом или каталогом; копия пересобрана resync - запись 59: находки одного рода — правил механику, не правил описывающее её вовне. Пять выводов, включая «скелет не описывает, а порождает» - в план добавлена пачка мелочи, оставленной сознательно, и сказано, что бумажная часть закрыта Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
12882911a9
|
словарь, манифесты, README: одно слово — одна вещь, одно описание — один дом
- «готовность» значила и «запись можно брать», и «что считается сделанным»; второй смысл стал «определением сделанного» — своё же правило про занятое слово запрещало это прямо - «пайплайн» жил в 24 местах вне журналов при том, что DECISIONS фиксирует его уход «целиком»; рабочее имя — конвейер - «чекпоинт» в review значил стадию и проход, в resolve — остановку человеку; слово оставлено за остановкой - у описания плагина было два дома, и три из четырёх уже разошлись. Сведены, и класс закрыт машиной: frontmatter.py сверяет plugin.json с marketplace, гейт разбужен на *.json - README врал про односторонние зависимости и терял healthcheck на диаграмме - перечень агентов в REMAINING отстал на два поколения Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
63ba36d71d
|
границы плагинов: путь в чужое дерево, безымянные стыки, звонящий у вычитки
Правило границы моё, копий восемь — и нарушал его я же. - путь в дерево чужого плагина снят из пяти мест; маркер копии, уезжающий в проект скелетом, оставлен, но сказано, что сама пара маркеров не едет - короткое имя чужого скилла в четырёх местах стало полным - стык «урожай ревью → задачи» не был назван ни с одной стороны, хотя механика написана с обеих; теперь назван, с веткой «плагина нет» - resolve звал av-dev-git:commit без строки доклада и пересказывал формат коммита, нарушая собственное «ссылайся, не пересказывай» - doc-wording обещал момент вызова, которого не исполнял никто. Правило: звонящий — тот, кто только что писал текст. Вызов появился шагом в docs, init, adopt и upgrade; healthcheck по-прежнему его не зовёт - openspec.py искал SHALL по всему файлу, а образец даёт его в context — проверка молчала ровно в том случае, ради которого написана - фаза 2 review-rubric была недостижима; проход стал судить задуманное, а не код, и это сходится с тем, что о нём говорит конвейер - rules.tasks в образце конфига, ветка «записи задачи нет» у review-scope, возвраты на чекпоинт в схеме resolve, старшинство правила дельта-спек Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
15dba79993
|
приоритет стал исполнимым: move без --section и тексты, догнавшие правило 4
Механизм расстановки приоритета не запускался ни разу: --section у move был обязательным, а все три места, где груминг его предписывает, дают команду без него — usage error. Чиню скриптом, а не текстами: перестановка внутри секции — самая частая операция груминга, и требовать повторить текущую секцию значит приглашать указать не ту. - move: --section необязателен, без него берётся секция из индекса; сообщение различает перестановку и перенос - докстринги, отрицавшие правило 4 («в беклоге порядок значения не имеет»), приведены к действительности - reopen ставил возвращённую строку после сырья и давал ошибку check на ровном месте - edit портил написание секции в мете; корень шире — брался нижний регистр из разбора, а не написание заголовка. То же в close и reopen - дыра гейта: между заведением и ready запись не судил никто. Своя строка здоровья check, отдельная от «готово к взятию» — она про другое - шесть файлов и два устава обещали, что схему типа проверяет check - раздел from-review о серьёзности стоял на «приоритетов нет» - остатки спринта и сессии в семи местах, включая description агента формы - индексов два, а не три; два определения порога готовности после adopt Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c1890d9e71
|
скелеты канона догнали канон 12: спринт, версия, чужая проверка
Аудит четырьмя сабагентами показал систематическую дыру: механика правилась, а описывающее её вовне — нет. Дороже всего скелеты: они уезжают в проект. - слоты спринта в скелете CLAUDE.md стали слотами груминга, имена взяты у groom, а не выдуманы заново — журнал версии 12 их уже назвал - "canon": 11 в двух образцах стал плейсхолдером: литерал протухал третий раз подряд, а незамещённый плейсхолдер ломает разбор громко - обещание, что docs.py проверяет форму openspec/config.yaml, снято из трёх мест; владелец назван полным именем, с оговоркой об отсутствии плагина - adopt ставил в гейт проекта один шаг из трёх; соседские ставятся по следу присутствия, следа нет — строка доклада - битая ссылка на tasks/ROADMAP.md из скелета паспорта Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
4354cc4146
|
healthcheck: у судей документов появился свой скилл и свой момент
doc-consistency и doc-code-drift звались шагом сессии между спринтами. Сессия стала грумингом, груминг судит задачи, а не документы, и звать чужих агентов не вправе — они в av-dev-docs. На живом проекте их не звал бы никто, кроме разовых adopt и upgrade. Момент назван у владельца. Разрез с canon check проверяемый: машина сверяет форму, healthcheck — утверждения. Почему скилл, а не просто описания агентов: двоим нужна оркестровка — позвать обоих на весь канон разом, передать doc-code-drift раздел запретов, разобрать урожай порциями, назвать границы покрытия и кого именно позвал. Этого агент о себе не знает. doc-wording внутрь не взят: ему оркестровка не нужна, и ритм другой — он нужен там, где текст только что писали. Заодно из shared/plugin-boundary.md и README убран счётчик скиллов: он протух дважды за день. |
||
|
|
df5af47dc3
|
хвосты после снятия спринтов: четыре штуки
resolve судил готовность записи глазами — текст писался до того, как появилась команда ready. Теперь зовёт её через av-dev-tasks:tasks, а отказ читает исходом «не доведена». Это ровно тот случай, где машина дешевле и точнее, а цена ошибки отложенная. canon.md всё ещё говорил, что невзятой запись делает sprint take. REMAINING перечислял три опоры против совпадения приёмщика с исполнителем, включая SPRINT.md под git. Опор осталось две, и третья не заменилась, а исчезла: у приёмки больше нет момента. Записано как есть. frontmatter.py: устаревший путь review-pipeline/SKILL.md в комментарии. В план добавлена дыра, которую открыло снятие сессии: двух агентов канона на живом проекте больше не зовёт никто, кроме adopt и upgrade. |
||
|
|
4a56753f0b
|
session стал groom: два вопроса вместо ритуала спринта
Предмет сузился до двух: что сейчас самое важное и что перестало быть важным. Ответ записывается порядком строк в беклоге. Из четырёх шагов сессии выжили два (вопросы, переоценка порциями), один заменился расстановкой очереди вместо набора спринта, два выпали. Приёмка — грумингу не по предмету, ритуала у неё больше нет, остаётся reopen; цена названа в тексте. Разбор процесса потерял якорь, и вместе с ним ушёл прямой вызов агентов doc-consistency и doc-code-drift — это починка, а не потеря: агенты принадлежат av-dev-docs, и груминг звал их мимо правила обращения к соседу. sprint.md удалён, cadence.md стал portions.md. Канон 12: запись в журнал велит проектам снести SPRINT.md и расставить порядок, с точным порядком шагов — сперва удалить файл, потом check --fix, иначе он увидит третий индекс и станет ругаться, а не чинить. Побочно: canon.md объявлял себя версией 7 при текущей 11. Пять версий дом канона врал о себе — машина сверяет константу скрипта, а прозу в заголовке не читает никто. |
||
|
|
3653c5cff5
|
скилл tasks: приоритет стал порядком строк в беклоге
Правило 4 переписано целиком. Было «порядка нет, есть цель», и обосновано это было тем, что на «что делать дальше» отвечает набор спринта. Набора нет — вопрос остался, отвечать нечем. Приоритет — свойство очереди, а не задачи, поэтому его дом индекс: то же исключение из правила 2, что и «в каком индексе лежит запись». Положи его в файл числом — два соседних файла смогли бы утверждать одно место, а строка индекса противоречить обоим. Цель и приоритет — независимые оси: очередь может идти поперёк целей. Расстановка — это move --after и move --first, и только они: руками поправленная строка не оставляет причины. Место сырья в конце секции из очереди изъято: оно производно от типа и заполненности, его назначает машина, приоритетом оно не становится. Схема состояний потеряла SPRINT.md и четыре перехода; шесть уставов типов, task-format, split, from-review и adopt переведены со «взятия в спринт» на ready. |
||
|
|
a73eedb893
|
tasks.py: спринт снят, гейт готовности переехал в команду ready
Спринт был вплетён в 215 мест: конфиг, разбор индексов, состояния задачи, add/edit/move/close/reopen, блок здоровья и CLI. Снято всё: SPRINT.md, четыре команды sprint, автотег урожая sprint:<слаг>, проверки набора в check. Гейт готовности стоял на sprint take — единственном месте, где запись судили целиком. Момент нужен и без спринта, иначе задача уезжает в работу без критериев приёмки. Теперь это команда ready <слаг>: тип, цель у feature, пустой раздел вопросов, схема типа. Отказ там рабочая ситуация, а не ошибка употребления, — код 1, не 2. Приоритет стал порядком строк в беклоге, и два места это уже знают: reopen и check --fix ставят восстановленную строку в конец секции и говорят, что позицию назначает человек. Молчаливое восстановление выдавало бы машинную позицию за его решение. Переезд проекта: снести SPRINT.md, прогнать check --fix — задачи из набора вернутся в беклог. Проверено на фикстуре. |
||
|
|
1bce854535
|
сверка после реорганизации: два неучтённых следа
REMAINING держал два утверждения, которые переименование сделало неверными. Перечень непрогнанного не знал про resolve — а это самый новый скилл и единственный с чекпоинтами. Риск «скиллы jellybit названы ровно как в плагине» снят: там task-pipeline, review-pipeline, task-batch, а плагин теперь даёт resolve, review, openspec — пересечений нет. Записано, что риск снят переименованием, а не устранён по существу. Заодно список проектных копий в resolve дополнен именами прошлого поколения: сносить надо и их. |
||
|
|
ee53ef8af8
|
resync.py поднят в scripts/: пересборка копий из домов
copies.py находит расхождение, а чинить его руками — та же работа, из-за которой копии и расходятся: правка дома касается стольких файлов, сколько у него копий, и последний забывают. Проверка была, починки не было. Разметку разбирает не свой код: copies.py импортируется целиком, иначе второй разборщик той же разметки разошёлся бы с первым молча. В гейт не ставится намеренно. Автоматическая пересборка протащила бы правку дома во все копии мимо глаз автора, а копия, уезжающая в репозиторий проекта, тянет ещё и запись в журнал версий канона — этого машина не напишет. Проверено на обеих формах копии: обычной и лежащей внутри объемлющей ограды. Ограда и пустые строки по краям принадлежат месту, а не дому, и пересборка возвращает их такими, какими были — round-trip побайтно чистый на всех 24 копиях. |
||
|
|
53cf6baedf
|
av-dev-pipeline стал av-dev-code, review-pipeline — review
Имя описывало устройство, а не предмет: «пайплайн» говорит, что внутри конвейер, — а плагин занят кодом по задачам, и с появлением чекпоинтов он уже не конвейер в чистом виде. Набор имён стал параллельным: docs / tasks / code / git, каждое называет материал. Заодно review-pipeline стал review — слово ушло из плагина целиком, а не наполовину; скиллы выровнялись: resolve / review / openspec. Журнал версий канона переписан вместе со всеми, DECISIONS.md — нет. Разрез по типу высказывания, а не файла: наблюдение и причина неприкосновенны, предписание и адрес обязаны оставаться исполнимыми. Запись версии 10 велит «проверить, что плагин av-dev-pipeline установлен» — проект, дошедший до неё, выполнил бы невыполнимое. |
||
|
|
c5e6883461
|
task-pipeline переписан в resolve: два плановых стопа
Автоматическое решение задач агентом работает плохо, и хуже того — в процессе перестаёт ориентироваться автор. В цикл возвращается человек, но не согласованием на каждом шаге: доктрина «делать, а не спрашивать» не отменена, а ограничена местом. Развилка до ближайшего чекпоинта копится в него, после последнего — уходит вопросом в запись. Чекпоинтов два. «Варианты» — у исследовательской задачи, до первого требования: 2-4 способа с ценой каждого и рекомендацией, выбор оседает по адресу, который назвала сама запись. «Объяснение» — у всякой, после ревью дизайна: человек читает просеянное машиной. Объяснение не завело своего артефакта — оно собирается из proposal.md и design.md, а требование к их форме уехало в openspec/config.yaml (rules.proposal, rules.design), то есть применяется в момент написания. Отдельный раздел был бы третьим домом одного объяснения. Закрыт открытый вопрос: находка ревью, меняющая дельта-спеки, отменяет одобрение — разметка пересчитывается, чекпоинт повторяется. |
||
|
|
c3828b3713
|
task-batch удалён вместе с хвостами
Пайплайн нескольких задач снят с повестки: работаем по одной. Каталог скилла удалён, и с ним всё, что держалось только на нём. Хвосты были не только ссылками. У review-specs исчез третий режим (стык после слияния) — вместе с исключением «живого change нет, берём актуальные спеки источником»: теперь отсутствие дельта-спеки это отказ. У review-triage исчезло единственное исключение из правила «плана нет — не запускаюсь». В каноне и у doc-code-drift имя основной ветки обосновывалось тем, что «в неё вливает батч», — довод заменён на верный. |
||
|
|
872732989a
|
адреса чужих документов сверяются с перечнем владельца
Адрес принадлежит одному плагину, а называют его все: docs/* стоит в сорока местах конвейера, tasks/ROADMAP.md — в четырёх местах канона. Переименование в каноне до них не доходит, и заметить это нечем: протухший адрес попадает в механизм честной деградации ревью и выходит правдоподобной строкой «документа в проекте нет», а не поломкой. Перечень берётся из константы владельца — той, по которой он и так проверяет раскладку. Судится упразднённое, а не незнакомое: список тем канона открытый, и «нет такого имени» опровергнуть нечем; зато карта переездов RETIRED и есть перечень запрещённого. Рядом одна догадка — почти совпавшее имя как опечатка, порог замерен (законные до 0.64, опечатки от 0.91). Первый прогон: одна настоящая находка — REMAINING иллюстрировал смысловой дубль адресом docs/specs/, упразднённым в версии 1 канона. В гейте без glob: перечень лежит в .py, упоминания в .md, и коммит с переименованием трогает только первую сторону. |
||
|
|
c6be879831
|
правило обращения к соседнему плагину получило дом
Стояло в пяти местах в пяти редакциях: два разных довода, ни в одном месте оба, и три места из пяти молчали о том, что делать при неразрешившемся вызове. Плюс невысказанный инвариант: $CLAUDE_PLUGIN_ROOT ведёт только в свой плагин. Дом — shared/plugin-boundary.md, блок «граница-плагинов», семь помеченных копий. В дом вошло правило, последствия остались на местах вызова: «нет плагина задач — учёт остаётся владельцу» знает только конвейер. Оглавление адресов в CLAUDE.md проекта отклонено — второй дом раскладки, и протухший адрес в нём выходит правдоподобной строкой честной деградации. Сверка адресов уходит машине, записана в TODO разделом 5. |
||
|
|
c91492e3f0
|
TODO переписан с чистого листа; canon и docs остаются раздельно
План описывал мир до раскола: av-dev-pm в живых, каталог задач в docs/, шаги повышения на каноны 3, 4 и 5 — при том что канон уже 11. Двести с лишним строк, из них живых полтора десятка, и найти их можно было только прочитав всё. Умер он двумя способами сразу, и оба записаны в новом заголовке, чтобы не повторились. Первый: сделанное помечалось галочкой и оставалось в файле — список из двух сотен [x] перестают читать целиком, и живые пункты в нём теряются. Теперь сделанное удаляется, след остаётся в коммитах и DECISIONS. Второй: план построчно повторял записи журнала версий канона, то есть был вторым домом для шагов повышения, и половина повторов протухла молча. Теперь на журнал стоит ссылка. Новый план — пять разделов: вернуть живые проекты в рабочее состояние, учёт работ без спринтов, калибровка, пайплайн одной задачи в три этапа, обкатка. Поимённой раскладки файлов healthlog в нём нет намеренно: её знает canon adopt, и второй перечень разошёлся бы со скиллом. Зато названо то, чего скилл не сделает и что легко потерять — гейт проекта теперь три шага вместо одного, потому что docs.py перестал тянуть за собой и задачи, и форму config.yaml. REMAINING ссылался на разделы TODO по номерам — переведён на имена; заодно строка про непрогнанное на живом проекте дополнена скиллом openspec и оговоркой, что раскол проверен только на фикстурах и на установке каждого плагина в одиночку. Решение 53: canon и docs остаются двумя скиллами. Довод не про объём, а про description — это триггер, по которому загрузчик решает, звать ли скилл, и моменты вызова у этих двух разные. Слитое описание покрывает оба хуже, чем два покрывают каждое своё. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
e408c51ac1
|
README: скилл openspec в диаграмме вызовов
Скилл появился коммитом раньше, а в карту «кто кого зовёт» не попал: init и canon зовут его наравне с tasks, и без этих двух стрелок диаграмма утверждает, что OpenSpec никто не заводит. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f40e0cd7bb
|
каталог задач уехал из docs/ в корень репозитория
Версия 8 отпустила задачи из канона — перестала требовать каталог и перестала в него смотреть, — но место он занимал всё то же, docs/tasks/. Полдела: каталог, принадлежащий одному плагину, лежал внутри дерева, которым владеет другой. Проекту, поставившему учёт работ без канона документов, приходилось заводить docs/ ради одной вложенной папки. Дом задач теперь tasks/ в корне. tasks.py ищет его там первым, docs/tasks и doc/tasks остались в списке поиска для непереехавших проектов, init заводит только в корне, --target у adopt тоже. Настройки лежат рядом, tasks/.tasks.json — после версии 8 они уже были в своём файле, теперь и файл вне чужого дерева. docs.py продолжает терпеть docs/tasks/ в списке нечитаемого: непереехавший проект не должен получать выдуманную ошибку «файл вне канона» вдобавок к записи журнала, которая и так велит ему переехать. Адреса упразднённых слотов (plan.md, backlog/) теперь ведут в tasks/ и называют плагин. Тридцать три живых упоминания пути разведены по смыслу, а не заменой строки: в раскладке канона tasks/ вышел из-под docs/ и стоит на своём уровне; у doc-consistency каталог перестал быть исключением внутри docs/** и стал чужой территорией, названной в обеих формах; у review-scope и review-pipeline процессный список поехал вместе с путём. В журнале версий тринадцать упоминаний оставлены как есть — они описывают прошлое состояние. Канон повышен до версии 11. В записи названа тихая часть переезда: файл tasks/items/x.md стал на уровень ближе к корню, и ../../passport.md в теле записи теперь ../docs/passport.md. Битую относительную ссылку внутри записи tasks.py check не ловит вовсе — её видит только docs.py и только у документов канона, так что этот шаг делается руками и тем же коммитом, что git mv. Фикстура переехала, поиск вверх по дереву находит новый путь, гейт зелёный. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
fdadfb65ac
|
валидатор config.yaml переехал в конвейер: у пайплайна свой скрипт
Решение 51 отдало OpenSpec конвейеру и честно оставило хвост: проверка формы и сторож версии остались в docs.py, потому что своего скрипта у пайплайна не было ни одного. Хвост не косметический — это ровно то состояние, против которого написан весь канон: у файла два владельца, один заводит, другой проверяет, и разойтись они могут молча. 252 строки переехали в av-dev-pipeline/skills/openspec/scripts/openspec.py: пять проверок формы, сторож версии, сверка слепка с живым инструментом. Команды две — check --dir <корень> и form; коды выхода общие со всеми скриптами av-dev. Из docs.py удалены константы OPENSPEC_*, check_openspec, openspec_cli, check_openspec_fresh, rules_keys и подкоманда openspec-form; про config.yaml он больше не говорит ничего, кроме строки границы механизируемого — что форму смотрит чужой скрипт. openspec/specs/ он по-прежнему знает: это дом темы requirements и часть карты тем. Переезд оплатился сразу, и не тем, чего ждали. Прежняя проверка требовала, чтобы context называл docs/passport.md и CLAUDE.md, безусловно — то есть на проекте без канона документов требовала ссылку на несуществующий файл. Пока код жил в скрипте канона, допущение «канон есть» было незаметным: скрипт канона запускают там, где канон есть. В скрипте конвейера то же допущение стало видно на первом прогоне. Теперь адрес требуется только к существующему документу, отсутствие идёт строкой «не проверялось» с названной ценой — без канона конвейер работает вслепую. Заодно починен хвост от раскола плагинов: pyrefly project-includes в pyproject всё ещё указывали на av-dev-pm. Линтер на явных файлах работал, а на обходе проекта не проверял ничего. Проверено пятью случаями: нет openspec (1), годный конфиг (0), опечатка в имени артефакта под rules (1), проект без канона (0, с двумя строками «не проверялось»), неизвестная команда (2). Канон повышен до версии 10. Главное в записи — тихая потеря: форму раньше проверял docs.py check заодно, теперь нужен отдельный шаг openspec.py check в гейте, иначе незаменённый пример в config.yaml перестанет ловиться. Решение — 52. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
9453a218d1
|
журнал решений: запись 51 про раскол плагинов
Три коммита раскола несут причины в теле, но дом у решения один. Записано то, чего в отдельных коммитах не видно: сцепка внутри одного владельца не выглядит сцепкой, пока владелец один, и обнаруживается не рассуждением, а попыткой поставить половину отдельно. Плюс правило разреза владения — по тому, кто инструментом пользуется, а не по тому, кто о нём подробнее написал. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
f0dd8f70c1
|
openspec уехал в конвейер: заводит его пайплайн, канон только высказывается
Версия 7 объявила openspec/ слотом канона: init его заводил, adopt тоже, образец config.yaml лежал в скелетах, отсутствие каталога docs.py считал отказом. Разрез был проведён не там. По OpenSpec работает конвейер — без каталога не запускаются ни opsx:propose, ни ревью дизайна, ни сверка требований, — а канон документов о нём только высказывался. Проект, которому конвейер не нужен, получал отказ за отсутствие того, чем не пользуется. Появился скилл av-dev-pipeline:openspec: заводит каталог, заменяет закомментированный пример в config.yaml настройкой, объясняет разрез между ссылкой и пересказом — утверждение, опровергаемое открытием другого файла, это пересказ; строка, говорящая какой файл открыть, это ссылка. Образец переехал туда же, в references/config-skeleton.md, а в скелетах канона остался указатель. init и canon adopt OpenSpec больше не заводят, а зовут скилл конвейера через пространство имён. Вызов не разрешился — плагина конвейера нет, и это строка доклада, а не поломка: docs.py о каталоге тогда тоже молчит. Отсутствие openspec/ стало неприменимостью вместо отказа, остальные четыре проверки формы идут только при живом каталоге. На фикстуре без openspec дрейф упал с 10 пунктов до 9. Что осталось на месте и названо честно: проверка формы config.yaml и сторож версии (docs.py openspec-form) пока живут в скрипте канона. Перенести их значит завести в конвейере свой скрипт, а этого у него нет ни одного. У файла сейчас два плагина — один заводит, другой проверяет, — и это временное состояние, а не задуманное; в журнале версий оно записано так же. Канон повышен до версии 9. Запись не двигает ни одного файла проекта: меняется только то, кто их заводит. Но в ней названа потеря, которую легко не заметить — проект по OpenSpec без установленного пайплайна теперь не услышит от docs.py ничего про свою настройку, и молчание это законное. Гейт зелёный, скиллов стало десять. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
1f31ac6afd
|
канон отпустил каталог задач: docs.py не зовёт tasks.py, конфиг разъехался
Пока владелец был один, docs/tasks/ числился слотом канона: docs.py требовал каталог, звал внутрь чужой скрипт подпроцессом и выдавал его дрейф за свой, а настройки задач жили ключом tasks в docs/.pm.json. Для проекта, поставившего только документы, всё это отказ на ровном месте — задач он не ведёт, и требовать их не за что. Раскол вскрыл это немедленно и молча: check_tasks искал tasks.py по пути parents[2]/tasks/scripts, то есть внутри своего плагина, и после переезда скатывался в ветку «скрипт не найден» на каждом прогоне. Проверка выглядела живой и не проверяла ничего. Теперь docs.py про задачи не говорит ни слова: check_tasks снят целиком, каталог остаётся в NOT_DOCS, его отсутствие дрейфом не считается. Канон резервирует место в docs/ и внутрь не смотрит. Дом настроек каталога задач вернулся в свой файл — <каталог>/.tasks.json. Прежний ключ tasks в docs/.pm.json читается, только когда своего файла нет, и скрипт говорит, куда его перенести; есть оба — побеждает свой, и об этом тоже говорится вслух. Порядок именно такой, потому что docs/ принадлежит другому плагину: дом настроек в чужом дереве это дом, которого у половины проектов нет. Заодно закрыта дыра, которую сам же и открыл первый вариант правки: битый docs/.pm.json ронял бы задачи даже при живом своём конфиге. Чужой файл здесь только повод для замечания, и его поломка не наша. Проверено на четырёх случаях — только чужой конфиг, оба, свой плюс битый чужой (код 0), только битый чужой (код 3, окружение). Канон повышен до версии 8 с записью, выполнимой upgrade. В ней названо и то, что легко потерять: раньше согласованность задач тянул за собой docs.py check, и проект, у которого в гейте стоял только он, обязан добавить второй шаг — иначе дрейф индексов перестанет ловиться молча. Гейт зелёный. Оба скрипта прогнаны: docs.py check на фикстуре про задачи не упоминает, tasks.py check код 0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
00ddfb0dde
|
av-dev-pm расколот на av-dev-docs и av-dev-tasks
Плагин владел двумя разными вещами сразу — документацией проекта и учётом работ, — и это мешало обеим. Канон нельзя было поставить без задач, задачи без канона, а язык проектных текстов лежал внутри скилла 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> |
||
|
|
86e22d932c
|
вычитка раздвоилась: doc-wording для документов, task-wording для записей
Решение ППП говорило: агент называется doc-wording, а не task-wording, потому что правила языка относятся ко всем проектным текстам, а не к одним задачам. Утверждение верно и сегодня — оно и есть причина, по которой правила уехали в shared/. Но из общности правила не следует общность прохода: docs и tasks расходятся самодостаточными плагинами, а самодостаточный плагин не может зависеть от агента соседа. ППП отменено, и отменено не по своей оси. Проходов теперь два, и разведены они по охвату — впервые в этом репозитории. И task-form против вычитки, и doc-consistency против doc-code-drift разведены по глубине; здесь глубина одна, а входы разные. doc-wording читает документы канона, конвенции, ADR, записки разведки и CLAUDE.md; task-wording — items/ и строки индексов, а документы проекта открывает только как словарь, чтобы отличить неизвестный термин от известного. Разрез по охвату дублирует устав, и потому весь общий текст стал домом. Оба судят по одним и тем же девяти правилам; отличаются входом, соседями по границе, машинной проверкой, о которой молчат (docs.py против tasks.py), и способом подстановки — команда edit у задач, редактор у документов. Копий в каждом уставе 151 строка, своего непустого текста 61 и 75. Домом стал и формат доклада — блок вычитка-доклад: форма находки, границы покрытия, пустой доклад. Это контракт прохода, а не правило языка, но лежит он в shared/language.md отдельным разделом: заводить под пятнадцать строк отдельный файл дороже, чем назвать раздел честно. Признак дома здесь не тема, а число потребителей больше одного при обязательной дословности — разойдись два прохода формой доклада, зовущий скилл разбирал бы два формата вместо одного. Ссылки разведены в семи местах: tasks/SKILL.md (таблица двух проходов), task-form (описание и обе границы), doc-code-drift, canon.md (сравнение разрезов), canon/SKILL.md, README дважды. doc-consistency и таблицы канона оставлены на doc-wording — они про документы. Гейт зелёный: копии 13 при 7 домах, фронтматтеров 24, диаграммы. Решение — 50. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c669215fc8
|
язык уехал в shared: дом вне плагинов, устав вычитки — копия целиком
Дом языка лежал в av-dev-pm/skills/canon/references/language.md — внутри одного скилла одного плагина. Пока плагин был один, это читалось как «дом рядом с главным потребителем». Разделение на самодостаточные docs и tasks превращает то же место в утверждение, что язык принадлежит канону: плагин задач, поставленный без канона, потерял бы правила письма вместе с ним. Дом переехал в shared/ и не принадлежит ни одному плагину, плагины везут дословные копии. Самодостаточность держится копией, а не ссылкой: shared/ нужен этому репозиторию, а не установленному плагину. Устав вычитки стал копией целиком. doc-wording копировал из дома англицизмы, словарь, жаргон и порог правки — четыре блока; девять правил он излагал своими словами, и эти слова с домом никто не сверял. Там дрейф и копился молча: в доме правило «одна мысль — одно предложение» требовало выносить придаточное, в уставе — не резать причинную связь, и каждая версия выглядела полной. Из десяти правил машина сверяла четыре, теперь сверяет все. Условие переезда: текст правил написан безлично, а всё, обращённое к проходу («пиши так-то», «про это молчи»), вынесено из блока в раздел «Что из этих правил докладывается особым образом». Правило принадлежит дому, способ доложить о нём — уставу. Блоков три, и делятся они по потребителю, а не по теме: язык-доктрина (зачем стиль, полезное действие, параллельность, заголовок, что отброшено), язык-правила (девять правил с тремя таблицами), порог-правки. Порог оставлен отдельным потому, что его берёт task-form, который правил языка не проверяет вовсе; вложенных блоков copies.py не знает, и внутри язык-правила забрать порог было бы нечем. Потребители собраны из дома скриптом, а не руками. Домов 6 вместо 7 — три таблицы слились в язык-правила; копий 9 вместо 8. Гейт зелёный: копии, фронтматтеры, диаграммы. Решение — 49. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
6ff12fedd5
|
форма config.yaml сверяется с живым openspec, а не с памятью
Проверка формы знала имя схемы и перечень артефактов константами — и это не наше решение, а состояние чужого инструмента. OpenSpec переименует артефакт: правила под прежним именем перестанут применяться, конфиг останется выглядеть написанным, канон продолжит требовать прежнее. Молчат при этом все три стороны, и заметить расхождение было некому. Сторожем поставлено сравнение версий. check спрашивает openspec --version — десятые доли секунды — и сравнивает major.minor с той, на которой форма сверялась. Разошлось — замечание, не отказ, с именем команды, которая перепроверяет. Патч-версия в сравнение не берётся намеренно: формы она не меняет, а нагоняй на каждый багфикс приучает пролистывать весь блок. Перепроверяет docs.py openspec-form: берёт openspec templates --json, то есть перечень артефактов текущей схемы, и печатает, что разошлось с константами. Дорогой вызов вынесен из check сознательно — он стоит втрое дороже опроса версии, а ответ меняется только вместе с версией. Дешёвая проверка служит воротами дорогой, и дорогая не ржавеет, потому что зовут её не по памяти. Чинится расхождение в плагине, а не в проекте, и команда печатает три адреса правки списком: константы скрипта, скелет, журнал версий канона. Пятой проверкой формы стали ключи под rules: — это имена артефактов, и правило, адресованное несуществующему, не применяется молча. rules.spec вместо rules.specs даёт конфиг, выглядящий написанным и не работающий. Первый вариант этой проверки искал ключи отступом по всему файлу и нашёл их внутри литерального блока context: строки «Language: Russian» и «av-dev-pm:review-pipeline» выглядят ключами. Оба живых проекта из-за этого покраснели на правде. Теперь разбор идёт от строки rules: до следующего ключа нулевой колонки; на тех же проектах чисто, а опечатка в имени артефакта по-прежнему находится. Решение — 48. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a79266cfcb
|
init заводит openspec сам; конфиг стал слотом канона
Каталог openspec/ был предпосылкой, о которой канон говорил, но за которой не следил. openspec/specs/ объявлен домом темы requirements, config.yaml описан абзацем — а заводилось всё руками, и не проверялось ничего. Новый проект выходил из init с полным каноном документов и без каталога, без которого не работают ни opsx:propose, ни ревью дизайна, ни сверка требований. Теперь init делает openspec init --tools claude шагом 3, до первого документа, а adopt заводит его тем же способом, если на переводимом проекте его нет. Команда названа поимённо в трёх местах — скилле, каноне и отказе docs.py: отказ без команды заставляет искать её в другом месте. Файл из коробки оказался хуже отсутствующего, и потому проверяется машиной. openspec init кладёт config.yaml, где context и rules — закомментированный пример на английском. Такой файл читается как настроенный: он есть, он валиден, имя правильное. Работает он как пустой, и узнаётся это по уже написанному предложению — на другом языке, с capability по имени пакета, без единого SHALL. docs.py проверяет четыре вещи, каждая про молчащий пробел: каталог есть; имя именно config.yaml (config.yml OpenSpec не читает и об этом не сообщает); context и rules.specs не остались примером, а правила называют SHALL; context называет passport и CLAUDE.md. Последние два обязательны по порядку работы: предложение пишется до того, как кто-либо откроет docs/, и без этих строк его пишут, не зная ни границы домена, ни инвариантов. Форма конфига записана скелетом и сформулирована разрезом: утверждение, которое можно опровергнуть, открыв другой файл проекта, — пересказ; строка, которая говорит, какой файл открыть, — ссылка. Машина этот разрез не проверяет, отличить одно от другого она не умеет; он отдан doc-consistency отдельным абзацем правила «один факт — один дом», и config.yaml добавлен ему во вход. Место второго дома там самое частое: context читается при порождении каждого артефакта, туда удобно дописать «чтобы агент знал», и так заводятся копии инвариантов, конвенций, состава гейта и правил ревью. Образец лёг в канон, а не в конвейер, как планировало решение C: форма документа принадлежит владельцу канона документов, конвейер её читатель. Иначе av-dev-pipeline завёл бы описание файла, который заводит и проверяет av-dev-pm. Канон повышен до версии 7 с записью, выполнимой upgrade: завести openspec, привести config.yaml к скелету, вычистить из context пересказ, проверить имя файла, поднять номер в .pm.json. Проверка прогнана на четырёх фикстурах — свежий openspec init, два живых проекта и пустой каталог; отличает все четыре случая. Решение — 47. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
91d4264b40
|
правило выбора метки уехало в свой документ, в скилле остался диспетчер
SKILL.md конвейера дорос до 1168 строк, и двести с лишним из них отвечали на вопрос, который на обычной задаче не задаётся: как выбирается метка. Называет её review-scope один раз, до обеих стадий, а всем остальным нужна не процедура выбора, а состав по уже названной метке — три строки таблицы. В references/review-levels.md переехали правило двух осей, «спорное решается вниз», «максимум по поверхности», разбор того, чем small дешевле medium, и обе проверки долей. В скилле остались таблица состава, схема процесса и раздача тем: метка названа — состав читается. Форма выбрана одна на все метки, а не по документу на метку, как у типов задач в av-dev-pm:tasks. Аналогия не переносится дважды. Типы задач разъединены — общее лежит в task-format.md, в файле типа только своё; метки вложены: medium это small плюс два прохода, large — medium плюс доказательство, и три файла повторяли бы костяк трижды. Такое расхождение copies.py не ловит: он сверяет дословные копии по маркерам, а вышли бы почти-копии с намеренными мелкими отличиями, неотличимые от задуманного. Причина сильнее: ценность текста в сравнении. Вопрос читателя не «что делает small», а «чем small отличается от medium» — на него отвечают и выбор метки, и «спорное вниз», и корректор; сравнение, разложенное по трём файлам, не читается. Механика рычагов осталась в скилле. Непуск, вход и потолок общие для всех проходов и всех меток, их дом — «Модель по проходу»; в переехавшем тексте от них только то, что они делают с small, и ссылка на дом. Точные потолки не продублированы, чтобы не заводить второй источник чисел. Ссылку на дом правила получили review-scope, для которого он основная опора, и task-pipeline, где раньше стояло безадресное «правило живёт в скилле конвейера». Заодно вычищено последнее живое упоминание quick и standard: имена удалены каноном 6, но уцелели в объяснении, зачем нужна проверка доли. Решение — 46. SKILL.md: 1168 → 1026 строк. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
9561af7b9b
|
корректор метки переехал в code; размер считается по пяти источникам
Сигнал «метка, вероятно, занижена» жил в review-basics — в единственном месте. А basics с меткой small не запускается, если у проекта нет своих тем: значит на типичном проекте задача с меткой small шла без рантайм-проверки того, что метка выбрана верно. Дыра появилась вместе с удешевлением small и попала в самую вероятную точку ошибки: занижают туда, где дешевле, а цена занижения там же и выросла — три темы ядра смотрятся только против записанных инвариантов. Сигнал перешёл в review-code, и он подходит по построению: идёт при любой метке, видит дифф целиком, а на small уже читает инварианты, то есть держит весь материал, из которого сигнал выводится. Признаков четыре, и один весит больше прочих — изменение, которое не откатывается обратной правкой, при метке small это прямой промах отрицательного теста. У basics сигнал остался вторым, подтверждающим: он смотрит оптикой тем и видит то, чего не видно из кода как кода, — что вопросов, отложенных до large, накопилось слишком много. Триаж теперь обязан сказать и когда сигнала нет: «корректор отработал, возражений нет» и «корректор не запускался» по молчанию неразличимы. У small появилась доля, и она сформулирована сравнением, а не порогом: small не должен обгонять medium, ориентир — до трети задач. Проверка нужна именно теперь. Пока quick и standard совпадали составом, дрейф между ними не стоил ничего, и её не было; сейчас он стоит трёх тем ядра. У дрейфа вниз есть стимул, и он назван прямо: метку выбирает не автор, но по описанию, написанному автором — занижённое описание даёт занижённую метку без чьего-либо умысла. Размер теперь считается по корпусу из пяти источников. Разметчик читал proposal.md и tasks.md, но design.md не открывал вовсе, а метод был описан одной фразой «размер считается по дельта-спекам». Дельты описывают заказанное поведение и молчат об объёме работы: шесть шагов в двух узлах видны в tasks.md, а факт, что форму решения выбирали из нескольких, — только в design.md. Каждый источник получил свою строку по каждой оси, и каждая цифра обоснования обязана быть привязана к источнику поимённо; «изменение выглядит средним» обоснованием больше не считается. Отсюда два правила, которых не было. Расхождение источников по объёму разрешается в пользу большего — и это не «спорное решается вниз»: то правило разрешает ничью при равных данных, а здесь один источник просто видел больше. Само расхождение при этом идёт доводом за незнакомое: если о задаче написано так, что источники не сходятся в объёме, форму решения по ней не знают. Отсутствие design.md у нетривиальной задачи читается так же — «форму знали заранее» ничем не подтверждено. Заодно две грамматические опечатки от вчерашнего переименования в SKILL.md. Решение — 45. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
d5bee11a6b
|
классификация задачи: три категории документов и метка вместо ступени
Канон 5 объявил «каждый документ docs/ — тема ревью». Правило верно ровно наполовину и потому вредно целиком. Паспорт и схему хранилища ревью читает, но темами они не являются: по ним нельзя сказать «в этом изменении сделано не так», они задают границу, по которой судит чужая тема. Журнал решений и журнал наблюдений ревью изменения не нужны вовсе — ADR объясняет прошлое, а не предъявляет требование. Разметчик, применявший правило буквально, обязан был либо завести фантомные темы passport, adr, database, research и продублировать ими работу architecture и operations, либо потерять четыре документа молча; случались обе ветки, и в собственном образце плана docs/passport.md не попадал ни строкой, а обязательная арифметика покрытия при этом не сходилась. Категорий теперь три, разрез проверяемый. Тема — да, прямо: conventions, security, architecture и любой свой документ проекта. Источник темы — нет, но он задаёт границу для чужой: passport, database, CLAUDE.md, openspec/specs. Процессный — нет, он про то, как мы работаем: tasks, review, adr, research, .pm.json. Открыта одна категория из трёх, две другие перечислены поимённо, так что документ вне раскладки — однозначно своя тема. adr и research прогон больше не открывает ни одним проходом; docs/review остаётся читаемым, но как настройка конвейера, а не критерий. Цена записана и стала обязательной строкой границ покрытия: расхождение с записанным решением ловит теперь только сверка документации, а число под находкой обязано быть снято на этом прогоне, с приложенной командой. Классификация выдаёт задаче метку — small, medium, large. Прежние quick, standard и wide назывались ступенью и описывали ревью: как глубоко смотрим. Классифицируется же задача, и пока величина называлась свойством прогона, её естественно было пересчитывать на каждом прогоне — что конвейер и делал. Слово «ступень» удалено, а не оставлено синонимом: два имени одной вещи расходятся. Выводится метка из двух разведённых осей — размер (малое, среднее, крупное) и сложность (знакомое, незнакомое), — и равна максимуму по ним. Метка не синоним размера: малое незнакомое изменение получает large, трогая один узел, поэтому план печатает три строки с обоснованием каждая и выводить одну из другой запрещено. Оси остались русскими словами — это суждение прозой; метка английская — это идентификатор, который проходы сравнивают. Разметка переехала из ревью кода в шаг 4 пайплайна, сразу после propose. Она шла первым проходом каждого ревью кода, а перед ревью дизайна ту же величину называл сам пайплайн — то есть оркестратор, который только что довёл предложение до propose. Одно и то же измерялось дважды, и один из двух раз без разведённости с автором, ровно в той точке, ради которой разметчик заведён. Теперь запуск один на задачу, диффа он не видит, план обслуживает обе стадии, и метка после кода не пересматривается: расхождение факта с разметкой ловит журнал дефектов постфактум, как и всякую другую ошибку выбора. На диск план не пишется — четвёртый артефакт рядом с proposal, tasks и design пережил бы задачу и разошёлся бы с ней молча. Ревью дизайна тоже растёт меткой: small — specs, medium — плюс rubric, large — плюс architecture и вопрос автору о трёх формах решения. Раньше rubric и architecture включались одним условием, и medium получал ровно один проход, то есть не отличался от quick ничем. Разведены они потому, что зарабатывают на разном: рубрика порождает свойства узла и окупается уже на среднем изменении, её выход уезжает приёмочными критериями в tasks.md; архитектура отвечает на вопрос про второй способ, а он на среднем знакомом изменении отвечается «нет» ещё до запуска. small подешевел тремя способами сразу. Составом: приёмник тем не запускается, три темы ядра переходят к code сверкой по записанным инвариантам CLAUDE.md с потолком в одну находку, и это не «глубина ниже», а другой дом темы. Входом: specs читает только дельта-спеку, code — только индекс конвенций. Потолком: он появился у каждого опиниативного прохода, а не у одного basics, и у половин code он раздельный, потому что конвенционных находок больше по построению и в общем списке они вытеснили бы техническую половину. Сработавший потолок обязан быть объявлен строкой — молчащий срез неотличим от «больше не нашлось». Отрицательный тест small от этого стал жёстче, а не мягче: вопросы про обратимость миграции задавал приёмник тем, и на этой метке их не задаст никто. Пайплайн задачи вырос до двенадцати шагов. Тривиальность перестала решать состав ревью — она влияет только на explore; глубину обеих стадий называет метка. Проверено прогоном ревьюверов по готовому результату: девять расхождений найдено и починено — контракт находок печатал старый перечень проходов вместо плана по темам, три ссылки в task-batch указывали на шаг коммита вместо закрытия, запись changelog не переводила вопросы, адресованные passport и database, ops и adversary утверждали, что на нижних метках их вопросы задаёт basics, шаблон покрытия в review-code зашивал потолки small намертво, триггеры метки рассыпались на два списка против трёх, тема из директивы CLAUDE.md могла остаться без запуска исполнителя. Гейт зелёный: фронтматтеры, копии, одиннадцать диаграмм, ruff, pyrefly; docs.py прогнан на живом фикстуре и печатает категорию в отказе. Канон повышен до версии 6 с записью, выполнимой upgrade. Решения — 40–44. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
61cd9fcd37
|
гейт судит staged-файлы; рендер диаграмм пошёл параллельно
Гейт проверял рабочее дерево целиком — то есть не то, что уедет в историю, а
то, что лежит на диске рядом. Плюс платил за это временем: пятнадцать секунд на
каждый коммит с правкой markdown, потому что одиннадцать блоков рендерились по
очереди, каждый своим запуском mermaid-cli со своим chromium.
diagrams.py научился двум вещам. Первая — принимать файлы списком: без
аргументов обходит репозиторий как раньше, с аргументами смотрит только
названные, отбирая из них markdown внутри корня (гейт передаёт весь staged, где
есть и скрипты, и удалённое). Вторая — рендерить пулом потоков: работа целиком в
ожидании подпроцесса, своего интерпретатора ей не надо, а потолок в восемь
воркеров упирается в память chromium, а не в двадцать четыре ядра. Порядок
находок берётся из порядка сбора, не из порядка ответов, так что вывод
детерминирован. Весь репозиторий — 3 секунды вместо 15, один файл — 1.
В хуке теперь {staged_files} у диаграмм, ruff и pyrefly. Два исключения
остались, и оба по существу: copies.py сверяет копию с домом, а дом лежит в
другом файле, которого в индексе может не быть — список staged дал бы «копии
дословны» ровно там, где правка дома их и разошлась; frontmatter.py обходит всё
за сотые доли секунды, экономить нечего. Оба объяснены прямо у своих задач.
ruff встал с --fix и stage_fixed: безопасное чинится само и доносится до этого
же коммита. Иначе исправленный файл оставался бы в рабочем дереве, а в историю
уезжал бы невычищенный — гейт зелёный, коммит грязный.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
5067bc2048
|
гейт коммита: пять машинных проверок встали в pre-commit
Проверки существовали и запускались руками — то есть тогда, когда о них вспоминали. Каждая из них ловит ровно тот класс поломок, который не виден при чтении: фронтматтер разбирает загрузчик скиллов, а не человек; копия правила расходится с домом молча; диаграмма mermaid выглядит правдоподобно и падает на рендере; ruff и pyrefly стерегут ноль внешних зависимостей, без которого tasks.py и docs.py перестают работать в чужом проекте. Полагаться на память в таком наборе — значит узнавать о поломке от того, кто скачал плагин. Ставится lefthook (конфиг в lefthook.yml, `lefthook install` один раз на клон), пять задач в parallel. Glob разводит две половины: правка одних скриптов не платит за рендер диаграмм (~15 секунд), правка документов не гоняет линтеры. Внутри своей половины проверяется весь репозиторий, а не изменённые файлы — и расхождение копии, и находка ruff в соседнем файле это ровно тот случай, когда правка сломала не себя. Два свойства названы в README и в шапке конфига, чтобы не выяснялись отладкой. Первое: судится рабочее дерево, а не индекс — скрипты написаны как обход репозитория и про git add не знают, поэтому частичный коммит при грязном дереве проверяется по тому, что на диске. Второе: обход разовый — LEFTHOOK=0, и он законен ровно для случая, когда найденное нечем чинить прямо сейчас. Заодно поправлена строка README про диаграммы: «поэтому он не в гейте, а в руках того, кто правит диаграмму» — с этой правкой она перестала быть верной. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
37394444e8
|
спринт без цели: цель стала необязательной, но не молчаливой
Цель была обязательной во всех трёх местах сразу: sprint start требовал слаг, check считал ошибкой набор без названной цели, sprint take отказывал задаче под чужой целью. Модель описывала только спринт развития — а спринт бывает под багфикс, под техдолг, под здоровье проекта: такой набор собран по работоспособности, а не по направлению, и цели у него нет не по недосмотру. Обходной путь существовал и был хуже прямого: завести цель-пустышку «Здоровье проекта» и вешать под неё fix-ы. Тогда ROADMAP.md — документ про то, что приложение умеет, — обрастает строками про то, что оно не ломается, а тег goal: перестаёт значить направление. Теперь sprint start принимает --goal <слаг> ИЛИ --no-goal, и голое отсутствие обоих — отказ с объяснением. Причина в стимуле: цель называет человек, и это единственный продуктовый вопрос всей сессии. Разреши мы заводить спринт просто без флага — забытый флаг, лень спросить и осознанное решение стали бы неотличимы на выходе, а дешевле всего из трёх агенту именно не спрашивать. Тот же обход записан в «Стимулы» скилла session вместе с защитой. В спринте без цели цель не проверяется вовсе: набор берёт что угодно готовое к взятию, включая задачи под разными целями. Правило «набор служит одной цели» не ослаблено, оно просто не применяется — целей там не больше одной, их ноль. Взамен машинной проверки остаётся показ набора человеку до заморозки, и в cadence.md сказано прямо: у бесцельного спринта это единственная проверка состава. Доклад обязан называть спринт бесцельным и объяснять, чем он был. Признак «спринт идёт» разъехался с целью и переехал на слаг: слаг есть у любого спринта, потому что без него нечем проставить sprint:<слаг>, то есть нечем собрать урожай. На sprint_started() переведены sprint take, блок здоровья check и reopen. Поле «Цель» в шапке остаётся и у бесцельного набора — пишется прозой без ссылки: «цели нет» и «цель потерялась» обязаны различаться. Побочно выправлен reopen: он возвращает задачу в набор идущего спринта тем же тестом, что и sprint take (мешает только чужая цель). Прежде тест был уже — совпадение целей, — и задача без цели, реопенутая при спринте с целью, уезжала в беклог вопреки прозе скилла. Тема 39 в DECISIONS.md, следствия 145-147. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
4386eb3e1c
|
шов между плагинами: канон перестал называть имена проходов
av-dev-pm и av-dev-pipeline раздельны: канон работает без конвейера, конвейер без канона — поразрядно деградируя и называя это строкой. Но канон в шести местах называл конвейер поимённо, и одно из них — вывод docs.py пользователю: «свои темы проекта: … — их разбирает review-basics». Такая строка чинится не правкой файла, а недоумением на чужом проекте. Правило записано в canon.md, чтобы не отрастало заново. Общий словарь — имена тем и имена ступеней, и только они: ими проект настраивает ревью, вопросами по темам и триггерами профиля. Имён проходов канон не называет нигде. Направление несимметрично, и это верно: конвейер называет документы канона поимённо, потому что он их читатель, а обратной ссылки быть не может — документ живёт дольше, чем раскладка проходов. Что вычищено: имя review-basics в canon.md, в changelog версии 5 и в выводе docs.py; «её берёт basics» из таблицы ролей; описательные адресации того же класса — «архитектурный проход судит», «враждебный проход выдумает». Худшей была строка в skeletons.md «там идут враждебный, эксплуатационный и архитектурный проходы»: утверждение о составе ступени, живущее на стороне, которая о составе не знает. Строка таблицы «эксплуатационный проход ревью» стала «тема ревью operations» — заодно совпала со словарём, к которому tasks/SKILL.md отсылает как к единому дому. Отдельно — пример, нарушавший собственное правило. Объяснение, почему вопросы адресуются темам, звучало «вопрос, адресованный ops, перестал задаваться в тот день, когда ops уехал в верхнюю ступень»: правило про нестабильность имён, проиллюстрированное именем. Стало «адресованный проходу» и переживёт переименование. Починена и висячая ссылка: project-facts.md отсылал к таблице «Кто читает» в каноне, которой там нет — она была убрана правкой, вводившей темы, и по новому правилу её и не должно быть. Списка читателей не ведёт никто: читателя назначает план прогона. Тема 38 в DECISIONS.md, следствия 143-144. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
900f3f83ca
|
gate и autotests сведены к одному имени
Тема звалась autotests, а закрывающий её проход — gate, и на всех трёх ступенях это была одна и та же клетка таблицы. Одна сущность под двумя именами — та же ошибка, что и два разных под одним, только тише: она не путает, а теряет. Вопрос проекта в docs/review адресуется теме; адресованный проходу не приезжает никуда, и ровно этот отказ уже случился однажды с ops. Победило имя темы. Тема первична по правилу 0, а имена тем — это имена документов: docs/autotests.md проект напишет (что покрыто, что нарочно нет, где testdata), docs/gate.md не напишет никто, потому что гейт это команда, а не предмет. Слово «гейт» к тому же занято дважды — команда проекта и ребро графа; третьим значением стал бы нечитаемым отчёт, где «гейт красный» и «гейт нашёл» про разное. И тема шире гейта ровно на «чего в гейте намеренно нет». Цена названа честно: autotests звучит уже своего содержимого — линт, типы и сканер уязвимостей тестами не являются. Гасится строкой в уставе: тема — это «проверено ли машиной», а не «есть ли тесты», гейт в ней инструмент, а не граница. Слово «гейт» осталось ровно в одном значении — команда проекта. Все прочие вхождения (семантика гейта, «пока гейт красный», финальный гейт в task-batch) именно про неё и не тронуты. Побочно: autotests — единственная тема, чей дом лежит не в docs/, а в CLAUDE.md. Канон править не пришлось: список тем открытый, и заведённый когда-нибудь docs/autotests.md ляжет на существующее имя. Тема 37 в DECISIONS.md, следствия 141-142. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a81dd1a5a7
|
ревью по темам: документ проекта стал направлением проверки
Замечено при сверке документов канона с составом ступеней: три документа остались без читателя ниже wide — security.md, database.md и adr/. Проект поддерживал их, а на 90% задач не открывал никто. Причина оказалась не в переезде проходов, а в том, как описан состав прогона. Список тем нигде не был записан: он существовал побочным продуктом списка проходов. Проход уезжал в верхнюю ступень — и тема уезжала с ним беззвучно. Отчёт честно говорил «ops не запускался» и не говорил «эксплуатацию не смотрел никто», а нужно второе. Теперь тема первична, проход вторичен — это правило 0 конвейера, а прогон описывается таблицей «тема → дом → глубина → кто закрывает», и таблица есть в каждом отчёте. Тема есть документ, список открытый. Всё, что проект кладёт в docs/, становится темой ревью; запретить нельзя, разрешения не надо. Не темы ровно две: docs/tasks/ и docs/review — настройка самого конвейера, слой над темами. Отсюда главное: docs/ перестал быть документацией и стал конфигурацией конвейера. Проект настраивает проверку тем, что пишет о себе, а не отдельным файлом настроек, который разошёлся бы с документами. Ядро — requirements, autotests, conventions, architecture, security, operations; всё сверх разбирает basics, потому что именных проходов конечное число, а тем столько, сколько заведёт проект. Тема живёт файлом или каталогом, на выбор проекта: docs/security.md и docs/security/ — одно и то же. Прежде форма была задана поимённо и обосновать её было нечем; заодно в TODO висел вопрос «а если architecture.md разрастётся». Теперь ответ механический: разросся — стал каталогом с README.md, и это не смена версии. Обе формы сразу — ошибка, docs.py её ловит. Заведён review-scope, sonnet, стадия 0, до гейта: находит документы, выводит темы, назначает глубины, выбирает ступень с обоснованием. Довод оказался сильнее синхронизации документов — до сих пор профиль называл тот же оркестратор, который написал код, то есть в точке выбора глубины проверки разведённости с автором не было вовсе, а решала она под давлением «я почти закончил». Вызывающий пайплайн профиль больше не передаёт. Поднять и понизить ступень разметчик вправе одинаково, но обоснование обязательно всегда. Sonnet ему хватает потому, что вывод устроен как список: каждый файл в docs/ обязан попасть в план темой или строкой «не тема, потому что», и план сверяется с ls docs/ за секунду. Выбор ступени — суждение, но у него три независимых корректора: отрицательный тест quick, правило «спорный случай вниз» и сигнал basics о заниженной ступени. Разметчик передаёт адреса, а не пересказ. Проект однажды уже держал review-brief.md и убрал его: второй дом расходится с первым и выглядит актуальным. Пересказ в задании — тот же посредник, живущий один прогон. Исключение одно: отсутствие дома, этого проход сам дёшево не выяснит. quick и standard совпали составом и разошлись глубиной — иначе требование «нижние ступени закрывают все темы, просто не так глубоко» не выполняется. Глубин три, и они про способ доказательства, а не про старательность: сверка (открыть дом, открыть дифф, сравнить), разбор (построить сценарий рассуждением), доказательство (прогнать, померить, построить путь). Третья есть только в wide. Цена принята: это единственное место, где профиль не выводится из списка проходов, поэтому глубина объявляется в отчёте наравне со ступенью. review-code переписан, и это оказалось крупнее исходной находки: код как код не читал никто. specs сверял с требованиями, basics — с отказами окружения, architecture — с устройством, а code был проходом только по прозаическим конвенциям и прямо объявлял, что рантайм и логика не его. «Здесь ошибка в логике» не говорил вообще никто. Теперь у прохода две половины: девять классов технического дефекта (необработанная ветка отказа, пустое и нулевое, граница диапазона, перепутанный операнд, неосвобождённый ресурс, изменение под итерацией, неверно применённый интерфейс библиотеки, недостижимая ветка, «сделано соседнее») и прежняя сверка с конвенциями. Модель поднята до opus по признаку темы 35: цена пропущенной находки — дефект в проде. Канон повышен до версии 5: форма дома на выбор, открытый список тем, AGENTS.md законно лежит рядом с CLAUDE.md, «Вопросы к проходам» → «Вопросы по темам» (имя прохода переезд не переживает, тема переживает), «Недоступно проверке» — тоже по темам. docs.py переписан под темы: ловит двойной дом, принимает обе формы, перечисляет свои темы проекта вместо «файл вне канона». Побочно закрыт давний пункт TODO про каталожную форму architecture.md — решать больше нечего. Прогон от всего этого стал дороже, а не дешевле, впервые за сессию: плюс scope в голове каждого прогона, плюс code на opus, плюс basics теперь и в quick. Куплены разведённость выбора ступени, видимость непокрытых тем и технический разбор кода, которого не было вовсе. Тема 36 в DECISIONS.md, следствия 137-140. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c93a9d1269
|
модели субагентов: двое из девяти опущены на sonnet, критерий переписан
Сквозной проход по тринадцати уставам с одним вопросом: кого из девяти opus-агентов можно опустить без потери. Ответ — двоих, и оба не из конвейера. По дороге выяснилось, что критерий, которым модели раздавались до сих пор, отвечает не на тот вопрос. Деление applicative против generative смотрит, откуда проход берёт критерий, а платит проект за разбирательство с находкой. Рабочий признак другой: находка со ссылкой на записанный источник — строку спеки, цель в манифесте, значение в конфиге — опровергается открытием файла, и дешёвая модель ошибается здесь проверяемо; находка-суждение опровергается рассуждением, а рассуждение стоит триажа или человека. Признак объясняет и прежнюю раскладку лучше, чем она сама себя: gate, code и ops дёшевы не потому, что у них чек-лист, а потому что каждая их находка показывает пальцем на строку. doc-code-drift переведён на sonnet. Закрытый перечень из восьми правил, каждое — пара «факт в документе ↔ команда, которой он проверяется». Устав прямо запрещает суждение, требует формы «написано X, в коде Y, проверено командой Z» и правила «нечем проверить — не находка». Ложная находка опровергается той же командой, которая её породила. task-form переведён на sonnet, и решило не устройство, а потребитель. Его находка это готовая формулировка, которую человек читает и отклоняет командой edit, а не оркестратор, который молча реализует всё прочитанное. Довод, державший triage наверху, здесь не работает вовсе: ошибка стоит строки чтения. review-specs рассмотрен всерьёз и оставлен на opus — по причине, обратной общей. Он самый частый opus-проход, идёт и в design, и на коде. По устройству applicative: SKILL.md сам называл стадию 1 «два applicative-прохода, оба дешёвые», платя за одного sonnet, за другого opus. Расхождение закрыто текстом, а не переводом. Наверху его держит направление code → spec, где надо заметить отсутствие: тихий фолбэк, самодеятельный дефолт, проглоченную ошибку. Прочие держат opus из-за цены ложных находок, этот — из-за цены пропущенных, а пропуск не оставляет следа ни в отчёте, ни в границах покрытия. Остальные шестеро оставлены с причиной у каждого: adversary и rubric порождают критерий по построению, architecture — чистое суждение о структуре, triage — сток, doc-consistency путал бы «упомянуто в двух местах» с «оба утверждают», basics заведён этой же сессией и половина его вопросов суждение. Это разбор уставов, а не замер, и так и записано. calibration.md двигает модель инъекцией дефекта; инъекции не было. Двое переведены потому, что цена их ошибки ограничена сверху независимо от модели. Поправлена проза, ссылавшаяся на прежние модели: «оба судьи на opus» в cadence, canon/SKILL, canon.md и docs/SKILL — теперь дорог по-настоящему один doc-consistency, второй читает репозиторий целиком, но идёт на sonnet. В tasks/SKILL снято «отсюда и разные модели»: у task-form и doc-wording она теперь одна, а разрез по глубине остался. Тема 35 в DECISIONS.md, следствия 134-136. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
21b840a8e4
|
профили ревью: тяжёлые проходы в верхнюю ступень, на умолчании — один базовый
Тема 33 сняла самую большую разовую статью расхода, но не тронула главную — частоту. Меряющая пара стояла в standard, то есть на большинстве задач, и именно она делала прогон долгим: два прохода держат машину, идут цепочкой и доказывают находки запуском. Цель разбора названа прямо: лучше поправить в следующей задаче, чем держать одну два часа. adversary и ops переехали в wide. Стадия осталась самой урожайной за всю историю замеров — пять из семи выживших находок дозапуска и единственная находка про молчаливый старт отката, — но её ценность оплачивается на каждой задаче, а получается на немногих. Решение по цене, не по ценности. Заведён review-basics: мелкая осадка двух тяжёлых проходов, без единого запуска. Стоит только в standard. Восемь вопросов, на которые отвечают чтением: таймаут и отказ соседа, идемпотентность и одновременная запись, остановка на середине, частичный откат при двух версиях, наблюдаемость и тишина, очевидный рост объёма, второй способ мимо единой точки (грепом, не картой), что отсюда удалить. Потолок 4 находки, машину не держит, ничего не меряет. Вопрос про частичный откат — не для полноты списка. Без него правило «миграция схемы не поднимает ступень» рассыпалось бы: раньше миграцию разбирал ops, а он теперь наверху. Проход заведён затем, чтобы у standard остался хоть один взгляд на ось времени. Модель у него верхняя, opus, и это не спорит со словом «средний»: усилие режется входом и потолком, а не моделью. Дешёвая модель на опиниативном проходе платит триажем — это записанный замер, отменять его без нового замера нечем. Лестница вышла 4/5/7. Главный выигрыш не в числе проходов, а в том, что из standard ушла цепочка: теперь там гейт, три прохода одним сообщением и триаж — граф плоский, ждать некому. Правило выбора ступени переписано на два вопроса, и объём изменения вошёл в него впервые. Крупное или незнакомое — трогает несколько узлов, переносит ответственность, форму решения нащупывают по ходу — это wide, и он рассчитан на 5-10% задач. Мелкое — один узел, форма очевидна заранее, откат сводится к обратной правке — quick. Всё остальное standard, рабочее умолчание. Раньше ступень выбиралась только по классу изменения и на размер смотреть запрещала; теперь признаков два: класс отвечает за обратимость, объём — за цену разбирательства. Отрицательный тест сохранил прежнюю мудрость в новой рамке: что после мерджа не откатывается обратной правкой — не quick, каким бы маленьким ни был дифф. Три строки миграции идут в standard. Спорный случай решается вниз, и асимметрия объяснена ценой: ошибка в сторону standard стоит находки на следующей задаче, ошибка в обратную — трёх тяжёлых проходов на каждой задаче, выбранной неверно. Сделка записана вместе с обратной связью, иначе это тихая потеря качества. На quick и standard не проверяется ничего, что требует запуска: построенный путь, эксперимент против драйвера, любое число. Это самая крупная граница покрытия конвейера, и она идёт строкой в каждом таком прогоне поимённо. Сигналов о том, что ступень занижена, два: журнал дефектов в docs/review.md и сам basics — он единственный, кто смотрит на дифф целиком на нижних ступенях, и обязан сказать строкой, если задача выглядит крупнее профиля. Побочно: условие профиля design то же самое, так что rubric и architecture на предложении тоже упали до 5-10% задач. Тема 34 в DECISIONS.md, следствия 130-133. Версия канона не поднята; инструкция проекту дописана в пункт 8 записи «Версия 4». Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
ea84a4fbb3
|
стоимость ревью: снят проход независимой реализации и самая дорогая модель
Прогоны стали долгими, а счёт в токенах заметным. Разбор шёл не по находкам, а по статьям расхода. Две названы прямо: убрать reimpl и убрать fable. reimpl писал свою реализацию узла, не открывая существующую, и диффил по решениям. Его счёт определялся объёмом вывода — он один писал код, а не читал его, — и на прогоне это была самая большая строка. Снят по цене. Профиль deep от этого не похудел, а исчез: reimpl был единственным, чем он отличался от wide, и без него у двух имён оказался бы один состав. Ровно от этой болезни лечилась ступень wide решением JJJ — у профиля обязан быть один правильный ответ, иначе реестр состава нечем проверять. Ступеней три: quick, standard, wide. Вместе с профилем снято всё, что обслуживало только его. Барьер стоимости — он держал дорогой проход, чтобы тот не писал реализацию против кода, который через час перепишут; дорогого прохода нет, граф стал плоским во всех профилях, рёбер осталось два вида вместо трёх. Тест «идентичность, слияние, разбор» — полторы страницы, служившие единственной цели: выбрать deep не по ощущению; вместе с ним ушёл проектный перечень мест в docs/review.md и его скелет в каноне. Стадии перенумерованы: 0 гейт, 1 сверка, 2 враждебный и эксплуатационный, 3 архитектурный, 4 триаж — дыра на месте третьей читалась бы как пропущенная стадия. Снятие записано как сознательное сужение, а не как «класс оказался пустым». calibration.md требует замера на двух проектах перед удалением прохода; замера не было, было решение о цене. Поэтому в «Честном пределе» стоит строка: «не знаю, чего не знаю» больше не достаёт никто. Остаток независимого взгляда дают профиль design и architecture, но альтернативной реализации, с которой можно сдиффить решения, у конвейера нет. Класс уходит в границы покрытия каждого прогона, у проекта — в подраздел «перестали проверять сознательно». Без этой записи снятие через месяц читается как «проверено и признано лишним». fable снят с троих: review-triage, review-architecture, doc-code-drift — все на opus. Основание верхней модели «ошибка распространяется дальше самой находки» осталось, но оно объясняет, почему двое не опускаются до sonnet, а не почему им нужна ступень выше opus: разницы в пользу более дорогой модели не показал ни один прогон, а время и счёт она множила. Палитра схлопнулась до двух цветов, красного в репозитории больше нет, frontmatter.py теперь отвергнет модель вне sonnet и opus. Версия канона не поднята сознательно. Проектам всё равно надо снести перечень мест для deep из docs/review.md, поэтому пункт вписан в «Что сделать проекту» записи «Версия 4» — её ещё не гонял ни один проект, оба ждут в TODO. Тема 33 в DECISIONS.md, следствия 127-129. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
cbfae90f3f
|
словарь: пять слов сняты, девять закрыты списком вместо оговорки «прижилось»
Проход упрощения уткнулся в один класс у всех пяти агентов: слово, живущее в трёх-шести файлах разом. Правка в одном месте развела бы словарь, правка во всех — уже не упрощение текста скилла. Каждый честно остановился и записал слово в отчёт, и одни и те же слова всплыли в разных отчётах. Разобрано этим проходом. Причина, по которой они вообще накопились, оказалась в самом уставе языка. Он разрешал не переводить «термин, у которого нет точного русского эквивалента и который в команде уже прижился». Проверить это нельзя: прижившимся выглядит любое слово, встреченное трижды, — и ровно так рассудили пять агентов подряд, каждый независимо. Оговорка заменена закрытым списком из девяти терминов с колонкой «что называет»: интейк, триаж, провенанс, дедуп, чек-лист, дифф, промпт, сущности OpenSpec, роды проходов ревью. Интейк оставлен потому, что «заведение» называет создание файла, и слить их значит смешать две операции; провенанс — потому что «источник» рядом называет саму запись, а не свойство числа. Слово не из списка и не из таблицы имён вещей — находка, а не стиль. Список заведён домом язык-словарь в language.md и копией в уставе doc-wording. Копия обязательна: агент работает в репозитории проекта, где плагина может не быть, и без списка предъявил бы интейк как англицизм. Снято пять слов, 29 мест: конфляция → смешение, декорреляция → разведённость, непоймание → почему не поймали, эвал-сет → проверочный набор, гайд → руководство. Латинизм или калька при живом русском слове в каждом случае. Разбор декорреляции показателен: проект уже владел нужным словом — «агенты разведены по глубине», «разведены по охвату» — и держал рядом латинский синоним того же понятия. Это не англицизм, а второй дом для слова. Непоймание снято ещё и потому, что форма журнала дефектов, которую канон кладёт в проекты, спрашивает «Почему не поймали», а проза рядом называла это «причиной непоймания». Скелет и проза о скелете говорили разными словами. Снятое записано вместе с оставленным, в одном списке и с заменой каждого. Иначе слово возвращается: из текстов оно уходит, но ничто не мешает следующему проходу завести его заново — оно ведь короткое и точное на вид. Тема 32 в DECISIONS.md, следствия 124-126. Нумерация правил в уставе doc-wording сдвинута: словарь встал шестым, жаргон и далее уехали на единицу. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |