diff --git a/docs/reviews/CODE-REVIEW-634-r1.md b/docs/reviews/CODE-REVIEW-634-r1.md new file mode 100644 index 00000000..cccc998b --- /dev/null +++ b/docs/reviews/CODE-REVIEW-634-r1.md @@ -0,0 +1,173 @@ +# 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 diff --git a/docs/reviews/INDEX.md b/docs/reviews/INDEX.md index c80526cd..e3ab54bf 100644 --- a/docs/reviews/INDEX.md +++ b/docs/reviews/INDEX.md @@ -1,6 +1,6 @@ # Индекс ревью -Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1018, issue: 359. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`. +Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 1019, issue: 360. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`. | Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы | |---|---|---|---|---:|---:|---|---| @@ -17,6 +17,7 @@ | #635 | [CODE-REVIEW-635-r1.md](CODE-REVIEW-635-r1.md) | code · r1 | 🟡 жёлтый | 1 | 0 | индекс молчаливо теряет находки и врёт числами по текущему | `docs/reviews/CODE-REVIEW-639-r1.md` `CODE-REVIEW-637-r1.md` `docs/reviews/CODE-REVIEW-594-r1.md` `docs/LESSONS.md` | | #635 | [CODE-REVIEW-635-r2.md](CODE-REVIEW-635-r2.md) | code · r2 | 🟡 жёлтый | 1 | 1 | docs/reviews/INDEX.md, зафиксированный в материале ревью, устарел на собственном SHA — …; parseFindings/parseFiles: фолбэк «первая строка тела блока» вырезает начало буллета и п… | `docs/reviews/INDEX.md` `SPEC-REVIEW-625-r1.md` `SPEC-REVIEW-625-r2.md` `CODE-REVIEW-625-r1.md` `CODE-REVIEW-625-r2.md` `process.yml` `test/reviews-index.test.mjs` `INDEX.md` | | #635 | [CODE-REVIEW-635-r3.md](CODE-REVIEW-635-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | firstParagraph: ветка нет\b в фильтре мёртвая из-за ASCII-only \b в JS-регэкспах, расхо… | `scripts/reviews-index.mjs` | +| #634 | [CODE-REVIEW-634-r1.md](CODE-REVIEW-634-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #633 | [CODE-REVIEW-633-r1.md](CODE-REVIEW-633-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #630 | [CODE-REVIEW-630-r1.md](CODE-REVIEW-630-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | | #629 | [SPEC-REVIEW-629-r1.md](SPEC-REVIEW-629-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — |