22 KiB
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, SHA9238ce666bee7ea9b7eddcd9e5b3f083b96ad114 - Трек: полный (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, SHA5847bf2b1bb6); - правка
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, канонический словарь редакторов). Остальные разделы ТЗ дельта не задевает — см. «Унаследовано».
Как проверялось
- Получены оба вердикта (
gh issue view 449 --json comments) и раскрыт их реальный порядок и содержание — расхождение с шапкой задачи описано выше. git diff e027b2a0..9238ce66 -- docs/specs/449-double-fit-all.md— ровно правка из предложения r2, больше в файле ничего не менялось.- Независимо пересчитан состав редакторов по тем же трём источникам, что
называло 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) теперь ровно три редактора, без расхождений.
- Ссылки новой строки на §6 (
:180-188) и AC7 (:279-286) открыты и сверены построчно — оба раздела называют те же три редактора, что и исправленная шапка. node scripts/check-docs.mjs— прогнан лично,Documentation checks passed (7 files, 12 external links), exit 0.git diff --check e027b2a0..9238ce66 -- docs/specs/449-double-fit-all.md— чисто, exit 0.- Обязательные разделы §7.1 пересчитаны по текущему файлу
(
grep -n "^## " docs/specs/449-double-fit-all.md) — все 15 присутствуют, структура не пострадала от правки одной строки. docs/specs/README.md:178— запись issue↔ТЗ на месте, дельтой не тронута.- Трейлеры
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— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
ee0b2f4528fb30de7b90d79323c7aa16c96af7e7git log --all --format='%H %T' | grep ee0b2f4528fb - ТЗ
docs/specs/449-double-fit-all.md, блобd6ddccbb3920bdffbb8414f4b6c225a4cdf4f420git log --all --find-object=d6ddccbb3920bdffbb8414f4b6c225a4cdf4f420 -- docs/specs/449-double-fit-all.md