Ревью #682 r1, Medium: перенос добавляет документу уровень вложенности (`docs/reviews/X.md` → `legacy/reviews/<тег>/X.md`, `docs/specs/` → `legacy/specs/`), а относительные ссылки внутри перенесённых документов и в соседях, ссылавшихся на них, никто не пересчитывал — на `97d19268` 53 битые ссылки в 46 файлах (заявление «все 26 резолвятся» в `7feb6177` было верно только до переноса документов ревью). Гейты архив не смотрят. `reviews-archive.mjs`: `repairLinks` пересчитывает ссылку, если она не резолвится от нового места, а цель находится от нового или старого места через карту переносов; битая и до переноса ссылка не трогается. `--apply` делает это само, `--repair-links=<rev>` — для всех переименований `<rev>..HEAD`, `--check-links` печатает битые. Этим коммитом `--repair-links=origin/dev` переписал ровно 53 ссылки в 46 файлах; остались две прежние «...»-заглушки в CODE-REVIEW-448-r2 (битые и на dev). Тесты: перенесённый документ, сосед со ссылкой в архив, ТЗ со ссылкой на позже перенесённое ревью, битая-до-переноса не трогается, в `legacy/` битых нет; мутант `reviews-archive-links-from-new-place-only`. PROCESS §2.10 и DEVELOPMENT › Release называют переписывание и `--check-links`. Issue: #682 User-Visible: no Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
12 KiB
SPEC-REVIEW-205-r1
- Issue: #205 — след пылесоса обнуляется после мойки швабр
- ТЗ: docs/specs/205-vacuum-trail-resume-grace.md
- Ветка:
issue/205-vacuum-trail-grace, коммит спеки:f3472de("docs: specify vacuum trail resume grace") - Этап: ТЗ на ревью (PROCESS.md §2.4)
- Цикл: r1/4 (лёгкий трек не применяется —
smallне выставлен, сложность 4, риск 7) - Ревьюер: Claude, свежая сессия, без переписки с автором
Скоуп ревью
Проверялось только ТЗ (docs/specs/205-vacuum-trail-resume-grace.md) и вход в него:
тело issue #205, комментарий аналитики с Q1–Q4 и ответами владельца, комментарий
«ТЗ готово к ревью». Продуктовый код не менялся веткой (единственный коммит на
ветке — сам файл спеки плюс строка в docs/specs/README.md), поэтому диапазон
git diff origin/dev...HEAD для этого цикла тривиален и не проверяется как код.
Как проверялось
- Прочитаны
docs/SCOPE.md,AGENTS.md,PROCESS.mdцеликом (обязательные разделы §7.1, лимиты циклов, формат вердикта, правило Medium-вне-скоупа #202). - Прочитаны тело issue #205 и оба комментария (аналитика с Q1–Q4, ссылка на ТЗ).
- Прочитан канонический документ подсистемы
docs/VACUUM.mdцеликом. - Каждое фактическое утверждение ТЗ о текущем поведении сверено с реальным кодом
на
origin/dev, а не принято на слово:custom_components/houseplan/trails.py—MOVING_STATES,TrailBook.on_point,TrailBook.end_run,TrailRecorder._sample(нейтральностьunavailable/unknown, идемпотентностьend_run, epoch-таймстемпы,async_refresh→ немедленный_sampleпосле рестарта);src/vacuum.ts:592-599—trail_modeпо умолчанию'cleaning';src/houseplan-card.ts:16658-16667—showCur = tmode==='always' || (tmode==='cleaning' && moving)и то, чтоpreviousрисуется только в'always'; убедился, что решение «показывать/скрывать» зависит отmoving(состояние вакуума), а не от поляendedв серверномcurrent— то есть фронтенд действительно не требует правок для этой задачи, как заявляет ТЗ;tests_backend/test_trails.py— текущий стиль pure-тестовTrailBook, подтверждает, что план тестирования (раздел 10) реалистичен и совпадает с существующей практикой;- существование
demo/smoke_vacuum.mjs, названного в разделе 10 как кандидат для AC8.
- Проверены §7.1 (обязательные разделы), однозначность и способ доказательства
каждого AC1…AC11, наличие явного блока принятых предположений (раздел 13),
соответствие
docs/CONFIG-COMPATIBILITY.md(новых персистентных полей нет, формат Store не меняется — отдельная запись в реестре не требуется). - Проверено попадание в
docs/SCOPE.md: явной строки про пылесосы в Core user jobs нет, но это не новая функция — Stage 1 vacuum уже принят и описан вVACUUM.md(«implemented contract»), а непрерывность следа — прямое продолжение J1 («live spatial overview… what's happening right now»). Это починка регресса принятой возможности, а не расширение скоупа продукта.
Что не проверялось (не применимо на этом этапе): исполнение кода, автотесты,
гейты (typecheck/test/build) — продуктовый код не менялся, спецификация
не содержит рантайм-артефактов для прогона.
Находки
Low — раздел 1 не называет персону и поверхность по имени (снято ревьюером)
Файл: docs/specs/205-vacuum-trail-resume-grace.md, раздел 1.
PROCESS.md §7.1 требует, чтобы первый раздел ТЗ явно называл персону из
docs/SCOPE.md и поверхность. Раздел 1 говорит «владелец робота» и не привязывает
это к строке персон (Home admin / Household members / Guests) и не называет
поверхность (десктоп, настенный планшет, телефон).
Почему это не блокирует: след пылесоса рисуется одинаково для любой персоны и
любой поверхности View — рендер не зависит от того, кто смотрит и с какого
устройства (подтверждено чтением _renderVacuums: решение о показе зависит только
от trail_mode и moving, не от персоны/поверхности). Формальное называние
персоны не изменило бы ни один AC и не создаёт риска разночтения между автором и
реализацией.
Решение: снимаю без правки ТЗ — добавление одной фразы ничего не меняет по существу, а цикл ревью на лёгкой правке дороже её отсутствия.
Других находок — High или Medium, в скоупе или вне скоупа — не выявлено.
Что проверено и признано корректным
- Причина (раздел 3) — точное совпадение с кодом:
_sampleзовётend_runдля любого state внеMOVING_STATES = {cleaning, returning, on};on_pointтрактует любой truthyendedкак безусловную границу ротацииcurrent → previous, независимо от длительности иmap_id.unavailable/unknownуже нейтральны (continueдо вызоваend_run) — заявлено верно, не догадка. - Контракт (раздел 6) — все 8 пунктов однозначны и непротиворечивы:
граница
0 <= now-ended <= 1800резолвится в пользу продолжения ровно на 30:00 (AC2 проверяет обе стороны границы); сменаmap_id— жёсткая граница независимо от времени (AC3); дубликат первой точки после resume не добавляется, ноchanged=True(AC4) — согласовано с тем, как_on_state/_schedule_save/bus.async_fireиспользуют возвращаемое значениеon_pointв текущем коде; idempotentend_runи нейтральностьunavailable/unknown— не новое поведение, а точная фиксация уже существующего. - Scope/Non-scope (разделы 4–5) — граница чистая: vendor dialect
(
washing/drying/emptying), task/session id, эвристики по координатам, UI-настройка grace, миграция Store и изменениеMOVING_STATES/trail_modeявно исключены и совпадают с Q4-default владельца. - Persistence и frontend (раздел 7) — заявление «фронтенд не требует
изменений» подтверждено чтением
_renderVacuums:showCurзависит отmoving, не отended;srvCur/srvPrevфильтруются только поmap_idи наличиюpoints. AC8 корректно указывает на существующийdemo/smoke_vacuum.mjsкак на реалистичный носитель доказательства. - AC1–AC11 (раздел 9) — каждый снабжён способом доказательства
(
unit/backend/smoke), формулировки проверяемы буквально (конкретные входные последовательности состояний, конкретные пороги времени, конкретные ожидаемые поля). AC1–AC6, AC8 — это ровно надмножество исходных шести AC из тела issue (сверено построчно), AC7/AC9/AC10/AC11 — обоснованные усиления (рестарт, регресс, mutation-guard, гейты). - Продуктовая неоднозначность (Q1–Q4) — корректно вынесена автору ТЗ
анализом-агентом до написания спеки, с default-вариантами и явным
trade-off; ни одна догадка не выдана в тексте спеки за факт — раздел 13
(«принятые предположения») содержит только технические решения (module-level
константа, fail-closed на malformed timestamp, судьба существующего
previousпри resume), которые ревьюер имеет право оспорить, но не находит спорными. - DoR-пригодность — миграция/compatibility (нет новых полей, формат Store неизменен), i18n (нет новых ключей), touch/accessibility («не затрагиваются», подтверждено — новых controls нет), производительность («O(1) на точку»), откат (revert коммита, Store совместим) — все пункты §2.5 закрыты текстом ТЗ.
- Формальности — файл лежит по конвенции
docs/specs/<NN>-<slug>.md, двусторонняя ссылка issue ↔ ТЗ на месте,docs/specs/README.mdобновлён в верной секции (P1), трейлеры коммита (Issue: #205,User-Visible: no) корректны для документационного коммита.
Чего не проверял
- Исполнение/падение автотестов — их не существует, писать код на этом этапе запрещено (Rule #1).
- Реальное поведение живого робота/симулятора демо-стенда — вне этапа spec.
- Будущие правки
docs/VACUUM.md/docs/USER-GUIDE.ru.md/docs/TESTING.md— раздел 12 корректно относит их к release-артефактам реализации, а не к этому документу.
Вердикт
Зелёный. High: 0. Medium: 0. Low: 1 (снят с записью, см. выше). ТЗ готово к разработке.