# Карта узлов iter9 — подсистема brain governance — Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Синхронизировать «карту узлов» (`docs/automation-graph.html` + `docs/automation-graph-data.js`) с подсистемой brain governance (ADR-011, 19.05.2026): +9 узлов, +12 рёбер, +1 GREEN-конфликт, +9 паспортов/edge-details/NODE_META, версии-метки ×4 — iter9.

**Architecture:** Подход A (subsystem-level) — новые узлы в их естественных функциональных группах. data.js — общий: правка кормит и `docs/observer/dashboard.html`. Верификация — рендером (нет unit-тестов у статической data-viz).

**Tech Stack:** vis-network 9.x, классический `<script>` (без ES-модулей в data.js), Node (sanity `node --check`), Playwright MCP (рендер-верификация), lefthook pre-commit.

**Спек:** `docs/superpowers/specs/2026-05-20-automation-map-iter9-brain-governance-design.md`
**Ветка:** `feat/automation-map-iter9` (уже создана; на ней лежит спек).

---

## File Structure

- **`docs/automation-graph-data.js`** (общий источник топологии): `NODES` (+9), версии-метки ×4, `EDGES` (+12), `CONFLICT` (+1 GREEN), `NODE_SECTION` (+9), count-комментарии, фикс шапки (строка 5).
- **`docs/automation-graph.html`** (паспорта/мета/детали): `NODE_DETAILS` (+9), `EDGE_DETAILS` (+12), `NODE_META` (+9 + bump `META_SNAPSHOT`/`META_WINDOW` + `changed` ×4).
- НЕ трогаем: `docs/observer/dashboard.html` (кормится из data.js), нормативку, `GROUPS`/`CATEGORY_LABELS` (новых групп нет).

**9 новых узлов** (id → group → ring·angle): `router_procedure`→rules·1·210; `observer_stophook`→hooks·4·205; `sk_brain_retro`→skills_proj·3·210; `observer_evidence`→memory·6·204; `lh_l1watcher`→lefthook·5·150; `lh_crossref`→lefthook·5·157; `lh_obs_obs`→lefthook·5·164; `lh_status_md`→lefthook·5·171; `lh_obs_cov`→lefthook·5·178.

---

### Task 1: data.js — NODES (+9), версии-метки (×4), count-комментарии, фикс шапки

**Files:**

- Modify: `docs/automation-graph-data.js`

- [ ] **Step 1: Фикс шапки (строка 5) — устаревшее имя дашборда**

Заменить:

```js
//   • docs/brain-dashboard.html   (classic <script>, same mechanism)
```

на:

```js
//   • docs/observer/dashboard.html (classic <script>, same mechanism)
```

- [ ] **Step 2: Версии-метки 4 узлов-правил**

В блоке `// ── ПРАВИЛА (4) ──` заменить лейблы:

- `label: 'Pravila v1.29'` → `label: 'Pravila v1.33'`
- `label: 'CLAUDE.md v2.16'` → `label: 'CLAUDE.md v2.20'`
- `label: 'PSR_v1 v3.14'` → `label: 'PSR_v1 v3.17'`
- `label: 'Tooling v2.15'` → `label: 'Tooling v2.17'`

- [ ] **Step 3: +router_procedure (rules)**

Заменить заголовок блока `// ── ПРАВИЛА (4) ── центр + первое кольцо ───────` → `// ── ПРАВИЛА (5) ── центр + первое кольцо ───────`.
После строки `tooling` (`{ id: 'tooling', ... ...pos(1, 270)  },`) добавить:

```js
  { id: 'router_procedure', label: 'router-procedure v1.0', group: 'rules', size: 24, ring: 1, ...pos(1, 210)  },
```

- [ ] **Step 4: +observer_stophook (hooks)**

Заменить заголовок `// ── ХУКИ (12) — S+infra + E (economy/skill) ───` → `// ── ХУКИ (13) — S+infra + E (economy/skill/brain) ───`.
После строки `hk_ruflo_queen` добавить:

