diff --git a/docs/reviews/INDEX.md b/docs/reviews/INDEX.md index 4021fbbe..652d7b39 100644 --- a/docs/reviews/INDEX.md +++ b/docs/reviews/INDEX.md @@ -1,6 +1,6 @@ # Индекс ревью -Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 234, issue: 114. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`. +Генерируется `node scripts/reviews-index.mjs` (#635) — не редактировать руками. Документов: 235, issue: 115. Вердикт: 🟢 зелёный · 🟡 жёлтый · 🔴 красный · ⚪ не распознан (свободная форма старых документов). H/M — число High/Medium по строке вердикта или заголовкам находок. Файлы — пути, названные в находках; ищите по имени файла: `grep form-kit INDEX.md`. | Issue | Документ | Этап · раунд | Вердикт | H | M | Находки | Файлы | |---|---|---|---|---:|---:|---|---| @@ -14,6 +14,7 @@ | #730 | [CODE-REVIEW-730-r2.md](CODE-REVIEW-730-r2.md) | code · r2 | 🟢 зелёный | 0 | 0 | — | — | | #730 | [CODE-REVIEW-730-r3.md](CODE-REVIEW-730-r3.md) | code · r3 | 🟢 зелёный | 0 | 0 | — | — | | #730 | [CODE-REVIEW-730-r4.md](CODE-REVIEW-730-r4.md) | code · r4 | 🟢 зелёный | 0 | 0 | — | — | +| #729 | [SPEC-REVIEW-729-r1.md](SPEC-REVIEW-729-r1.md) | spec · r1 | 🟢 зелёный | 0 | 0 | — | — | | #728 | [SPEC-REVIEW-728-r1.md](SPEC-REVIEW-728-r1.md) | spec · r1 | 🟡 жёлтый | 1 | 0 | 1. АС3/К3: заявленное различение причин validate-red и conflict «на текстах из констант…; 2. АС8: заявленное доказательство правки process-metrics.yml (fetch-depth: 0, timeout-m… | `wait-verdict.mjs` `review-doc-guard.mjs` `scripts/wait-verdict.mjs` `.github/workflows/_process.yml` `_process.yml` `_process-metrics.yml` `test/process-metrics.test.mjs` | | #728 | [SPEC-REVIEW-728-r2.md](SPEC-REVIEW-728-r2.md) | spec · r2 | 🟢 зелёный | 0 | 0 | — | — | | #728 | [CODE-REVIEW-728-r1.md](CODE-REVIEW-728-r1.md) | code · r1 | 🟢 зелёный | 0 | 0 | — | — | diff --git a/docs/reviews/SPEC-REVIEW-729-r1.md b/docs/reviews/SPEC-REVIEW-729-r1.md new file mode 100644 index 00000000..d431c8c5 --- /dev/null +++ b/docs/reviews/SPEC-REVIEW-729-r1.md @@ -0,0 +1,213 @@ +# SPEC-REVIEW-729-r1 + +Issue: #729 «Процесс: черновая реализация ask параллельно ревью ТЗ (изменение +правила №1 — решение владельца)» +Этап: spec (PROCESS.md §2.4) · Трек: ask · Заход: r1 · блокирующих циклов +израсходовано 0 из 4 + +## Скоуп + +ТЗ (тело issue, раздел `## ТЗ`) вводит новое исключение из правила №1: на +`track:ask`, в статусе `S4-spec-review`, автор вправе вести локальный +непушенный черновик продуктового кода (класс A) в рабочей копии, если каждый +черновой коммит несёт трейлер `Spec-Draft: sha256:<хеш нормализованного тела +issue>`. Правило 10 (`checkCommitEraStatuses`, `scripts/process-gate.mjs`) +получает исключение, которое принимает такой коммит только если: + +- трек на момент написания коммита — `ask`; +- эпоха `S4`, в которую попадает коммит, закрыта именно `S5-ready`; +- в этой эпохе есть зелёный `SPEC-REVIEW--rK.md` (найден в `` или + `origin/dev`) с «Тело issue:», равным трейлеру коммита. + +Исключение строится **поверх модели #738** (эпохи статуса для правила 10), +которая на момент ревью ещё не смёржена (`S6-in-progress`) — ТЗ это прямо +называет зависимостью («после `S8` #738») и критически для реализации не +маскирует как решённый факт. Также правятся `scripts/task-packet.mjs` (права +и раздел «Черновик» в пакете на `S4`/`S5`), тесты +(`test/process-gate.test.mjs`, `test/task-packet.test.mjs`, +`test/process-digests.test.mjs`) и канон (PROCESS.md §1, §2.4–2.6, §3 п.1, +§7.2, §9, §10.2, новый §11.8, §12, `docs/process/AUTHOR.md`, +`docs/process/REVIEWER.md`, `AGENTS.md`). Файлов класса A в этой задаче нет — +трек `ask` взят явно (меняет правило №1 и публичный контракт процесса), что +соответствует §5.1. Решение владельца на изменение правила №1 дано в теле +issue текстом «по #729 - разрешаю» (01.10) — ревьюер судит исполнимость и +проверяемость контракта, а не само разрешение, как и требует задание. + +## Как проверялось + +Раунд первый, документов ревью на #729 в дереве ещё нет — разбор полный. +Метод — не поверить формулировкам «сверено с кодом», а перепроверить каждую +построчную ссылку чтением текущего файла на материале ревью +(`76558bf2a0bf72dcfed369743639c989b4099450`, рабочая копия уже на нём): + +- `docs/SCOPE.md`, `AGENTS.md`, `docs/process/REVIEWER.md`, PROCESS.md §1, + §2.3–2.7, §4, §5, §5.1, §7.1, §7.2, §8, §11.7, §12 — целиком по ссылкам + промпта; +- тело issue #729 целиком (раздел `## ТЗ`, все 11 подразделов) и его + единственный комментарий («Оценка… трек ask…», решение владельца); +- статус и зависимости: `gh issue view` для #738 (`S6-in-progress`, не + смёржено — подтверждает, что ТЗ корректно называет его незавершённой + зависимостью, а не фантомной), #707 и #726 (оба `S8-merged`, их контракт + уже в `dev` — трековые метки, формат строки владельца, `trackFromLabels`); +- `3b9f25ea` (SHA, с которым ТЗ сверяет «что сейчас») подтверждён как предок + текущего `HEAD` (`git merge-base --is-ancestor`) и как коммит #727 — ссылка + не мёртвая; +- построчно сверены все ключевые ссылки раздела «Что сейчас (сверено с + кодом)» с текущими файлами: + - `scripts/process-gate.mjs`: `isInfrastructureRange` (строка 407), + `checkCommitEraStatuses` (ровно строки 505–556, включая сигнатуру и + `return out`), использование `statusOptional` и вызов правила 10 только + при `!statusOptional` (строки 778, 788–797) — всё сходится дословно; эта + функция сейчас реализует **старую**, безэпоховую модель (`readyAt` — + первое когда-либо событие допустимого статуса), что ожидаемо: #738 ещё + не смёржен, и ТЗ честно пишет будущий контракт «поверх» неё, а не выдаёт + его за текущее поведение; + - `scripts/review-doc-guard.mjs`: `normalizeIssueBody` (266–273), + `issueBodyDigest` (276–278), `anchorIssueBodyFrom` (281–287), + `issueBodyChanged` (298–308), `materialAnchorBlock` (315…, блок «Тело + issue:» начинается на 335) — сходится; + - `scripts/validate-commit-provenance.mjs`: `TRAILER`-регэксп (строка 9), + `terminalTrailers` (42) — подтверждает заявление «любой трейлер вида + `Имя: значение` в финальном блоке проходит, `Spec-Draft:` не ломает + требование терминального `Issue:`»; + - `scripts/task-packet.mjs`: `rightsFor` (33), `collectInputs` (404), + строки 44 и 52 — ровно те тексты, что цитирует ТЗ («продуктовый код + трогать НЕЛЬЗЯ…», «идёт ревью ТЗ: ждать вердикт…»); чтение ветки и + `reviewDocs` — строки 409–412 (fetch/for-each-ref) и 437–438 + (`ls-tree`/`git show` по `docs/reviews`) — сходится; + - `.github/workflows/_process.yml`: снятие хеша тела issue (645–657, блок + `m.issueBodyDigest(`), публикация документа ревью **до** перестановки + метки (шаг «Опубликовать документ ревью» на 1485 действительно идёт + раньше шага «Переставить метку» на 1873; переход `S4→S5` — строка 1736, + в ТЗ названа «:1735», расхождение на одну строку, не искажает факт) — + сходится; + - `scripts/process-track.mjs`: `trackFromLabels` (72–77, дефолт `ask` при + пустом списке меток), `labelTrack` (88, инфраструктура-осведомлённая + обёртка) — ТЗ сознательно берёт `trackFromLabels`, а не `labelTrack`: + это корректно, потому что правило 10 судит только коммиты с файлом + класса A, а такой коммит по определению §1 не принадлежит + инфраструктурному диапазону — защита от «дефолт `show`» здесь не нужна; + - PROCESS.md §5.1: «продуктовая задача без трековой метки — как + `track:ask`» — цитата К3 п.2б «Событий нет → ask» дословно совпадает с + каноном, а не придумана; + - `test/process-gate.test.mjs`: тест `rule 10 pins DoR…` существует + (строка 869, #311), AC #562-стиль прогона с временным git-репозиторием и + подставным `gh` существует (строка 776) — оба ориентира плана автотестов + реальны, не выдуманы; + - `docs/reviews/` сейчас плоский каталог (`SPEC-REVIEW--r.md`, + 235 файлов, включая существующие `SPEC-REVIEW-651..742`), архив + `legacy/reviews/<тег>/` наполняется только `reviews-archive.mjs` после + стабильного релиза (прочитан целиком) — подтверждает «принято + предположительно» п.5 (документы читаются только из `docs/reviews/` на + ``/`origin/dev`, `legacy/reviews/**` не участвует) и снимает + опасение, что недавние коммиты «индекс после сдвига каталога» (#727, + #730) могли переименовать путь `docs/reviews/SPEC-REVIEW-*` — не + переименовали; + - PROCESS.md §11 — секций 11.1–11.7 ровно семь, 11.8 свободен, коллизии + анкоря заголовка не будет; +- вручную прогнаны все граничные сценарии AC1–AC6 по описанным в ТЗ шкалам + времени (две эпохи `S4`, повтор `S4` reconcile, два зелёных документа в + одной эпохе, эпоха без `S5`, коммит вне `S4`) — результат (findings/ + отсутствие findings) в каждом случае соответствует порядку проверок + а→д, который описывает К3 п.2, расхождений не найдено; +- проверено отсутствие файлов класса A в диапазоне (`git diff --stat + 3b9f25ea..HEAD -- src/ custom_components/` — пусто), что подтверждает + заявление ТЗ «Файлов класса A нет». + +## Находки + +Нет. Блокирующих (High) и находок в скоупе (Medium) не обнаружено. + +## Что проверено и корректно + +- Обязательные разделы §7.1 — полный комплект: сценарий (три персоны: + агент-автор, владелец, ревьюер ТЗ — корректная адаптация для процессной, не + продуктовой задачи), что человек увидит до/после, проблема, скоуп/не-скоуп, + контракт поведения (К1–К5), UX, модель данных и миграция, i18n, критерии + приёмки AC1–AC10 с доказательством и oracle, план автотестов (включая + отдельный блок «чем краснеет»), риски, откат, release-артефакты. +- Каждый AC однозначен и привязан к конкретному тестовому файлу и + конкретному входу/выходу (явные хеши `H`/`H1`/`H2`/`H3`, временные метки, + ожидаемый текст находки) — ни один не сформулирован описательно без + оракула. +- Защитные AC (AC1–AC6 — гард по трейлеру, эпохе, треку, соответствию + документу) имеют явный отрицательный случай либо в столбце + «Доказательство/Oracle» самой таблицы, либо в отдельном перечне «чем + краснеет» — пустого третьего столбца нет ни у одной защитной строки. +- Продуктовых вопросов владельцу нет, и это обоснованно: единственный + продуктовый вопрос задачи — само изменение правила №1 — уже решён + владельцем явной строкой в теле issue («по #729 - разрешаю»), остальное — + технические решения, корректно вынесенные в «Принято предположительно» + (11 пунктов), а не выданные за факт. `docs/SCOPE.md` эту задачу не + ограничивает: она процессная, ни одной строки Core user jobs не касается, + как и соседние #726/#727/#728/#738. +- Зависимость на #738 названа честно и не замаскирована: #738 сейчас + `S6-in-progress` (проверено `gh issue view`), контракт эпох, на который + опирается К3, в коде ещё не существует (`checkCommitEraStatuses` на + текущем HEAD — дочерняя, безэпоховая модель) — ТЗ прямо пишет «DoR #729 + требует `S8` у #738» и даёт план на случай расхождения формулировок + (строить поверх фактического кода #738, AC5 держит тесты #738 + неизменными). Это дисциплинирует порядок работы, а не создаёт скрытую + невыполнимость спецификации. +- Технический выбор `trackFromLabels` вместо «единой» `labelTrack` в К3 п.2б + корректен по смыслу §1 (коммит класса A не может принадлежать + инфраструктурному диапазону), а не недосмотр совместимости функций. +- Ссылки на существующие тестовые ориентиры (`:776`, `:869` в + `test/process-gate.test.mjs`) и на существующие функции хеша/якоря + (`review-doc-guard.mjs`) реальны, не фантомны. +- Откат описан верно: ревёрт коммита задачи возвращает правило №1 без + исключения; уже прошедшие Validate черновые коммиты границей диапазона + (#703) повторно не судятся — соответствует существующей модели ревью. + +## Чего не проверял + +- `npx tsc --noEmit`, `npm test`, `npm run build` не гонял: зависимости + (`node_modules`) не установлены — на этапе spec они не ставятся (#696), что + подтверждено (`npm run typecheck` на материале даёт только ошибки + `Cannot find module 'lit'`/`'polyclip-ts'`, то есть отсутствие `npm ci`, а + не дефект кода). У задачи #729 нет диффа продуктового или тестового кода — + ветки `issue/729-*` не существует ни локально, ни на origin, класс A в + диапазоне `3b9f25ea..HEAD` отсутствует (проверено `git diff --stat`) — + гонять эти гейты не над чем. +- Мутанты по диффу не запрашивались (см. заголовок задачи) и не применимы: + диффа продуктового кода нет. +- Смоки, golden, `pytest tests_backend`, инварианты модели, performance — не + применимы: задача не трогает `src/**`, `demo/**`, Python, геометрию. +- Не проверял, останется ли сопоставление «реализатор пишет исключение в + `checkCommitEraStatuses` рядом с кодом #738» дословно жизнеспособным после + фактического код-ревью #738 — это риск следующего раунда (код-ревью #729), + явно признанный в разделе «Риски» ТЗ и ограниченный требованием AC5 «тесты + #738 неизменны». +- Не проверял форматирование трейлера `Spec-Draft` хуком `commit-msg` в + реальном git-хуке (его и не должно быть — К2 прямо говорит, что формат + судит правило 10 при push, а не `commit-msg`) — это заявлено как принятое + предположение, а не как факт текущего кода, и реализация ещё не + существует. +- Не проверял живое поведение `process-gate.mjs --issues` на реальном GitHub + API (сетевой вызов `gh`) — AC1–AC5 рассчитаны на unit-фикстуры с + инъекцией timeline/документов, AC6 — на временный git-репозиторий с + подставным `gh`, как и у #562; живой прогон по плану тестов не требуется + для приёмки ТЗ. + +## Вердикт + +Зелёный. ТЗ полно по §7.1, каждый AC однозначен и привязан к оракулу, +многочисленные ссылки «сверено с кодом» перепроверены построчным чтением +текущих файлов и подтвердились без расхождений, продуктовый вопрос (само +изменение правила №1) уже решён владельцем, остальные решения корректно +зафиксированы как технические допущения. Зависимость на не смёрженный #738 +названа прямо и не выдаётся за готовую базу. Находок нет. + +--- + + + +## Материал раунда + +- Ветка: `dev`, коммит `76558bf2a0bf` — ребейз его осиротит, и это нормально: ниже якоря, которые ребейз не меняет. +- Дерево материала: `e4d6aac31897c3f952332ec219cff7fbd5e9c793` + ``` + git log --all --format='%H %T' | grep e4d6aac31897 + ``` +- Тело issue: `94cd1bca3f851c8c9d9fc64b3b6227fb2fd3dac9f47715053a95dd133ae40bed` +- Вердикт конвейера: `green` · High 0 · маршрут `fix`