Files
houseplan-card/docs/reviews/SPEC-REVIEW-449-r2.md
T
2026-09-04 18:18:14 +03:00

22 KiB
Raw Blame History

SPEC-REVIEW — issue #449 · заход r3 (см. «Расхождение нумерации» ниже)

  • Issue: https://github.com/Matysh/houseplan-card/issues/449
  • Этап: ревью ТЗ (PROCESS.md §2.4)
  • ТЗ: docs/specs/449-double-fit-all.md
  • Материал: ветка issue/449-double-fit-all, SHA 9238ce666bee7ea9b7eddcd9e5b3f083b96ad114
  • Трек: полный (issue не помечен small); лимит циклов ревью ТЗ — 4 (§2.4)
  • Заход r3 (истинный порядковый номер — см. ниже), блокирующих циклов израсходовано до этого вердикта: 2/4 (r1 — жёлтый, r2 — жёлтый)

Расхождение нумерации: env дал «заход r2 · циклов 1/4», это неверно

Заголовок задачи для этого прогона (needs.guard.outputs.cycle/spent, рендерится в .github/workflows/process.yml:437-440,625) сообщил «Заход: r2 · блокирующих циклов израсходовано 1 из 4». Это не совпадает с историей issue:

  • r1 — жёлтый вердикт, коммент #issuecomment-5542152824, документ опубликован коммитом 9206ef64 под именем docs/reviews/SPEC-REVIEW-449-r1.md;
  • правка e027b2a0 закрыла M1;
  • r2 — жёлтый вердикт, коммент #issuecomment-5542290451, сам документ внутри себя корректно называет себя «заход r2» и явно ссылается на материал r1 (9206ef64, SHA 5847bf2b1bb6);
  • правка 9238ce66 (материал этого раунда) закрывает M2.

То есть до этого прогона фактически было два жёлтых вердикта, а не один, и этот прогон — третий, а не второй.

Корневая причина найдена. guard-джоб считает attempt/spent не по номеру, а по числу комментариев issue, которые одновременно проходят два regex-теста: Вердикт: и буквальную подстроку маркера (SPEC-REVIEW для этапа spec) — .github/workflows/process.yml:87-93. Комментарий r1 закончился фразой «Документ: см. артефакт ревью (публикуется шагом конвейера)» — без имени файла, поэтому подстроки SPEC-REVIEW в его теле нет, и jq-фильтр of_stage его не засчитывает. Комментарий r2, наоборот, заканчивается «Документ: docs/reviews/SPEC-REVIEW-449-r2.md» — с маркером — и он единственный учтён. Итог на момент этого прогона: of_stage = 1 (только r2), attempt = 1+1 = 2, spent = 1. Оба числа занижены ровно на единицу — комментарий r1 исключён из подсчёта навсегда, если его текст не поправить.

Уже нанесённый ущерб. Тем же образом на предыдущем прогоне guard посчитал cycle=1 для того, что публикующийся ревьюер верно назвал «заход r2» в тексте. Шаг публикации (.github/workflows/process.yml:661, doc="docs/reviews/${marker}-${NUM}-r${CYCLE}.md") берёт номер не из текста ревью, а из $CYCLE — и положил документ r2 в файл …-r1.md, затерев оригинальный документ r1. Оригинал не потерян безвозвратно — он читается из истории git:

git show 9206ef64:docs/reviews/SPEC-REVIEW-449-r1.md

— но рабочее дерево на origin/dev сейчас содержит под именем …-r1.md содержимое второго раунда, а файла …-r2.md не существует вовсе.