```js
  { id: 'observer_stophook', label: 'Stop:\nobserver-stop-hook', group: 'hooks', size: 22, ring: 4, ...pos(4, 205) },
```

- [ ] **Step 5: +sk_brain_retro (skills_proj)**

После строки `discovery_interview` (`{ id: 'discovery_interview', ... ...pos(3, 387) },`) добавить:

```js
  // brain governance iter9 (19.05.2026) — проектный скил факторного анализа
  { id: 'sk_brain_retro',     label: '/brain-retro\n(skill)',       group: 'skills_proj', size: 18, ring: 3, ...pos(3, 210) },
```

- [ ] **Step 6: +observer_evidence (memory)**

Заменить заголовок `// ── MEMORY FILES (23) — внешнее кольцо ──────────` → `// ── MEMORY FILES (24) — внешнее кольцо ──────────`.
После строки `mem_sprint3` (`{ id: 'mem_sprint3', ... ...pos(6, 180) },`) добавить:

```js
  // brain governance iter9 (19.05.2026) — хранилище evidence «мозга»
  { id: 'observer_evidence', label: 'docs/observer/\nepisodes+STATUS', group: 'memory', size: 16, ring: 6, ...pos(6, 204) },
```

- [ ] **Step 7: +5 контролёров (lefthook)**

Заменить заголовок `// ── LEFTHOOK JOBS (10) — S+W (infra/data) ─────` → `// ── LEFTHOOK JOBS (15) — S+W (infra/data/brain) ─────`.
После строки `lh_squawk` (`{ id: 'lh_squawk', ... ...pos(5, 320) },`) добавить:

```js
  // brain governance iter9 (19.05.2026) — 5 контролёров C1-C5 (lefthook jobs 11-15)
  { id: 'lh_l1watcher', label: 'lefthook:\nl1-watcher (C1)',          group: 'lefthook', size: 16, ring: 5, ...pos(5, 150) },
  { id: 'lh_crossref',  label: 'lefthook:\ncross-ref-checker (C2)',   group: 'lefthook', size: 16, ring: 5, ...pos(5, 157) },
  { id: 'lh_obs_obs',   label: 'lefthook:\nobserver-of-observer (C3)',group: 'lefthook', size: 16, ring: 5, ...pos(5, 164) },
  { id: 'lh_status_md', label: 'lefthook:\nstatus-md (C4)',           group: 'lefthook', size: 16, ring: 5, ...pos(5, 171) },
  { id: 'lh_obs_cov',   label: 'lefthook:\nobserver-coverage (C5)',   group: 'lefthook', size: 16, ring: 5, ...pos(5, 178) },
```

- [ ] **Step 8: Sanity — синтаксис data.js**

Run: `cd "c:/моя/проекты/портал crm/Документация" && node --check docs/automation-graph-data.js && echo OK`
Expected: `OK` (нет SyntaxError).

---

### Task 2: data.js — EDGES (+12) + CONFLICT (+1 GREEN)

**Files:**

- Modify: `docs/automation-graph-data.js`

- [ ] **Step 1: +12 рёбер**

Перед строкой-комментарием `// ══════════════════════════════════════════════════` (которая начинает блок `// КОНФЛИКТЫ — 3-color classification (iter2 §4)`) добавить:

