# Router-Mentor sub-plans — EDIT-PLAN (ревью 5-скил цепочки) Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:executing-plans (или subagent-driven-development) — задачи редактируют .md-планы и добавляют новые планы/задачи. Steps — чек-боксы (`- [ ]`).

**Goal:** Внести в 5 sub-plan'ов (A/B/C/D/E) + спеку R6.2 правки, закрывающие 24 находки ревью-цепочки (нах.F1–F7 / SE1–SE13 / VF-1 / V1–V6 / C1–C4), по решениям владельца: производитель вердикта (C-1), новый sub-plan C2 «манифест интеграции» (V-1), радары как код (F2), ВСЕ правки.

**Architecture:** Документ-план о правках ДРУГИХ планов. Для правок СУЩЕСТВУЮЩИХ задач — точные OLD→NEW с цитатами кода (верифицированы построчно в ревью). Для НОВЫХ модулей/задач — точный КОНТРАКТ (экспорт-имена, сигнатуры, формы возврата, полярность, инварианты, цитаты); полный TDD-код этих задач пишется при ИСПОЛНЕНИИ соответствующего sub-plan'а (executor по контракту). Каждая правка .md — мутирующее действие → отдельный FLOOR-ESCAPE при исполнении.

**Tech Stack:** Markdown plan-файлы в `docs/superpowers/plans/` + спека в `docs/superpowers/specs/`. Целевой код — Node ESM `tools/*.mjs`, vitest (tools-config, ТОЛЬКО из `app/`).

**Источники находок (полные формулировки):** транскрипт ревью-сессии 2026-06-10, скилы 1–5. Спека: `docs/superpowers/specs/2026-06-10-router-mentor-live-rebuild-design.md` (R6.2).

**Коллизия имён (важно):** мои находки `нах.F1–F7` ≠ спека-фундамент `§2 F1–F6`. Ниже — `нах.Fn` для находок.

**Цели-файлы:**
- A: `docs/superpowers/plans/2026-06-10-router-mentor-subplan-a-context-verity.md`
- B: `docs/superpowers/plans/2026-06-10-router-mentor-subplan-b-layered-graph.md`
- C: `docs/superpowers/plans/2026-06-10-router-mentor-subplan-c-live-seam.md`
- D: `docs/superpowers/plans/2026-06-10-router-mentor-subplan-d-reading-discipline.md`
- E: `docs/superpowers/plans/2026-06-10-router-mentor-subplan-e-footgun-fixes.md`
- C2 (новый): `docs/superpowers/plans/2026-06-10-router-mentor-subplan-c2-integration-manifest.md`
- F (новый, радары): `docs/superpowers/plans/2026-06-10-router-mentor-subplan-f-completeness-radars.md`
- Спека: `docs/superpowers/specs/2026-06-10-router-mentor-live-rebuild-design.md`

**Порядок исполнения правок (мастер):** Task 1 (спека R6.3 шапка) → Task 2 (C: производитель вердикта) → Task 3 (C2 манифест) → Task 4 (F радары) → Task 5 (A) → Task 6 (B) → Task 7 (D) → Task 8 (E) → Task 9 (cross-cutting + F7) → Task 10 (финальная сверка).

---

### Task 1: Спека R6.2 → R6.3 (зафиксировать решения ревью ДО правки планов)

**Files:** Modify: спека `...2026-06-10-router-mentor-live-rebuild-design.md`

**Зачем:** C-1 — спека-уровня (конфлейт «роутер=наставник» двух выходов LLM). Прежде чем менять планы, спека должна явно развести РОЛИ и закрыть неназначенные механизмы (нах.F2/F5/F7), иначе планы снова разойдутся со спекой (урок V-5).

