// ════════════════════════════════════════════════════
// automation-graph-data.js — shared topology constants
// Consumed by:
//   • docs/automation-graph.html  (classic <script>, reads bare consts via shared lexical scope)
//   • docs/observer/dashboard.html (classic <script>, same mechanism)
// Do NOT add ES-module syntax (import/export) — keep as classic script.
// ════════════════════════════════════════════════════

// ════════════════════════════════════════════════════
// SECTION 1: NODES
// ════════════════════════════════════════════════════

// Радиально-секторная компоновка.
// Сектора (по 90°): N=workflow (0–90), E=UI (90–180), S=infra (180–270), W=data/RLS (270–360).
const RADII = [0, 220, 400, 600, 800, 1000, 1180];
function pos(ring, angleDeg) {
  const r = RADII[ring];
  const a = angleDeg * Math.PI / 180;
  return { x: Math.round(r * Math.cos(a)), y: Math.round(r * Math.sin(a)) };
}

const NODES = [
  // ── ПРАВИЛА (5) ── центр + первое кольцо ───────
  { id: 'pravila',      label: 'Pravila v1.38',        group: 'rules', size: 38, ring: 0, ...pos(0, 0)    },
  { id: 'claude_md',    label: 'CLAUDE.md v2.26',       group: 'rules', size: 34, ring: 1, ...pos(1, 30)   },
  { id: 'psr_v1',       label: 'PSR_v1 v3.21',          group: 'rules', size: 32, ring: 1, ...pos(1, 150)  },
  { id: 'tooling',      label: 'Tooling v2.22',         group: 'rules', size: 30, ring: 1, ...pos(1, 270)  },
  { id: 'router_procedure', label: 'router-procedure v1.3', group: 'rules', size: 24, ring: 1, ...pos(1, 210)  },

  // ── ПЛАГИНЫ (13) ── второе кольцо ──────────────
  { id: 'superpowers',    label: 'Superpowers v5.1',    group: 'plugins', size: 30, ring: 2, ...pos(2, 45)   },
  { id: 'fd_plugin',      label: 'Frontend Design',      group: 'plugins', size: 26, ring: 2, ...pos(2, 135)  },
  { id: 'upm',            label: 'UI UX Pro Max',        group: 'plugins', size: 22, ring: 2, ...pos(2, 165)  },
  { id: 'claude_md_mgmt', label: 'claude-md-mgmt',       group: 'plugins', size: 22, ring: 2, ...pos(2, 225)  },
  { id: 'hookify_plugin', label: 'hookify (плагин)',     group: 'plugins', size: 22, ring: 2, ...pos(2, 200)  },
  { id: 'skill_creator',  label: 'skill-creator',        group: 'plugins', size: 20, ring: 2, ...pos(2, 70)   },
  { id: 'claude_setup',   label: 'claude-code-setup',    group: 'plugins', size: 22, ring: 2, ...pos(2, 90)   },
  { id: 'plugin_dev',     label: 'plugin-dev',           group: 'plugins', size: 22, ring: 2, ...pos(2, 290)  },
  { id: 'context7',       label: 'context7 (docs MCP)',  group: 'plugins', size: 20, ring: 2, ...pos(2, 315)  },
  // A6 architecture-tooling — adr-kit / architecture-patterns (плагины) + deptrac (composer dev-dep, job 10) — раздел «Архитектура систем»
  { id: 'adr_kit',        label: 'adr-kit',              group: 'plugins', size: 22, ring: 2, ...pos(2, 240)  },
  { id: 'arch_patterns',  label: 'architecture-patterns',group: 'plugins', size: 20, ring: 2, ...pos(2, 250)  },
  { id: 'deptrac',        label: 'deptrac',              group: 'plugins', size: 20, ring: 2, ...pos(2, 260)  },
  // D3 audit-security (17.05.2026) — 2 плагина раздела «Аудит и управление рисками»
  { id: 'tob_skills',     label: 'Trail of Bits\nskills', group: 'plugins', size: 22, ring: 2, ...pos(2, 330)  },
  { id: 'sec_guidance',   label: 'Security\nGuidance',   group: 'plugins', size: 20, ring: 2, ...pos(2, 345)  },
  // C9 project-management-tooling (17.05.2026) — плагин раздела «Управление проектами»
  { id: 'product_mgmt',   label: 'product-\nmanagement', group: 'plugins', size: 20, ring: 2, ...pos(2, 355)  },
  // A4 design-tooling (17.05.2026) — раздел «Дизайн (UI/UX, графика, бренд)» (плагины)
  { id: 'design_plugin',  label: 'Design\nplugin',       group: 'plugins', size: 20, ring: 2, ...pos(2, 155)  },

  // ── СКИЛЫ SUPERPOWERS (14) — N sector (0–90) ────
  { id: 'sk_brainstorm',  label: 'brainstorming',        group: 'skills_sp', size: 18, ring: 3, ...pos(3, 5)   },
  { id: 'sk_wplans',      label: 'writing-plans',        group: 'skills_sp', size: 20, ring: 3, ...pos(3, 11)  },
  { id: 'sk_eplans',      label: 'executing-plans',      group: 'skills_sp', size: 18, ring: 3, ...pos(3, 17)  },
  { id: 'sk_subagent',    label: 'subagent-driven',      group: 'skills_sp', size: 20, ring: 3, ...pos(3, 23)  },
  { id: 'sk_tdd',         label: 'TDD',                  group: 'skills_sp', size: 18, ring: 3, ...pos(3, 29)  },
  { id: 'sk_verify',      label: 'verification-before-completion', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 36) },
  { id: 'sk_debug',       label: 'systematic-debugging', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 43)  },
  { id: 'sk_parallel',    label: 'parallel-work',        group: 'skills_sp', size: 18, ring: 3, ...pos(3, 50)  },
  { id: 'sk_worktree',    label: 'worktree',             group: 'skills_sp', size: 18, ring: 3, ...pos(3, 57)  },
  { id: 'sk_pr',          label: 'finishing-pr',         group: 'skills_sp', size: 18, ring: 3, ...pos(3, 64)  },
  { id: 'sk_coderev',     label: 'code-review',          group: 'skills_sp', size: 16, ring: 3, ...pos(3, 71)  },
  { id: 'sk_spreview',    label: 'spec-review',          group: 'skills_sp', size: 16, ring: 3, ...pos(3, 78)  },
  { id: 'sk_wskills',     label: 'writing-skills',       group: 'skills_sp', size: 16, ring: 3, ...pos(3, 85)  },
  { id: 'sk_elements',    label: 'elements-of-style',    group: 'skills_sp', size: 16, ring: 3, ...pos(3, 92)  },

  // ── СКИЛЫ ПРОЕКТА (6) — W sector (RLS/arch/audit) ────
  { id: 'sk_rls',         label: 'rls-check',            group: 'skills_proj', size: 20, ring: 3, ...pos(3, 305) },
  { id: 'sk_qitem',       label: 'q-item-add',           group: 'skills_proj', size: 20, ring: 3, ...pos(3, 220) },
  { id: 'sk_regression',  label: 'regression',           group: 'skills_proj', size: 20, ring: 3, ...pos(3, 260) },
  // A6 architecture-tooling (17.05.2026) — вендоренный скил диаграмм
  { id: 'mermaid_skill',  label: 'mermaid (skill)',      group: 'skills_proj', size: 18, ring: 3, ...pos(3, 280) },
  // D3 audit-security (17.05.2026) — скилы раздела «Аудит и управление рисками»
  { id: 'sk_security_review', label: 'security-review',  group: 'skills_proj', size: 20, ring: 3, ...pos(3, 315) },
  { id: 'sk_audit_portal',    label: 'audit-portal',     group: 'skills_proj', size: 20, ring: 3, ...pos(3, 325) },
  // C9 project-management-tooling (17.05.2026) — вендоренный скил раздела «Управление проектами»
  { id: 'ccpm',               label: 'CCPM\n(skill)',    group: 'skills_proj', size: 18, ring: 3, ...pos(3, 335) },
  // A11 ml-ai-tooling (17.05.2026) — скилы и CLI раздела «ML / AI-разработка»
  { id: 'claude_api',         label: 'claude-api\n(skill)',      group: 'skills_proj', size: 18, ring: 3, ...pos(3, 345) },
  { id: 'data_scientist',     label: 'Data Scientist\n(skill)',  group: 'skills_proj', size: 18, ring: 3, ...pos(3, 355) },
  { id: 'promptfoo',          label: 'promptfoo',                group: 'plugins',     size: 20, ring: 2, ...pos(2, 365) },
  // C10 business-process (17.05.2026) — плагин и скилы раздела «Бизнес-процессы (общее)»
  { id: 'ops_plugin',         label: 'operations\n(plugin)',        group: 'plugins',     size: 20, ring: 2, ...pos(2, 385) },
  { id: 'process_modeling',   label: 'process-modeling\n(skill)',   group: 'skills_proj', size: 18, ring: 3, ...pos(3, 367) },
  { id: 'process_analysis',   label: 'process-analysis\n(skill)',   group: 'skills_proj', size: 18, ring: 3, ...pos(3, 377) },
  // discovery-tooling (18.05.2026) — self-authored скил интервью-discovery
  { id: 'discovery_interview', label: 'discovery-interview\n(skill)', group: 'skills_proj', size: 18, ring: 3, ...pos(3, 387) },
  // finance-tooling C6+C7 (20.05.2026) — разделы «Финансы»
  { id: 'finance_plugin', label: 'finance\n(plugin)',          group: 'plugins',     size: 20, ring: 2, ...pos(2, 200) },
  { id: 'billing_audit',  label: 'billing-audit\n(skill)',     group: 'skills_proj', size: 18, ring: 3, ...pos(3, 397) },
  { id: 'ru_tax',         label: 'ru-tax-accounting\n(skill)', group: 'skills_proj', size: 18, ring: 3, ...pos(3, 407) },
  // A1 backend-tooling (20.05.2026) — раздел «Программирование — backend»
  { id: 'rector',          label: 'Rector\n(dev-dep)',          group: 'plugins',     size: 18, ring: 2, ...pos(2, 210) },
  { id: 'php_insights',    label: 'PHP Insights\n(dev-dep)',     group: 'plugins',     size: 18, ring: 2, ...pos(2, 220) },
  { id: 'backend_patterns', label: 'backend-patterns\n(skill)',  group: 'skills_proj', size: 18, ring: 3, ...pos(3, 417) },
  { id: 'nightowl',        label: 'NightOwl\n(DEFERRED)',        group: 'mcp',         size: 16, ring: 3, ...pos(3, 427) },
  // A8 infosec-tooling (21.05.2026) — раздел «Информационная безопасность»
  { id: 'mcp_zap',           label: 'MCP: OWASP ZAP\n(DAST)',                  group: 'mcp',         size: 18, ring: 5, ...pos(5, 360) },
  { id: 'nuclei',            label: 'Nuclei\n(CLI, известные уязвимости)',       group: 'lefthook',    size: 18, ring: 5, ...pos(5, 370) },
  { id: 'ward',              label: 'Ward\n(CLI, Laravel безопасность)',          group: 'lefthook',   size: 18, ring: 5, ...pos(5, 380) },
  { id: 'sk_pdn_152fz',      label: 'ПДн / 152-ФЗ\n(скил)',                     group: 'skills_proj', size: 18, ring: 3, ...pos(3, 437) },
  { id: 'sk_threat_model',   label: 'Моделирование угроз\nSTRIDE (скил)',        group: 'skills_proj', size: 18, ring: 3, ...pos(3, 447) },
  { id: 'sk_security_golive', label: 'Прогон перед\nпубликацией (скил)',         group: 'skills_proj', size: 20, ring: 3, ...pos(3, 457) },

  // 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) },

  // C1 marketing-tooling (22.05.2026) — раздел «Маркетинг и лидогенерация»
  { id: 'mkt_plugin',     label: 'plugin:\nmarketing',                     group: 'plugins',     size: 18, ring: 5, ...pos(5, 390) },
  { id: 'mkt_skills',     label: 'skill:\nmarketingskills\n(vendored)',     group: 'skills_proj', size: 18, ring: 5, ...pos(5, 400) },
  { id: 'brand_voice',    label: 'plugin:\nbrand-voice',                   group: 'plugins',     size: 18, ring: 5, ...pos(5, 410) },
  { id: 'sk_marketing_ru', label: 'skill:\nmarketing-ru',                  group: 'skills_proj', size: 18, ring: 5, ...pos(5, 420) },
  { id: 'mcp_metrika',    label: 'MCP:\nЯндекс.Метрика',                   group: 'mcp',         size: 18, ring: 5, ...pos(5, 430) },
  { id: 'mcp_ya_direct',  label: 'MCP:\nЯндекс.Wordstat',                  group: 'mcp',         size: 18, ring: 5, ...pos(5, 440) },
  { id: 'mcp_telegram',   label: 'MCP:\nTelegram',                         group: 'mcp',         size: 18, ring: 5, ...pos(5, 450) },
  { id: 'postiz',         label: 'self-host:\nPostiz (VK+TG)',              group: 'mcp',         size: 18, ring: 5, ...pos(5, 460) },
  { id: 'mcp_dataforseo', label: 'MCP:\nDataForSEO\n(DEFERRED)',            group: 'mcp',         size: 18, ring: 5, ...pos(5, 470) },
  { id: 'mcp_unisender',  label: 'MCP:\nUnisender Go\n(DEFERRED)',          group: 'mcp',         size: 18, ring: 5, ...pos(5, 480) },

  // ── ХУКИ (13) — S+infra + E (economy/skill/brain) ───
  { id: 'hk_session',     label: 'SessionStart:\ncontext-inject', group: 'hooks', size: 24, ring: 4, ...pos(4, 100) },
  { id: 'hk_economy',     label: 'UserPromptSubmit:\neconomy-mode', group: 'hooks', size: 22, ring: 4, ...pos(4, 95) },
  { id: 'hk_pre_claude',  label: 'PreToolUse:\nCLAUDE.md-warn',   group: 'hooks', size: 22, ring: 4, ...pos(4, 215) },
  { id: 'hk_post_md',     label: 'PostToolUse:\nmarkdownlint',    group: 'hooks', size: 20, ring: 4, ...pos(4, 195) },
  { id: 'hk_post_schema', label: 'PostToolUse:\nschema-changelog',group: 'hooks', size: 20, ring: 4, ...pos(4, 300) },
  { id: 'hk_self_check',   label: 'SessionStart:\neconomy-self-check',   group: 'hooks', size: 20, ring: 4, ...pos(4, 105) },
  { id: 'hk_skill_marker', label: 'PreToolUse:\nskill-marker',           group: 'hooks', size: 20, ring: 4, ...pos(4, 115) },
  { id: 'hk_skill_check',  label: 'PreToolUse:\nskill-check',            group: 'hooks', size: 20, ring: 4, ...pos(4, 125) },
  { id: 'hk_state_guard',  label: 'PreToolUse:\neconomy-state-guard',    group: 'hooks', size: 20, ring: 4, ...pos(4, 135) },
  { id: 'hk_postcompact',  label: 'PostCompact:\neconomy-postcompact',   group: 'hooks', size: 20, ring: 4, ...pos(4, 145) },
  { id: 'hk_verifier',     label: 'Stop:\neconomy-verifier (агент)',     group: 'hooks', size: 22, ring: 4, ...pos(4, 155) },
  { id: 'hk_ruflo_queen',  label: 'UserPromptSubmit:\nruflo-queen-hook', group: 'ruflo', size: 20, ring: 4, ...pos(4, 165) },
  // brain governance iter9 (19.05.2026) — Stop-хук observer
  { id: 'observer_stophook', label: 'Stop:\nobserver-stop-hook', group: 'hooks', size: 22, ring: 4, ...pos(4, 205) },

  // ── АГЕНТЫ (11) — N (workflow) + W (RLS) ──────
  { id: 'ag_explore',     label: 'Explore',                group: 'agents', size: 20, ring: 4, ...pos(4, 10)  },
  { id: 'ag_general',     label: 'general-purpose',        group: 'agents', size: 20, ring: 4, ...pos(4, 25)  },
  { id: 'ag_plan',        label: 'Plan',                   group: 'agents', size: 20, ring: 4, ...pos(4, 40)  },
  { id: 'ag_pest',        label: 'pest-parallel-debugger', group: 'agents', size: 24, ring: 4, ...pos(4, 55)  },
  { id: 'ag_guide',       label: 'claude-code-guide',      group: 'agents', size: 18, ring: 4, ...pos(4, 70)  },
  { id: 'ag_statusline',  label: 'statusline-setup',       group: 'agents', size: 18, ring: 4, ...pos(4, 85)  },
  { id: 'ag_hookify',     label: 'hookify:\nconversation-analyzer', group: 'agents', size: 18, ring: 4, ...pos(4, 230) },
  { id: 'ag_pcreator',    label: 'plugin-dev:\nagent-creator',  group: 'agents', size: 16, ring: 4, ...pos(4, 245) },
  { id: 'ag_pvalid',      label: 'plugin-dev:\nplugin-validator',group: 'agents', size: 16, ring: 4, ...pos(4, 260) },
  { id: 'ag_skreview',    label: 'plugin-dev:\nskill-reviewer',  group: 'agents', size: 16, ring: 4, ...pos(4, 275) },
  { id: 'ag_rls',         label: 'rls-reviewer',           group: 'agents', size: 22, ring: 4, ...pos(4, 315) },
  // A3 integration-tooling (17.05.2026) — agent раздела «Программирование — интеграции»
  { id: 'ag_apidocs',  label: 'api-docs (agent)',     group: 'agents', size: 18, ring: 4, ...pos(4, 175)  },

  // ── MCP-СЕРВЕРЫ (9) — E (UI) + W (data) ───────
  { id: 'mcp_21st',       label: 'MCP: 21st.dev Magic',   group: 'mcp', size: 20, ring: 5, ...pos(5, 130) },
  // A4 design-tooling (17.05.2026) — MCP-серверы раздела «Дизайн (UI/UX, графика, бренд)»
  { id: 'mcp_figma',      label: 'MCP: Figma\n(DEFERRED)', group: 'mcp', size: 18, ring: 5, ...pos(5, 140) },
  { id: 'mcp_icons',      label: 'MCP: Universal\nIcons', group: 'mcp', size: 18, ring: 5, ...pos(5, 120) },
  { id: 'mcp_pw',         label: 'MCP: playwright',       group: 'mcp', size: 22, ring: 5, ...pos(5, 110) },
  { id: 'mcp_gh',         label: 'MCP: github',           group: 'mcp', size: 22, ring: 5, ...pos(5, 75)  },
  { id: 'mcp_boost',      label: 'MCP: laravel-boost',    group: 'mcp', size: 24, ring: 5, ...pos(5, 290) },
  { id: 'mcp_redis',      label: 'MCP: redis',            group: 'mcp', size: 22, ring: 5, ...pos(5, 310) },
  { id: 'mcp_sentry',     label: 'MCP: sentry',           group: 'mcp', size: 22, ring: 5, ...pos(5, 330) },
  { id: 'mcp_semgrep',    label: 'MCP: semgrep',          group: 'mcp', size: 20, ring: 5, ...pos(5, 350) },
  // A3 integration-tooling (17.05.2026) — MCP-сервер раздела «Программирование — интеграции»
  { id: 'mcp_openapi', label: 'MCP: openapi',         group: 'mcp', size: 20, ring: 5, ...pos(5, 5) },

  // ── LEFTHOOK JOBS (15) — S+W (infra/data/brain) ─────
  { id: 'lh_mdlint',      label: 'lefthook:\nmarkdownlint',   group: 'lefthook', size: 18, ring: 5, ...pos(5, 185) },
  { id: 'lh_cspell',      label: 'lefthook:\ncspell',         group: 'lefthook', size: 18, ring: 5, ...pos(5, 200) },
  { id: 'lh_stylelint',   label: 'lefthook:\nstylelint',      group: 'lefthook', size: 16, ring: 5, ...pos(5, 215) },
  { id: 'lh_eslint',      label: 'lefthook:\neslint-vue',     group: 'lefthook', size: 18, ring: 5, ...pos(5, 230) },
  { id: 'lh_lychee',      label: 'lefthook:\nlychee-links',   group: 'lefthook', size: 18, ring: 5, ...pos(5, 245) },
  { id: 'lh_gitleaks',    label: 'lefthook:\ngitleaks',       group: 'lefthook', size: 18, ring: 5, ...pos(5, 260) },
  { id: 'lh_gitleaks2',   label: 'lefthook:\ngitleaks pre-push', group: 'lefthook', size: 18, ring: 5, ...pos(5, 275) },
  { id: 'lh_pint',        label: 'lefthook:\npint',           group: 'lefthook', size: 18, ring: 5, ...pos(5, 25)  },
  { id: 'lh_larastan',    label: 'lefthook:\nlarastan',       group: 'lefthook', size: 18, ring: 5, ...pos(5, 50)  },
  { id: 'lh_squawk',      label: 'lefthook:\nsquawk',         group: 'lefthook', size: 18, ring: 5, ...pos(5, 320) },
  // 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) },

  // ── MEMORY FILES (24) — внешнее кольцо ──────────
  { id: 'mem_user',       label: 'memory:\nuser_profile',        group: 'memory', size: 16, ring: 6, ...pos(6, 0)   },
  { id: 'mem_comm',       label: 'memory:\nfeedback_comm',       group: 'memory', size: 14, ring: 6, ...pos(6, 24)  },
  { id: 'mem_env',        label: 'memory:\nfeedback_env',        group: 'memory', size: 16, ring: 6, ...pos(6, 48)  },
  { id: 'mem_sp',         label: 'memory:\nfeedback_superpowers',group: 'memory', size: 16, ring: 6, ...pos(6, 72)  },
  { id: 'mem_plugins',    label: 'memory:\nfeedback_plugins',    group: 'memory', size: 16, ring: 6, ...pos(6, 96)  },
  { id: 'mem_handoff',    label: 'memory:\nreference_handoff',   group: 'memory', size: 14, ring: 6, ...pos(6, 120) },
  { id: 'mem_redesign',   label: 'memory:\nportal_redesign',     group: 'memory', size: 14, ring: 6, ...pos(6, 144) },
  { id: 'mem_devindices', label: 'memory:\ndev_indices',         group: 'memory', size: 12, ring: 6, ...pos(6, 168) },
  { id: 'mem_phase1',     label: 'memory:\nphase1_strategy',     group: 'memory', size: 14, ring: 6, ...pos(6, 192) },
  { id: 'mem_state',      label: 'memory:\nproject_state',       group: 'memory', size: 16, ring: 6, ...pos(6, 216) },
  { id: 'mem_brain',      label: 'memory:\nclaude_brain',        group: 'memory', size: 14, ring: 6, ...pos(6, 240) },
  { id: 'mem_supplier',   label: 'memory:\nsupplier_integration',group: 'memory', size: 14, ring: 6, ...pos(6, 264) },
  { id: 'mem_audit',      label: 'memory:\naudit_2026-05-13',    group: 'memory', size: 14, ring: 6, ...pos(6, 288) },
  { id: 'mem_archive',    label: 'memory:\nreference_archive',   group: 'memory', size: 14, ring: 6, ...pos(6, 312) },
  { id: 'mem_github',     label: 'memory:\nreference_github',    group: 'memory', size: 14, ring: 6, ...pos(6, 336) },
  { id: 'mem_audit_b',    label: 'memory:\naudit_B_status',      group: 'memory', size: 12, ring: 6, ...pos(6, 12)  },
  { id: 'mem_audit_c',    label: 'memory:\naudit_C_pending',     group: 'memory', size: 12, ring: 6, ...pos(6, 36)  },
  { id: 'mem_suppliercrm',label: 'memory:\nsupplier_crm',        group: 'memory', size: 12, ring: 6, ...pos(6, 60)  },
  { id: 'mem_audit12',    label: 'memory:\nfull_audit_05-12',    group: 'memory', size: 12, ring: 6, ...pos(6, 84)  },
  { id: 'mem_audit14',    label: 'memory:\nfull_audit_05-14',    group: 'memory', size: 12, ring: 6, ...pos(6, 108) },
  { id: 'mem_sprint1',    label: 'memory:\nsprint1_p0_closure',  group: 'memory', size: 12, ring: 6, ...pos(6, 132) },
  { id: 'mem_sprint2',    label: 'memory:\nsprint2_p1_progress', group: 'memory', size: 12, ring: 6, ...pos(6, 156) },
  { id: 'mem_sprint3',    label: 'memory:\nsprint3_progress',    group: 'memory', size: 12, ring: 6, ...pos(6, 180) },
  // brain governance iter9 (19.05.2026) — хранилище evidence «мозга»
  { id: 'observer_evidence', label: 'docs/observer/\nepisodes+STATUS', group: 'memory', size: 16, ring: 6, ...pos(6, 204) },

  // ── RUFLO ОРКЕСТРАТОР (9) — фактический реколлаж iter5 — кластер вне радиального layout (верх-лево) ──
  { id: 'ruflo_queen',          label: 'ruflo Queen\n(hive-mind)',                 group: 'ruflo', size: 44, x: -1340, y: -700 },
  { id: 'ruflo_plugins',        label: 'плагины ruflo\n0 из 20 · скилов 0',        group: 'ruflo', size: 20, x: -1340, y: -880 },
  { id: 'ruflo_workers',        label: '10 воркеров\nhive-mind (idle)',            group: 'ruflo', size: 26, x: -1160, y: -800 },
  { id: 'ruflo_agents_catalog', label: 'каталог агентов ruflo\n(100 определений)', group: 'ruflo', size: 24, x: -1530, y: -830 },
  { id: 'ruflo_commands',       label: 'slash-команды\nruflo (88)',                group: 'ruflo', size: 22, x: -1140, y: -630 },
  { id: 'ruflo_daemon',         label: 'демон ruflo\n(воркеры падают)',            group: 'ruflo', size: 24, x: -1560, y: -650 },
  { id: 'ruflo_memory',         label: 'память ruflo\n(~0 записей)',               group: 'ruflo', size: 24, x: -1380, y: -500 },
  { id: 'ruflo_mcp',            label: 'ruflo MCP\n(~210 инструментов)',           group: 'ruflo', size: 26, x: -1190, y: -460 },
  { id: 'ruflo_recall_hook',    label: 'хук recall\n(UserPromptSubmit)',           group: 'ruflo', size: 22, x: -1570, y: -470 },

  // ── MEMORY +1 (артефакт ruflo big-bang) ──
  { id: 'mem_ruflo',            label: 'memory:\nproject_ruflo_integration',       group: 'memory', size: 14, x: -1740, y: -620 },
];

