18 KiB
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— ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. - Дерево материала:
8264e3f8d100607a9a0a73eb524ebb5f8aa5ae2fgit log --all --format='%H %T' | grep 8264e3f8d100 - Тело issue:
687a2c8867e593a6e98a5c816a50580cc6fb2385c4bc98464c899106c42c9390 - Вердикт конвейера:
green· High 0