19 KiB
SPEC-REVIEW-520-r3
Якоря
- Issue: #520
«Первый устойчивый кадр большого дома вырос до 3.36 с при потолке 3.0 с —
регрессия после #509/#500», метка
S4-spec-review, состояниеOPEN(подтвержденоgh issue view 520 --json labels,state, 2026-09-10). - ТЗ: тело issue #520, раздел
## ТЗ, продолжает жить в теле issue (#517: архивdocs/specs/закрыт для новых ТЗ) — то же место, что в r1/r2. - sha256 текущего тела issue (
gh issue view 520 --repo Matysh/houseplan-card --json body -q .body | sha256sum):5eca6e230c290483bba634505217d17072f4b4a121c4aa2111b08a0fc6d007c3. Отличается от хеша r2 (7f68e4cd99242f44e13e9929cd0a7aa9dc3cb6ae5f871878670 bade18a2436ac) — тело менялось, как и ожидается после возврата на правки. - Заход r3. Бюджет циклов §4 до этого ревью: 2/4 (израсходован r1 и r2, оба жёлтые). Вердикт ниже — зелёный, цикла не образует, бюджет остаётся 2/4.
- Материал кода не менялся между r2 и r3:
git log --oneline ad2f9afd.. b49721a0даёт ровно один коммит — публикацию документа r2 (docs/reviews/SPEC-REVIEW-520-r2.md, 203 добавленных строки,git diff --stat ad2f9afd..b49721a0 -- src/ demo/ scripts/ test/пуст). Рабочая копия сейчас наb49721a0(detached HEAD отorigin/issue/520-first-frame, подтвержденоgit status,git rev-parse HEAD). Изменилось только тело issue на GitHub — SHA репозитория тут не причём, доказательство ТЗ находится вне git.
Скоуп ревью
Повторный заход ревью ТЗ (PROCESS.md §2.4, §2.9/§2.10) после жёлтого
вердикта r2. Предмет — дельта тела issue между r2 и r3: одна правка,
заявленная автором в комментарии 2026-09-10T15:33:29Z
(«Исправление по ревью ТЗ r2 → заход r3»): AC4 расширен на
firstStableRenderMs изометрии, плюс отрицательный результат про
cache.entries.cleanFloor изометрии перенесён из документа r2 в текст
«Причины». Автор сам называет объём дельты: «одна строка AC4 и одна фраза
в «Причине»» — проверено построчно, а не принято на слово (см. «Как
проверялось»).
Дельта локальна: правка текста ТЗ, ни ребейза, ни смены контракта, ни новой подсистемы — код продукта между r2 и r3 не менялся вовсе (см. «Якоря»). Полный разбор всей задачи заново не требуется.
Как проверялось
- Получено текущее тело issue #520 (
gh issue view 520 --json body) и комментарий автора после r2 (единственный новый комментарий, меткаS4-spec-reviewвозвращена). - Прочитан
docs/reviews/SPEC-REVIEW-520-r2.mdцеликом — вердикт, одна находка Medium-1, материал (SHAad2f9afd2bfe, деревоcc8e3bd73eeb, телоc5e79b63b531…) — иdocs/reviews/SPEC-REVIEW-520-r1.mdдля раздела «Унаследовано». - Находка Medium-1 r2 сверена построчно с текущим текстом, а не
принята на слово автора. r2 требовал: строка AC4 должна покрывать
firstStableRenderMsизометрии тем же относительным пределом, что иmodelReadyMs, — либо явно исключить её одной фразой. Текущая строка AC4 (тело issue, строка 59):«
timing.firstStableRenderMs.medianпрофиля взаимодействия ≤ 3000 (абсолютный потолок) и обе метрики старта —modelReadyMsиfirstStableRenderMs— внутри относительного лимита к базеa44fbd37на обоих профилях, взаимодействия и изометрии», «чем краснеет»: «превышение любого из четырёх относительных пределов или абсолютного потолка — job красный». Это буквально включаетfirstStableRenderMsизометрии — предмет находки Medium-1. Закрытие полное, не частичное. - Пересчитаны все четыре относительных предела, которые теперь
называет AC4, по формуле
demo/performance/evaluate.mjs:73-118(relativeLimit = max(base*(1+ratio), base+allowance),effective = min(hardMaxMs, relativeLimit)), чтобы убедиться, что счёт «четырёх» верен и не сбит на единицу:modelReadyMsinteraction: база 1382,budgets-large-house- interaction.json(maxRegressionRatio: 0.3, noiseAllowanceMs: 200, hardMaxMs: 2500) →max(1796.6, 1582) = 1796.6; кандидат 1930 > 1796.6 — нарушен.firstStableRenderMsinteraction: база 2792.7, тот же файл (ratio 0.3, allowance 250, hardMax 3000) →max(3630.5, 3042.7) = 3630.5,effective = min(3000, 3630.5) = 3000— здесь относительный предел поглощён абсолютным потолком, что и заявляет отдельная первая половина AC4; двойного счёта нет.modelReadyMsisometric: база 2165.6,budgets-large-house- isometric.json(ratio 0.2, allowance 200, hardMax 3000) →max(2598.72, 2365.6) = 2598.72; кандидат 2626.3 > 2598.72 — нарушен (установлено ещё в r1).firstStableRenderMsisometric: база 2227, тот же файл (ratio 0.2, allowance 250, hardMax 3500) →max(2672.4, 2477) = 2672.4; кандидат 2678.2 > 2672.4 — нарушен (предмет находки Medium-1 r2, теперь покрыт текстом AC4). Итого ровно четыре относительных предела, все они действительно сейчас нарушены кандидатом — формулировка AC4 точна, не расширяет и не сужает набор относительно того, что показывает «Симптом».
- Проверено согласование «Контракта» (строка 46: «изометрия … чинится тем же изменением и проверяется теми же метриками старта (AC4)») с новым текстом AC4 — формулировка «тем же способом» из r2 заменена на «теми же метриками старта», что точнее отражает: AC4 теперь буквально покрывает обе метрики обоих профилей, а не «тот же способ» в общем виде. Расхождений между «Контрактом» и таблицей AC больше нет.
- Проверена вторая часть дельты — фраза в «Причине» (строка 24): «В
бюджетах изометрии этот потолок не поднимался и уже равен 100 — там
правка не нужна». Перепроверено чтением файлов (не принято на слово):
grep -n cleanFloor demo/performance/budgets-{isometric-smoke,large- house-isometric,interaction-smoke,large-house-interaction}.json— оба файла изометрии дают100, оба файла взаимодействия —180. Совпадает с отрицательным результатом, который сам r2 получил самостоятельно (не то же самое, что просто скопировать вывод r2, — числа сверены заново на этом SHA, хоть код и не менялся). git log --oneline ad2f9afd..b49721a0иgit diff --stat— единственный новый коммит это публикация документа r2; продуктовый код (src/**,demo/**,scripts/**,test/**) не менялся между r2 и r3 — гейты кода этому раунду не относятся (см. «Чего не проверял»), как и в r1/r2.- Проверены state/labels issue (
OPEN,bug,P1,S4-spec-review) — соответствуют ожиданиям заголовка задания (заход r3, 2/4 циклов).
Находки
Нет находок, переживших проверку. Единственная находка r2 (Medium-1) закрыта полностью — см. «Закрытие раунда r2» и п.3–5 «Как проверялось». Новых находок делом дельты не выявлено: правка локальна (одна строка AC4, одна фраза «Причины»), обе проверены построчно и не вводят новых противоречий с остальным текстом ТЗ.
Закрытие раунда r2
| Находка r2 | Чем закрыта | Где это видно |
|---|---|---|
Medium-1 — амендированный AC4 не покрывал firstStableRenderMs изометрии (второе число того же предложения «Симптома», что и уже покрытый modelReadyMs) |
AC4 переписан: «обе метрики старта — modelReadyMs и firstStableRenderMs — внутри относительного лимита… на обоих профилях»; «чем краснеет» — «любого из четырёх относительных пределов»; «Контракт» синхронизирован формулировкой «теми же метриками старта (AC4)» |
Тело issue, AC4 (строка 59) и «Контракт» (строка 46). Численно перепроверено в п.4 «Как проверялось» — все четыре предела названы верно, счёт не сбит |
Унаследовано из r2 (и, транзитивно, из r1)
Приняты без повторной проверки — дельта r2→r3 их не задевает, код между раундами не менялся:
- Причина регрессии измерена, не догадка: три технических утверждения
о поведении
wrapped-свойств Lit — r1 сверил дословно с исходником@lit/reactive-element(docs/reviews/SPEC-REVIEW-520-r1.md, «Как проверялось» п.4, материал SHA27ea23c1ec25, деревоf80bcdd58b72). - M1 (раздел «Риски») и M2 (AC3) из r1 — закрыты в r2 и сверены там
построчно (
docs/reviews/SPEC-REVIEW-520-r2.md, «Как проверялось» п.3, «Закрытие раунда r1»), текст этих разделов между r2 и r3 не менялся. - AC1 (source-scan тест по образцу
config-adoption-ownership. test.mjs) и AC2 (юнит наonBodyReplaced) — доказуемы дёшево и детерминированно, текст этих строк не менялся с r1 (сверено построчно с текущим телом в этом раунде — строки идентичны цитатам r1/r2). - AC5 (
cache.entries.cleanFloor≤ 100 на двух interaction-файлах бюджетов) — привязан к точным файлам, не менялся; числа перепроверены заново в п.6 «Как проверялось» этого раунда (не просто унаследованы). - Откат (revert двух строк
static properties+ потолка 180) и release-артефакты (User-Visible: no, разблокируетv1.74.0-beta.1) — просты, однозначны, текст не менялся с r1. - Продуктовая рамка (администратор дома, поверхность — первый показ
большого дома) совпадает с
docs/SCOPE.mdJ1 и фикстурой 60 комнат/200 устройств — r1 сверил, текст не менялся. - Выбор полного трека — верен, не оспаривается ни разу за три раунда.
- Ни одного вопроса владельцу не требуется — весь материал технический (см. обоснование r1: «продуктовых развилок в задаче нет»), подтверждено в r1 и не оспорено в r2; делта r3 тоже чисто техническая (числа, счёт относительных пределов) — вывод не меняется.
Документы-источники: docs/reviews/SPEC-REVIEW-520-r1.md (материал —
ветка issue/520-first-frame на 27ea23c1ec25, дерево f80bcdd58b72),
docs/reviews/SPEC-REVIEW-520-r2.md (материал — та же ветка на
ad2f9afd2bfe, дерево cc8e3bd73eeb).
Что проверено и корректно (этот раунд)
- Единственная правка фикс-комментария автора (
2026-09-10T15:33:29Z) подтверждена чтением текущего тела issue, а не принята по заявлению — Medium-1 r2 закрыт полностью, не частично. - Счёт «четырёх относительных пределов» в AC4 арифметически точен: пересчитаны все четыре по опубликованной формуле и файлам бюджетов, все четыре сейчас действительно нарушены кандидатом — AC4 не занижает и не завышает то, что реально показывает «Симптом».
- «Контракт» (строка 46) и таблица AC4 больше не расходятся в формулировке охвата изометрии — предыдущая асимметрия («тем же способом» против буквально одной метрики) устранена.
- Фраза «Причины» про потолок
cache.entries.cleanFloorизометрии (100, правка не нужна) подтверждена чтением всех четырёх файлов бюджетов заново на этом SHA, не просто перенесена из документа r2 на слово. - Код между r2 и r3 не менялся (
git log,git diff --statна диапазонеad2f9afd..b49721a0) — дешёвые гейты кода (tsc,test,build) этому раунду не относятся по той же причине, что и в r1/r2: предмет этапа — текст ТЗ, продуктовой правки в дереве ещё нет. - Остальной текст ТЗ (унаследованное) не тронут дельтой — проверка
инвариантов и код-ревью инфраструктуры (мутант, тесты) остаются
предметом код-ревью после
S5-ready.
Чего не проверял
- Гейты кода (
tsc --noEmit,npm test,npm run build,check-docs.mjs) — не гонял:src/**не менялся ни разу за три раунда, весь диапазон коммитов ветки — диагностика бенчмарка (test(perf):). Предмет этапа spec — текст ТЗ. npm run invariants— не гонял: геометрия и её ссылки не тронуты ни кодом, ни правкой ТЗ.- Реальный прогон
Full Performance— не запускал; числа «Симптома» и пересчитанные относительные пределы взяты из текста issue и файлов бюджетов в дереве, перепроверены арифметически по опубликованной формуле, не переизмерены заново на живом рантайме. - Регистрацию мутанта
adoption-bodies-declared-reactiveвscripts/mutation-gate.mjs— предмет код-ревью, ещё не существует (продуктовой правки AC1/AC2 в дереве ещё нет). - Полную сверку разделов §7.1, не тронутых дельтой (Риски, откат, release-артефакты, продуктовая рамка) — заново не перечитывал построчно, только сверил, что их текст байт-в-байт совпадает с тем, что видели r1 и r2 (см. «Унаследовано»).
Вердикт
Зелёный. High: 0, Medium: 0. ТЗ готово к разработке (S5-ready).
Единственная находка r2 закрыта полностью и точно; новых находок дельта
не вносит. Бюджет циклов §4 не расходуется (зелёный вердикт цикла не
образует) и остаётся 2/4.
Материал раунда
- Ветка:
issue/520-first-frame, коммитb49721a0bd98— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
50d8affd923b0a5e133ee1e453bb9388a5f44c78git log --all --format='%H %T' | grep 50d8affd923b - Тело issue:
60492a3aec5ff7fed54f7b32c040b7a118526c209609d736ee68e116eb8f0aa6 - Вердикт конвейера:
green· High 0