Что это значит для этого прогона. Публикующий шаг снова возьмёт номер из $CYCLE (=2, по тому же занижению) и положит этот документ в docs/reviews/SPEC-REVIEW-449-r2.md. Это не перезапишет существующий файл (такого файла ещё нет), поэтому данные в этот раз не теряются — но нумерация файла (r2) разойдётся с истинным порядковым номером раунда (третий), и то же занижение на единицу останется навсегда, пока кто-то не поправит текст комментария r1 (добавив в него подстроку SPEC-REVIEW-449-r1) либо саму логику подсчёта в guard. Ни то, ни другое не лечится в ветке issue/449-double-fit-all и не входит в скоуп ТЗ #449, поэтому заведён отдельный issue — #454 — со ссылкой на этот документ и точной репродукцией.

Числа spent/limit, которые увидит владелец в шапке будущих прогонов, тоже занижены на единицу: лимит review-4 фактически сработает на пятом жёлтом вердикте вместо четвёртого. На этом issue лимит не выбирается ни при буквальном, ни при истинном счёте (2 или 3 из 4), поэтому решение по вердикту этого раунда не меняется — расхождение зафиксировано для владельца и починки инфраструктуры, а не потому, что оно блокирует #449.

Дальше в этом документе использую истинный счёт (r3, циклов 2 уже потрачено до этого раунда), а не буквальные числа из шапки задачи — иначе номер в тексте противоречил бы фактической истории раунда, которую сам же документ и восстанавливает. Это решение не влияет на будущий автоматический подсчёт: guard считает по наличию подстрок Вердикт:/SPEC-REVIEW в теле комментария, а не по значению, которое написано после «заход r».

Скоуп проверки — по дельте (PROCESS.md §2.10)

Предыдущий раунд (r2 по факту истории, физически опубликован как документ docs/reviews/SPEC-REVIEW-449-r1.md из-за описанного выше искажения нумерации) получен на материале SHA e027b2a06d62b79530840a36369651d5eea38839. Правка — один коммит 9238ce66 поверх него, ребейза не было (git merge-base origin/dev 9238ce66 = 89647c10, та же база, что и у r1/r2).

git diff e027b2a0..9238ce66 -- docs/specs/449-double-fit-all.md
- **Touch editor: not exposed** — жест живёт только во View и kiosk; редакторы
-  Плана, Устройств, Декора и Подложки его не получают, их touch-поведение и
-  редакторский double-click не меняются (§6 «Режимы», AC7). Правило
+ **Touch editor: not exposed** — жест живёт только во View и kiosk; редакторы
+  Плана, Устройств и Подложки (в ней редактируется декор) его не получают, их
+  touch-поведение и редакторский double-click не меняются (§6 «Режимы», AC7).
   `docs/TOUCH-SUPPORT.md` → «Documentation rule».

3 строки, ровно та формулировка, которую предыдущий раунд предложил как исправление M2. docs/specs/README.md не менялся. git diff origin/dev...HEAD содержит только docs/reviews/SPEC-REVIEW-449-r1.md (артефакт прошлого раунда), docs/specs/449-double-fit-all.md, docs/specs/README.md — класс C целиком, продуктовый код по-прежнему не тронут.

Дельта локальна: не ребейз, не смена контракта, не новая подсистема, объём — 3 строки против находки в одну неточность. Разбор ограничен дельтой плюс всем, до чего она дотягивается: сама строка и разделы, на которые она ссылается (§6, AC7, канонический словарь редакторов). Остальные разделы ТЗ дельта не задевает — см. «Унаследовано».