```js
  // ── BRAIN GOVERNANCE iter9 (19.05.2026, ADR-011) — связи 9 новых узлов ──
  E('claude_md',         'router_procedure',  '§3.6: SoT\nпроцедуры роутера'),
  E('tooling',           'router_procedure',  '§4.X реестр →\nшаг 3 роутера'),
  E('pravila',           'router_procedure',  '§12/§14/§15\nhard-floor'),
  E('pravila',           'observer_stophook', '§16: observer\n+ routing-тег'),
  E('observer_stophook', 'observer_evidence', 'пишет эпизоды\n+ routing-gate'),
  E('pravila',           'sk_brain_retro',    '§16: факторный\nанализ раз в спринт'),
  E('sk_brain_retro',    'observer_evidence', 'читает эпизоды\n(факторный анализ)'),
  E('lh_l1watcher',      'tooling',           'C1 STRICT: settings.json\n↔ Tooling drift'),
  E('lh_crossref',       'claude_md',         'C2 STRICT: version\ndrift §0 cross-refs'),
  E('lh_obs_obs',        'observer_evidence', 'C3 warn: счётчик\n+54w self-prune'),
  E('lh_status_md',      'observer_evidence', 'C4: генерит\nSTATUS.md'),
  E('lh_obs_cov',        'observer_evidence', 'C5 warn: покрытие\n+ регистрация'),

```

- [ ] **Step 2: +1 GREEN-конфликт**

После строки `CONFLICT('hk_economy', 'superpowers', '§12 — hard-rule уровня 0; economy-режим §12 не отменяет (Pravila §12.4)', 'GREEN'),` добавить:

```js
  CONFLICT('observer_stophook', 'hk_verifier', 'HK1 §5.3: оба на Stop-event — коллизии нет (append-chain). Оба способны decision:block; Claude Code прогоняет все Stop-хуки, любой block ⇒ продолжение хода. observer-gate детерминированный и дешёвый.', 'GREEN'),
```

- [ ] **Step 3: Sanity**

Run: `cd "c:/моя/проекты/портал crm/Документация" && node --check docs/automation-graph-data.js && echo OK`
Expected: `OK`.

---

### Task 3: data.js — NODE_SECTION (+9) + coverage-комментарий

**Files:**

- Modify: `docs/automation-graph-data.js`

- [ ] **Step 1: Обновить coverage-комментарий**

Заменить `// Узел -> раздел. Покрывает все 125 узлов карты.` → `// Узел -> раздел. Покрывает все 134 узла карты.`

- [ ] **Step 2: +9 записей NODE_SECTION**

После строки `discovery_interview: 'E5',` (последняя перед закрывающей `};` объекта `NODE_SECTION`) добавить:

```js
  // brain governance iter9 19.05.2026 — ADR-011 подсистема
  router_procedure: 'E1', observer_stophook: 'E2', sk_brain_retro: 'E8', observer_evidence: 'E4',
  lh_l1watcher: 'E1', lh_crossref: 'E1', lh_obs_obs: 'E2', lh_status_md: 'E2', lh_obs_cov: 'E2',
```

- [ ] **Step 3: Sanity**

Run: `cd "c:/моя/проекты/портал crm/Документация" && node --check docs/automation-graph-data.js && echo OK`
Expected: `OK`.

---

### Task 4: html — NODE_DETAILS (+9 паспортов)

**Files:**

- Modify: `docs/automation-graph.html`

- [ ] **Step 1: Вставить 9 паспортов**

В объекте `NODE_DETAILS` (в `<script>` файла `automation-graph.html`) перед его закрывающей `};` (сразу после записи `mem_sprint3: nd(...)`) добавить блок:

