diff --git a/tasks/BACKLOG.md b/tasks/BACKLOG.md index cdadda2..04956d9 100644 --- a/tasks/BACKLOG.md +++ b/tasks/BACKLOG.md @@ -39,11 +39,7 @@ ## Очередь -- [🐞 Починить путь миграций в настройке сверки документов](items/fix-migrations-path-in-docs-config.md) — Ключ migrations указывает на каталог migrations/, которого в репозитории нет: шаг гейта зелен при изменённой миграции и нетронутом database.md, а конвенции числят этот род механизированным. -- [🧹 Привести коды выхода шагов гейта к общему словарю](items/gate-step-exit-codes.md) — CLAUDE.md объявляет словарь кодов общим для четырёх проверочных шагов и описывает код 3 как «каталог или файл не найден», но все четыре обёртки в Taskfile.yml при отсутствующем скрипте отдают 1 («дрейф»), из-за чего читатель кода идёт искать разъехавшееся там, где просто неполно дерево. -- [🧹 Судить ответ в тестах по готовому ответу](items/response-assertions-judge-result.md) — Проверка, читающая изменяемую карту заголовков обработчика, зелена при неработающем коде: класс всплыл трижды, последний раз на уборке куки входа. - [🧹 Ронять гейт на изменённой функции, которую не выполняет ни один тест](items/gate-changed-lines-coverage.md) — Свойство «изменённое место покрыто хоть одним тестом» записано в docs/review.md, но не механизировано: за две задачи подряд непокрытые шаги ловили руками. -- [🧹 Ловить уязвимости в зависимостях шагом гейта](items/gate-dependency-vulnerabilities.md) — govulncheck находит две достижимые уязвимости в клиентах Yandex, а ни гейт, ни список «чего в гейте нет» о нём не знают: узнать о третьей будет неоткуда. - [🧹 Поднимать сервис локально без действующего токена бота](items/local-run-without-telegram-token.md) — Адаптер Telegram проверяет токен обращением к Telegram и роняет старт, а боевым токеном запускаться запрещено: проверить поведение живым прогоном не может ни одна задача. - [🐞 Убрать код провайдера из журнала запросов хранилища](items/provider-code-out-of-storage-log.md) — Строка запроса с кодом входа целиком уезжает в таблицу _logs и лежит там пять суток, хотя спека access требует, чтобы код в журнал не попадал. - [🐞 Вести учёт употреблённых состояний входа на сервере](items/server-side-login-state.md) — Одноразовость возврата держится на уборке куки, то есть на браузере: сервер не помнит, какие состояния уже потрачены. @@ -98,4 +94,5 @@ - [🧹 Завести недостающие проверки: shellcheck, hadolint и тест скрипта сверки версий](items/gate-extra-linters.md) — Скрипты оболочки и Dockerfile машина не проверяет: shellcheck и hadolint не заведены, lefthook смотрит только gitleaks, а единственный исполняемый скрипт проекта на shell — scripts/check-go-version.sh — разбирали на ревью глазами построчно, потому что машине его показать нечем. - [🧹 Закрепить версию рантайм-базы образа](items/pin-runtime-image-base.md) — Финальный слой Dockerfile собирается на alpine:latest, а task image идёт с --pull, поэтому два образа из одного коммита с разницей в неделю несут разный ffmpeg — регрессия конвертации после такой пересборки выглядит как задачи в failed при пустом диффе репозитория, и откат на прежний коммит её не чинит. - [🧹 Настроить конвейер ревью по итогам прогона go-1-26-upgrade](items/review-config-from-go-upgrade.md) — Прогон вскрыл две прорехи настройки: «Типовые узлы» знают только рантайм и не знают рода «проверочный шаг набора проверок», а «Триггеры метки» не видят оси «изменение трогает канон» — и именно она дала обе блокирующие находки. +- [🐞 Починить срок сессии, который ставит откат шага входа](items/rollback-restores-wrong-session-duration.md) — Константа defaultAuthTokenDuration в шаге 202608120001 названа умолчанием библиотеки, но 1209600 — это 14 суток, а умолчание PocketBase 432000, пять суток: откат объявляет возврат к умолчанию и ставит срок вдвое больше выбранных владельцем семи. - [🔬 Квота по общему размеру загруженного на пользователя](items/per-user-size-quota.md) — Паспорт и security.md запрещают отказы по квоте пользователю, а заметка владельца просит квоту по умолчанию 5 ГБ — открытое противоречие с границей домена, которое владелец решил не разбирать сейчас. diff --git a/tasks/items/fix-migrations-path-in-docs-config.md b/tasks/items/fix-migrations-path-in-docs-config.md deleted file mode 100644 index 63d1e51..0000000 --- a/tasks/items/fix-migrations-path-in-docs-config.md +++ /dev/null @@ -1,48 +0,0 @@ -# 🐞 Починить путь миграций в настройке сверки документов - -- **Тип:** fix -- **Категория:** Очередь — Шаг гейта зелен при изменённой миграции и нетронутом database.md: на этом шаге стоит приёмка всякой следующей задачи, трогающей схему. -- **Зачем:** Ключ migrations указывает на каталог migrations/, которого в репозитории нет: шаг гейта зелен при изменённой миграции и нетронутом database.md, а конвенции числят этот род механизированным. - -Найдено ревью задачи `oidc-login` 2026-08-12, отчёт триажа — -[review/report.md](../../openspec/changes/archive/2026-08-12-oidc-login/review/report.md), -раздел «Promote candidates». - -Проверка сверяет изменённые файлы с префиксом `migrations/`, а шаги схемы лежат -в `internal/adapter/repo/pocketbase/`. Совпадений не бывает никогда, значит шаг -проходит зелёным всегда. Оракул сегодняшнего состояния: -`git ls-files | grep -c "^migrations/"` отдаёт `0`. - -Цена уже заплачена дважды: задача `oidc-login` изменила шаг схемы и не тронула -`docs/database.md`, и гейт этого не заметил — расхождение нашёл человек на -ревью. Так же провалится всякая следующая миграция. - -Развилка внутри задачи: либо поправить путь, либо снять пометку -«механизировано» в `docs/conventions/README.md` и отдать род человеку. Второе -дешевле, но тогда проверять его будет некому. - -## Воспроизведение - -1. Изменить любой файл шагов схемы в `internal/adapter/repo/pocketbase/`. -2. `docs/database.md` не трогать. -3. Прогнать `task docs BASE=origin/master`. -4. Шаг проходит зелёным, хотя должен назвать расхождение. Сегодняшнее состояние - настройки видно командой `git ls-files | grep -c "^migrations/"` — она отдаёт - `0`, то есть каталога с таким именем в репозитории нет. - -## Затрагивает - -- `docs/.docs.json`, ключ `migrations`; -- `docs/conventions/README.md`, таблица «Механизировано», строка про миграцию; -- шаг `docs` в `Taskfile.yml` — его исход меняется. - -## Критерии приёмки - -- Изменённый шаг схемы при нетронутом `docs/database.md` роняет шаг гейта. - Оракул — правка любого файла шагов схемы без правки схемы в документах, затем - `task docs BASE=origin/master`: ненулевой код возврата. -- Изменённый шаг схемы вместе с правкой `docs/database.md` шаг гейта проходит. - Оракул — то же с обеими правками: код возврата 0. -- Строка «Механизировано» в `docs/conventions/README.md` соответствует тому, что - проверка делает на самом деле. Оракул — чтение таблицы против исхода первых - двух проверок. diff --git a/tasks/items/gate-dependency-vulnerabilities.md b/tasks/items/gate-dependency-vulnerabilities.md deleted file mode 100644 index a1441fa..0000000 --- a/tasks/items/gate-dependency-vulnerabilities.md +++ /dev/null @@ -1,35 +0,0 @@ -# 🧹 Ловить уязвимости в зависимостях шагом гейта - -- **Тип:** chore -- **Категория:** Очередь — govulncheck находит две достижимые уязвимости, а гейт о нём не знает: о третьей узнать будет неоткуда. -- **Зачем:** govulncheck находит две достижимые уязвимости в клиентах Yandex, а ни гейт, ни список «чего в гейте нет» о нём не знают: узнать о третьей будет неоткуда. - -Обе найдены ревью задачи `pocketbase-storage` 2026-08-12 и достижимы из кода -распознавателя: `GO-2026-6061` в `google.golang.org/grpc` (исправлено в v1.82.1) -и `GO-2026-5764` в `aws-sdk-go-v2` — `aws/protocol/eventstream` (в v1.7.8) и -`service/s3` (в v1.97.3). Ни одну из них эта задача не вносила: `git diff -origin/master -- go.mod` их версий не касался. - -## Затрагивает - -- версии `google.golang.org/grpc`, `aws-sdk-go-v2/service/s3` и - `aws-sdk-go-v2/aws/protocol/eventstream` в `go.mod`; -- набор шагов `task gate` в `Taskfile.yml`; -- семантика гейта в `CLAUDE.md` — раздел «Гейт», список «что красит безусловно» - либо «чего в гейте намеренно нет». - -## Критерии приёмки - -- Обе объявленные уязвимости из кода недостижимы. Оракул — `govulncheck ./...` - печатает «No vulnerabilities found» либо оставляет только недостижимые. -- Новая достижимая уязвимость роняет гейт. Оракул — прогон `task gate` на - дереве с намеренно откаченной версией `grpc`: шаг краснеет с именем уязвимости. -- Место шага названо в `CLAUDE.md`: либо в перечне красящих безусловно, либо в - «чего в гейте нет» с указанием, кто тогда обязан его гонять. Оракул — - `task gate`, шаг `docs.py check`. - -## Рамки - -Обновление версий трогает клиентов Yandex — прогон на реальных ключах запрещён, -подставляй `internal/adapter/recognizer/memory.go`. Решение, ронять ли гейт на -уязвимости без исправления, принимает человек. diff --git a/tasks/items/gate-step-exit-codes.md b/tasks/items/gate-step-exit-codes.md deleted file mode 100644 index 2458c5a..0000000 --- a/tasks/items/gate-step-exit-codes.md +++ /dev/null @@ -1,35 +0,0 @@ -# 🧹 Привести коды выхода шагов гейта к общему словарю - -- **Тип:** chore -- **Категория:** Очередь — Словарь кодов уже разъехался с обёртками: три новых шага гейта ниже напишутся по неверному образцу и попадут под переписывание. -- **Зачем:** CLAUDE.md объявляет словарь кодов общим для четырёх проверочных шагов и описывает код 3 как «каталог или файл не найден», но все четыре обёртки в Taskfile.yml при отсутствующем скрипте отдают 1 («дрейф»), из-за чего читатель кода идёт искать разъехавшееся там, где просто неполно дерево. - -Расхождение старое и повторено всеми четырьмя обёртками одинаково — дефектом -одного изменения оно не является. Сами скрипты словарю следуют: при пропавшем -источнике `scripts/check-go-version.sh` выходит с кодом 3, проверено прогоном -2026-08-12. - -Развилка тут есть, и решать её придётся: либо обёртки приводятся к 3, либо из -описания кода 3 в памятке убирается «или файл не найден» и `exit 1` объявляется -нормой для «скрипта шага нет». Второй вариант меняет только текст памятки, а не -код всех четырёх обёрток, и тоже не расходится с фактами. - -## Затрагивает - -- шаги `docs`, `tasks`, `openspec` и `go-version` в `Taskfile.yml`; -- словарь кодов в `CLAUDE.md`, раздел «Гейт». - -## Критерии приёмки - -- Один и тот же исход даёт один и тот же код у всех четырёх шагов. Оракул — - убрать по очереди каждый из четырёх скриптов и прогнать его шаг: коды - совпадают между собой и с тем, что обещает памятка. -- Памятка и поведение сошлись. Оракул — прочитать словарь в `CLAUDE.md` и - сверить с четырьмя прогонами выше поимённо. -- Гейт зелёный целиком. Оракул — `task gate`. - -## Рамки - -Скрипты плагинов (`docs.py`, `tasks.py`, `openspec.py`) не правятся: они живут -вне репозитория, и их коды уже следуют словарю. Правятся только обёртки в -`Taskfile.yml` и текст памятки. diff --git a/tasks/items/response-assertions-judge-result.md b/tasks/items/response-assertions-judge-result.md deleted file mode 100644 index 843fb10..0000000 --- a/tasks/items/response-assertions-judge-result.md +++ /dev/null @@ -1,36 +0,0 @@ -# 🧹 Судить ответ в тестах по готовому ответу - -- **Тип:** chore -- **Категория:** Очередь — Тест, читающий живую карту заголовков, зелен при неработающем коде: класс всплывал трижды и трижды стоил ложной приёмки. -- **Зачем:** Проверка, читающая изменяемую карту заголовков обработчика, зелена при неработающем коде: класс всплыл трижды, последний раз на уборке куки входа. - -Найдено ревью задачи `oidc-login` 2026-08-12, отчёт триажа — -[review/report.md](../../openspec/changes/archive/2026-08-12-oidc-login/review/report.md), -раздел «Promote candidates», первый пункт. - -Инструмент проверки устроен зеркально настоящему серверу: у сервера заголовки -фиксируются в момент, когда ответ начинают писать, а у него живая карта остаётся -доступной и после. Проверка, читающая живую карту, видит то, чего клиент не -получит, и остаётся зелёной при любой регрессии в этом месте. - -Класс повторяется третий раз — записи журнала дефектов от 2026-08-10, 2026-08-11 -и 2026-08-12, — и все три раза стоил зелёного гейта при неработающем поведении. -Отсюда продвижение: правило в конвенции плюс механизация, а после механизации проза -из конвенции убирается. - -## Затрагивает - -- `docs/conventions/` — новая запись либо раздел существующей: чем судят ответ; -- `docs/conventions/README.md`, перечень механизированного; -- набор шагов `task gate` — место, где живёт проверка правила; -- существующие тесты обработчиков: те, что читают живую карту заголовков. - -## Критерии приёмки - -- Правило записано в конвенциях одной формулировкой, и названо место - механизации. Оракул — чтение `docs/conventions/README.md`: строка есть, ссылка - ведёт в существующее место. -- Проверка, читающая живую карту заголовков, роняет гейт. Оракул — завести такую - строку в любом тесте и прогнать гейт: ненулевой код возврата. -- Проза из конвенции убрана после механизации, а не осталась дублем. Оракул — - чтение записи: правило названо один раз, дальше ссылка на механизацию. diff --git a/tasks/items/rollback-restores-wrong-session-duration.md b/tasks/items/rollback-restores-wrong-session-duration.md new file mode 100644 index 0000000..5a04ed3 --- /dev/null +++ b/tasks/items/rollback-restores-wrong-session-duration.md @@ -0,0 +1,53 @@ +# 🐞 Починить срок сессии, который ставит откат шага входа + +- **Тип:** fix +- **Категория:** Очередь — Путь сегодня недостижим: откаты не подключены, и пока они не подключены, цена дефекту нулевая. +- **Зачем:** Константа defaultAuthTokenDuration в шаге 202608120001 названа умолчанием библиотеки, но 1209600 — это 14 суток, а умолчание PocketBase 432000, пять суток: откат объявляет возврат к умолчанию и ставит срок вдвое больше выбранных владельцем семи. + +Найдено ревью пачки задач о гейте 2026-08-12, проход разбора кода. Дефект +пришёл из задачи `oidc-login` и её правкой не был замечен; переезд шагов схемы в +свой каталог развёл противоречащие комментарии по разным файлам, где раньше они +стояли в трёх строках друг от друга: `provider.go` пишет «умолчание библиотеки в +пять суток», шаг — «умолчание библиотеки» о числе в 14 суток. + +Оракул сегодняшнего состояния: +`grep -n "Duration: 432000" ~/go/pkg/mod/github.com/pocketbase/pocketbase@v0.39.10/core/collection_model_auth_options.go` +отдаёт строку `Duration: 432000, // 5days`. Числа `1209600` в модуле нет ни разу +как длительности токена. + +**Развилка, которую решает человек:** правка меняет поведение **применённого** +шага схемы, а такое спрашивается всегда. Либо константа приводится к 432000 +внутри существующего шага (откат ещё не исполнялся ни разу, и переписывание +трогает только будущие откаты), либо 14 суток объявляются выбранным числом — и +тогда меняется имя константы и её комментарий, а не значение. + +## Воспроизведение + +1. Подключить откаты (`migratecmd`) — сегодня их не подключает ничто. +2. Откатить шаг `202608120001_oidc_login.go`. +3. Прочитать `AuthToken.Duration` коллекции `users`: там 1209600 — вдвое больше + семи суток, выбранных владельцем, и в 2.8 раза больше умолчания библиотеки, + к которому откат обещал вернуть. + +## Затрагивает + +- `internal/adapter/repo/pocketbase/migrations/202608120001_oidc_login.go`, + константа `defaultAuthTokenDuration` и комментарий `down202608120001`; +- `internal/adapter/repo/pocketbase/provider.go`, комментарий к + `SessionDuration` — он называет умолчание пятью сутками; +- поведение откатов, если их подключат. + +## Критерии приёмки + +- Число в откате и число, названное умолчанием библиотеки, совпадают. Оракул — + чтение константы против `core/collection_model_auth_options.go` версии + PocketBase из `go.mod`. +- Комментарии шага и `provider.go` говорят об умолчании одно и то же. Оракул — + чтение обоих мест подряд. +- Гейт зелёный целиком. Оракул — `task gate`. + +## Рамки + +Правка применённого шага схемы — необратимое: решение принимает человек. Новым +шагом это не лечится: новый шаг накатывается вперёд, а исправить нужно ветку +отката прежнего.