// ════════════════════════════════════════════════════
// SECTION 2: EDGES
// ════════════════════════════════════════════════════
const CONFLICT_TYPES = {
  RED:   { color: '#ff5f57', bg: '#2d0000', emoji: '🔴', label: 'Не закрыт правилом',  rank: 1 },
  BLACK: { color: '#888888', bg: '#1a1a1a', emoji: '⚫', label: 'Возник на практике', rank: 2 },
  GREEN: { color: '#859900', bg: '#0e1a00', emoji: '🟢', label: 'Закрыт правилом',    rank: 3 },
};
const E = (from, to, label) => ({
  from, to,
  title: label,
  color: { color: '#586e75', highlight: '#93a1a1', hover: '#93a1a1' },
  arrows: { to: { enabled: true, scaleFactor: 0.6 } },
  smooth: { type: 'continuous', roundness: 0.5 }
});
const CONFLICT = (from, to, label, type = 'RED') => ({
  from, to,
  title: label,
  label: CONFLICT_TYPES[type].emoji,
  dashes: true,
  width: 2,
  color: { color: CONFLICT_TYPES[type].color, highlight: '#ff8880', hover: '#ff8880' },
  arrows: { to: { enabled: true, scaleFactor: 0.7 }, from: { enabled: true, scaleFactor: 0.7 } },
  font: { color: CONFLICT_TYPES[type].color, size: 14, align: 'middle', strokeWidth: 3, strokeColor: '#1e1e2e' },
  smooth: { type: 'curvedCW', roundness: 0.35 }
});