```js
  // ── BRAIN GOVERNANCE iter9 (19.05.2026, ADR-011) ──
  router_procedure: nd(
    'Единый источник истины процедуры роутера «задача → узел(ы)» — docs/router-procedure.md v1.0. 5 шагов: hard-floor (§12/§14/§15) → классификация → выбор по триггерам (Tooling Прил. Н §4.X) → проверка связок L1-L12 → исполнение. ADR-011.',
    'При любой задаче (имплицитно) определяет узел/связку; явно — при разборе routing-решений и в /brain-retro.',
    'Не вводит новый реестр — формализует процедуру над существующим (Tooling §4.X). Кэша «проверенных цепочек» нет (router-only). Каждая задача — свежая сборка пути.',
    [{ name: 'Pravila §12/§14/§15', cond: 'hard-floor — шаг 1 процедуры' }, { name: 'CLAUDE.md §3.6', cond: 'cross-ref на router-procedure.md' }],
    [{ name: 'Tooling Прил. Н §4.X', cond: 'реестр узлов — вход шага 3' }],
    [{ name: 'observer (Stop-хук)', cond: 'пишет evidence о routing-решениях' }, { name: '/brain-retro', cond: 'факторный анализ routing' }],
    []
  ),
  observer_stophook: nd(
    'Stop-хук observer (tools/observer-stop-hook.mjs, project-level) — пишет один JSONL-эпизод в docs/observer/episodes-YYYY-MM.jsonl в конце каждого хода + routing-gate. Внутри: transcript-parser (схема v2), routing-detector + choice-detector (provenance), pii-filter (маскирование ПДн). ADR-011 + observer factor-analysis.',
    'Конец каждого хода (Stop-event). routing-gate: при навязанном методе без routing-тега → decision:block (необойдёмо).',
    'Только пишет evidence, не вмешивается в нормативку. При внутреннем отказе — маркер observer_error, не тихий пропуск. HK1 §5.3: сосуществует с economy-verifier на Stop (append-chain).',
    [{ name: 'Pravila §16', cond: 'observer + routing-тег-дисциплина' }, { name: '.claude/settings.json', cond: 'зарегистрирован как Stop-хук' }],
    [{ name: 'observer-transcript-parser / routing-detector / choice-detector / pii-filter', cond: 'внутренние .mjs модули' }],
    [{ name: 'docs/observer/ evidence', cond: 'пишет эпизоды' }, { name: '/brain-retro', cond: 'читает то, что хук пишет' }],
    [{ name: 'hk_verifier', desc: 'HK1 §5.3: оба на Stop-event — коллизии нет (append-chain), оба decision:block отрабатываются', type: 'GREEN' }]
  ),
  sk_brain_retro: nd(
    'Проектный скил /brain-retro (.claude/skills/brain-retro/) — раз в спринт читает docs/observer/episodes-*.jsonl и строит факторный анализ: распределение path_type, топ-узлы/связки, вывод исхода, факторная матрица (9 осей × outcome). Анализатор tools/brain-retro-analyzer.mjs.',
    'Раз в спринт по команде заказчика («брейн-ретро»). Read-only агрегатор.',
    'Только читает и предлагает кандидатов на корректировку нормативки — не пишет в логи, не правит Tooling/Pravila/PSR_v1. Решение по правкам — за заказчиком.',
    [{ name: 'Pravila §16', cond: 'evidence-loop, раз в спринт' }, { name: 'PSR_v1 R16', cond: 'brain evidence loop' }],
    [{ name: 'tools/brain-retro-analyzer.mjs', cond: 'детерминированный анализатор' }],
    [{ name: 'docs/observer/ evidence', cond: 'читает эпизоды' }],
    []
  ),
  observer_evidence: nd(
    'Хранилище evidence «мозга» — docs/observer/: помесячные episodes-YYYY-MM.jsonl (схема v2), STATUS.md (панель C1-C5), .read-counter.json (для C3), notes/. Визуализируется страницей docs/observer/dashboard.html (Карта/Лента/Разбор/Агрегат/конфликты; кормится из общего automation-graph-data.js).',
    'Пишется Stop-хуком (эпизоды) + контролёрами (STATUS.md, счётчик); читается /brain-retro и dashboard.',
    'ПДн маскируется pii-filter перед записью (§5.4). Помесячное rotation; архив после 12 месяцев. Память ruflo (.swarm/memory.db) — отдельное хранилище, не связано.',
    [{ name: 'observer Stop-хук', cond: 'источник эпизодов' }],
    [],
    [{ name: '/brain-retro', cond: 'читатель' }, { name: 'C3/C4/C5 контролёры', cond: 'счётчик / STATUS / покрытие' }],
    []
  ),
  lh_l1watcher: nd(
    'Контролёр C1 (lefthook pre-commit job 11, tools/l1-watcher.mjs) — детектор «плагин включён в settings.json без формализации в Tooling Прил. Н». Закрывает трижды повторившийся L1-паттерн (UPM/21st, Sentry/Redis, Anthropic dev-tooling). 0 LLM-вызовов.',
    'pre-commit при правке .claude/settings.json или docs/Tooling_v8_3.md.',
    'STRICT: блокирует коммит при drift. Групповые/human-имена разрешаются через tools/.l1-watcher-aliases.txt. ADR-011 spec §6.1.',
    [{ name: 'lefthook.yml', cond: 'job 11 pre-commit' }, { name: 'ADR-011 §6.1', cond: 'C1' }],
    [],
    [{ name: 'tooling', cond: 'сверяет settings.json ↔ Tooling' }, { name: 'C2 cross-ref', cond: 'оба — нормативная консистентность' }],
    []
  ),
  lh_crossref: nd(
    'Контролёр C2 (lefthook pre-commit job 12, tools/cross-ref-checker.mjs) — детектор version drift между нормативными файлами (Tooling v2.11 collision 17.05). Сверяет версии в §0 cross-refs vs шапки целевых файлов. 0 LLM-вызовов.',
    'pre-commit при правке Pravila / Tooling / PSR_v1 / CLAUDE.md / MEMORY.md.',
    'STRICT: блокирует коммит при расхождении версии. Link-anchored детекция + scope-cut по history-маркерам (исторические «наследие»-цепочки не дают ложных срабатываний). ADR-011 spec §6.2.',
    [{ name: 'lefthook.yml', cond: 'job 12 pre-commit' }, { name: 'ADR-011 §6.2', cond: 'C2' }],
    [],
    [{ name: 'claude_md / pravila / tooling / psr_v1', cond: 'сверяет 5 нормативных файлов' }, { name: 'C1 l1-watcher', cond: 'оба — нормативная консистентность' }],
    []
  ),
  lh_obs_obs: nd(
    'Контролёр C3 (lefthook pre-commit job 13, tools/observer-of-observer.mjs) — счётчик чтений docs/observer/ + 54-недельный self-prune. «Кто наблюдает за наблюдателями»: если evidence-loop не читается ≥54 недель — предлагает архивировать observer.',
    'pre-commit (каждый коммит) — обновляет/проверяет docs/observer/.read-counter.json.',
    'Warn-only (скрипт всегда exit 0) — не блокирует. 54 недели (≈год) — порог осознанно поднят заказчиком с 4 недель. ADR-011 spec §6.3.',
    [{ name: 'lefthook.yml', cond: 'job 13 pre-commit' }, { name: 'ADR-011 §6.3', cond: 'C3' }],
    [],
    [{ name: 'docs/observer/ evidence', cond: 'читает .read-counter.json' }],
    []
  ),
  lh_status_md: nd(
    'Контролёр C4 (lefthook post-commit job, tools/status-md-generator.mjs) — генерит docs/observer/STATUS.md (панель: C1-C5 + информационные метрики). Pure JS, Security Guidance #40 compliant.',
    'post-commit (после каждого коммита) — перегенерит STATUS.md, git add (для следующего коммита).',
    'Через `|| true` — не блокирует. Метрика «N раз использован» — информационная, не алерт (capability-readiness). ADR-011 spec §6.4.',
    [{ name: 'lefthook.yml', cond: 'post-commit job' }, { name: 'ADR-011 §6.4', cond: 'C4' }],
    [],
    [{ name: 'docs/observer/ evidence', cond: 'пишет STATUS.md' }, { name: 'C1/C2/C3', cond: 'агрегирует их сигнал' }],
    []
  ),
  lh_obs_cov: nd(
    'Контролёр C5 (lefthook pre-commit job 15, tools/observer-coverage-checker.mjs) — observer factor-analysis spec §5.2. Флагует пропуски покрытия (git-активность есть, эпизодов 0) + поломки регистрации (Stop-хук снят из settings.json, post-commit не установлен).',
    'pre-commit (каждый коммит).',
    'Warn-only (скрипт всегда exit 0) — не блокирует; находки в docs/observer/STATUS.md строка C5.',
    [{ name: 'lefthook.yml', cond: 'job 15 pre-commit' }, { name: 'observer factor-analysis §5.2', cond: 'C5' }],
    [],
    [{ name: 'docs/observer/ evidence', cond: 'проверяет покрытие + регистрацию' }, { name: 'C4 status-md', cond: 'находки в STATUS.md' }],
    []
  ),
```

