Files
houseplan-card/docs/reviews/CODE-REVIEW-634-r1.md
T
2026-09-24 02:47:09 +00:00

18 KiB
Raw Blame History

CODE-REVIEW-634-r1

Issue: #634 — «Стоимость входа агента ≈ 43 k токенов до первого файла кода: ролевые конспекты PROCESS, индекс TESTING.md, генерируемый STATUS.md». Этап: code · заход r1 · блокирующих циклов израсходовано 0/4. Материал: коммит 7dc7597260239f63a25a4f4538dbac3bd67072a5 (один коммит поверх fe92ce06, уже на dev-линии). Рабочая копия проверена ровно на этом SHA; git fetch/checkout на другой коммит не выполнялись.

Скоуп

Класс задачи — B/C (инфраструктура/документация): .github/workflows/process.yml, AGENTS.md, PROCESS.md, docs/DEVELOPMENT.md, docs/STATUS.md + docs/STATUS-FEATURES.md (новый), docs/TESTING.md + docs/testing-notes/* (8 новых файлов), docs/process/AUTHOR.md + REVIEWER.md (новые), docs/TESTING-DEMO.md, scripts/entry-cost.mjs, scripts/status-snapshot.mjs, scripts/md-anchors.mjs, scripts/inventory.mjs, scripts/check-inputs.mjs, scripts/mutation-registry.mjs, четыре новых тестовых файла. Ни одного файла класса A — подтверждено чтением git show --stat. Задача не обязана служить строке docs/SCOPE.md (это процесс/инструменты, не продуктовая фича); ей корректно присвоены метки process и tech-debt, без S* до первого S7-code-review — по правилу для инфраструктурных задач.

Предмет: три AC из тела issue — AC1 (вход автора по маршруту ≤ 12 000 слов, замер скриптом), AC2 (каждый пункт ролевого конспекта ссылается на существующий раздел канона), AC3 (TESTING.md ≤ 800 строк, приложения по индексу) — плюс заявленные в хендоффе побочные правки: генерируемый Snapshot в docs/STATUS.md, сокращённый промпт ревьюера в process.yml, порядок чтения по роли в AGENTS.md.

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

Дешёвые гейты подтверждены зелёным Validate на этом же SHA (https://github.com/Matysh/houseplan-card/actions/runs/35947737578) — tsc, npm test, npm run build со сверкой бандла повторно не гонялись.

Дополнительно прогнано вручную (диф не трогает src/**, custom_components/**/*.py, геометрию — golden/pytest/invariants/смоки не требуются, и это не пропуск, а предмет диффа):

