mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 04:09:17 +00:00
@@ -0,0 +1,81 @@
|
||||
# SPEC-REVIEW-512-r2
|
||||
|
||||
- **Issue:** #512 — «Golden: текст версии через seam вне кадров; `docs:accept --identical` по попиксельной идентичности»
|
||||
- **Этап:** ревью ТЗ (PROCESS.md §2.4)
|
||||
- **Материал:** `docs/specs/512-golden-version-seam-and-docs-identical-accept.md` на HEAD `8fba3987` (ветка на этом коммите же и стоит); дельта — `git diff e606b808..HEAD -- docs/specs/512-golden-version-seam-and-docs-identical-accept.md`.
|
||||
- **Заход:** r2 · блокирующих циклов израсходовано 1 из 4 (зелёный вердикт бюджет не тратит, §4/#227).
|
||||
- **Предыдущий раунд:** SPEC-REVIEW-512-r1, вердикт красный, High 1 (H1), получен на SHA `e606b808`.
|
||||
|
||||
## Скоуп ревью
|
||||
|
||||
Раунд не первый и делта локальна: правка задевает только §6 (`docs:accept --identical`, п.1 и п.3), формулировку AC3 и список §11 «Затронутые файлы». Остальные разделы (§1–5, §7–10, §12) байт-в-байт совпадают с версией, проверенной в r1. Ребейза нет, контракт поведения продукта не менялся (`User-Visible: no` по-прежнему), новая подсистема не затронута — оснований для полного повторного разбора нет. Разбираю дельту и всё, до чего она дотягивается: закрытие H1, консистентность нового текста §6 с реальным кодом `demo/docs/capture.mjs`/`scripts/docs-accept.mjs`, и не подрывает ли новая формулировка соседние AC (AC4, AC5), которых дельта не называет впрямую.
|
||||
|
||||
## Как проверялось
|
||||
|
||||
- Прочитан вердикт r1 из комментариев issue: находка H1 (правка `demo/docs/capture.mjs` через новый флаг `--out` ломает отдельный от `sourceFingerprint` инвариант `captureScriptSha256`, из-за чего первый же кандидат беты красит `docs` в `check-docs --screenshots=strict` независимо от визуальных отличий; AC3 не называл, обновляется ли это поле).
|
||||
- `git diff e606b808..HEAD -- docs/specs/512-golden-version-seam-and-docs-identical-accept.md` — единственный содержательный диф раунда (второй файл в `git diff --stat` — сам `docs/reviews/SPEC-REVIEW-512-r1.md`, публикация предыдущего раунда, не предмет ревью).
|
||||
- Подтверждено, что `src/**`/`scripts/**` в дереве всё ещё не тронуты: `git diff origin/main...HEAD --stat` показывает только три файла в `docs/**`. Гейты кода по-прежнему неприменимы (см. «Чего не проверял»).
|
||||
- Новый текст §6 п.1 сверен построчно с реальным `demo/docs/capture.mjs`:
|
||||
- `OUTPUT = resolve(ROOT, 'docs/images')` (`capture.mjs:20`) — скрипт действительно пишет PNG и `screenshots.json` прямо в `docs/images`, а не в параметризуемый каталог; отказ ТЗ от флага `--out` в пользу «бэкап → штатный прогон на месте → восстановление» соответствует реальной сигнатуре инструмента, а не выдуман.
|
||||
- Манифест, который пишет `capture.mjs` в конце прогона (`capture.mjs:342-355`), уже содержит `captureScriptSha256: sha256(readFileSync(SCRIPT))` — то есть кандидат, полученный локальным прогоном без правки `capture.mjs`, естественно несёт **актуальный** хеш текущего файла. Формулировка §6 п.3 «`captureScriptSha256` берётся из кандидата» технически исполнима без дополнительного вычисления — это то же поле, что кандидат и так посчитал.
|
||||
- `scripts/docs-accept.mjs` (`verifyDocsCandidate`, строки 67-69) уже сегодня сравнивает `manifest.captureScriptSha256` с фактическим sha диска для существующего флоу `--from`/`--reviewed` — семантика поля («хеш `capture.mjs` на момент съёмки кандидата») в проекте уже установлена, новый режим её не изобретает, а переиспользует.
|
||||
- Текущий закоммиченный `docs/images/screenshots.json` содержит ровно поля, которые §6 п.3 перечисляет как «из закоммиченного» (`imageSha256` для каждого кадра, `chromium`, `oxipng`) и «из кандидата» (`sourceFingerprint`, `captureScriptSha256`) — набор полей в ТЗ и в реальном манифесте совпадает 1:1.
|
||||
- Число кадров: `grep -c '"file":' docs/images/screenshots.json` = 11, совпадает с «11 кадров» в новом предложении §6 п.3 про одноразовую переприёмку.
|
||||
- Проверено отсутствие остаточных упоминаний отменённого флага `--out` где-либо в файле ТЗ (`grep -n -- '--out\b'` — пусто) — старая формулировка не оставила следов в §8/§11.
|
||||
- Обновлённое AC3 и обновлённая строка теста `test/docs-accept.test.mjs` в §8 сверены на согласованность: AC3 требует «идентичные кадры → только fingerprint и `captureScriptSha256` в манифесте», тест описывает то же плюс явно называет, что `imageSha256`/`chromium` остаются прежними и что кадры на диске не меняются (через инъекцию, без реального Chromium в unit-тесте) — согласовано с §6 п.1 «в любом исходе возвращает байты кадров на место».
|
||||
- Перечитаны §7 (симметричный кейс для golden) и §12 (принятые предположения) — дельта их не касается и не должна: правка H1 закрывает вопрос иначе (авто-обновление поля при любом будущем прогоне инструмента), а не через добавление ещё одного разового шага вида §7.
|
||||
|
||||
## Закрытие раунда r1
|
||||
|
||||
| Находка (r1) | Чем закрыта | Где видно |
|
||||
|---|---|---|
|
||||
| **H1** — ТЗ правит `demo/docs/capture.mjs` (`--out`), из-за чего меняется его sha256, `captureScriptSha256` расходится с диском, и `check-docs --screenshots=strict` красит `docs` на первом кандидате беты; AC3 не называл, чинит ли это `--identical` | ТЗ отказалось от правки `capture.mjs`: новый механизм §6 п.1 запускает штатный, неизменённый `capture.mjs` (пишет прямо в `docs/images`, как и сегодня), инструмент сам бэкапит закоммиченные кадры+манифест во временную папку и восстанавливает байты кадров при любом исходе; манифест-приёмка (§6 п.3) теперь берёт `captureScriptSha256` из кандидата наравне с `sourceFingerprint` — это закрывает класс дефекта навсегда (любая будущая правка `capture.mjs` без визуальных изменений чинится тем же локальным прогоном), а не только для этой задачи | `docs/specs/512-…md` §6 п.1 («не меняется», «в любом исходе возвращает байты кадров на место»), §6 п.3 («`captureScriptSha256` берётся из кандидата»), AC3, §11 (`demo/docs/capture.mjs` убран из списка правок, `docs/images/screenshots.json` добавлен как «fingerprint-only, через `--identical`»), §8 (обновлённая строка теста) |
|
||||
|
||||
Находка закрыта полностью: и убрана причина (правка файла-сторожа), и добавлена общая защита (поле обновляется из кандидата), а не только точечный костыль под эту задачу.
|
||||
|
||||
## Унаследовано из r1
|
||||
|
||||
Без повторной проверки приняты (документ `docs/reviews/SPEC-REVIEW-512-r1.md`, SHA `e606b808`, дельта их не касается):
|
||||
|
||||
- Обоснование полного трека и провал критерия §5 «одна поверхность» (семь мест продукта + отдельный инструмент приёмки).
|
||||
- §4 «Seam версии» — построчное совпадение перечня точек чтения `CARD_VERSION` в `houseplan-card.ts`/`houseplan-editor-runtime.ts` с реальным кодом, включая исключения (`hp_retry`, `console.info`) и то, что `release-contract.mjs` продолжает читать константы, а не seam.
|
||||
- §5 «Golden-харнес» — единственность использования `cardVersion` из `package.json` в `harness.mjs:1923`, сохранение `integrationVersion: '0.0.0-golden-backend'` в `matrix.mjs`, нормализация версии бандла в `baselines-index.json` через `foreignFingerprintNormalizer` (#481).
|
||||
- §8 мутанты (`version-seam-ignores-override`, `docs-identical-accepts-any-frame`) — конкретны и ловятся названными тестами по образцу существующего `test/houseplan-source.mjs`.
|
||||
- Отсутствие продуктового вопроса владельцу: задача `User-Visible: no`, единственное DOM-видимое место `gs.about_version` — внутри `support-dialog`, ключ и текст не меняются (AC6).
|
||||
- Низкоприоритетное наблюдение r1 (не находка): `--identical` даёт 0 отличий только в среде, воспроизводящей растеризацию шрифтов закоммиченных кадров (тот же канон Linux/WSL, что и у `docs:capture`) — сценарий §1.1 обещает «минуту локально» без этой оговорки; не блокирует, стоит упомянуть в будущей правке `docs/DEVELOPMENT.md` (уже в списке затронутых файлов).
|
||||
|
||||
## Находки
|
||||
|
||||
Нет.
|
||||
|
||||
## Что проверено и корректно
|
||||
|
||||
- Новый текст §6 технически исполним и не содержит непомеченных догадок: каждое фактическое утверждение (что `capture.mjs` пишет прямо в `docs/images`, что манифест уже содержит `captureScriptSha256`, что существующий `verifyDocsCandidate` уже понимает семантику этого поля) сверено с реальным кодом, а не принято на слово автора.
|
||||
- AC3 однозначен и доказуем тем же способом, что был заявлен в r1 (unit на компаратор + интеграционный прогон на реальных кадрах текущего дерева), формулировка соответствует новому механизму §6.
|
||||
- §11 «Затронутые файлы» согласован с новым §6: `demo/docs/capture.mjs` корректно исключён (не правится), `docs/images/screenshots.json` корректно добавлен (одноразовая fingerprint-only переприёмка в этом же PR, т.к. seam трогает `src/**`, входящий в `sourceFingerprint`).
|
||||
- Новая формулировка §6 п.3 не противоречит §7 (переприёмка golden) и не нуждается в симметричном шаге по образцу §7 — выбранное решение («поле обновляется из кандидата всегда») по факту сильнее того, что просил r1 (не разовый костыль, а постоянное поведение инструмента).
|
||||
- Дельта не расширяет и не сужает скоуп (§2/§3 не менялись), не вводит нового продуктового поведения — `User-Visible: no` остаётся верным.
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- Гейты кода (`npx tsc --noEmit`, `npm test`, `npm run build`, `node scripts/check-docs.mjs`) не прогонял: на этапе ревью ТЗ они неприменимы и в r1, и сейчас — изменений в `src/**`/`scripts/**` по-прежнему нет, `git diff origin/main...HEAD --stat` показывает только три файла в `docs/**`. Менять нечего, прогонять не на чем.
|
||||
- Не проверял поведение нового механизма §6 при аварийном прерывании процесса (`SIGKILL`) между записью кандидата и восстановлением бэкапа — это деталь реализации (try/finally на уровне кода), не тестируемая на уровне ТЗ/unit; не поднимаю как находку: не новый класс риска для проекта (общий для любого инструмента, временно перезаписывающего рабочее дерево с последующим восстановлением), ни один AC от этого не ломается, ничего не коммитится автоматически (`docs-accept.mjs` прямо документирует «здесь не делается коммит»).
|
||||
- `docs/USER-GUIDE.ru.md` — не проверял повторно, задача не меняет видимое поведение (наследовано из r1, дельта тем более не меняет).
|
||||
- Демо/смоки, golden:verify, инварианты модели, performance-профили — не запускал: нет ни одного изменения в `src/**` (спек-стадия), поэтому эти гейты неприменимы, а не пропущены.
|
||||
|
||||
---
|
||||
|
||||
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||||
|
||||
## Материал раунда
|
||||
|
||||
- Ветка: `issue/512-golden-version-seam-docs-identical`, коммит `8fba3987df92` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||||
- Дерево материала: `66d626bb0e5fbf4c669c8c0e796af0dbf0dffeba`
|
||||
```
|
||||
git log --all --format='%H %T' | grep 66d626bb0e5f
|
||||
```
|
||||
- ТЗ `docs/specs/512-golden-version-seam-and-docs-identical-accept.md`, блоб `0ff211f5598812b6d66f31cb136727b161b9c7ed`
|
||||
```
|
||||
git log --all --find-object=0ff211f5598812b6d66f31cb136727b161b9c7ed -- docs/specs/512-golden-version-seam-and-docs-identical-accept.md
|
||||
```
|
||||
- Вердикт конвейера: `green` · High 0
|
||||
Reference in New Issue
Block a user