---

### Task 5: html — EDGE_DETAILS (+12)

**Files:**

- Modify: `docs/automation-graph.html`

- [ ] **Step 1: Вставить 12 edge-details**

В объекте `EDGE_DETAILS` перед его закрывающей `};` (после последней ruflo-записи `'ruflo_daemon->ag_pest': { ... }`) добавить:

```js
  // ── BRAIN GOVERNANCE iter9 (19.05.2026, ADR-011) ──
  'claude_md->router_procedure':          { type: 'документирует', when: 'CLAUDE.md §3.6 — cross-ref на router-procedure.md v1.0',           transfers: 'документация',           mandatory: 'обязательно',            rule: 'CLAUDE.md §3.6 (single SoT routing procedure)' },
  'tooling->router_procedure':            { type: 'питает',        when: 'реестр Прил. Н §4.X — вход шага 3 процедуры роутера',               transfers: 'данные',                 mandatory: 'обязательно',            rule: 'router-procedure.md §4.2 шаг 3' },
  'pravila->router_procedure':            { type: 'подчиняет',     when: 'hard-floor §12/§14/§15 — шаг 1 процедуры роутера',                  transfers: 'контроль',               mandatory: 'hard-floor',             rule: 'router-procedure.md §4.2 шаг 1 (Pravila §12/§14/§15)' },
  'pravila->observer_stophook':           { type: 'подчиняет',     when: '§16: observer + routing-тег-дисциплина',                           transfers: 'контроль',               mandatory: 'обязательно',            rule: 'Pravila §16.2/§16.7 (ADR-011)' },
  'observer_stophook->observer_evidence': { type: 'пишет',         when: 'конец каждого хода (Stop-event)',                                  transfers: 'данные (эпизод JSONL)',  mandatory: 'обязательно (exit-0-safe)', rule: 'ADR-011 §5.2 (observer scope B)' },
  'pravila->sk_brain_retro':              { type: 'подчиняет',     when: '§16: факторный анализ раз в спринт',                               transfers: 'контроль',               mandatory: 'по команде заказчика',   rule: 'Pravila §16 + PSR_v1 R16' },
  'sk_brain_retro->observer_evidence':    { type: 'читает',        when: 'раз в спринт — агрегирует эпизоды',                                transfers: 'данные',                 mandatory: 'read-only',              rule: 'ADR-011 §5.5 (/brain-retro — читатель)' },
  'lh_l1watcher->tooling':                { type: 'проверяет',     when: 'pre-commit при правке settings.json / Tooling',                    transfers: 'проверка',               mandatory: 'STRICT (блокирует)',     rule: 'ADR-011 §6.1 (C1) + lefthook.yml job 11' },
  'lh_crossref->claude_md':               { type: 'проверяет',     when: 'pre-commit при правке любого из 5 нормативных файлов',             transfers: 'проверка',               mandatory: 'STRICT (блокирует)',     rule: 'ADR-011 §6.2 (C2) + lefthook.yml job 12' },
  'lh_obs_obs->observer_evidence':        { type: 'проверяет',     when: 'pre-commit (каждый коммит) — счётчик чтений',                      transfers: 'проверка',               mandatory: 'warn-only',              rule: 'ADR-011 §6.3 (C3) + lefthook.yml job 13' },
  'lh_status_md->observer_evidence':      { type: 'пишет',         when: 'post-commit — перегенерит STATUS.md',                              transfers: 'данные',                 mandatory: 'не блокирует (|| true)', rule: 'ADR-011 §6.4 (C4) + lefthook.yml post-commit' },
  'lh_obs_cov->observer_evidence':        { type: 'проверяет',     when: 'pre-commit (каждый коммит) — покрытие + регистрация',              transfers: 'проверка',               mandatory: 'warn-only',              rule: 'observer factor-analysis §5.2 (C5) + lefthook.yml job 15' },
```