Как проверялось

  1. Получены оба вердикта (gh issue view 449 --json comments) и раскрыт их реальный порядок и содержание — расхождение с шапкой задачи описано выше.
  2. git diff e027b2a0..9238ce66 -- docs/specs/449-double-fit-all.md — ровно правка из предложения r2, больше в файле ничего не менялось.
  3. Независимо пересчитан состав редакторов по тем же трём источникам, что называло r2, плюс дополнительно код:
    • docs/USER-GUIDE.ru.md:201-206 — таблица режимов называет три редактора: План / Устройства / Подложка;
    • docs/UX-MODES.md:186 — ## Background — the decor underlay, декор — содержимое Подложки;
    • scripts/check-docs.mjs:115 — [/\bDecor editor\b/gi, 'Background editor'] нормализует устаревшее имя того же редактора;
    • grep -n -i "декор\|редактор" docs/specs/449-double-fit-all.md — во всём файле (шапка, «Не-скоуп» :73, AC7 :279-286) теперь ровно три редактора, без расхождений.
  4. Ссылки новой строки на §6 (:180-188) и AC7 (:279-286) открыты и сверены построчно — оба раздела называют те же три редактора, что и исправленная шапка.
  5. node scripts/check-docs.mjs — прогнан лично, Documentation checks passed (7 files, 12 external links), exit 0.
  6. git diff --check e027b2a0..9238ce66 -- docs/specs/449-double-fit-all.md — чисто, exit 0.
  7. Обязательные разделы §7.1 пересчитаны по текущему файлу (grep -n "^## " docs/specs/449-double-fit-all.md) — все 15 присутствуют, структура не пострадала от правки одной строки.
  8. docs/specs/README.md:178 — запись issue↔ТЗ на месте, дельтой не тронута.
  9. Трейлеры 9238ce66 (git show -s --format=full) — Issue: #449, User-Visible: no, верно для документационной правки без изменения поведения.

Закрытие раунда r2 (по факту истории; физически — документ …-r1.md)

Находка r2 Чем закрыта Где это видно
M2 (Medium, в скоупе): строка Touch editor: not exposed называла несуществующий четвёртый редактор («Декора» отдельно от «Подложки») Формулировка заменена на «Плана, Устройств и Подложки (в ней редактируется декор)» — те же три редактора, что в §6/AC7/гайде docs/specs/449-double-fit-all.md:9-12 (коммит 9238ce66)

Проверено не на слово автора: цитаты трёх источников (USER-GUIDE.ru.md, UX-MODES.md, check-docs.mjs) сверены заново лично (см. «Как проверялось» п.3), а не приняты по формулировке коммента. Новая строка теперь дословно согласована с §6 и AC7, на которые сама же ссылается — расхождения, которое породило M2, больше нет нигде в файле.

Находки

Нет находок уровня High/Medium/Low в дельте r3 по содержанию ТЗ #449.

Отдельно (не находка против ТЗ, а находка против инфраструктуры ревью) — см. раздел «Расхождение нумерации» выше и заведённый #454. Не учитывается в счётчике High/Medium этого вердикта: предмет ревью — ТЗ #449, а не пайплайн.

Что проверено и корректно

  • M2 закрыта по существу, а не только по форме: три независимые сверки (USER-GUIDE.ru.md, UX-MODES.md, check-docs.mjs) плюс перечитанные §6/AC7 подтверждают, что шапка теперь называет ровно тех же трёх редакторов, что и остальной документ.
  • Никакого нового текста, кроме согласованной формулировки, правка не вносит — дифф ограничен тремя строками ровно там, где была неточность.
  • node scripts/check-docs.mjs зелёный (прогнан лично на этом SHA).
  • git diff --check чист — не внесено пробельных дефектов.
  • Обязательные разделы §7.1 на месте, docs/specs/README.md не требовал правки и не тронут.
  • Трейлеры 9238ce66 корректны: Issue: #449, User-Visible: no.
  • Дельта действительно локальна — не ребейз (merge-base не изменился с r1/r2), не новая подсистема, не смена контракта: полный повторный разбор не требовался.

Унаследовано из r1 и r2