const EDGES = [
  // ── ПРАВИЛА — иерархия ──────────────────────────
  E('pravila', 'claude_md',    'подчиняет\n(уровень 1→2a)'),
  E('pravila', 'psr_v1',       'подчиняет\n(уровень 1→3)'),
  E('claude_md', 'tooling',    'ссылается\nна реестр'),
  E('pravila', 'superpowers',  '§12: обязывает\nинвокировать 1-м'),

  // ── PSR_v1 координирует плагины ─────────────────
  E('psr_v1', 'superpowers',   'R5: координирует\nпарный стек'),
  E('psr_v1', 'fd_plugin',     'R5: координирует\nпарный стек'),
  E('psr_v1', 'upm',           'R14.3: активирует\nтолько через pipeline'),
  E('psr_v1', 'mcp_21st',      'R14.4: активирует\nтолько через pipeline'),
  E('psr_v1', 'claude_md_mgmt','R10.1 блок 1:\nинфраструктурный'),

  // ── CLAUDE.md ────────────────────────────────────
  E('claude_md', 'mcp_boost',  'описывает §3.2'),
  E('claude_md', 'mcp_sentry', 'описывает §4.8'),
  E('claude_md', 'mcp_redis',  'описывает §4.9'),
  E('claude_md', 'claude_md_mgmt', '§5п.10:\nединственный канал'),
  E('claude_md', 'ag_pest',    'описывает\nкогда вызывать'),
  E('claude_md', 'ag_rls',     'описывает\nкогда вызывать'),

  // ── ХУКИ ────────────────────────────────────────
  E('hk_pre_claude',  'claude_md',    'проверяет\nпри Edit/Write'),
  E('hk_post_md',     'lh_mdlint',    'дублирует задачу\n(локально)'),
  E('hk_post_schema', 'claude_md',    'напоминает про\nCHANGELOG_schema'),
  E('hk_session',     'mem_user',     'читает\nпри старте'),
  E('hk_session',     'mem_env',      'читает\nпри старте'),
  E('hk_session',     'mem_sp',       'читает\nпри старте'),
  E('hk_session',     'mem_plugins',  'читает\nпри старте'),
  E('hk_session',     'mem_state',    'читает\nпри старте'),
  E('hk_economy',     'superpowers',  'парсит уровень\nэкономии'),

  // ── SUPERPOWERS содержит скилы ──────────────────
  E('superpowers', 'sk_brainstorm', 'содержит'),
  E('superpowers', 'sk_tdd',        'содержит'),
  E('superpowers', 'sk_debug',      'содержит'),
  E('superpowers', 'sk_wplans',     'содержит'),
  E('superpowers', 'sk_eplans',     'содержит'),
  E('superpowers', 'sk_verify',     'содержит'),
  E('superpowers', 'sk_parallel',   'содержит'),
  E('superpowers', 'sk_worktree',   'содержит'),
  E('superpowers', 'sk_pr',         'содержит'),
  E('superpowers', 'sk_subagent',   'содержит'),
  E('superpowers', 'sk_wskills',    'содержит'),
  E('superpowers', 'sk_spreview',   'содержит'),
  E('superpowers', 'sk_coderev',    'содержит'),
  E('superpowers', 'sk_elements',   'содержит'),

  // ── СКИЛЫ вызывают друг друга ───────────────────
  E('sk_brainstorm', 'sk_wplans',  'вызывает\nпосле дизайна'),
  E('sk_wplans',     'sk_eplans',  'вызывает\nдля выполнения'),
  E('sk_wplans',     'sk_subagent','альтернатива\nexecuting-plans'),
  E('sk_subagent',   'ag_explore', 'запускает\nдля поиска'),
  E('sk_subagent',   'ag_general', 'запускает\nдля задач'),
  E('sk_subagent',   'ag_plan',    'запускает\nдля архитектуры'),
  E('sk_parallel',   'sk_worktree','использует\nдля изоляции'),

  // ── СКИЛЫ ПРОЕКТА ───────────────────────────────
  E('sk_rls',   'tooling',      'использует\nsquawk + grep §3.2'),
  E('sk_rls',   'mcp_boost',    'SQL запросы\nк схеме'),
  E('sk_qitem', 'claude_md_mgmt','делегирует\nправку CLAUDE.md'),

  // ── CLAUDE-MD-MGMT ──────────────────────────────
  E('claude_md_mgmt', 'claude_md', 'единственный\nканал правок'),

  // ── HOOKIFY ─────────────────────────────────────
  E('ag_hookify', 'hookify_plugin', 'передаёт\nанализ'),
  E('hookify_plugin', 'hk_pre_claude', 'может создавать\nновые хуки'),
  E('hookify_plugin', 'hk_economy',    'может создавать\nновые хуки'),

  // ── АГЕНТЫ используют MCP ───────────────────────
  E('ag_pest',  'mcp_redis',  'читает\nочереди/кэш'),
  E('ag_rls',   'mcp_boost',  'SQL запросы\nк БД'),
  E('ag_guide', 'mcp_gh',     'ищет\nв репозитории'),

  // ── LEFTHOOK вызывается git ──────────────────────
  E('lh_gitleaks',  'mem_plugins', 'блокирует коммит\nпри ПДн в staged'),
  E('lh_larastan',  'mcp_boost',   'Boost даёт\nконтекст типов'),
  E('lh_squawk',    'tooling',     'соответствует\n§3.2 #15'),
  E('lh_gitleaks2', 'lh_gitleaks', 'строже:\nвся история'),
  E('lh_lychee',    'claude_md',   'проверяет\nссылки в .md'),

  // ── MEMORY читается Claude ──────────────────────
  E('mem_env',     'ag_pest',    'квирки 73/77\nиспользует агент'),
  E('mem_plugins', 'psr_v1',     'отражает\nтекущие версии'),
  E('mem_archive', 'claude_md',  'синхронизирует\nверсии доков'),

  // ── MCP ─────────────────────────────────────────
  E('mcp_pw',    'hk_session',  'используется\nдля a11y smoke'),
  E('mcp_gh',    'sk_pr',       'PR, issues\nпри finishing-pr'),
  E('mcp_boost', 'ag_rls',      'схема БД\nдля RLS-review'),

  // ── АУДИТ-АКТУАЛИЗАЦИЯ 16.05.2026 — связи новых узлов ──
  // 4 ребра psr_v1→skill_creator/claude_setup/plugin_dev/context7 — перенесены
  // в ADT-блок 18.05.2026 (точные категории authoring-tooling/dev-support, дедуп)
  E('plugin_dev', 'ag_pcreator', 'содержит\nагента'),
  E('plugin_dev', 'ag_pvalid',   'содержит\nагента'),
  E('plugin_dev', 'ag_skreview', 'содержит\nагента'),
  E('skill_creator', 'sk_wskills', 'обе создают\nскилы'),
  E('hk_self_check',   'hk_economy',     'система\nэкономии'),
  E('hk_skill_marker', 'hk_skill_check', 'пара\nmarker/check'),
  E('hk_skill_check',  'superpowers',    'энфорсит §12:\nскил перед кодом'),
  E('hk_state_guard',  'hk_economy',     'система\nэкономии'),
  E('hk_postcompact',  'hk_economy',     'переинжект\nрежима после компакта'),
  E('hk_verifier',     'sk_verify',      'энфорсит\nпроверку готовности'),
  E('hk_ruflo_queen',  'ruflo_queen',    '§14: маршрут\nqueen-задач'),
  E('sk_regression',   'ag_pest',        'передаёт разбор\nпадений Pest --parallel'),

  // ── A6 ARCHITECTURE-TOOLING 17.05.2026 — связи новых узлов ──
  E('psr_v1',  'adr_kit',       'R10.1 блок 1:\narchitecture-tooling'),
  E('psr_v1',  'arch_patterns', 'R10.1 блок 1:\narchitecture-tooling'),
  E('tooling', 'mermaid_skill', '§4.12: реестр\n(вендоренный скил)'),
  E('psr_v1',  'deptrac',       'R10.1 блок 1 note:\narchitecture-tooling'),

  // ── A4 DESIGN-TOOLING 17.05.2026 — связи новых узлов ──
  E('psr_v1',    'design_plugin', 'R10.1 блок 1:\ndesign-tooling'),
  E('psr_v1',    'mcp_icons',     'R10.1 блок 3:\ndesign-tooling'),
  E('psr_v1',    'mcp_figma',     'R10.1 блок 3:\ndesign-tooling (DEFERRED)'),

  // ── D3 AUDIT-SECURITY 17.05.2026 — связи новых узлов ──
  E('psr_v1',          'tob_skills',         'R10.1 блок 1:\naudit-security'),
  E('psr_v1',          'sec_guidance',       'R10.1 блок 1:\naudit-security'),
  E('tooling',         'tob_skills',         '§4.14 #39 — реестр'),
  E('tooling',         'sec_guidance',       '§4.15 #40 — реестр'),
  E('sk_audit_portal', 'sk_security_review', 'оркеструет\nкак фазу аудита'),
  E('sk_audit_portal', 'tob_skills',         'оркеструет\nглубокие кампании'),
  E('sk_audit_portal', 'sk_regression',      'использует\nна фазе тестов'),
  CONFLICT('tob_skills', 'mcp_semgrep', 'TB1: граница разграничена — Semgrep = inline SAST, Trail of Bits = глубокие on-demand аудит-кампании. Параллельное использование разрешено при разных сценариях.', 'GREEN'),

  // ── A3 INTEGRATION-TOOLING 17.05.2026 — связи новых узлов ──
  E('psr_v1',     'mcp_openapi', 'R10.1 блок 3:\nintegration-tooling'),
  E('tooling',    'mcp_openapi', '§4.22 #47 — реестр'),
  E('ag_apidocs', 'mcp_openapi', 'спека → MCP-ресурс'),

  // ── A11 ML-AI-TOOLING 17.05.2026 — связи новых узлов ──
  E('psr_v1',  'promptfoo',      'R10.1 блок 1:\nml-ai-tooling'),
  E('tooling', 'claude_api',     'reuse — built-in skill\n(PSR_v1 R10.1 блок 2)'),
  E('tooling', 'data_scientist', '§4.24 #49 — реестр'),

  // ── C10 BUSINESS-PROCESS 17.05.2026 — связи новых узлов ──
  E('psr_v1',  'ops_plugin',       'R10.1 блок 1:\nbusiness-process'),
  E('tooling', 'process_modeling', '§4.27 #52 — реестр'),
  E('tooling', 'process_analysis', '§4.28 #53 — реестр'),

  // ── DISCOVERY-TOOLING 18.05.2026 — связи узла discovery-interview ──
  E('tooling',             'discovery_interview', '§4.30 #55 — реестр'),
  E('psr_v1',              'discovery_interview', 'R10.1 блок 1 note:\ndiscovery-tooling'),
  E('discovery_interview', 'sk_brainstorm',       'хэндофф:\nFEATURE-brief'),
  E('discovery_interview', 'process_analysis',    'граница: слой-источник\n(ADR-009 DI2)'),

  // ── ANTHROPIC DEV-TOOLING 18.05.2026 — связи 5 узлов ──
  E('psr_v1', 'skill_creator',  'R10.1 блок 1:\nauthoring-tooling'),
  E('psr_v1', 'plugin_dev',     'R10.1 блок 1:\nauthoring-tooling'),
  E('psr_v1', 'hookify_plugin', 'R10.1 блок 1:\nauthoring-tooling (HK1)'),
  E('psr_v1', 'claude_setup',   'R10.1 блок 1:\ndev-support'),
  E('psr_v1', 'context7',       'R10.1 блок 1:\ndev-support'),

  // ── 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+ регистрация'),

  // ── FINANCE-TOOLING C6+C7 (20.05.2026, ADR-012) — связи 3 узлов ──
  E('tooling',        'finance_plugin', '§4.36 #61 — реестр'),
  E('tooling',        'billing_audit',  '§4.37 #62 — реестр'),
  E('tooling',        'ru_tax',         '§4.38 #63 — реестр'),
  E('billing_audit',  'ag_pest',        'аудит инвариантов\nчерез тесты'),
  E('mcp_boost',      'billing_audit',  'модели биллинга'),
  E('finance_plugin', 'ru_tax',         'РФ-специфика поверх\nUS-механики (ADR-012)'),
  E('billing_audit',  'ru_tax',         'выручка C6 →\nналог.база C7'),
  // ── A1 BACKEND-TOOLING (20.05.2026, ADR-013) — связи 4 узлов ──
  E('tooling',          'rector',           '§4.39 #64 — реестр'),
  E('tooling',          'php_insights',     '§4.40 #65 — реестр'),
  E('tooling',          'backend_patterns', '§4.41 #66 — реестр'),
  E('tooling',          'nightowl',         '§4.42 #67 — реестр'),
  E('rector',           'php_insights',     'backend-quality\nchain L14'),
  E('php_insights',     'lh_larastan',      'L14: метрики →\nтипы'),
  E('rector',           'lh_pint',          'трансформация ↔\nстиль (BT1)'),
  E('backend_patterns', 'billing_audit',    '«как писать» ↔\n«аудит денег» (BT6)'),
  E('mcp_boost',        'backend_patterns', 'Eloquent-контекст'),
  E('nightowl',         'mcp_sentry',       'трейс ↔ ошибки\n(BT7, ADR-013)'),

  // ── C1 MARKETING-TOOLING (22.05.2026) — связи 10 новых узлов + L16 chain ──
  E('tooling',         'mkt_plugin',      '§4.X #C1 — реестр (marketing plugin)'),
  E('tooling',         'mkt_skills',      '§4.X #C1 — реестр (vendored skills)'),
  E('tooling',         'brand_voice',     '§4.X #C1 — реестр (brand-voice plugin)'),
  E('tooling',         'sk_marketing_ru', '§4.X #C1 — реестр (RU-специфика)'),
  E('tooling',         'mcp_metrika',     '§4.X #C1 — реестр (Яндекс.Метрика)'),
  E('tooling',         'mcp_ya_direct',   '§4.X #C1 — реестр (Яндекс.Wordstat)'),
  E('tooling',         'mcp_telegram',    '§4.X #C1 — реестр (Telegram MCP)'),
  E('tooling',         'postiz',          '§4.X #C1 — реестр (Postiz self-host)'),
  E('tooling',         'mcp_dataforseo',  '§4.X #C1 — реестр (DataForSEO DEFERRED)'),
  E('tooling',         'mcp_unisender',   '§4.X #C1 — реестр (Unisender Go DEFERRED)'),
  // L16 marketing chain: mkt_skills → mkt_plugin (материал подкрепляет решатель, MKT3)
  E('mkt_skills',      'mkt_plugin',      'материал → решатель\n(L16, MKT3)'),
  // L16: brand_voice → mkt_plugin (фирменный голос питает контент, MKT6)
  E('brand_voice',     'mkt_plugin',      'бренд-голос → контент\n(L16, MKT6)'),
  // L16: mkt_plugin → sk_marketing_ru (РФ-специфика, 152-ФЗ согласия)
  E('mkt_plugin',      'sk_marketing_ru', 'оркеструет (L16)'),
  // L16: sk_marketing_ru → каналы
  E('sk_marketing_ru', 'mcp_metrika',     'канал аналитики (L16)'),
  E('sk_marketing_ru', 'mcp_ya_direct',   'канал поиска (L16)'),
  E('sk_marketing_ru', 'mcp_telegram',    'канал мессенджера (L16)'),
  E('sk_marketing_ru', 'postiz',          'канал соцсетей (L16)'),

  // ── A8 INFOSEC-TOOLING (21.05.2026) — связи 6 новых узлов + L15 chain ──
  E('tooling',             'mcp_zap',             '§4.X #A8 — реестр (DAST)'),
  E('tooling',             'nuclei',              '§4.X #A8 — реестр (CVE CLI)'),
  E('tooling',             'ward',                '§4.X #A8 — реестр (Laravel security)'),
  E('tooling',             'sk_pdn_152fz',        '§4.X #A8 — реестр (ПДн скил)'),
  E('tooling',             'sk_threat_model',     '§4.X #A8 — реестр (STRIDE скил)'),
  E('tooling',             'sk_security_golive',  '§4.X #A8 — реестр (go-live скил)'),
  // sk_security_golive оркеструет — L15 security go-live chain
  E('sk_security_golive', 'mcp_zap',             'оркеструет (L15)'),
  E('sk_security_golive', 'nuclei',              'оркеструет (L15)'),
  E('sk_security_golive', 'ward',                'оркеструет (L15)'),
  E('sk_security_golive', 'sk_pdn_152fz',        'оркеструет (L15)'),
  E('sk_security_golive', 'sk_threat_model',     'оркеструет (L15)'),
  // L15 — reuse: существующие A8/D3 узлы
  E('sk_security_golive', 'mcp_semgrep',         'L15 go-live chain'),
  E('sk_security_golive', 'lh_gitleaks',         'L15 go-live chain'),
  E('sk_security_golive', 'tob_skills',          'L15 go-live chain'),
  E('sk_security_golive', 'sec_guidance',        'L15 go-live chain'),

  // ══════════════════════════════════════════════════
  // КОНФЛИКТЫ — 3-color classification (iter2 §4)
  // 🔴 не закрыт правилом / ⚫ возник на практике / 🟢 закрыт правилом
  // ══════════════════════════════════════════════════
  CONFLICT('sk_rls',         'ag_rls',          'RLS: граница задана — скил по таблице, агент по diff/PR (spec 2026-05-16)', 'GREEN'),
  CONFLICT('hookify_plugin', 'hk_pre_claude',   'Закрыто правилом HK1 (ADR-010, PSR_v1 R10.1 v3.14): hookify вызывается только по явному /hookify + обязательный pre-check на коллизию с зарегистрированными хуками; перезапись economy/skill-discipline архитектуры запрещена',   'GREEN'),
  CONFLICT('mcp_pw',         'sk_parallel',     'Профиль Playwright MCP хэшируется per-cwd (квирк #95) → worktrees получают разные mcp-chrome-{hash}, не конфликтуют. Same-dir parallel — редкий случай (две Claude-сессии в одной dir), регулируется Pravila §15.2 claim в docs/sessions/CURRENT.md', 'GREEN'),
  CONFLICT('ag_pest',        'mcp_redis',       'Квирк 72 устранён 16.05.2026 (commit 0fa1a73 — array-стор в тестах): гонки в Redis при Pest --parallel больше нет', 'GREEN'),
  CONFLICT('psr_v1',         'claude_md',       'Закрыто §5п.10 CLAUDE.md + хук CLAUDE.md-warn', 'GREEN'),
  CONFLICT('upm',            'fd_plugin',       'PSR_v1 R14.5: не параллельно',                  'GREEN'),
  CONFLICT('mcp_21st',       'fd_plugin',       'PSR_v1 R14.5: не параллельно',                  'GREEN'),
  CONFLICT('hk_economy',     'superpowers',     '§12 — hard-rule уровня 0; economy-режим §12 не отменяет (Pravila §12.4)', 'GREEN'),
  CONFLICT('observer_stophook', 'hk_verifier', 'HK1 §5.3: оба на Stop-event — коллизии нет (append-chain). Оба способны decision:block; Claude Code прогоняет все Stop-хуки, любой block ⇒ продолжение хода. observer-gate детерминированный и дешёвый.', 'GREEN'),

  // ══════════════════════════════════════════════════
  // RUFLO ОРКЕСТРАТОР — фактический реколлаж (iter5, 2026-05-15)
  // ══════════════════════════════════════════════════
  // Queen → артефакты установки ruflo init (рой idle, артефакты не задействованы)
  E('ruflo_queen', 'ruflo_workers',        'координирует\n(0 задач)'),
  E('ruflo_queen', 'ruflo_agents_catalog', 'ruflo init высыпал\n(не задействовано)'),
  E('ruflo_queen', 'ruflo_commands',       'ruflo init высыпал\n(не задействовано)'),
  E('ruflo_queen', 'ruflo_plugins',        'плагинов ruflo:\n0 установлено'),
  // MCP-сервер ruflo — связывает половины кластера + читает/пишет память
  E('ruflo_mcp',   'ruflo_queen',          'инструменты\nуправления роем'),
  E('ruflo_mcp',   'ruflo_memory',         'читает/пишет\nпамять'),
  // память ruflo — recall-хук и воркер consolidate демона
  E('ruflo_recall_hook', 'ruflo_memory',   'запускает\nruflo memory search'),
  E('ruflo_daemon',      'ruflo_memory',   'воркер consolidate\nобращается к памяти'),
  // 4 узла-правила → Queen (реколлаж 16.05.2026: ruflo — advisory-подсистема; Pravila §14 — queen-триггер)
  E('pravila',   'ruflo_queen', '§14:\nqueen-триггер'),
  E('claude_md', 'ruflo_queen', '§3.5: описывает\n(advisory-подсистема)'),
  E('psr_v1',    'ruflo_queen', '§14:\ncross-ref'),
  E('tooling',   'ruflo_queen', '§4.10: реестр\n(advisory-подсистема)'),
  // memory → ruflo
  E('mem_ruflo',   'ruflo_queen', 'документирует\nинтеграцию'),

  // 3 конфликта ruflo (3-color, iter2 §4)
  CONFLICT('ruflo_queen',  'pravila',   'Закрыто реколлажем 16.05.2026: нормативка приведена к рантайму — ruflo переописан в advisory/automation-подсистему, декларация уровня −1 убрана', 'GREEN'),
  CONFLICT('ruflo_memory', 'mem_state', 'Два хранилища памяти не синхронизированы; память ruflo почти пуста (0 записей)', 'BLACK'),
  CONFLICT('ruflo_daemon', 'ag_pest',   'Worker-jitter демона ruflo усиливает Pest-квирки 73/77 (квирк 72 устранён 16.05 — его jitter больше не усиливает)', 'BLACK'),
];