---

### Task 6: html — NODE_META (+9 + bump снимка/окна + changed ×4)

**Files:**

- Modify: `docs/automation-graph.html`

- [ ] **Step 1: Bump снимка и окна**

- `const META_SNAPSHOT = '18.05.2026';` → `const META_SNAPSHOT = '20.05.2026';`
- `const META_WINDOW   = '09–18.05.2026';` → `const META_WINDOW   = '09–20.05.2026';`

- [ ] **Step 2: changed ×4 на узлах-правилах**

В блоке `// ── ПРАВИЛА (4) ──` объекта `NODE_META` заменить `changed: '18.05.2026'` → `changed: '19.05.2026'` у `pravila`, `claude_md`, `psr_v1`, `tooling` (4 строки; остальные поля без изменений).

- [ ] **Step 3: +9 записей NODE_META**

Перед закрывающей `};` объекта `NODE_META` (после блока discovery-tooling `discovery_interview: { ... }`) добавить:

```js
  // ── BRAIN GOVERNANCE iter9 (19.05.2026, ADR-011) ──
  // uses: observer_stophook=31 эпизодов; lh_obs_obs/status_md/obs_cov=112 коммитов с 19.05
  // (glob-less, каждый коммит); lh_l1watcher=10, lh_crossref=13 (коммиты по glob с 19.05);
  // observer_evidence=0 (.read-counter.json — 0 чтений); router_procedure=null (rule-like).
  router_procedure:  { since: '19.05.2026', changed: '—', uses: null, usesSrc: '—' },
  observer_stophook: { since: '19.05.2026', changed: '—', uses: 31,   usesSrc: 'хук (эпизоды)' },
  sk_brain_retro:    { since: '19.05.2026', changed: '—', uses: 1,    usesSrc: 'интеграция' },
  observer_evidence: { since: '19.05.2026', changed: '—', uses: 0,    usesSrc: 'observer counter' },
  lh_l1watcher:      { since: '19.05.2026', changed: '—', uses: 10,   usesSrc: 'коммиты (с 19.05)' },
  lh_crossref:       { since: '19.05.2026', changed: '—', uses: 13,   usesSrc: 'коммиты (с 19.05)' },
  lh_obs_obs:        { since: '19.05.2026', changed: '—', uses: 112,  usesSrc: 'коммиты (с 19.05)' },
  lh_status_md:      { since: '19.05.2026', changed: '—', uses: 112,  usesSrc: 'коммиты (с 19.05)' },
  lh_obs_cov:        { since: '19.05.2026', changed: '—', uses: 112,  usesSrc: 'коммиты (с 19.05)' },
```