- [ ] **Step 1: §0 changelog — добавить абзац R6.2 → R6.3.** Перечислить: разведение mentor-ролей (выбор-скила vs разбор-плана), производитель вердикта, манифест интеграции, радары-код, F7 дозапрос, VF-1 INFERRED-guard.
- [ ] **Step 2: §6.1 — развести ДВА выхода наставника (корень C-1).** Добавить абзац: «Наставник делает ДВА типа вызовов LLM с РАЗНЫМИ выходами: (а) ВЫБОР-СКИЛА — router-трасса `{candidates,chosen,why_chosen,twins_considered,confidence}` (существующий `runRouter`-пайплайн); (б) РАЗБОР-ПЛАНА — mentor-вердикт `{plan_points_addressed,reasoning,recommendation,confidence}` (СОБСТВЕННЫЙ промпт, просит именно эти слоты). Это РАЗНЫЕ промпты и РАЗНЫЕ валидаторы. Гейт `freezePlan` требует вердикт (б), не трассу (а).» Цитаты: `[router-engine.mjs:48 TRACE_SLOTS]` vs mentor-verdict слоты `[spec §6.1 R2-SE-c]`.
- [ ] **Step 3: §6.1 — производитель вердикта.** Добавить: «Вердикт ПРОИЗВОДИТСЯ `runMentorVerdict` (зеркало `runRouter`, но verdict-промпт + `validateMentorVerdict`); `onPlanWrite` (A0) инициирует его при записи плана и персистит результат (task-id-bound).»
- [ ] **Step 4: §6.2 R2-VA-5 — усилить binding.** Уточнить: «mentor-вердикт НЕСЁТ `plan_hash` замораживаемого плана; freeze-gate сверяет `verdict.plan_hash === planId(frozenPlan.steps)` `[plan-lock.mjs:15-17]` — устаревший/чужой вердикт не проходит (нах.F4).»
- [ ] **Step 5: §5.5 — INFERRED-guard (VF-1).** Уточнить SE-2: «INFERRED ОБЯЗАН нести непустой `derivation_ref` (машинный guard); отсутствие → flagged. `verifyArtifact` это энфорсит. Лимит доли (O9) и owner-sign-off — отдельно (O9 открыт). Без guard INFERRED — полоса в обход verity.»
- [ ] **Step 6: §5.7 / §8 — радары как КОД (нах.F2, решение владельца).** Снять лимбо: «Граф-радар и скелет-радар — ЧИСТЫЕ МОДУЛИ (sub-plan F), опираются на граф B; проверка ПОЛНОТЫ исполнения (§8 Q3).» Убрать двусмысленность «код или поведение».
- [ ] **Step 7: §5.3 / ДР-P1 — дозапрос соседнего района (нах.F7).** Уточнить механизм: «Наставник в трассе может выставить `request_district:<name>` с обоснованием; контроллер фетчит `districtDetail(neighbor)` (B), добавляет в граф-секцию следующего круга; бюджет — отдельный счётчик `DISTRICT_PROBE_CAP` (= MENTOR_PROBE_CAP=2/круг, дешёвое чтение КАРТЫ, не файлов).»
- [ ] **Step 8: §9 / §10 — обновить «новое vs существующее» + закрыть ✅O.** Перенести нах.F2/F5/F7 из неявных в явные (назначены sub-plan F / C2 / C). §10: пометить, что C-1 разрешён в R6.3 (развод ролей).
- [ ] **Step 9: §11 реестр цитат — без изменений** (цитаты верифицированы в ревью точны). Добавить NB «R6.3 — фолд ревью 5-скил цепочки».
- [ ] **Step 10: Self-review спеки** — §§ согласованы, нет противоречий с §2 F1–F6.

---

### Task 2: Sub-plan C — производитель вердикта (C-1/нах.F4/нах.F5) + renderDistricts (нах.F1/C-2) + renames (SE2/SE3/SE10)

**Files:** Modify: sub-plan C.

**Зачем:** C-1 [КРИТ] — freeze-gate потребляет `mentorVerdict`, но никакой код его не производит (T5 `runMentorRound` даёт router-трассу; промпт T4 просит router-слоты). Добавить производителя + binding + renderDistricts + развести имена.