// ════════════════════════════════════════════════════
// SECTION 3: CATEGORY LABELS
// ════════════════════════════════════════════════════
const CATEGORY_LABELS = {
  rules: 'Правило',  plugins: 'Плагин',    skills_sp: 'Скил Superpowers',
  skills_proj: 'Скил проекта', hooks: 'Хук .claude', agents: 'Агент',
  mcp: 'MCP-сервер', lefthook: 'Lefthook job', memory: 'Memory-файл',
  ruflo: 'ruflo (изолирован)'
};

// ════════════════════════════════════════════════════
// SECTION 3.4: SECTION BUCKETS & SECTIONS
// ════════════════════════════════════════════════════
const SECTION_BUCKETS = [
  { id: 'A', label: 'Технические и продуктовые' },
  { id: 'B', label: 'Коммуникации' },
  { id: 'C', label: 'Бизнес и операции' },
  { id: 'D', label: 'Право и комплаенс' },
  { id: 'E', label: 'Мета и управление' },
];
const SECTIONS = [
  { id: 'A1',  bucket: 'A', label: 'Программирование — backend' },
  { id: 'A2',  bucket: 'A', label: 'Программирование — frontend' },
  { id: 'A3',  bucket: 'A', label: 'Программирование — интеграции (API, вебхуки)' },
  { id: 'A4',  bucket: 'A', label: 'Дизайн (UI/UX, графика, бренд)' },
  { id: 'A5',  bucket: 'A', label: 'Тестирование, QA и отладка' },
  { id: 'A6',  bucket: 'A', label: 'Архитектура систем' },
  { id: 'A7',  bucket: 'A', label: 'DevOps, инфраструктура, деплой' },
  { id: 'A8',  bucket: 'A', label: 'Информационная безопасность' },
  { id: 'A9',  bucket: 'A', label: 'Работа с данными (БД, миграции, RLS)' },
  { id: 'A10', bucket: 'A', label: 'Аналитика и отчётность (BI)' },
  { id: 'A11', bucket: 'A', label: 'ML / AI-разработка' },
  { id: 'B1',  bucket: 'B', label: 'Голосовое общение по телефону' },
  { id: 'B2',  bucket: 'B', label: 'Мессенджеры' },
  { id: 'B3',  bucket: 'B', label: 'Электронная почта' },
  { id: 'B4',  bucket: 'B', label: 'SMS-рассылки' },
  { id: 'B5',  bucket: 'B', label: 'Видеосвязь' },
  { id: 'B6',  bucket: 'B', label: 'Чат на сайте / онлайн-консультант' },
  { id: 'B7',  bucket: 'B', label: 'Социальные сети' },
  { id: 'B8',  bucket: 'B', label: 'Push / in-app уведомления' },
  { id: 'C1',  bucket: 'C', label: 'Маркетинг и лидогенерация' },
  { id: 'C2',  bucket: 'C', label: 'Продажи' },
  { id: 'C3',  bucket: 'C', label: 'Квалификация и обработка лидов' },
  { id: 'C4',  bucket: 'C', label: 'Работа с поставщиками лидов' },
  { id: 'C5',  bucket: 'C', label: 'Клиентский успех, поддержка, удержание' },
  { id: 'C6',  bucket: 'C', label: 'Финансы — биллинг и тарификация' },
  { id: 'C7',  bucket: 'C', label: 'Финансы — бухгалтерия и налоги' },
  { id: 'C8',  bucket: 'C', label: 'HR и управление персоналом' },
  { id: 'C9',  bucket: 'C', label: 'Управление проектами' },
  { id: 'C10', bucket: 'C', label: 'Бизнес-процессы (общее)' },
  { id: 'D1',  bucket: 'D', label: 'Юриспруденция и договорная работа' },
  { id: 'D2',  bucket: 'D', label: 'Защита ПДн (152-ФЗ, РКН)' },
  { id: 'D3',  bucket: 'D', label: 'Аудит и управление рисками' },
  { id: 'E1',  bucket: 'E', label: 'Мета — правила и нормативка' },
  { id: 'E2',  bucket: 'E', label: 'Мета — оркестрация и автоматизация (Claude-воркфлоу)' },
  { id: 'E3',  bucket: 'E', label: 'Документация' },
  { id: 'E4',  bucket: 'E', label: 'Управление знаниями и память' },
  { id: 'E5',  bucket: 'E', label: 'Стратегия и принятие решений' },
  { id: 'E6',  bucket: 'E', label: 'Обучение и онбординг' },
  { id: 'E7',  bucket: 'E', label: 'Исследования' },
  { id: 'E8',  bucket: 'E', label: 'Самообучение Claude' },
];
// Узел -> раздел. Покрывает все 147 узлов карты (141 base + 6 A8 infosec).
const NODE_SECTION = {
  // правила (4)
  pravila: 'E1', claude_md: 'E1', psr_v1: 'E1', tooling: 'E1',
  // плагины (5)
  superpowers: 'E2', fd_plugin: 'A4', upm: 'A4', claude_md_mgmt: 'E1', hookify_plugin: 'E2',
  // скилы superpowers (14)
  sk_brainstorm: 'E5', sk_wplans: 'E2', sk_eplans: 'E2', sk_subagent: 'E2',
  sk_tdd: 'A5', sk_verify: 'A5', sk_debug: 'A5', sk_parallel: 'E2',
  sk_worktree: 'E2', sk_pr: 'E2', sk_coderev: 'A5', sk_spreview: 'A5',
  sk_wskills: 'E2', sk_elements: 'E3',
  // скилы проекта (2)
  sk_rls: 'A9', sk_qitem: 'E3',
  // хуки (5)
  hk_session: 'E4', hk_economy: 'E2', hk_pre_claude: 'E1', hk_post_md: 'E3', hk_post_schema: 'A9',
  // агенты (11)
  ag_explore: 'E2', ag_general: 'E2', ag_plan: 'E2', ag_pest: 'A5', ag_guide: 'E6',
  ag_statusline: 'E2', ag_hookify: 'E2', ag_pcreator: 'E2', ag_pvalid: 'E2',
  ag_skreview: 'E2', ag_rls: 'A9',
  // MCP-серверы (7)
  mcp_21st: 'A4', mcp_pw: 'A5', mcp_gh: 'A7', mcp_boost: 'A1',
  mcp_redis: 'A7', mcp_sentry: 'A7', mcp_semgrep: 'A8',
  // lefthook jobs (10)
  lh_mdlint: 'E3', lh_cspell: 'E3', lh_stylelint: 'A2', lh_eslint: 'A2',
  lh_lychee: 'E3', lh_gitleaks: 'A8', lh_gitleaks2: 'A8', lh_pint: 'A1',
  lh_larastan: 'A1', lh_squawk: 'A9',
  // memory files (16)
  mem_user: 'E4', mem_comm: 'E4', mem_env: 'E4', mem_sp: 'E4', mem_plugins: 'E4',
  mem_handoff: 'E4', mem_redesign: 'E4', mem_devindices: 'E4', mem_phase1: 'E4',
  mem_state: 'E4', mem_brain: 'E4', mem_supplier: 'E4', mem_audit: 'E4',
  mem_archive: 'E4', mem_github: 'E4', mem_ruflo: 'E4',
  // ruflo (9)
  ruflo_queen: 'E2', ruflo_plugins: 'E2', ruflo_workers: 'E2', ruflo_agents_catalog: 'E2',
  ruflo_commands: 'E2', ruflo_daemon: 'E2', ruflo_memory: 'E4', ruflo_mcp: 'E2',
  ruflo_recall_hook: 'E4',
  // АУДИТ-АКТУАЛИЗАЦИЯ 16.05.2026 — новые узлы
  skill_creator: 'E8', claude_setup: 'E8', plugin_dev: 'E2', context7: 'E7',
  hk_self_check: 'E2', hk_skill_marker: 'E2', hk_skill_check: 'E2', hk_state_guard: 'E2',
  hk_postcompact: 'E2', hk_verifier: 'E2', hk_ruflo_queen: 'E2',
  sk_regression: 'A5',
  mem_audit_b: 'E4', mem_audit_c: 'E4', mem_suppliercrm: 'E4', mem_audit12: 'E4',
  mem_audit14: 'E4', mem_sprint1: 'E4', mem_sprint2: 'E4', mem_sprint3: 'E4',
  // A6 architecture-tooling 17.05.2026 — раздел «Архитектура систем» наполнен (+deptrac)
  adr_kit: 'A6', arch_patterns: 'A6', mermaid_skill: 'A6', deptrac: 'A6',
  // D3 audit-security 17.05.2026 — раздел «Аудит и управление рисками» наполнен
  tob_skills: 'D3', sec_guidance: 'D3', sk_security_review: 'D3', sk_audit_portal: 'D3',
  // C9 project-management-tooling 17.05.2026 — раздел «Управление проектами» наполнен
  ccpm: 'C9', product_mgmt: 'C9',
  // A4 design-tooling 17.05.2026 — раздел «Дизайн (UI/UX, графика, бренд)» расширен (3→6 узлов)
  mcp_figma: 'A4', mcp_icons: 'A4', design_plugin: 'A4',
  // A3 integration-tooling 17.05.2026 — раздел «Программирование — интеграции» наполнен
  ag_apidocs: 'A3', mcp_openapi: 'A3',
  // A11 ml-ai-tooling 17.05.2026 — раздел «ML / AI-разработка» наполнен
  claude_api: 'A11', promptfoo: 'A11', data_scientist: 'A11',
  // C10 business-process 17.05.2026 — раздел «Бизнес-процессы (общее)» наполнен
  ops_plugin: 'C10', process_modeling: 'C10', process_analysis: 'C10',
  // discovery-interview 18.05.2026 — раздел E5 «Стратегия и принятие решений» (рядом с brainstorming)
  discovery_interview: 'E5',
  // 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',
  // finance-tooling C6+C7 (20.05.2026) — разделы «Финансы»
  finance_plugin: 'C7', billing_audit: 'C6', ru_tax: 'C7',
  // A1 backend-tooling (20.05.2026) — раздел «Программирование — backend»
  rector: 'A1', php_insights: 'A1', backend_patterns: 'A1', nightowl: 'A1',
  // A8 infosec-tooling (21.05.2026) — раздел «Информационная безопасность»
  mcp_zap: 'A8', nuclei: 'A8', ward: 'A8',
  sk_pdn_152fz: 'A8', sk_threat_model: 'A8', sk_security_golive: 'A8',
  // C1 marketing-tooling (22.05.2026) — раздел «Маркетинг и лидогенерация»
  mkt_plugin: 'C1', mkt_skills: 'C1', brand_voice: 'C1', sk_marketing_ru: 'C1',
  mcp_metrika: 'C1', mcp_ya_direct: 'C1', mcp_telegram: 'C1', postiz: 'C1',
  mcp_dataforseo: 'C1', mcp_unisender: 'C1',
};
// Вторичная классификация: узел первично в NODE_SECTION, дополнительно — в этих
// разделах (кросс-реф). Введено A3-интеграцией 17.05.2026 — раздел A3 наполняется
// частично кросс-реф существующих интеграционных инструментов. NODE_SECTION 1:1 не трогается.
const NODE_SECTION_SECONDARY = {
  mcp_boost:   ['A3', 'C6', 'C7'],
  context7:    ['A3', 'C6'],
  ag_pest:     ['A3', 'C6', 'C7'],
  mcp_semgrep: ['A3'],
  mcp_sentry:  ['A3', 'C6'],
  // C10 business-process 17.05.2026 — кросс-реф reuse-инструментов раздела «Бизнес-процессы»
  mermaid_skill: ['C10'],
  arch_patterns: ['C10'],
  ccpm:          ['C10'],
  product_mgmt:  ['C10', 'C6'],
  sk_wplans:     ['C10'],
  // C1 marketing-tooling (22.05.2026) — cross-ref: marketing-ru затрагивает 152-ФЗ согласия (D2)
  sk_marketing_ru: ['D2'],
  // finance-tooling C6+C7 (20.05.2026) — finance cross-ref + reuse-классификация
  finance_plugin: ['C6'],
  lh_larastan:   ['C6'], mcp_redis: ['C6'],
  data_scientist: ['C6', 'C7'], ops_plugin: ['C6', 'C7'],
  process_modeling: ['C6'], process_analysis: ['C6'],
};