Команда Результат
node --test test/process-digests.test.mjs test/entry-cost.test.mjs test/status-snapshot.test.mjs test/testing-notes-index.test.mjs 15/15 pass
node scripts/entry-cost.mjs --check exit 0 (author 10747/12000, reviewer 7890/9000)
node scripts/status-snapshot.mjs --check exit 1, «snapshot block is stale» — ожидаемо: намеренно не подключён в CI (комментарий в скрипте и в хендоффе), число тестов в дереве уже сдвинулось на 20 (2868→2888) после других задач, влившихся в dev после коммита. Это не находка — блок честно называет себя снимком на дату, а не живым значением
node scripts/check-inputs.mjs --coverage exit 0, тихо (scripts/inventory.mjs снят с NOT_AN_INPUT, покрыт тестом)
node --check scripts/mutation-registry.mjs + импорт MUTANTS 868 id, 868 уникальных — новые 7 присутствуют, коллизий нет
Ручной прогон 2 из 7 новых мутантов (process-digest-dead-anchor, status-snapshot-hides-version-mismatch): патч → тест краснеет → откат, git status чист оба поймали мутацию (см. «AC · чем доказан · чем краснеет»)
Построчная сверка «каждая непустая строка старого docs/TESTING.md есть в новом наборе файлов» (питоновский скрипт по множеству строк) расхождение ровно в 2 строках — заголовок # Manual testing checklist и разделитель ---, как заявлено в хендоффе
Аналогичная сверка блока «feature surface» docs/STATUS.md → docs/STATUS-FEATURES.md тело перенесено дословно; секции «Where things live», «Open items», «How to resume», «Product scope» осознанно оставлены в STATUS.md (авторская пометка «принято предположительно»)
Чтение диффа process.yml, сверка требуемых фраз/якорей и грамотности сокращения (какие абзацы ушли в канон §2.10/§8, что там всё ещё есть — #150, #102, #403, #234, #233, #237, #244, #252–259, single-source-numbers.test.mjs) ничего не потеряно, только перенесено; числа слов промпта укладываются в тест ≤ 1400
Чтение docs/process/AUTHOR.md, REVIEWER.md, scripts/md-anchors.mjs, test/process-digests.test.mjs, test/entry-cost.test.mjs, test/status-snapshot.test.mjs, scripts/status-snapshot.mjs, scripts/inventory.mjs целиком проверено чтением, не исполнением, где не отмечено иное

Не прогонялось и не требовалось: golden:verify, smoke_*, pytest tests_backend, model-invariants, perf-профили — диф не затрагивает src/**, custom_components/**/*.py, геометрию и перф-чувствительные пути. git fetch/pull/checkout на другой SHA не выполнялись.

AC · чем доказан · чем краснеет

AC Чем доказан Чем краснеет
AC1: вход автора ≤ 12 000 слов test/entry-cost.test.mjs, дополнительно node scripts/entry-cost.mjs --check (10747/12000) мутант entry-cost-author-route-over-budget (+2000 слов в AUTHOR.md) — заявлен автором, не перепроверялся мной, признан по образцу двух проверенных вручную аналогов; мутант entry-cost-budget-never-over (over всегда false) — тоже заявлен, паттерн идентичен проверенным
AC2: каждый пункт конспекта ссылается на раздел канона test/process-digests.test.mjs (3 теста: ссылки резолвятся, каждый пункт верхнего уровня цитирует канон, ключевые формулировки дословны и лежат в названном разделе) мутант process-digest-dead-anchor — перепроверен вручную: битый якорь в AUTHOR.md красит тест «каждая ссылка» (AssertionError, expected: true actual: false), откат подтверждён git status пустым
AC3: TESTING.md ≤ 800 строк, приложения по индексу test/testing-notes-index.test.mjs; независимая сверка — wc -l docs/TESTING.md = 699 мутант testing-notes-index-drops-section (удалена строка индекса) — заявлен автором по тому же паттерну, что и два проверенных
Snapshot генерируется, а не пишется руками test/status-snapshot.test.mjs (фикстурный git-репозиторий с тегами и версиями) мутант status-snapshot-hides-version-mismatch — перепроверен вручную: подмена versions.mismatches.length на false красит тест «рассинхрон … не сглажен» (AssertionError на regex-match), откат подтверждён
Промпт ревьюера не потерял обязательного test/process-digests.test.mjs («#634 промпт ревьюера») — список обязательных фраз + якорей, бюджет ≤ 1400 слов пустое множество — тест регекспами ищет точные фразы; проверено чтением, что список фраз реально покрывает машинно значимые части (строка вердикта, material_sha, запрет fetch, REVIEW_DOC, таблица «чем краснеет», разделы повторного раунда, S1-new)

Строка «мутант заявлен, не перепроверялся мной» — не пропуск: паттерн (find/replace одной строки → guard тест по --test-name-pattern) идентичен двум проверенным вручную образцам, оба ловятся корректно; отдельно проверен факт регистрации всех 7 id в scripts/mutation-registry.mjs без коллизий.

Находки

Нет находок уровня High или Medium.

Low (снимается записью, без правки): в хендоффе автор указал «684 строки» для docs/TESTING.md, фактическое значение — 699 строк. AC3 (≤ 800) от этого не страдает, тест это подтверждает; расхождение — неточность числа в тексте комментария, не в проверяемом артефакте. Не считаю нужным возвращать на правку.

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

  • Класс изменений — B/C, файлов класса A нет; правило «инфраструктурная задача — сразу в ветку, без ТЗ» соблюдено, метка S7-code-review корректна.
  • PROCESS.md: ни одно правило по существу не изменено — диф ограничен абзацем о конспектах в шапке и уточнением про промпт ревьюера в §10.4; сверено построчно.
  • Ролевые конспекты (docs/process/AUTHOR.md, REVIEWER.md) — каждый пункт верхнего уровня ссылается на существующий якорь PROCESS.md, ключевые формулировки дословны и лежат в названном разделе (проверено тестом и выборочно вручную по нескольким пунктам — трейлеры, лимит циклов, шесть классов риска, «одно число — один источник», запрещённое).
  • scripts/md-anchors.mjs строит якоря по алгоритму GitHub без схлопывания дефисов (сознательно отличается от check-docs.mjs, комментарий это объясняет) — по построенным тестам расхождений не найдено.
  • scripts/entry-cost.mjs/test/entry-cost.test.mjs держат маршрут автора и AGENTS.md («Reading order by role») в синхроне машинной сверкой списков файлов и их порядка, а не на слово автора.
  • scripts/status-snapshot.mjs: версии берутся из parseVersionSources (release-contract.mjs, не тронут), счётчики — из вынесенной в отдельную экспортируемую функцию testInventory (scripts/inventory.mjs, CLI-вывод при прямом запуске не изменился), рассинхрон версий не сглаживается, а показывается текстом «NOT synchronized: …». --check намеренно не в CI — причина документирована в самом скрипте и подтверждена наблюдением (счётчик тестов уже разошёлся на 20 всего за несколько влившихся задач).
  • docs/TESTING.md → docs/testing-notes/*: перенос дословный (независимая построчная сверка, расхождение только в заголовке и разделителе), test/golden-matrix.test.mjs обновлён читать индекс с приложениями и реально проходит (id #242/#250 резолвятся из geometry.md).
  • docs/STATUS.md → docs/STATUS-FEATURES.md: раздел «feature surface» перенесён дословно (независимая построчная сверка), таблица «Standing state and decisions» сохранила все прежние строки, кроме Version (ушла в генерируемый Snapshot).
  • scripts/inventory.mjs: рефакторинг в чистую экспортируемую функцию не изменил CLI-поведение (monolith-блок и структура вывода на месте), снятие с NOT_AN_INPUT подтверждено зелёным check-inputs.mjs --coverage.
  • Промпт ревьюера в process.yml сокращён с делегированием правил в канон и конспект; все примеры-прецеденты (#150, #102, #403, #234, #233, #237, #244, #252–259) остались в PROCESS.md §2.10/§8, а не исчезли вместе с текстом промпта — сверено чтением обеих версий. Битая ссылка «§2.9» → «§2.10» действительно исправлена.
  • Трейлеры коммита корректны: Issue: #634, User-Visible: no — оправдано (нет пользовательского поведения), changelog не требуется и не тронут.
  • Метамомент: этот самый прогон ревью выполняется по старому промпту process.yml (ссылка на «§2.9», а не «§2.10» в системном приглашении этой сессии) — ровно то расхождение, которое хендофф объявляет ожидаемым («process.yml исполняется из main», нужно зеркало после слияния). Это независимое наблюдение подтверждает точность авторского отчёта, а не находка против задачи.

Чего не проверял

  • golden:verify, demo/smoke_*.mjs, pytest tests_backend, model-invariants, perf-профили — diff не касается src/**, custom_components/**/*.py, геометрии/layout/marker.space или перф-чувствительных путей; запуск был бы гейтом без предмета.
  • Оставшиеся 5 из 7 новых мутантов (process-digest-bullet-without-canon-link, process-digest-key-rule-dropped, entry-cost-author-route-over-budget, entry-cost-budget-never-over, testing-notes-index-drops-section) не прогонялись вручную по одному — проверены только регистрацией id без коллизий и структурным сходством с двумя вручную подтверждёнными; будь один из них некорректен по существу (например, find не находит целевую строку), это не изменило бы вердикт этого раунда, но стоило бы отметить при полном прогоне node scripts/mutation-gate.mjs --check (не выполнялся — дорогой гейт, не гейт ревью при отсутствии диффа в исполняемом продуктовом коде).
  • Живой прогон конвейера новым промптом — по документированной причине (process.yml только на main) физически не наблюдаем на этом материале.
  • docs/reviews/INDEX.md, legacy/reviews/ — этот диф их не касается, вне предмета ревью.

Вердикт

Все три AC выполнены и доказаны автотестами, которые умеют падать (два проверены лично). Побочные правки (Snapshot, промпт ревьюера, порядок чтения) согласованы между собой и с каноном без потери содержания. High/Medium находок нет.


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

  • Ветка: issue/634-entry-cost, коммит 7dc759726023 — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет.
  • Дерево материала: 8264e3f8d100607a9a0a73eb524ebb5f8aa5ae2f
    git log --all --format='%H %T' | grep 8264e3f8d100
    
  • Тело issue: 687a2c8867e593a6e98a5c816a50580cc6fb2385c4bc98464c899106c42c9390
  • Вердикт конвейера: green · High 0