- [ ] **Step 1: Новая задача C-T3b «buildMentorVerdictPrompt» (производитель-промпт).** Контракт: `buildMentorVerdictPrompt({plan, verifiedContext, negotiationLog, graphSection}) → {system, user}`. system ПРОСИТ JSON со слотами `plan_points_addressed (массив: по пункту плана — статус+замечание), reasoning, recommendation, confidence (0..1)` — НЕ router-слоты. Зеркало идиомы `buildClassifierPromptStructured`/`buildRouterPrompt` `[router-engine.mjs:98]`, но СВОЙ набор. Тест: user содержит план по-пунктам + проверенный контекст; system просит именно verdict-слоты.
- [ ] **Step 2: Новая задача C-T5b «runMentorVerdict» (производитель).** Контракт: `runMentorVerdict({plan, verifiedContext, negotiationLog, graphSection, planHash, llmCall, confidenceThreshold=0.5}) → {ok, wired, verdict, reason?}`. Поток: `buildMentorVerdictPrompt` → `llmCall` → parse → `validateMentorVerdict` (C T3) → при валидном `wired:true` + `verdict = {...slots, plan_hash: planHash}` (binding нах.F4). Сбой/stub → `{ok:false, wired:false}` (SE-R6-6: не суд). Зеркало `runMentorRound` `[C T5]`, но verdict-форма. Тесты: валидный → ok+wired+verdict.plan_hash; пустой слот → ok:false; сбой → wired:false.
- [ ] **Step 3: C T6 freezeGate — binding plan_hash (нах.F4) + rename verityImpl (SE3).** OLD-сигнатура `freezeGate({mentorVerdict, mentorWired, verifiedContextArtifact, verityImpl})`. NEW: `freezeGate({mentorVerdict, mentorWired, planHash, verifiedContextArtifact, hasUnresolvedExtractedImpl})`. Добавить проверку ПЕРЕД verity: `if (mentorVerdict?.plan_hash !== planHash) return {pass:false, reason:'вердикт не привязан к замораживаемому плану (stale/чужой) — нах.F4'}`. Переименовать `verityImpl` → `hasUnresolvedExtractedImpl` ВЕЗДЕ + JSDoc-нота полярности: «возвращает true=ЕСТЬ неразрешённая EXTRACTED=ГРЯЗНО=блок (зеркало `artifactHasUnresolvedExtracted` из A)». Обновить тесты freeze-gate под новую сигнатуру + добавить тест «verdict.plan_hash ≠ planHash → блок».
- [ ] **Step 4: C T5 runMentorRound — rename graph→groundingGraph (SE2).** Сигнатура: `graph` (нод-граф для `groundTrace`) переименовать в `groundingGraph`; `graphSection` (B-секция для промпта) — оставить. Внутри `groundTrace(trace, groundingGraph)` `[router-engine.mjs:73-79]`. JSDoc: «`groundingGraph` = ПОЛНЫЙ нод-граф (заземление, CD-R6-G «против полного»); `graphSection` = прунённая карта районов (в промпт). НЕ путать — разные формы, своп ломает заземление.» Обновить тесты (передают `groundingGraph`).
- [ ] **Step 5: C T4 buildMentorPrompt — assert districts (нах.F1/C-2).** Добавить в тест T4 проверку, что user содержит имена районов из `graphSection.layer0` (напр. `expect(p.user).toMatch(/tools|app-backend/)`). Сам рендеринг районов делает правка `buildRouterPrompt` (Task 3 C2-W1) — buildMentorPrompt передаёт `graph: graphSection`, после чего layer0 рендерится. Нота в C T4: «districts рендерятся через CD-R6-G-правку buildRouterPrompt (C2-W1) — без неё layer0 теряется (нах.F1).»
- [ ] **Step 6: C T2 appendNegotiation — обработка throw (SE10).** Нота + контракт: «throw на пустом обосновании обязан ловиться вызывающим (`onPlanWrite`/контроллер) → НЕ крах круга; при пустом обосновании → требовать обоснование заново (переспрос), не падать.» Добавить в C T2 тест-нота: производитель оборачивает в try/catch.
- [ ] **Step 7: C scope/«Боевая проводка» — снять claim onPlanWrite** (переезжает в C2-W3). Уточнить: «`onPlanWrite` — задача C2 (манифест), не C.»
- [ ] **Step 8: C Self-review — обновить под новые задачи** (T3b/T5b + renames + binding).