---

### Task 7: Верификация (рендер + структурная сверка)

**Files:**

- Read-only проверки + 1 PNG-артефакт.

- [ ] **Step 1: Синтаксис data.js**

Run: `cd "c:/моя/проекты/портал crm/Документация" && node --check docs/automation-graph-data.js && echo OK`
Expected: `OK`.

- [ ] **Step 2: Структурная сверка счётчиков (без исполнения data.js — только regex по тексту)**

Run (число определений узлов = вхождения `{ id: '` в тексте файла; ожидаем 134):

```bash
cd "c:/моя/проекты/портал crm/Документация"
node -e "const s=require('fs').readFileSync('docs/automation-graph-data.js','utf8');console.log('node defs:',(s.match(/\{ id: '/g)||[]).length);"
```

Expected: `node defs: 134`. Полнота покрытия NODE_SECTION гарантируется Task 3 (добавлены все 9 id) и подтверждается рендером Step 3 (паспорт показывает раздел). `vm`/`eval` не используем — Security Guidance #40.

- [ ] **Step 3: Рендер карты — Playwright MCP**

`browser_navigate` на `file:///c:/моя/проекты/портал crm/Документация/docs/automation-graph.html` → `browser_console_messages` (0 errors) → `browser_snapshot`. Проверить: граф отрисован; поиск «observer-stop-hook», «brain-retro», «router-procedure», «l1-watcher» находит узлы; клик по `observer_stophook` открывает паспорт с GREEN-конфликтом; клик по ребру `observer_stophook→observer_evidence` открывает edge-details. Визуально убедиться в отсутствии наложений 9 новых узлов на соседей.