Всё, что предыдущие раунды проверили и признали корректным, а дельта r3 (3 строки правки M2) не задевает, принято без повторной проверки:

  • продуктовая рамка — job J1, персоны Household/Guest (View) и Home admin (kiosk), задача в скоупе docs/SCOPE.md; проверено в r1 (docs/reviews/SPEC-REVIEW-449-r1.md@9206ef64, доступен по этому SHA в истории git — рабочая копия того же пути сейчас содержит текст r2, см. «Расхождение нумерации»);
  • решения владельца Q1/Q2 корректно перенесены в контракт поведения (§5) и таблицу §6; сама таблица §6 не менялась ни в r2, ни в r3 — построчно перечитана в этом раунде заново только по факту ссылки новой строки на неё (см. «Как проверялось» п.4), не как повторная приёмка всего раздела;
  • построчная сверка «текущего поведения по коду» (_lastTap/_swipeStart внутри kiosk-ветки, отсутствие dblclick на stage, сигнатура _fitAll, ROOM_FIT_INTERACTIVE_OWNER, CameraTransitionReason, no-op на sameCameraState) — код не менялся ни разу за все три раунда, повторная сверка не требуется;
  • существование всех файлов, названных в «Плане автотестов» и AC1–AC11 (smoke/test/mutation-gate) — файлы не переименовывались и не удалялись;
  • обязательные разделы §7.1 присутствуют все, AC пронумерованы и каждый несёт способ доказательства — подтверждено в r1, пересчитано механически заново в этом раунде (п.7 «Как проверялось»), без повторного смыслового чтения каждого AC;
  • блок «Принятые предположения» отделяет техническое от продуктового корректно — не менялся с r1;
  • вне-скоуп находка «Показать всё» / «Вписать всё» в docs/USER-GUIDE.ru.md верно заведена r1 как #452 и не относится к предмету этого раунда.

Чего не проверял и почему

  • Реализацию — её по-прежнему нет: git diff origin/dev...HEAD не содержит класса A/B, только docs/**.
  • npx tsc --noEmit / npm test / npm run build — не гонял: раунд не меняет ни одной строки кода, а Validate на предыдущем продуктовом SHA к этому ТЗ не относится (ТЗ ещё не имеет реализации).
  • Инварианты модели / golden / браузерные smoke — не применимо: дифф не трогает src/**, геометрию, рендер.
  • Полный текст ТЗ вне зоны дельты (сценарий, скоуп/не-скоуп кроме списка редакторов, модель данных, риски, план автотестов, откат, release-артефакты) — не перечитывал заново; ничто из этого не зависит от трёх изменённых строк, см. «Унаследовано».
  • Q1/Q2 продуктовую историю — не переоткрывал: решения владельца зафиксированы до r1, дельта их не касается.
  • Историческую правку комментария r1 (добавление в него маркера SPEC-REVIEW-449-r1, чтобы восстановить корректный счёт guard) — не делал: это чужой опубликованный комментарий, редактировать его не входит в роль ревьюера; чинить нужно логику подсчёта, а не задним числом переписывать историю issue. Отражено в заведённом #454.

Вердикт

High: 0 · Medium в скоупе ТЗ #449: 0 · Medium вне скоупа: 0 (обе прежние вне-скоуп находки уже закрыты решением r1: #452 заведена, эта находка выше — о пайплайне, а не о соседнем продуктовом поведении, заведена отдельно как #454 в силу серьёзности, но не считается в этом тэлли, так как её предмет — не ТЗ).

Зелёный вердикт (PROCESS.md §2.4, §12): M2 закрыта по существу, новых находок против содержания ТЗ #449 нет. Зелёный вердикт бюджет циклов не тратит — истинный счёт остаётся 2/4 (r1, r2), а не увеличивается этим раундом.

ТЗ #449 готово к S5-ready.


Материал раунда

  • Ветка: issue/449-double-fit-all, коммит 9238ce666bee — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: ee0b2f4528fb30de7b90d79323c7aa16c96af7e7
    git log --all --format='%H %T' | grep ee0b2f4528fb
    
  • ТЗ docs/specs/449-double-fit-all.md, блоб d6ddccbb3920bdffbb8414f4b6c225a4cdf4f420
    git log --all --find-object=d6ddccbb3920bdffbb8414f4b6c225a4cdf4f420 -- docs/specs/449-double-fit-all.md