---

### Task 3: Новый sub-plan C2 «манифест интеграции» (V-1: нах.F1/F3/F5/«(100%)»/E-warn + V-2)

**Files:** Create: sub-plan C2.

**Зачем:** V-1 [СИСТЕМНЫЙ] — B/D/E откладывают «→ C», C не забирает всё; нет единого манифеста «деферрал → владелец». C2 перечисляет КАЖДЫЙ отложенный wiring с явным владельцем (задача C2 vs активация владельца) + кросс-модульный интеграционный тест + контракты инъекций (V-2).

- [ ] **Step 1: Шапка + раздел «Реестр деферралов» (таблица).** Колонки: ID · что · источник (план/§) · владелец (C2-task / owner-activation) · контракт.
- [ ] **Step 2: W1 renderDistricts + «(100%)»-rewrite (нах.F1/C-2) — задача C2.** Modify `tools/router-engine.mjs` `buildRouterPrompt` `[:98-124]`: (а) при `graph && Array.isArray(graph.layer0)` — рендерить ОТДЕЛЬНУЮ секцию «--- ГРАФ ПРОЕКТА: КАРТА РАЙОНОВ (прунённая, заземление против полного каталога) ---» из `graph.layer0` (district/nodeCount/topNodes); (б) переписать `[:114]` `'--- ГРАФ+КАТАЛОГ УЗЛОВ (100%) ---'` → `'--- КАТАЛОГ УЗЛОВ (skill-каталог) ---'` (разделить catalog и graph, CD-R6-G); (в) `nodesForCtx` `[:99]` — каталог берёт ТОЛЬКО `catalog.nodes` (граф-районы рендерятся отдельной секцией, не как каталог-фолбэк). Тесты: districts-секция присутствует при graphSection с layer0; «(100%)» больше нет; существующие router-тесты (catalog-only) зелены. **NB:** router-engine — это М3 (наставник-движок, который мы оживляем), не М2/М5/М6 → правка В scope (CD-3 запрещает трогать М2/М5/М6, не М3).
- [ ] **Step 3: W2 reading-discipline wiring (нах.F3) — задача C2.** (а) Modify `tools/enforce-supreme-gate.mjs` `decide`: в impl-режиме (frozenPlan) перед observe-only пропуском Read-сырья — звать `decideReadEvent` (D) и при `gate.block` блокировать авторское сырьё-чтение вне шага плана. (б) `planAuthorizesPath` ПРОИЗВОДИТЕЛЬ: построить из `frozenPlan`+`stepPtr` через `actionMatchesStep` `[plan-lock.mjs:86]` (путь авторизован, если есть шаг плана с этим object) — НЕ always-true (SE5). (в) `probeCountThisRound` — реальный per-round счётчик из состояния кругов C. (г) `contentType` (D) → прокинуть в выбор reading-скила существующим роутером. Контракт каждого — в таблице. **NB scope:** правка enforce-supreme-gate (М2) — аддитивный предусловный слой ПЕРЕД observe-only (CD-3 «встраиваемся поверх»), согласовать с владельцем как затрагивающую М2.
- [ ] **Step 4: W3 onPlanWrite (нах.F5) — задача C2.** Контракт: `onPlanWrite({planSteps, sessionId, ...injections}) → {taskId, verdict}`. Поток: `deriveTaskId`+persist (C T1) → `runMentorVerdict` (C T5b) → `appendNegotiation` персист (try/catch SE10) → вернуть для freeze-gate. Регистрация хука в settings.json — owner-activation. Тесты: первый план присваивает task-id; вердикт произведён + персистнут.
- [ ] **Step 5: W4 warn→owner-резюме (E O18, нах.F3-adjacent) — задача C2 / owner.** Прокинуть `decideMode(...).warn/warnReason` `[enforce-supreme-gate.mjs:211-216 после E T4]` в текст owner-гейта-1 резюме (§7.0). owner-activation если резюме формируется владельцем.
- [ ] **Step 6: W5 мастер-порядок + W6 кросс-модульный интеграционный тест (V-2).** Порядок сборки sub-plan'ов: A,B,D,E → C → C2 → F. W6: ОДИН интеграционный тест `tools/router-mentor-integration.test.mjs` — реальные `artifactHasUnresolvedExtracted` (A) + `buildGraphSection` (B) + `decideReadEvent` (D) проведены в C `buildMentorPrompt`/`freezeGate`/`runMentorRound` с ВЕРНОЙ полярностью/формой → end-to-end зелено (ловит SE2/SE3/SE5 на реальной проводке, не стабах).
- [ ] **Step 7: W7 контракты инъекций (V-2) + C-3.** Таблица на каждый инъектируемый предикат: полярность / форма / продакшен-источник / поведение-на-дефолте. Включить C-3: `hasUnresolvedExtractedImpl`'s readFileImpl = `(f)=>fs.readFileSync(path.resolve(REPO_ROOT, f), 'utf8')` (НЕ голый `fs.readFileSync` — Buffer + относительный путь от CWD хука ломают резолв → всё downgrade → вечный блок).
- [ ] **Step 8: C2 Self-review** — каждый деферрал из A/B/C/D/E self-review'ов имеет строку в реестре с владельцем; ни один не в щели.

