mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 04:09:17 +00:00
@@ -0,0 +1,166 @@
|
||||
# Спек-ревью #162 — заход r2
|
||||
|
||||
- Issue: [#162](https://github.com/Matysh/houseplan-card/issues/162) — «Многоэтажный робот: сопоставление карт пространствам отдельно от базы»
|
||||
- Этап: spec (PROCESS.md §2.4)
|
||||
- Документ ТЗ: `docs/specs/162-vacuum-map-space-routing.md`
|
||||
- Заход: r2, SHA `4c56b389`
|
||||
- Заход r1: SHA `086b3682`, вердикт жёлтый, документ `docs/reviews/SPEC-REVIEW-162-r1.md` (закоммичен на `dd2b5d74`)
|
||||
- Блокирующих циклов израсходовано: 1 из 4 (жёлтые/красные тратят бюджет; этот заход зелёный — бюджет не меняется, PROCESS.md §4, #227)
|
||||
|
||||
## Скоуп разбора
|
||||
|
||||
Правка r1→r2 — точечный ответ на единственную находку прошлого раунда (Medium,
|
||||
§11.3 «compatible source»), без ребейза на ушедший вперёд dev и без смены
|
||||
контракта поведения где-либо ещё. Дельта локальна:
|
||||
|
||||
```
|
||||
git diff 086b3682..4c56b389 -- docs/specs/162-vacuum-map-space-routing.md
|
||||
```
|
||||
|
||||
затрагивает только:
|
||||
- заголовок статуса документа (строка 7);
|
||||
- §11.3 «Legacy trails» (переписан, добавлен §11.3.1 «Правило усыновления»);
|
||||
- таблицу AC — строка AC14;
|
||||
- таблицу §16.5 — новый мутант M-H и итоговое число мутантов (7→8);
|
||||
- changelog в конце документа — новый bullet.
|
||||
|
||||
Ни один другой раздел, AC или мутант диффом не затронут. Это укладывается в
|
||||
критерий локальности из инструкции (не ребейз, не новая подсистема, объём
|
||||
несопоставим с исходной задачей) — разбор ПОЛНЫЙ по дельте, остальное
|
||||
наследуется из r1 без повторной проверки.
|
||||
|
||||
## Как проверялось
|
||||
|
||||
1. Прочитан вердикт r1 и весь тред комментариев issue #162, включая ответ
|
||||
автора на Medium (комментарий 2026-09-03T15:28:32Z) и уточнение SHA
|
||||
(2026-09-03T15:29:15Z: правка перебазирована с `3ed21af5` на `4c56b389`
|
||||
после коммита артефакта ревью `dd2b5d74`).
|
||||
2. Сверен факт: `git log --oneline 086b3682..4c56b389` → ровно два коммита
|
||||
(`dd2b5d74` документ ревью, `4c56b389` правка ТЗ). Рабочее дерево на
|
||||
`4c56b389` соответствует HEAD ветки — ревьюется именно эта версия.
|
||||
3. Перечитан переписанный §11.3 и новый §11.3.1 целиком, сверены все
|
||||
перекрёстные ссылки внутри документа (§8.1 `VacuumMapRoute.source`/`map_id`,
|
||||
§8.2 nullish-контракт, §7.3 explicit conversion, AC13, AC14, M-H, §12).
|
||||
4. Фактическая посылка нового текста — «серверная запись run физически несёт
|
||||
только `{map_id, started, ended, points}`, и recorder всегда пишет её по
|
||||
единственному текущему `marker.vacuum.source`» — перепроверена чтением
|
||||
`custom_components/houseplan/trails.py` заново (не унаследовано из r1,
|
||||
так как это ядро самой правки):
|
||||
- `TrailBook.on_point` создаёт `cur = {"map_id": map_id, "started": now,
|
||||
"ended": None, "points": []}` (`trails.py:98`) — поля `source` нет,
|
||||
утверждение верно;
|
||||
- `async_refresh` строит `pairs: source → [(marker_id, vac)]` из
|
||||
`v.get("source")` — ровно один root source на marker в момент подписки
|
||||
(`trails.py:167-184`); `_sample` вызывает `book.on_point(marker, ...)`
|
||||
для источника, на который сейчас подписан marker (`trails.py:350-384`).
|
||||
Это подтверждает, что «единственный свидетель» — текущий
|
||||
`marker.vacuum.source`, а не историческая величина, восстановить которую
|
||||
неоткуда — с этим ограничением текст ТЗ прямо работает (fail-closed при
|
||||
несовпадении/пустом source), а не скрывает его.
|
||||
5. Проверено, что старый неопределённый термин «compatible source» пропал из
|
||||
нормативного текста (остался только в заголовке статуса документа как
|
||||
ссылка на закрытую находку — `grep` подтверждает единственное вхождение).
|
||||
6. Проверена согласованность схемы: `VacuumMapRoute.map_id`/`source` —
|
||||
обязательные `string` (§7.1, docs/specs/162-vacuum-map-space-routing.md:254-260),
|
||||
`MarkerVacuumCfg.source` — `string | null` (строка 267), поэтому проверка
|
||||
«`rootSource` пуст/удалён» в §11.3.1 корректно покрывает `null`/`undefined`/`""`.
|
||||
7. Пересчитано число мутантов в таблице §16.5 (7 строк M-A…M-G + новая
|
||||
M-H = 8) против итоговой фразы «каждый из восьми» — совпадает.
|
||||
8. Дешёвые гейты кода не запускались: дельта раунда — правка одного .md-файла
|
||||
в `docs/specs/`, `src/**` и `custom_components/**/*.py` не затронуты
|
||||
(`git diff --stat 086b3682..4c56b389` — единственный файл,
|
||||
`docs/specs/162-vacuum-map-space-routing.md`). `npx tsc --noEmit`,
|
||||
`npm test`, `npm run build`, `node scripts/check-docs.mjs`, инварианты
|
||||
модели и смоки к этой правке неприменимы: они гоняют код, а код не менялся.
|
||||
Значения из r1 (tsc чисто, build собирается, `npm test` 1819/0/1,
|
||||
идентично базовой линии ТЗ) наследуются без повторного прогона — правка их
|
||||
не затрагивает.
|
||||
|
||||
## Находки
|
||||
|
||||
Нет. Единственная находка r1 (Medium, §11.3, в скоупе) закрыта содержательно,
|
||||
новых находок делтой не внесено.
|
||||
|
||||
## Закрытие раунда r1
|
||||
|
||||
| Находка r1 | Чем закрыта | Где это видно |
|
||||
|---|---|---|
|
||||
| §11.3 п.2: термин «compatible source» не определён; серверная схема run не хранит `source`, поэтому «совместимость источника» нельзя вычислить сравнением с содержимым run буквально; AC14 не сводится к детерминированному unit-тесту | §11.3 переписан: явно назван единственный свидетель — корневой `marker.vacuum.source` в момент записи, а не поле run. Введена чистая функция `adoptLegacyRun(run, routes, rootSource)` с явным двухусловным отбором кандидатов (`map_id` строго, `source` — только если `rootSource` непустой) и ровно тремя исходами (unique / `orphan_run` / `ambiguous_run`), все три fail-closed кроме unique. AC14 переформулирован под эти три исхода со ссылкой на §11.3.1; добавлен мутант M-H на конкретную регрессию («при двух кандидатах берётся первый») | `docs/specs/162-vacuum-map-space-routing.md` §11.3 и §11.3.1 (строки ~529–566 после правки), таблица AC строка AC14, таблица §16.5 строка M-H, changelog-bullet в конце файла |
|
||||
|
||||
Факт закрытия подтверждён не заявлением автора, а перечитыванием переписанного
|
||||
текста и независимой перепроверкой его фактической посылки в
|
||||
`custom_components/houseplan/trails.py` (см. «Как проверялось», п.4) — текст
|
||||
не просто переименовал термин, а свёл его к вычислимому по сохранённым данным
|
||||
правилу.
|
||||
|
||||
## Унаследовано из r1
|
||||
|
||||
Без повторной проверки в этом раунде — дельта их не задевает:
|
||||
|
||||
- Все факты §3.2 «Подтверждённая техническая база», сверенные в r1 чтением
|
||||
`src/houseplan-card.ts:11334,12347`, `src/types.ts`, `src/vacuum.ts:310,322`,
|
||||
`src/space-deletion.ts`, `src/space-reference-repair.ts`,
|
||||
`test/core-file-budget.test.mjs` — правка их не касается.
|
||||
- Полнота обязательных разделов §7.1 PROCESS.md (21 раздел) и то, что все 20
|
||||
AC пронумерованы и снабжены способом доказательства — делта меняет
|
||||
формулировку только одной строки (AC14), остальные 19 не тронуты.
|
||||
- Overpromise в `docs/USER-GUIDE.ru.md:1504`, зафиксированный как часть
|
||||
продуктового обоснования задачи.
|
||||
- Результаты дешёвых гейтов на коде: `npx tsc --noEmit` чисто, `npm run build`
|
||||
собирается, `npm test` → 1819 pass / 0 fail / 1 skip (совпадает с базовой
|
||||
линией ТЗ).
|
||||
- Продуктовая рамка (docs/SCOPE.md, J1/J6) и оценка сложности/риска — не
|
||||
предмет этого раунда, изменений в §1–§6, §9–§10, §13–§15, §17 нет.
|
||||
|
||||
Источник наследования: `docs/reviews/SPEC-REVIEW-162-r1.md`, SHA `086b3682`.
|
||||
|
||||
## Что проверено и корректно (по дельте r2)
|
||||
|
||||
- §11.3.1 определяет `adoptLegacyRun` как чистую функцию от только сохранённых
|
||||
данных — тестируема unit-тестом без HA, как и заявлено.
|
||||
- Оба поля, на которые опирается правило (`route.map_id`, `route.source`),
|
||||
обязательные строки в схеме `VacuumMapRoute` (§7.1) — отбор кандидатов не
|
||||
зависит от опциональных полей, кроме сознательно опционального `rootSource`.
|
||||
- Три исхода (unique/`orphan_run`/`ambiguous_run`) исчерпывающие и
|
||||
fail-closed по обоим отрицательным веткам: ничего не рисуется, `route_id`
|
||||
не дописывается, запись не переписывается и не удаляется — согласуется с
|
||||
общей fail-closed доктриной документа (§8, §12).
|
||||
- AC13 («byte-for-byte until routing edit») не сломан: §11.3 явно оставляет
|
||||
поведение при отсутствии explicit routes прежним «байт в байт».
|
||||
- Число мутантов в тексте и таблице согласовано (8).
|
||||
- Никаких новых недоказанных допущений (незаявленных как предположение)
|
||||
правка не вносит — единственное новое фактическое утверждение (структура
|
||||
serverной записи run и то, что recorder пишет её по текущему root source)
|
||||
проверено чтением кода, а не принято на слово.
|
||||
|
||||
## Чего не проверял
|
||||
|
||||
- Реализацию — её нет, этап spec. Соответствие `adoptLegacyRun`/`trails.py`
|
||||
зеркалированию будет предметом code-review.
|
||||
- Остальные 19 AC и разделы вне §11.3/§11.3.1/AC14/§16.5 — не проверялись
|
||||
повторно, приняты по наследованию из r1 (см. выше), т.к. дельта их не
|
||||
касается.
|
||||
- Гейты кода (tsc/test/build/check-docs/invariants/smoke) в этом раунде не
|
||||
запускал: дельта не трогает `src/**` и `custom_components/**/*.py`, значения
|
||||
из r1 остаются в силе без изменений входных файлов.
|
||||
|
||||
## Вердикт
|
||||
|
||||
Зелёный. Находка r1 закрыта по существу и проверяемо, новых находок нет,
|
||||
бюджет циклов не расходуется (PROCESS.md §4, #227).
|
||||
|
||||
---
|
||||
|
||||
<!-- material-anchors: сгенерировано конвейером (#414) -->
|
||||
|
||||
## Материал раунда
|
||||
|
||||
- Ветка: `issue/162-vacuum-map-space-routing`, коммит `4c56b389ca9e` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
|
||||
- Дерево материала: `ec0c63dac8b0e34afb2f04aa30708ee5b8b3216e`
|
||||
```
|
||||
git log --all --format='%H %T' | grep ec0c63dac8b0
|
||||
```
|
||||
- ТЗ `docs/specs/162-vacuum-map-space-routing.md`, блоб `a8edcfbe6c37700095f6f8582258eac4fcb58ad9`
|
||||
```
|
||||
git log --all --find-object=a8edcfbe6c37700095f6f8582258eac4fcb58ad9 -- docs/specs/162-vacuum-map-space-routing.md
|
||||
```
|
||||
Reference in New Issue
Block a user