specs: в state-reconciliation разведены Cancel и Dismiss по состояниям
- требование «Ручное закрытие загрузки» приведено к коду: два пути закрытия, error_code на каждом, раскладка поверхностей — описательно, а не SHALL - уборка своего торрента после отмены названа исключением по состоянию, а не по команде; убрана ложная гарантия «данных пользователя не касается» - в docs/review.md записан проскочивший дефект гарда окна после add и новый вопрос проходу adversary про асимметрию признака владения
This commit is contained in:
@@ -0,0 +1,367 @@
|
||||
# Триаж чекпоинта 2 — change `cancel-dismiss-split-wording`
|
||||
|
||||
Дата: 2026-08-06. Профиль: `standard`, режим: `по графу`.
|
||||
База диффа: `01e64d60de7495900d9a4c8f5ce9bf811ee7b7e6`.
|
||||
|
||||
## Сводка
|
||||
|
||||
**Гейт:** зелёный. Кодовые шаги (build/vet/lint/gofmt/test/flaky/race/
|
||||
diff-coverage/migrations/govulncheck) — `SKIP` с причиной «кода в диффе нет»;
|
||||
`canon` — `OK`; `gitleaks` — `OK`.
|
||||
|
||||
**Проходы поимённо:**
|
||||
|
||||
| Проход | Исход |
|
||||
|---|---|
|
||||
| `review-gate` | зелёный (кодовые шаги SKIP — кода в диффе нет) |
|
||||
| `review-specs` | отработал, 4 находки + 4 строки границ |
|
||||
| `review-code` | отработал, 1 находка + подтверждение A3 + блок «нарушений нет» |
|
||||
| `review-adversary` | отработал, 5 находок (4 воспроизводящих теста), 3 свойства без пути |
|
||||
| `review-reimpl` | **не запускался** — стадия 3, только `deep`; вне профиля `standard` |
|
||||
| `review-architecture` | **не запускался на этом чекпоинте** — стадия 4 (`wide`/`deep`); отработал на чекпоинте 1 в профиле `design`, находки закрыты правками предложения (design.md, D1–D3, D6–D8) |
|
||||
| `review-ops` | отработал, 3 находки + ответы на обязательные вопросы |
|
||||
|
||||
Состав запущенного сверен с профилем `standard` — расхождений нет.
|
||||
|
||||
**Счёт находок:** на входе 13 (S1–S4, C2, A1, A2, A3adv, A4, A5, O1–O3; C1 —
|
||||
подтверждение приёмки, не находка). После дедупа — 10 (S1=A3adv, C2=A4,
|
||||
S4=A5). Разложено: 3 блокируют, 4 стоит исправить сейчас, 0 гипотез,
|
||||
6 в урожай, 1 promote-кандидат.
|
||||
|
||||
**Состояние change:** файлы staged, но не закоммичены (`HEAD` == база; дифф
|
||||
worktree против базы — 5 файлов, 514 вставок, все под
|
||||
`openspec/changes/cancel-dismiss-split-wording/`). Перед архивацией нужен
|
||||
коммит — это состояние прогона, не находка.
|
||||
|
||||
**Вердикт по архивации:** change **годится к архивации после инлайн-правок**
|
||||
секций 1–2. Находки, требующей остановки или переработки предложения, нет:
|
||||
все семь пунктов — правки текста дельты, локальные и однозначные, кроме одной
|
||||
развилки (п. 7, выбор регистра нормы о подтверждении). Дефекты в коде,
|
||||
вскрытые тестами adversary, — пред-существующие, изменением не введены и не
|
||||
задеты (критерий A3 требует пустой кодовый дифф); они уходят урожаем.
|
||||
|
||||
## Приёмка A1–A3 (доклад приёмщику, не отметка «принято»)
|
||||
|
||||
- **A1** — требование различает `Cancel`/`Dismiss` по состояниям (не-терминальные
|
||||
против «любое кроме `deleted`», конфликт против no-op) и называет `error_code`
|
||||
обоих путей (`user_dismiss` против пустого). Оракул:
|
||||
`openspec validate --strict cancel-dismiss-split-wording` → `Change … is valid`,
|
||||
exit 0 (прогнано мной). **Выполнен**, с оговоркой: нормативная фраза «SHALL
|
||||
называть путь закрытия» внутренне противоречит пустому коду `Cancel` — п. 4 ниже.
|
||||
- **A2** — сценарий «Закрытие не-терминальной загрузки из веб-UI идёт отменой»
|
||||
(дельта, строки 112–119): исход `cancelled`, `error_code` назван (пустой).
|
||||
Оракул: тот же прогон + чтение сценария. **Выполнен.**
|
||||
- **A3** — `git diff --stat <база> -- internal web cmd` — **пусто** (прогнано
|
||||
мной по worktree; полный дифф — 5 файлов только под `openspec/changes/`).
|
||||
Гейт `Dismissable` и danger-zone шаблона не тронуты. **Выполнен.**
|
||||
|
||||
---
|
||||
|
||||
## Блокирует мердж (архивацию)
|
||||
|
||||
Все три — корзина **(а): дефект введён текстом этого изменения**. Все три —
|
||||
правки одного-двух абзацев дельты
|
||||
`openspec/changes/cancel-dismiss-split-wording/specs/state-reconciliation/spec.md`.
|
||||
|
||||
### 1. Дельта гарантирует «`Dismiss` SHALL NOT вызывать qBittorrent» — гарантия ложна: `Dismiss` из `catched` в окне после `add` даёт `torrents/delete` с `deleteFiles=true`
|
||||
|
||||
- Файл: дельта, строки 36–47; код `internal/worker/worker.go:520–556` (уборка
|
||||
по условию `after.State != store.StateCatched`, безразлична к команде),
|
||||
`internal/httpapi/review.go:384–391` (маршрут `dismiss` по состоянию не
|
||||
гейтится — путь достижим сегодня прямым POST)
|
||||
- Severity: major, Confidence: high. Корзина: **(а)** — сам механизм уборки
|
||||
пред-существует и нормирован командо-нейтрально в `download-tracking`
|
||||
(строки 216–234); ложна только атрибуция исключения одной команде `Cancel`.
|
||||
- Оракул (прогнан мной): `go test ./tmp/adv/ -run TestDismissInAddWindow -v` →
|
||||
«ADV-3 воспроизведён: закрытие путём Dismiss (error_code="user_dismiss")
|
||||
вызвало torrents/delete deleteFiles=[true]». Плюс
|
||||
`internal/worker/catched_test.go:244–268` — штатный тест уборки ставит
|
||||
`cancelled` напрямую, не через `Cancel`.
|
||||
- Дедуп: S1 (`specs`) + A3adv (`adversary`) — одна причина: исключение в коде
|
||||
привязано к состоянию/окну, а не к команде.
|
||||
- Действие: **инлайн**. Переформулировать исключение по условию, а не по
|
||||
команде: «закрытие **любым путём**, уведшее задачу из `catched` в окне между
|
||||
нашим `add` и записью перехода» — как это уже сформулировано в
|
||||
`download-tracking`. Тем же правом убрать из абзаца атрибуцию «`Cancel` тем же
|
||||
ограничен, с одним исключением» — исключение общее для обоих путей.
|
||||
- **В ту же правку входит C2/A4** (дедуп: одна ссылка, одно предложение):
|
||||
markdown-ссылка `../../../specs/download-tracking/spec.md` (строка 44) не
|
||||
резолвится **ни из позиции дельты** (нормализуется в
|
||||
`openspec/changes/specs/download-tracking/spec.md`, файла нет; верно было бы
|
||||
4 уровня), **ни после архивации** (из `openspec/specs/state-reconciliation/`
|
||||
нормализуется в `specs/download-tracking/spec.md`; верно — 1 уровень).
|
||||
Единого относительного пути, верного в обеих позициях, не существует.
|
||||
Проверено арифметикой пути (`os.path.normpath` + `exists`, прогнано мной).
|
||||
Фикс: дать ссылку **бэктиком** — `openspec/specs/download-tracking/spec.md` —
|
||||
как во всех соседних кросс-ссылках capability (прецедент:
|
||||
`openspec/specs/state-reconciliation/spec.md:92`); markdown-ссылок в
|
||||
`openspec/specs/` нет ни одной (grep пуст), и `docs.py check` этот каталог
|
||||
не проверяет — битую ссылку не покрасил бы никто.
|
||||
|
||||
### 2. Дельта заявляет, что уборка в окне после `add` «данных пользователя не касается» — безусловное утверждение сильнее того, что гарантирует код: пред-существующие файлы под `paths.downloads` уничтожаются
|
||||
|
||||
- Файл: дельта, строки 45–46; код `internal/worker/worker.go:495–556` (гард
|
||||
«подтверждённое отсутствие» проверяет отсутствие **торрента**, не отсутствие
|
||||
**данных**)
|
||||
- Severity: major (для текста; кодовый дефект — кандидат `critical`, см. урожай
|
||||
У-1), Confidence: high для текстовой части. Корзина: **(а)** для текста /
|
||||
**(в)** для кода — дыра в гарде пред-существует, изменением не задета; этим
|
||||
change введена только ложная гарантия.
|
||||
- Оракул (прогнан мной): `go test ./tmp/adv/ -run TestCancelInAddWindow -v` →
|
||||
«ADV-1 воспроизведён: worker вызвал torrents/delete deleteFiles=[true];
|
||||
данные …/downloads/Show/e1.mkv существовали под paths.downloads ДО add
|
||||
(гард проверял отсутствие торрента, а не отсутствие данных)».
|
||||
- Почему текст — major, а не перенос `critical` с кода: текст сам данных не
|
||||
уничтожает; но, будучи влит в нормативный дом, он узаконивает дыру — следующий
|
||||
аудит поверит «данных не касается» и закроет расследование. Severity кода на
|
||||
severity текста автоматически не переносится; кодовый дефект едет урожаем со
|
||||
своим весом.
|
||||
- Действие: **инлайн**. Убрать безусловное «и данных пользователя не касается».
|
||||
Right-size замена — отослать к дому нормы без собственной гарантии
|
||||
(«нормирована в `download-tracking`»), не расширяя дельту признанием дыры:
|
||||
дыра — предмет задачи У-1, а не этого требования.
|
||||
|
||||
### 3. Обещание «библиотечные ссылки без штатной команды снятия **до повторной привязки**» ложно: перепривязка их не снимает никогда — `Undo`/`Delete` работают только с последним батчем
|
||||
|
||||
- Файл: дельта, строки 62–66 и сценарий 93–101; код
|
||||
`internal/worker/review.go:332` (каждый `Apply` — новый батч), `:557–572`
|
||||
(`Undo` — только `LatestBatchID`), `:625–641` (`Delete` — только
|
||||
`LatestBatchID`)
|
||||
- Severity: major, Confidence: high. Корзина: **(а)** для формулировки /
|
||||
**(в)** для кода (поведение батчей пред-существует, изменением не задето).
|
||||
- Оракул (прогнан мной): `go test ./tmp/adv/ -run 'TestDismissRelink|TestStrandedLink' -v` →
|
||||
«ADV-2: в библиотеке осталась неуправляемая ссылка (батч 1), которую не
|
||||
снимает ни Undo, ни Delete»; «ADV-2b: запись в deleted, раздача снесена с
|
||||
файлами, но в библиотеке осталась неуправляемая ссылка с живыми данными —
|
||||
место не освобождено».
|
||||
- Последствие текста: единственный маршрут к брошенной ссылке — ровно та связка
|
||||
`Dismiss` из `done` → relink, которую дельта нормирует; «до повторной
|
||||
привязки» называет relink лекарством, которым он не является, а после него
|
||||
«полное удаление» перестаёт освобождать место — danger-зона обещает обратное.
|
||||
- Действие: **инлайн**. Заменить «до повторной привязки» честным: «…без штатной
|
||||
команды снятия; последующая перепривязка их **не** снимает — `Undo` и
|
||||
`Delete` работают только с последним батчем раскладки». Расширение
|
||||
`Undo`/`Delete` на все батчи — урожай У-2.
|
||||
|
||||
## Стоит исправить сейчас
|
||||
|
||||
### 4. Нормативное «`error_code` SHALL называть путь закрытия» нарушено пустым кодом `Cancel` и опровергнуто тем же документом тремя абзацами ниже
|
||||
|
||||
- Файл: дельта, строка 49; код `internal/worker/worker.go:985`
|
||||
(`SetDownloadState(ctx, id, StateCancelled, "", "")` — проверено чтением)
|
||||
- Severity: major, Confidence: high. Корзина: **(а)** — фраза введена этим
|
||||
изменением.
|
||||
- Оракул: код (пустой код ничего не «называет») + сам документ: строки 56–58
|
||||
(«пустота кода на пути `Cancel` … не закреплена нормативно») и 73–82
|
||||
(«известное ограничение»). `SHALL`, который документ сам объявляет
|
||||
неудовлетворённым, — приглашение следующему аудиту завести ту же задачу.
|
||||
- Действие: **инлайн**. Перевести фразу в согласованный регистр: например,
|
||||
«`error_code` перехода SHALL **различать** пути закрытия, а не унифицировать
|
||||
их» (пустой у `Cancel` против `user_dismiss` у `Dismiss` — различает), либо
|
||||
сузить нормативность до `Dismiss` (его `SHALL user_dismiss` уже стоит строкой
|
||||
ниже). Остальной абзац и «известное ограничение» уже согласованы.
|
||||
|
||||
### 5. «Прежняя диагностика остаётся только в логе перехода» — фактически неверно: лог-строки перехода `Cancel`/`Dismiss` прежних `error_code`/`error_msg` не содержат
|
||||
|
||||
- Файл: дельта, строки 53–58 и сценарий 103–110; код
|
||||
`internal/worker/worker.go:985–991, 1016–1022` — проверено чтением: `Cancel`
|
||||
логирует только `from`/`to`, `Dismiss` — `from`/`to`/`code` **нового**
|
||||
перехода; контракт поля `code` — `docs/conventions/logging.md:26–30`.
|
||||
- Severity: major, Confidence: high. Корзина: **(а)** для формулировки /
|
||||
**(б)** для наблюдаемости (лог и раньше не нёс прежней диагностики — урожай
|
||||
У-3).
|
||||
- Последствие: причина падения восстановима только по более ранней, никак не
|
||||
связанной по смыслу лог-строке, чья доступность зависит от неописанной
|
||||
ретенции логов (`docs/architecture.md` — только «логи в stdout контейнера»).
|
||||
- Действие: **инлайн**. Поправить формулировку: прежние код и текст «в записи
|
||||
не сохраняются; лог-строка перехода их не дублирует — они остаются лишь в
|
||||
более ранних строках лога состояния». Добавление `prev_error_code`/`prev_error_msg`
|
||||
в лог — кодовая правка, запрещённая критерием A3, → урожай У-3.
|
||||
|
||||
### 6. Описанная раскладка Telegram врёт в трёх клетках построенной по ней таблицы «состояние × поверхность»
|
||||
|
||||
- Файл: дельта, строки 30–34; код `internal/tgbot/bot.go:452–461`,
|
||||
`internal/tgbot/render.go:44–50, 281–290` — проверено чтением: уведомление
|
||||
`EventDone` — текст без клавиатуры; `EventTargetMissing`/`EventOrphaned` —
|
||||
только ссылка в веб (`webOnly`, и та `nil` при пустом `web_base_url`);
|
||||
`StateLinking` — клавиатуры нет вовсе (не «отсылает в веб»). «Закрыть»
|
||||
появляется на **карточке** (`renderCard`/refresh), а не в уведомлении.
|
||||
- Severity: minor, Confidence: high. Корзина: **(а)** — перечень введён этим
|
||||
изменением (текст описателен: «сегодня раскладка такова», но неверен).
|
||||
- Последствие: реальный пробел — уведомление о рассинхроне приходит без
|
||||
стоп-крана — текстом замаскирован.
|
||||
- Действие: **инлайн**. Либо уточнить: «Telegram даёт „Закрыть“ на **карточке**
|
||||
загрузки в `failed`/`stuck`/`done`/`orphaned`/`target_missing`; уведомления
|
||||
о `done` и рассинхроне кнопок закрытия не несут», либо снять перечень
|
||||
Telegram целиком, оставив нормативную гарантию только за страницей загрузки
|
||||
(раскладка по поверхностям всё равно объявлена ненормативной).
|
||||
|
||||
### 7. Новый `SHALL` об «отдельном подтверждающем шаге» въезжает уже нарушенным: без JS диалога нет, в Telegram нет ни danger-зоны, ни подтверждения
|
||||
|
||||
- Файл: дельта, строки 68–71; код
|
||||
`web/templates/partials/download_main.html:95–98` — проверено чтением,
|
||||
комментарий дословно: «без JS гейт — только раскрытие details и явный submit
|
||||
(диалога нет)»; `internal/tgbot/render.go:266–290` — «Закрыть» в общем ряду
|
||||
кнопок. `openspec/specs/web-ui/spec.md` нормирует «без JavaScript не
|
||||
ломается».
|
||||
- Severity: minor, Confidence: medium. Корзина: **(а)** — прежняя редакция
|
||||
обязательства не содержала (уточнение adversary), норма введена этим
|
||||
изменением; тот же изъян в пред-существующем требовании «Полное удаление
|
||||
загрузки пользователем» — корзина (в), урожай У-6.
|
||||
- Дедуп: S4 (`specs`) + A5 (`adversary`) — одна причина.
|
||||
- Действие: **развилка** — выбор регистра нормы, а не правка формулировки:
|
||||
1. **Сузить норму до фактического гейта**: «„Закрыть“ SHALL размещаться в
|
||||
обособленной danger-зоне, скрытой по умолчанию (раскрытие — сознательный
|
||||
шаг); с JS дополнительно SHALL показываться диалог подтверждения» + назвать
|
||||
известным ограничением, что Telegram danger-зоны не даёт. Цена: слабее
|
||||
звучит R7, зато спека не лжёт и код не требуется.
|
||||
2. **Оставить `SHALL` как цель** и завести урожаем задачу: no-JS-подтверждение
|
||||
(например, промежуточная страница-подтверждение) и danger-гейт в Telegram.
|
||||
Цена: до выполнения задачи нормативный дом содержит невыполненный `SHALL`
|
||||
(ровно то, за что бьёт п. 4).
|
||||
Рекомендация триажа — вариант 1: он согласуется с R12 («спека фиксирует
|
||||
наблюдаемое») и с решением п. 4.
|
||||
|
||||
## Гипотезы без доказательства
|
||||
|
||||
Пусто. Все выжившие находки имеют прогнанный оракул (тест, чтение названных
|
||||
строк кода, арифметика пути, вывод команды). Понижений за отсутствие оракула
|
||||
не было; `critical` кода из A1 не понижен, а отделён от текстовой находки и
|
||||
уехал урожаем со своим весом (У-1) — его единственный непрогнанный шаг назван
|
||||
там честно.
|
||||
|
||||
Отдельно: совпадение S1/A3adv и S4/A5 в разных проходах учтено как рост
|
||||
приоритета, не как рост Confidence — под всеми проходами одна модель.
|
||||
|
||||
## Promote candidates
|
||||
|
||||
- **Проверка ссылок в `openspec/`** — шаг `canon` (`docs.py check`) обходит
|
||||
только `docs/` и `CLAUDE.md`; битую markdown-ссылку в спеке не красит никто
|
||||
(п. 1/C2 прожил бы до архивации молча). Кандидат: расширить проверку битых
|
||||
ссылок на `openspec/specs/` и `openspec/changes/`, либо записать конвенцией
|
||||
«кросс-ссылки в спеках — только бэктиком» (сегодня это фактическая, но
|
||||
нигде не записанная практика: markdown-ссылок в `openspec/specs/` ноль).
|
||||
Провенанс: `review-code` C2 + `review-adversary` A4.
|
||||
|
||||
## Урожай (пред-существующие дефекты — владельцу задач, не в этот change)
|
||||
|
||||
- **У-1 (кандидат `critical`, Confidence: medium).** Отмена/закрытие в окне
|
||||
после `add` сносит **пред-существующие** файлы пользователя под
|
||||
`paths.downloads`: гард «подтверждённое отсутствие» (`worker.go:495–509`)
|
||||
проверяет отсутствие торрента в qBittorrent, но не отсутствие данных на
|
||||
save_path; `qbt.Add` подхватывает лежащие там файлы, уборка бьёт
|
||||
`torrents/delete` с `deleteFiles=true`. Путь: пользователь снял раздачу,
|
||||
файлы оставив (это предписывает сам `download-tracking:169–174` как
|
||||
восстановление) → подал тот же торрент → отменил в окне листинг+add (сотни
|
||||
мс — секунды). Инвариант «источник неприкосновенен»: исключение (2) покрывает
|
||||
«собственный торрент», но не пред-существующие данные; UI при этом обещает
|
||||
«файлы и раздача останутся нетронутыми» (`download_main.html:100–111`).
|
||||
Оракул: `tmp/adv/adv_test.go`, `TestCancelInAddWindowDeletesPreExistingData` —
|
||||
прогнан, воспроизводит (каталог gitignored — при заведении задачи тест
|
||||
перенести в её материалы). Единственный непрогнанный шаг — семантика боевого
|
||||
qBittorrent `deleteFiles=true` над пред-существующими файлами: в бой ходить
|
||||
запрещено, отсюда medium. Провенанс: `review-adversary` A1, чекпоинт 2
|
||||
change `cancel-dismiss-split-wording`.
|
||||
- **У-2 (major, Confidence: high).** `Undo`/`Delete` работают только с
|
||||
последним батчем (`review.go:557–572, 625–641`), каждый `Apply` создаёт новый
|
||||
(`review.go:332`): связка «закрыть `done` → relink» бросает ссылку батча 1
|
||||
навсегда, а «полное удаление» после этого не освобождает место (инод жив за
|
||||
счёт брошенной ссылки). Оракул: `TestDismissRelinkStrandsLibraryLinks`,
|
||||
`TestStrandedLinkDefeatsDelete` — прогнаны, воспроизводят. Провенанс:
|
||||
`review-adversary` A2.
|
||||
- **У-3 (minor, наблюдаемость).** Лог-строки переходов `Cancel`/`Dismiss` не
|
||||
несут прежних `error_code`/`error_msg`, хотя `d` их держит в момент записи
|
||||
(`worker.go:985–991, 1016–1022`): «почему задача упала» после закрытия не
|
||||
восстановить одной строкой. Кандидат: `prev_error_code`/`prev_error_msg` в
|
||||
лог перехода. Оракул: чтение кода + контракт `logging.md:26–30`. Провенанс:
|
||||
`review-ops` O1.
|
||||
- **У-4 (minor).** «Per-download блокировка» из `CLAUDE.md` (инвариант
|
||||
«переходы состояний») и `worker.go:11` — фактически один глобальный
|
||||
`sync.Mutex` (`worker.go:239`), удерживаемый `Apply` на весь файловый
|
||||
ввод-вывод: долгая раскладка блокирует команды по **другим** загрузкам и
|
||||
поллинг. Минимум — поправить формулировку в двух местах; по существу —
|
||||
per-id блокировка либо вынос I/O из-под замка. Оракул: чтение кода (одно
|
||||
поле, не карта). Провенанс: `review-ops` O2.
|
||||
- **У-5 (minor, эффект — гипотеза при сегодняшнем профиле «единицы/день»).**
|
||||
Дефолтный список — `SCAN download` (негативный `state NOT IN` мимо
|
||||
`idx_download_state`, измерено `EXPLAIN QUERY PLAN` на копии схемы), а
|
||||
`cancelled` копятся без ретенции, и требование под ревью расширяет канал их
|
||||
производства. Частичный индекс или позитивный список состояний; ретеншен —
|
||||
задача в беклоге уже есть. Провенанс: `review-ops` O3.
|
||||
- **У-6 (minor).** Пред-существующее требование «Полное удаление загрузки
|
||||
пользователем» (`openspec/specs/state-reconciliation/spec.md:463–465`) несёт
|
||||
ту же формулировку о подтверждающем шаге с той же no-JS-дырой, что п. 7.
|
||||
Судьба зависит от развилки п. 7 — править согласованно. Провенанс:
|
||||
`review-specs` S4 (смягчающее наблюдение).
|
||||
|
||||
Уже назначено урожаем ранее (не дублирую задачей): R10 из рубрики чекпоинта 1 —
|
||||
«допустимость команды переоценивается на момент исполнения, а не по снимку
|
||||
рендера» (`tasks.md`); туда же примыкает граница `specs` про `/review/{id}`,
|
||||
открытый для любого состояния.
|
||||
|
||||
## Границы покрытия
|
||||
|
||||
**Запускалось:** профиль `standard`, режим «по графу», чекпоинт 2 (после
|
||||
apply). `review-gate` (кодовые шаги SKIP — кода в диффе нет; canon, gitleaks —
|
||||
OK), `review-specs`, `review-code`, `review-adversary`, `review-ops`.
|
||||
|
||||
**Не запускалось:** `review-reimpl` — стадия 3, только в `deep`;
|
||||
`review-architecture` — стадия 4 (`wide`/`deep`); оба вне профиля `standard`.
|
||||
`review-architecture` отработал на чекпоинте 1 (профиль `design`) вместе с
|
||||
`review-specs` и `review-rubric`; его находки закрыты правками предложения
|
||||
(design.md, решения D1–D3, D6–D8) и на этом чекпоинте не перепроверялись.
|
||||
|
||||
**Что запущенные проходы не могли проверить в принципе (из charter'ов):**
|
||||
|
||||
- `specs`: поведение живых qBittorrent/Telegram — клавиатуры Telegram не
|
||||
покрыты тестами вовсе, сверка была чтением кода; плюс его заявленные границы:
|
||||
владение целевым путём после закрытия `done` (ушло в У-2), `/review/{id}`
|
||||
без гейта состояния (примыкает к R10), «активный список» как три разных
|
||||
множества (`store/list.go`, `store/download.go`).
|
||||
- `code`: только записанные конвенции; конвенции о форме OpenSpec-спек в
|
||||
`docs/conventions/` нет — норму задавали `openspec/config.yaml` и `CLAUDE.md`.
|
||||
- `adversary`: семантика **боевого** qBittorrent (`deleteFiles=true` над
|
||||
пред-существующими файлами) — в бой ходить запрещено; это единственный
|
||||
непрогнанный шаг У-1. Свойства без пути: снятие последней копии
|
||||
последовательностью команд не строится; секретов в `error_msg`/логах не
|
||||
найдено; негейченный маршрут `dismiss` в сегодняшнем периметре
|
||||
(`docs/security.md`) — операторское действие, не дефект (совпадает с
|
||||
«Типовым ложноположительным» про отсутствие авторизации — корректно не
|
||||
выведен находкой).
|
||||
- `ops`: `-race` на этом диффе не гонялся (кода нет — SKIP); гонки суждены
|
||||
рассуждением. Ретенция логов stdout нигде не описана — доступность «более
|
||||
ранней лог-строки» из У-3 неизвестна.
|
||||
- триаж (я): нового не ищу по определению — работаю с чужими выводами; пропуск
|
||||
любого прохода — мой пропуск тоже. Тесты `tmp/adv/` прогнаны и воспроизводят,
|
||||
но их фикстуры — фейковый qbt и локальная ФС: они доказывают поведение
|
||||
**нашего** кода, не связки с боем.
|
||||
|
||||
**Осталось целиком на человеке** (из `docs/review.md`, два списка раздельно):
|
||||
|
||||
*Не проверит ни один проход:*
|
||||
- история инцидентов на umbar и что уже ломалось в проде;
|
||||
- поведение SQLite под реальным объёмом и профилем нагрузки;
|
||||
- завязка внешних потребителей (Jellyfin, закладки, чужие ссылки) на текущее
|
||||
поведение;
|
||||
- качество распознавания (корпус решено не собирать, REJECTED 2026-08-06);
|
||||
- суждение «этой функциональности не должно существовать».
|
||||
|
||||
*Перестали проверять сознательно:*
|
||||
- идиоматичность Go — с 2026-08-04, вместе с упразднением прохода `idiom` при
|
||||
переезде на плагин; различение «идиоматично против распространено» не
|
||||
спрашивает никто; пересмотр — задача `quality-review-agents`.
|
||||
|
||||
**Каких документов/фактов не хватило (поразрядно, с причиной):**
|
||||
|
||||
- `docs/conventions/` — конвенции о форме OpenSpec-спек нет: правило «ссылки
|
||||
бэктиком, не markdown» пришлось выводить grep'ом по фактике (`review-code`);
|
||||
- `docs/architecture.md` — ретенция логов не описана (только «stdout
|
||||
контейнера»): судьба «прежней диагностики в логе» из У-3 неопределима
|
||||
(`review-ops`);
|
||||
- `docs/review.md`, журнал дефектов — пуст (заведён 2026-07-23): оракулов
|
||||
«такое здесь уже воспроизводилось» не было ни для одной находки, все
|
||||
подтверждения добывались тестами и чтением кода (триаж);
|
||||
- `CLAUDE.md`, инварианты — присутствуют и использованы (ранжирование У-1 по
|
||||
«необратимо» и границе исключения (2)); «Типовые ложноположительные» и оба
|
||||
подраздела «Недоступно проверке» — присутствуют и использованы. Здесь
|
||||
пробелов нет.
|
||||
Reference in New Issue
Block a user