---

### Task 4: Новый sub-plan F — completeness-радары (нах.F2, код)

**Files:** Create: sub-plan F.

**Зачем:** нах.F2 — граф-радар и скелет-радар (лестница ДР-3 §5.7, проверка полноты §8 Q3) не покрыты. Владелец: код.

- [ ] **Step 1: Шапка + scope** (чистые модули, опираются на граф B; wiring в исполнение — C2/behavioral).
- [ ] **Step 2: Задача F1 «graph-radar».** Контракт: `buildGraphRadar({touchedFiles, graph}) → {neighbors:[{node, viaTouched, addressed:false}], summary}`. Логика: для каждого touched-файла → его узлы в графе → соседи по `links` (degree>0) → список «граф связывает touched X с Y — адресован?». Чистый (граф инъектируется, форма B `graph.json`). Тесты: touched tools/x → соседи из links; пустой → пусто.
- [ ] **Step 3: Задача F2 «skeleton-radar».** Контракт: `buildSkeletonRadar({headers, touchedSections}) → {items:[{header, status:'touched'|'not-relevant'|'not-read'}], unreported}`. `headers` — grep заголовков/сигнатур файла (инъектируется). Claude отчитывается по КАЖДОМУ пункту (§5.7). Чистый. Тесты: каждый header → пункт; не-отчитанные → unreported.
- [ ] **Step 4: Задача F3 регрессия + нота wiring** (radars зовутся на ФАЗЕ исполнения как проверка полноты — C2/контроллер).
- [ ] **Step 5: F Self-review.**

---

### Task 5: Sub-plan A — SE6 (anchor-для-EXTRACTED) + VF-1 (INFERRED-guard) + SE9 (T4 reframe)

**Files:** Modify: sub-plan A.