- [ ] **Step 4: Рендер дашборда (тот же data.js)**

`browser_navigate` на `file:///c:/моя/проекты/портал crm/Документация/docs/observer/dashboard.html` → `browser_console_messages` (0 errors) → его Карта-view содержит новые узлы (кормится из общего AGD). Если dashboard падает из file:// (относительные пути / fetch) — зафиксировать как ограничение, не блокер: data.js валиден (Step 1-2).

- [ ] **Step 5: Smoke-PNG**

`browser_take_screenshot` карты → сохранить как `automation-graph-smoke.png` в корне (перезаписать существующий).

- [ ] **Step 6: Финальный коммит (один логический change = iter9)**

Перед коммитом pre-commit прогонится автоматически (stylelint на .html — CSS не трогали; gitleaks protect --staged; markdownlint/cspell — .md не затронут; cross-ref-checker/l1-watcher — glob не на эти файлы). Стейджить только 3 файла явными путями:

```bash
cd "c:/моя/проекты/портал crm/Документация"
git add docs/automation-graph-data.js docs/automation-graph.html automation-graph-smoke.png
git commit -m "feat(map): iter9 — brain governance subsystem (+9 nodes, +12 edges, +1 GREEN)" -m "Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>" -- docs/automation-graph-data.js docs/automation-graph.html automation-graph-smoke.png
```

Expected: pre-commit зелёный; коммит создан на `feat/automation-map-iter9`.

- [ ] **Step 7: verification-before-completion**

Invoke `superpowers:verification-before-completion` — подтвердить фактическим выводом: node --check OK, node defs=134, рендер без console-errors + 4 узла находятся + паспорт/edge открываются, коммит создан. Только после этого — claim «iter9 готов».

---

## Self-Review (выполнено при написании плана)

**1. Spec coverage:** §3 (9 узлов) → Task 1; §4 (версии-метки + NODE_META) → Task 1 Step 2 + Task 6; §5 (12 рёбер) → Task 2 Step 1; §6 (1 GREEN) → Task 2 Step 2; §7 (секции+счётчики) → Task 3 + count-комментарии в Task 1; §8 паспорта/детали/верификация → Tasks 4/5/7; §9 вне scope (нормативка не трогается) — соблюдено; §10 файлы → File Structure. Пробелов нет.

**2. Placeholder scan:** все uses-числа конкретны (31/112/10/13/0/null/1); паспорта и edge-details — полный текст; команды точные. Нет TBD/TODO. eval() убран (Security Guidance #40).

**3. Type consistency:** id узлов в NODES (Task 1) ↔ NODE_SECTION (Task 3) ↔ NODE_DETAILS (Task 4) ↔ NODE_META (Task 6) ↔ EDGES from/to (Task 2) ↔ EDGE_DETAILS ключи `from->to` (Task 5) — сверены, совпадают (router_procedure, observer_stophook, sk_brain_retro, observer_evidence, lh_l1watcher, lh_crossref, lh_obs_obs, lh_status_md, lh_obs_cov). GREEN-конфликт `observer_stophook↔hk_verifier` — `hk_verifier` существует в карте (узел economy-verifier).