// ════════════════════════════════════════════════════
// SECTION 4: VIS GROUPS
// ════════════════════════════════════════════════════
const GROUPS = {
  rules:       { color: { background: '#073642', border: '#268bd2', highlight: { border: '#93a1a1', background: '#0d4a5a' } }, font: { color: '#fdf6e3', size: 13, bold: true } },
  plugins:     { color: { background: '#001a00', border: '#859900', highlight: { border: '#b8cc00', background: '#002600' } }, font: { color: '#fdf6e3', size: 12 } },
  skills_sp:   { color: { background: '#1a0033', border: '#6c71c4', highlight: { border: '#9b9fea', background: '#250047' } }, font: { color: '#fdf6e3', size: 11 } },
  skills_proj: { color: { background: '#2d0020', border: '#d33682', highlight: { border: '#e869a8', background: '#3d0028' } }, font: { color: '#fdf6e3', size: 12 } },
  hooks:       { color: { background: '#002233', border: '#2aa198', highlight: { border: '#4dd7ce', background: '#003344' } }, font: { color: '#fdf6e3', size: 11 } },
  agents:      { color: { background: '#1a1200', border: '#b58900', highlight: { border: '#e0ad00', background: '#261a00' } }, font: { color: '#fdf6e3', size: 11 } },
  mcp:         { color: { background: '#2d1200', border: '#cb4b16', highlight: { border: '#ff6b30', background: '#3d1900' } }, font: { color: '#fdf6e3', size: 11 } },
  lefthook:    { color: { background: '#2d0000', border: '#dc322f', highlight: { border: '#ff5f5c', background: '#3d0000' } }, font: { color: '#fdf6e3', size: 10 } },
  memory:      { color: { background: '#112233', border: '#586e75', highlight: { border: '#839496', background: '#1a2f40' } }, font: { color: '#eee8d5', size: 10 } },
  ruflo:       { color: { background: '#262626', border: '#555555', highlight: { border: '#777777', background: '#333333' } }, font: { color: '#8a8a8a', size: 12, bold: true }, shapeProperties: { borderDashes: [4, 4] } },
};

// Expose for ES-module consumers (the dashboard). The map's classic inline
// script reads the bare consts directly via the shared global lexical scope.
window.AGD = {
  NODES, EDGES, SECTIONS, SECTION_BUCKETS,
  NODE_SECTION, NODE_SECTION_SECONDARY,
  CONFLICT_TYPES, GROUPS, CATEGORY_LABELS,
};
