- migrations-step-norm-and-tests, gate-steps-subject-guard и
review-config-from-go-upgrade уехали в голову: слой проверок, которым верят
все задачи ниже;
- rollback-restores-wrong-session-duration встал рядом с соседом про откат,
bot-api-only-through-bot-client — рядом с чисткой транспорта,
pin-runtime-image-base — перед spa-skeleton, откуда начинаются пересборки;
- pipeline-spec-purpose-drift закрыта реализованной, а
docs-consistency-2026-08-13 переписана под пять оставшихся находок: шестую
свело повышение раскладки.
- ссылки на tasks/ROADMAP.md переведены на BACKLOG.md и на openspec/specs,
упоминания целей — на задачи, которые эту работу делают;
- судьи документации нашли восемь расхождений: Purpose спеки pipeline объявлял
неописанным то, что уже нормирован пятью требованиями, вид времени в
конвенции спорил со схемой, а квоты, шесть часов и отказ от Web Push жили
сразу в двух документах без ссылки друг на друга;
- два числа получили провенанс: 259 200 запросов в сутки и потолок в шесть
часов теперь ведут к записке разведки, а не читаются как замер.
- 11 записей типа goal закрыты с причиной, называющей задачи-наследники;
ROADMAP.md удалён, индекс остался один — BACKLOG.md;
- 33 записи переписаны: ссылка «Двигает пункты N «Завершения» цели» уступила
место прямому утверждению — без целей номера пунктов вели в никуда;
- шапка BACKLOG.md размечена парой <!-- стадия -->, порядок строк теперь
объявлен зависимостью, а не важностью.
Каталог скилла зовётся skills/canon, а переменная вела в skills/doc-canon:
шаг гейта скрипт не находил и краснел кодом 3, что читалось как отсутствие
плагина, — раскладку документов при этом не проверял никто.
- Перевод на канон 1 доделан: адреса служебного файла и имена скиллов
переставлены в девяти местах прозы и кода, гейт зовёт три скрипта по новым
путям, прежние docs/.docs.json и tasks/.tasks.json удалены.
- Сверка двумя агентами нашла четырнадцать расхождений, тринадцать сведены
строками: число прогонов ревью и преамбула журнала дефектов, счёт capability,
маршруты README, дубли инварианта захвата и кодов прогона, протухшие указатели
записок разведки, маркер долга на переехавшем абзаце. Срок жизни сессии
нормирует спека access, database.md на неё ссылается.
- Purpose спеки pipeline объявляет неописанным то, что в ней же и стоит; правка
идёт изменением openspec, поэтому заведена задача pipeline-spec-purpose-drift.
- четыре новые записи: проверить шаг migrations так же, как шаг сверки версий Go;
свести шесть расхождений между документами канона; запретить обращаться к Bot
API мимо клиента бота; разведка о шагах гейта, теряющих предмет
- context-cancel-in-pipeline приведена к правде: дописан перечень сделанного
попутно, критерий с оракулом «тест на трёх прерываниях подряд» разбит надвое —
проверена была только его узкая половина
- порядок заведения правила пополнен строкой: правка, снявшая последнее
употребление импорта, роняет сборку, а не проверку, и её вывод легко принять
за сработавшую мутацию. Случай был в этом же сеансе — проба приёма по HTTP
- в go-linters.md заведён раздел «Отмена и внешний собеседник», перечень
механизированного пополнен девятью правилами и двумя шагами гейта, названы
остатки: contextcheck не видит сигнатуру без контекста вовсе, шаг migrations
судит только шаги, бывшие в базе диффа, rowserrcheck и sqlclosecheck
профилактические — предмета в коде нет
- в logging.md и security.md чистка отказа Telegram описана по факту: точка одна
и лежит на границе клиента, закрыты все пять путей вместе с логгером самой
библиотеки. Прежнее «*Расхождение:* вычистки нет... она не логируется» было
неверным дважды
- в журнал дефектов записаны две находки: отказ скачивания уносил токен бота
(проскочил, жил с самого начала) и остановка сервиса хоронила конвертируемую
запись в failed (поймано ревью до коммита)
- вопрос темы operations про отмену переформулирован: спрашивать надо не
«доходит ли контекст», а «что шаг делает с задачей, деньгами и ответом
отправителю»; вопрос про таймаут оставлен с оговоркой, что проброс контекста
на него не отвечает
- в памятке: словарь кодов новых шагов, требование компилятора C у детектора
гонок и оговорка, что «CGO не нужен» относится к сборке, а не к гейту
- включены noctx, contextcheck и bodyclose (отмена доходит до внешнего вызова,
контекст приезжает сверху, тело ответа закрывается), nilerr, rowserrcheck и
sqlclosecheck (отказ не теряется молча), testifylint и nolintlint (форма
утверждения и форма подавления), плюс errcheck check-type-assertions:
непроверенное приведение типа паникует, и check-blank его не видит
- заведён шаг tests: go test -race, потому что «результат пишет только держатель
захвата» — утверждение об одновременности. Без компилятора C шаг гоняет тесты
без детектора и краснеет кодом 3 после них: гонки не повод отнимать у гейта
сами тесты
- заведён шаг migrations: у файла шага схемы допустим один статус — A. Баз диффа
две, BASE и HEAD: первая отвечает на «уже уехал» настолько, насколько свежа
origin/master, вторая ловит правку закоммиченного шага независимо от неё.
Каталог берётся из docs/.docs.json, пустой каталог роняет шаг
- единственное подавление — noctx на httptest.NewRequest в проверках: за
фикстурой запроса внешнего собеседника нет. Граница проверена мутацией —
http.Get и exec.Command из проверки правилу по-прежнему подсудны
- контекст проложен от воркера и обоих входов до внешних вызовов: ffmpeg и
ffprobe заводятся через exec.CommandContext, SpeechKit и Object Storage
принимают ctx вместо context.Background, скачивание записи идёт запросом с
контекстом. Прежде остановка сервиса не доходила до чужой работы вовсе
- прерванный шаг приговора не выносит: убитый по контексту ffmpeg отдаёт
«signal: killed», от настоящего отказа неотличимо ни типом, ни errors.Is, и
различает их только ctx.Err(). Задача остаётся на повтор, попытку не тратит и
отправителю о несуществующем сбое не сообщает; воркер не считает остановку
отказом, а задача не забирается вовсе, если нас уже остановили
- клиента Bot API заводит единая точка internal/adapter/telegram: токен стоит в
пути каждого обращения, а http.Client кладёт адрес в *url.Error целиком.
Чистка на месте употребления закрывала один вызов из пяти — теперь свой Do
чистит отказ, подменённый логгер вычищает токен из строк самой библиотеки, а
транспорт бота токена не получает вовсе
- принятие операции распознавания защищено от отмены своим пределом: SpeechKit
мог её принять и начать считать деньги, а потерянный идентификатор заставил
бы повтор оплатить ту же запись второй раз
- приём по HTTP доводит запись до задачи независимо от отправителя: на
контексте запроса один обрыв соединения терял полностью загруженную запись
- ответ Telegram с не-2xx кодом больше не становится записью: прежде тело
отказа доезжало до хранилища и умирало на ffprobe, уводя диагностику
- документ docs/autotests.md снят: перечень правил, подавлений и лестница
механизации — это конвенция о том, чем машина читает код, и место ей среди
прочих записей
- в шапке названо, чего в записи нет: как писать тесты. Свойства, которые обязан
проверять тест, остаются в review.md, «Типовые узлы»
- ссылки переставлены в памятке, индексе конвенций, четырёх записях, review.md,
.golangci.yml, lefthook.yml и пакете сканеров
- лестница механизации из пяти ступеней, два круга проверок, перечень правил
таблицами по родам, перечень подавлений с причинами, порядок заведения
правила; названы остатки правил и отклонённые подъёмы
- утверждения «Механизировано» в четырёх записях конвенций и единые точки в
architecture.md приведены к сегодняшнему состоянию; изъятие «транспорт знает
адаптер хранилища» названо строкой
- в журнал дефектов записаны две находки: узнавание конца потока по тексту и
правило гейта, обходимое одной лишней строкой
- шаги shell (shellcheck) и dockerfile (hadolint) заведены; два правила hadolint
подавлены поимённо с причиной — DL3007 до задачи pin-runtime-image-base и
DL3018 по существу
- lefthook гоняет на затронутых файлах gofmt, golangci-lint по их каталогам,
shellcheck, hadolint и gitleaks — около секунды; полный набор в pre-commit не
переносится намеренно
- заведён мутационный тест скрипта сверки версий: 20 сценариев спеки toolchain
плюс требование сообщения называть все четыре места, независимость исхода от
установленного go и запрет звать go, docker и сеть
- включены sloglint, misspell, depguard; forbidigo получил запреты на чтение
времени, окружения и вывод в stdout — каждый по свойству, а не по одному
имени: запрет на os.Getenv без соседей обходится os.LookupEnv
- заведён internal/archrules — тесты-сканеры: направление зависимостей между
ядром, транспортами и адаптерами, узнавание ошибки по тексту в шести формах,
и согласованность колонок очереди во всех четырёх местах плюс шаг схемы
- каждое правило проверено мутацией, каждое исключение объявлено с причиной
- заведён internal/clock: Now даёт метку в UTC, Start — начало измерения
длительности с монотонными часами; девять мест рабочего кода и запрос захвата
переведены на него, долг «время time.Now() по месту» закрыт
- клиент SpeechKit узнавал конец потока сравнением err.Error() == "EOF": отказ
с тем же текстом вернул бы усечённую расшифровку как готовую, теперь
errors.Is(err, io.EOF)
- починены находки новых линтеров: две опечатки, два slog.DiscardHandler,
четыре неэкранированные подстановки в docker/entrypoint.sh
- перечень «Механизировано» и то, что осталось прозой, снято из конвенций: они
про то, как писать код, а не про инструменты, которые его читают
- новый документ — дом темы ревью autotests, с границами: семантика гейта
остаётся в CLAUDE.md, журнал дефектов и вопросы по темам — в review.md
- вопрос ревью о суждении по готовому ответу сужен до того, что машина не
проверяет: до ответа мимо recorder
- шаг vulns гоняет govulncheck последним: ему одному нужна сеть, и он самый
долгий; отсутствие инструмента даёт код окружения, а не пропуск
- закрыты обе достижимые находки — grpc до 1.82.1, aws-sdk-go-v2/service/s3 до
1.97.3 с eventstream 1.7.8; прогон на реальных ключах Yandex не делался
- место шага названо в семантике гейта: он судит достижимость из кода, и
недостижимая GO-2026-5932 в golang.org/x/crypto/openpgp его не роняет
- forbidigo с analyze-types запрещает в файлах проверок обращение к
httptest.ResponseRecorder.Header и .HeaderMap: правило судит по типу
приёмника, поэтому ловит и цепочку, и переменную, и индекс, и обход
- класс стоил трёх зелёных гейтов при неработающем коде; правило записано
строкой в перечне механизированного, прозой не дублируется
- поправлены два утверждения «механизировано: ничего», разошедшиеся с
включённым линтером и со сверкой шага схемы
- недостающий скрипт у всех четырёх обёрток в Taskfile.yml даёт 3, как обещает
словарь: прежний 1 значил «дрейф» и отправлял искать разъехавшееся там, где
просто неполно дерево
- в словарь кодов CLAUDE.md добавлены сами обёртки и оговорка про 201: этим
кодом task отдаёт наружу любой отказ шага, а код шага печатает строкой
- шаги PocketBase переехали из файла в пакет
internal/adapter/repo/pocketbase/migrations, файл на шаг с именем
зарегистрированного шага; туда же имена коллекций, срок сессии — в provider.go
- ключ migrations в docs/.docs.json наведён на этот каталог: прежнее значение
указывало на несуществующий migrations/, и шаг гейта проходил зелёным при
всякой правке схемы
- app.go подключает пакет шагов явным пустым импортом: пропавшая ссылка на
константы унесла бы регистрацию, и хранилище поднялось бы без коллекций
- периметр: passport.md и security.md больше не утверждают, что HTTP API
открыт без аутентификации, а review.md не числит эту находку типовой
ложноположительной — приём, опрос и файл закрыты сессией с 2026-08-12;
- logging.md писал, что расширение попадает в журнал полем пути: описано
изъятие инварианта приватности — собственное поле, имени и пути нет;
- узел ревью переименован в repo/pocketbase, поведение конвейера из обзора
уехало ссылкой в спеку pipeline, Purpose спеки storage написан вместо
заглушки, в ADR о переезде дописано уточнение о действующей раскладке.
- порядок беклога и роадмапа назначен слоями: проверки, которым можно
верить → долги входа → владелец записи и контракт API → конвейер под
тестами → приложение и возможности поверх; у каждого движения записана
причина;
- заведены восемь задач под пункты «Завершения», которых не закрывала ни
одна запись, — цель any-audio-source была без задач вовсе;
- у четырёх задач сняты критерии, требовавшие того, что делает задача ниже
по очереди; исправлены ссылки на несуществующий repo/sqlite и на
отменённую разведку об очереди.
- шаг схемы закрывает поверхность, которую хранилище приносит открытой:
собственную регистрацию, вход по паролю и одноразовый код — без этого
закрытие приёма обходилось двумя запросами
- продление сессии выключено, срок семь суток: иначе отзыв доступа у
провайдера до сервиса не доходит никогда
- файл записи отдаётся вошедшему по токену файла — пересмотр
ADR-2026-08-12-file-link-open-but-not-logged
- четыре задачи из находок ревью и заметки владельца: проверки shellcheck и
hadolint с тестом скрипта сверки версий, закрепление рантайм-базы образа,
коды выхода шагов гейта, настройка конвейера ревью
- INBOX разобран целиком и очищен
- шаг go-version в task gate сверяет объявленную версию в go.mod, Dockerfile,
CLAUDE.md и README.md; судит по репозиторию, go не зовёт, docker и сети не
требует
- заведена capability toolchain: до сих пор спеки нормировали только поведение
сервиса, теперь и инструмент сборки. Причина и цена — в двух ADR
- закрыт дефект 2026-08-12: образ на golang:1.24-alpine разошёлся с go.mod и
перестал собираться, а восемь шагов гейта и шесть проходов ревью были зелёными
- записи, метаданные и файлы съехались под один каталог данных; появилась
панель владельца, а gin, goqu, goose и требование CGO ушли
- захват задачи стал одним запросом с RETURNING; заведены число попыток,
состояние dead и нарастающая пауза вместо признака is_error
- имя файла в хранилище задаёт сервис и в журнал не идёт: вместе с
идентификатором записи оно собирало бы ссылку на скачивание
- признаки «работы нет» и «задача не найдена» узнаются по смыслу, а не
приведением типа: обёртка `%w` на пути больше не превращает пустой прогон
воркера в отказ раз в секунду
- отказ закрытия соединения с распознавателем доходит до вызывающего
(`errors.Join`) либо до журнала; у `errcheck` включён `check-blank`, иначе
критерий принимал реализацию, выбрасывающую отказ в пустоту
- заведены первые тесты пакета worker и capability `pipeline`; долг из четырёх
замечаний линтера закрыт, гейт зелёный целиком
- хвост после последней точки попадает в журнал внутри пути файла и остаётся
там осознанно; наружу он выходит только приведённым к перечню
- в модели угроз это перестало читаться незакрытым остатком
- расширение приводится к перечню известных форматов прежде метки метрики:
страница метрик открыта, и хвост имени уезжал на неё дословно
- проверки приёма перехватывают все три потока журнала и читают реестр метрик,
каждая падает при снятии того, что сторожит
- заведены записка разведки docs/research/spa-framework.md со сравнением Svelte,
Vue и React на одном экране и решение ADR-2026-08-11-spa-on-vue
- docs/conventions/web-ui.md переписан под Vue: компоненты, маршруты, состояние,
обращение к API и показ ошибок
- закрыт вопрос «Приложение» в docs/architecture.md, уточнена задача spa-skeleton
- заведены записка разведки job-queue-choice и ADR: готовые библиотеки River и
goqite отвергнуты, захват сворачивается в один запрос с RETURNING
- в architecture.md уточнён принцип «очередь таблицей» и закрыт открытый вопрос
«Очередь», кроме холостого опроса
- задача pocketbase-storage забрала очередь себе: границы, счётчик попыток,
состояние «мертва» и оракулы
- сняты повтор слова в записке разведки и та же строка в цитате ADR,
убран термин «чекпоинт», разведена цепочка местоимений в паспорте
- oidc-login: «зачем» перестало повторять тело, задача заявила пункт 3
«Завершения» цели multi-user — он не был закрыт ни одной её задачей
- разведка pocketbase-admin-fit ответила замером панели версии 0.39.10:
записка в docs/research/pocketbase.md, решение — в ADR
- панель показывает файлы и пользователей только своих, поэтому файлы
переезжают в её раскладку, а вход идёт через её провайдера OIDC
- периметр расширился панелью на /_/ и паролем суперпользователя;
закрывает её Authelia на прокси, задачи в беклоге у этого нет
- README разгружен: контракт HTTP API, таблицы БД, состояния задач и белый
список отданы нормативным источникам ссылками
- в `architecture.md` и `review.md` числа и механика захвата задачи заменены
ссылками на `database.md`, а описание конвейера ревью — на прогон от 2026-08-11
- в `CLAUDE.md` и `security.md` поправлены границы домена, оценка объёма записи
и адрес очереди задач
- `docs/.pm.json` переименован в `docs/.docs.json`, версия канона — 14
- ADR принимает записку разведки как источник решения наравне с архивным
`design.md`
- заведён `tasks/.tasks.json`, а в описании гейта — шаги `tasks.py check` и
`openspec.py check`
- data-ownership — обратное право к бессрочному хранению: человек убирает свою
запись вместе с файлом, объектом в Object Storage и всеми уровнями текста;
- delete-record закрывает все пять пунктов цели: подтверждение, необратимость,
чужую запись не тронуть, повторная загрузка того же файла заводит новую
задачу, а строки потребления остаются — деньги потрачены;
- docs/security.md: пункт «Удаление данных по требованию» перестал говорить,
что задачи под это нет.