- [ ] **Step 1: SE6 — A T1 схема.** Изменить нота схемы: «`anchor` ОБЯЗАТЕЛЕН при `kind==='EXTRACTED'` (без него `resolveCitation` не резолвит → secure-default понижает до INFERRED). Помечен `anchor?` в типе, но для EXTRACTED — условно-обязателен.» Добавить в A T2/T3 явный тест «EXTRACTED без anchor → downgraded» (поведение уже есть в `resolveCitation` `[A T2]` — закрепить тестом против footgun'а).
- [ ] **Step 2: VF-1 — A T3/T4 verifyArtifact INFERRED-guard.** Изменить `verifyArtifact`: INFERRED-запись с пустым/отсутствующим `derivation_ref` → `flagged` (не молчаливо проходит). NEW-тест: `{kind:'INFERRED', derivation_ref:''}` → flagged; с непустым → ok. Нота: «закрывает полосу обхода verity через INFERRED-метку (§5.5 SE-2); лимит доли O9 — открыт.»
- [ ] **Step 3: SE9 — A T4 переформулировать.** Заголовок «Step 1: Write the failing test» → «Step 1: Закрепляющий тест инварианта Task 3 (характеризация, БЕЗ RED)». Step 2 «Run test to verify it fails OR passes» → «Run — Expected PASS (инвариант уже в коде Task 3, не red-green)». Добавить нота про TDD-gate: «характеризационный тест проходит сразу — это норма, не нарушение TDD.»
- [ ] **Step 4: A Self-review — обновить spec-coverage** (+SE6/VF-1/SE9).

---

### Task 6: Sub-plan B — SE7 (Step0↔тесты) + SE8 (junction-fallback) + SE11 (behind-unknown)

**Files:** Modify: sub-plan B.

- [ ] **Step 1: SE7 — B T2/T3 Step 0.** Добавить в Step 0 обоих: «Вывод Step 0 правит И `DISTRICT_RULES`/`PRUNE_PREFIXES`, И КЕЙСЫ тестов Step 1 — предзаписанные assert'ы ИЛЛЮСТРАТИВНЫ (под реальные top-N префиксы). Сохранять инвариант "specific перед generic" + OTHER<10% (T8).»
- [ ] **Step 2: SE8 — B T2/T3 Step 0 + T8 Step 2.** Добавить fallback-ноту: «Если junction `graphify-out/graph.json` отсутствует/нечитаем (СТАЛЫЙ, commit 81cbd8c1) — НЕ застревать: владелец регенерирует граф (`/graphify --update`) ЛИБО использовать baseline-префиксы из этого плана + пометить смок OTHER «не верифицирован на живых данных».»
- [ ] **Step 3: SE11 — B T6 readStaleness/gatherStalenessInputs.** Изменить контракт: при ошибке `git rev-list` (граф-commit вне истории) — `commits_behind` помечать как `null` (неизвестно), НЕ `0`. `readStaleness` возврат: `{stale, commits_behind: number|null, uncommitted}`. Нота: «`stale:true` + `commits_behind:null` = «устарел, величина неизвестна» (честнее, чем вводящий 0).» Обновить тесты T6.
- [ ] **Step 4: B Self-review + V-3 placeholder-метки** (DISTRICT_RULES/PRUNE_PREFIXES помечены «PLACEHOLDER — заменить выводом Step 0»).

---

### Task 7: Sub-plan D — SE4 (типы↔производители) + SE5 (контракт-инъекций) + SE12 (.env basename)

**Files:** Modify: sub-plan D.

- [ ] **Step 1: SE4 — D T1/T2 синк списка типов с производителями.** `READING_CONTENT_TYPES`: убрать `narrative-doc` (нет производителя — generic .md уходит в abstain→переспрос роутера) ИЛИ добавить производитель. ДОБАВИТЬ производитель `scientific`: `grepHeaderFallback` +маркеры (`\bAbstract\b`, `\bDOI:`, `arXiv`, `\bСтатья\b` в научном контексте) → `'scientific'` (роутер → deep-research, D-нота). После правки: КАЖДЫЙ тип в `READING_CONTENT_TYPES` имеет производителя ИЛИ удалён. Обновить тест «список заморожен и содержит ожидаемые». Нота-D: «синк закрывает мёртвые типы (SE4).»
- [ ] **Step 2: SE5 — D T3/T7 контракт опасных инъекций + DANGER-нота.** Добавить в D (и cross-ref в C2-W7): «`planAuthorizesPath` ОБЯЗАН строиться из frozenPlan+stepPtr (always-true стаб ОТКЛЮЧАЕТ гейт ДР-1 — configuration cliff); `probeCountThisRound` ОБЯЗАН быть реальным per-round счётчиком (дефолт 0 отключает probe-cap). Производитель — C2-W2/W3.» DANGER-блок в D scope.
- [ ] **Step 3: SE12 — D T1 .env по basename.** Изменить `classifyReadingContent`: config-детект ТАКЖЕ по `path.basename(path) === '.env'` (т.к. `extname('.env')===''`). NEW-тест: `{path:'app/.env'}` (ext='') → `config`. Нота: «dotfiles без расширения ловятся basename'ом.»
- [ ] **Step 4: D Self-review** (+SE4/SE5/SE12).

---

### Task 8: Sub-plan E — SE1 (объявлять точный skill-id) + C-4 (синк owner-runbook)

**Files:** Modify: sub-plan E.

- [ ] **Step 1: SE1 — E coordination-нота + onPlanWrite/seam объявляет id.** Усилить: «O13 требует ТОЧНЫЙ `input.skill`-id (есть близнецы `audit-context-building:audit-context` vs `:audit-context-building`). Перед запросом escape формального скила Claude ОБЯЗАН ОБЪЯВИТЬ точную строку `FLOOR-ESCAPE: skill:<id>` для копирования владельцем — НЕ заставлять угадывать.» Добавить нота в E + cross-ref C2 (mentor-seam объявляет).
- [ ] **Step 2: C-4 — E activation-coordination задача.** Новая нота/задача: «При активации E (canonicalAction Skill-ветка) — СИНХРОННО обновить owner-runbook/handoff: формальный escape `write:cwd` → `skill:<id>`. До синка владелец, печатая старый `write:cwd`, получит блок (грант не совпадёт `[escape-grant.mjs:43-44]`). Это plan↔runbook контракт-рассинхрон — обязателен в момент активации.»
- [ ] **Step 3: E Self-review** (+SE1/C-4 coordination).

---

### Task 9: Cross-cutting (V-3/V-6/SE13) + F7 (дозапрос соседнего района)

**Files:** Modify: A, B, C, D, E + C (F7).

- [ ] **Step 1: V-6 — метить не-TDD шаги во ВСЕХ планах.** Enumeration (B T2/T3 Step0), характеризация (A T4), smoke (B T8 Step2), регрессия (все финальные) — пометить явно «[НЕ-TDD: enumeration/характеризация/smoke/регрессия]» + нота про обработку enforce-tdd-gate (проходит сразу — норма).
- [ ] **Step 2: V-3 — data-const как PLACEHOLDER** (уже в Task 6 Step 4 для B; добавить D `CODE_EXT`/`SPEC_PATH_PREFIXES` — помечены «уточнить под реальный набор расширений проекта»).
- [ ] **Step 3: SE13 — passed-счётчики иллюстративны.** Во всех планах: per-task «N passed» → нота «иллюстративно; точное число зависит от структуры тестов исполнителя — сверяй ЗЕЛЁНОСТЬ, не число».
- [ ] **Step 4: F7 — дозапрос соседнего района (C/спека).** Новая задача в C: `runMentorRound` распознаёт в трассе `request_district:<name>` → возвращает сигнал; контроллер фетчит `districtDetail(neighbor)` (B) → в граф-секцию следующего круга; `DISTRICT_PROBE_CAP=2/круг` (дешёвое чтение карты, не файлов; ДР-P1). Контракт + тест: трасса с request_district → escalateDistrict сигнал; сверх cap → отказ.
- [ ] **Step 5: ДР-1 гранулярность (нах.F6, lightweight).** Добавить в `buildMentorPrompt`/verdict-промпт строку: «единица плана = растяжка до следующей НЕИЗВЕСТНОСТИ; громкость церемонии по риску (`detectHighRisk` `[router-engine.mjs:19]`)». Поведенческая инъекция в промпт.

---

### Task 10: Финальная сверка edit-плана

**Files:** (нет правок — проверка)

- [ ] **Step 1: Реестр-сверка** — каждая из 24 находок (нах.F1–F7 / SE1–SE13 / VF-1) + 6 классов (V1–V6) + 4 шва (C1–C4) имеет адресующую задачу выше. Таблица «находка → Task».
- [ ] **Step 2: Регрессия после ВСЕХ правок кода** — `cd app && node node_modules/vitest/vitest.mjs run --config vitest.config.tools.mjs --reporter dot` → ВЕСЬ tools-набор зелёный, новые модули (verdict-producer / radars / integration-test) включены, 0 регрессий М1–М7. Зафиксировать число passed.
- [ ] **Step 3: §2 F1–F6 не нарушены** — перечитать фундамент после правок.

---

## Self-Review (writing-plans)

**1. Spec coverage (находка → Task):**
- C-1 (вердикт без производителя) → Task 1 Step 2-3 (спека развод ролей) + Task 2 Step 1-2 (buildMentorVerdictPrompt/runMentorVerdict). ✅
- C-2 / нах.F1 (layer0 теряется + «(100%)») → Task 3 W1 (renderDistricts + rewrite) + Task 2 Step 5 (assert). ✅
- C-3 (verityImpl readFile) → Task 3 W7. ✅
- C-4 (escape vs runbook) → Task 8 Step 2. ✅
- нах.F2 (радары) → Task 4. ✅ нах.F3 (D/E wiring) → Task 3 W2/W4. ✅ нах.F4 (binding) → Task 1 Step 4 + Task 2 Step 3. ✅ нах.F5 (onPlanWrite) → Task 3 W3. ✅ нах.F6 (detectHighRisk) → Task 9 Step 5. ✅ нах.F7 (сосед) → Task 1 Step 7 + Task 9 Step 4. ✅
- SE1 → Task 8 Step 1. SE2 → Task 2 Step 4. SE3 → Task 2 Step 3. SE4 → Task 7 Step 1. SE5 → Task 7 Step 2 + Task 3 W2. SE6 → Task 5 Step 1. SE7 → Task 6 Step 1. SE8 → Task 6 Step 2. SE9 → Task 5 Step 3. SE10 → Task 2 Step 6. SE11 → Task 6 Step 3. SE12 → Task 7 Step 3. SE13 → Task 9 Step 3. ✅
- VF-1 → Task 1 Step 5 + Task 5 Step 2. ✅
- V-1 → Task 3 (C2). V-2 → Task 3 W6/W7. V-3 → Task 6 Step 4 + Task 9 Step 2. V-4 → Task 1 Step 4 + Task 2 Step 3. V-5 → Task 1 Step 6-7. V-6 → Task 9 Step 1. ✅

**2. Placeholder scan:** правки существующих задач — точные OLD→NEW с цитатами (верифицированы построчно в ревью); новые модули — КОНТРАКТ (сигнатура/форма/инвариант/цитата), полный TDD-код пишется при исполнении соответствующего sub-plan'а (явно указано). Нет «TBD».

**3. Type consistency:** `runMentorVerdict`→`{ok,wired,verdict,reason?}`; `freezeGate`→`{pass,reason}` (новые поля planHash/hasUnresolvedExtractedImpl); `buildGraphRadar`→`{neighbors,summary}`; `buildSkeletonRadar`→`{items,unreported}`; `readStaleness.commits_behind`→`number|null`. Имена согласованы с цитатами кода.

**Известное ограничение (честно):** этот edit-план — план ПРАВОК планов; полный TDD-код новых задач (buildMentorVerdictPrompt/runMentorVerdict/onPlanWrite/радары/интеграционный тест) пишется при ИСПОЛНЕНИИ — здесь зафиксированы их КОНТРАКТЫ (достаточно для executor'а по образцу соседних задач), не полная реализация. O9 (лимит доли INFERRED), O5 (канал записи наставника), §8 надзор O7 — остаются открытыми (не в scope этих правок).
