Files
portal/docs/superpowers/specs/2026-05-14-automation-graph-refactor-design.md
T
Дмитрий b747880ddc docs(spec): automation-graph refactor — 4 fixes (фон / подписи / радиальная иерархия / when+limits)
Дизайн рефакторинга docs/automation-graph.html после визуальной проверки
коммита 7ee78a9:
- canvas background на самом canvas + удаление hideEdgesOnDrag (artifacts)
- удаление labels с edges, переход на title-tooltip + legend section
- radial-sector layout: 6 колец × 4 функциональных сектора, physics off
- 2 новые секции легенды: «Когда используется» + «Ограничения»

cspell: +mgmt (валидный идентификатор узла claude_md_mgmt)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 08:55:32 +03:00

10 KiB
Raw Blame History

Дизайн: рефакторинг автоматизация-графа Лидерры

Дата: 2026-05-14 Статус: Approved Файл результата: docs/automation-graph.html Базовая итерация: коммит 7ee78a9 (73 узла, 6 конфликтов, Solarized dark, force-directed)


Цель

Устранить 4 проблемы первой итерации, найденные при визуальной проверке:

  1. Rendering artifacts на canvas — прямоугольные тени от прошлых redraw'ов поверх фона.
  2. Подписи на 72 рёбрах загромождают canvas, нечитаемо.
  3. Force-directed layout не показывает иерархии — узлы расположены произвольно, нельзя на глаз понять, что главное.
  4. Легенда не отвечает на два важных вопроса: «когда узел активируется» и «какие ограничения на его использование».

Решения по пунктам

1. Rendering artifacts фона

Причина: vis.js рендерит на прозрачный canvas; фон #1e1e2e поставлен на родительский <div id="network">. Когда canvas делает partial redraw на тёмном фоне, оставшиеся «следы» от прошлых позиций узлов видны как прямоугольные регионы.

Исправление:

#network canvas { background: #1e1e2e; }

И в vis.Network options:

interaction: {
  hover: true,
  tooltipDelay: 400,
  // hideEdgesOnDrag: true,  ← УДАЛИТЬ — триггерит partial redraws
  multiselect: false,
}

Объём: 2 строки CSS + 1 строка JS.

2. Подписи рёбер → в легенду

Удалить label из E() и CONFLICT() factory:

const E = (from, to, label) => ({
  from, to,
  title: label,  // ← было label, стало title (показывается как tooltip)
  color: { color: '#586e75', highlight: '#93a1a1', hover: '#93a1a1' },
  arrows: { to: { enabled: true, scaleFactor: 0.6 } },
  smooth: { type: 'continuous' }
});

Конфликтные рёбра остаются красными пунктирными, но с пометкой через label (короткий маркер) — это единственный текст, остающийся на canvas. Все детали — в panel.

Подписи перестают визуально захламлять граф; информация доступна:

  • через tooltip при hover на ребро (атрибут title)
  • через legend panel при клике на узел — обе стороны связи в секциях «Кому подчиняется» / «Кто подчиняется ему» / «С кем работает одновременно».

3. Радиально-секторная иерархия

Структура: 6 концентрических колец + центр.

Кольцо Радиус Группы (узлы) Кол-во
0 (центр) 0 pravila 1
1 220 claude_md, psr_v1, tooling 3
2 400 superpowers, fd_plugin, upm, claude_md_mgmt, hookify_plugin 5
3 600 14 SP-skills + 2 проектных skills 16
4 800 5 hooks + 11 agents 16
5 1000 7 MCP + 10 lefthook jobs 17
6 1180 15 memory files 15

Группировка по секторам: угол узла на кольце выбирается не только по индексу, но и по функциональному кластеру:

Сектор Угловой диапазон Функционал
N (workflow) 0° – 90° (верх-право) Superpowers + skills (brainstorm/wplans/eplans/subagent/parallel/...) + agents (Plan, Explore, general)
E (UI-stack) 90° – 180° (право-низ) Frontend Design + UPM + 21st MCP + sk_elements + skill_proj UI items
S (infra) 180° – 270° (низ-лево) hookify + claude-md-mgmt + memory + lefthook jobs (md/cspell/stylelint/eslint)
W (data/RLS) 270° – 360° (лево-верх) Boost + sentry + redis + sk_rls + ag_rls + lh_squawk + lh_pint + lh_larastan

Это сократит длину edges (связанные узлы — в одной четверти) и сделает граф визуально читаемым.

Вычисление позиций:

function positionNode(ringIdx, angleDeg) {
  const RADII = [0, 220, 400, 600, 800, 1000, 1180];
  const r = RADII[ringIdx];
  const a = angleDeg * Math.PI / 180;
  return { x: Math.round(r * Math.cos(a)), y: Math.round(r * Math.sin(a)) };
}

Каждому из 73 узлов в массиве NODES добавляются два новых поля: ring (индекс кольца 0–6) и sectorAngle (угол в градусах). Все 73 декларации NODES обновляются. В скрипте после декларации NODES добавляется цикл, который выставляет x, y через positionNode(). Поле fixed: false оставляется по умолчанию (vis.js разрешит drag), но physics: { enabled: false } гарантирует, что узел не «спружинит» на место после drag.

vis.js options:

physics: {
  enabled: false,  // узлы стоят детерминированно по заданным x,y
},
edges: {
  smooth: { type: 'continuous', roundness: 0.5 },
  selectionWidth: 2,
}

Поведение кнопок:

  • «Расшевелить» — включает physics с forceAtlas2Based, damping: 0.6 (мягкая интерактивность).
  • «Зафиксировать» — выключает physics обратно (physics.enabled = false); узлы остаются в текущих позициях после драга.
  • «Сбросить вид» — выполняет два действия: (а) восстанавливает radial positions всех узлов через nodesDS.update(...) (если пользователь подвинул узлы вручную) + (б) делает network.fit() для центрирования камеры.
  • «Снять выделение» — без изменений (closes legend panel, сбрасывает search).

4. Секции «Когда используется» и «Ограничения» в legend panel

HTML: добавить 2 секции между «Что делает» и «Кому подчиняется»:

<div class="legend-section"><h4>Когда используется</h4><p id="ld-when"></p></div>
<div class="legend-section"><h4>Ограничения</h4><p id="ld-limits"></p></div>

Структура данных NODE_DETAILS[id]:

function nd(desc, when, limits, reportsTo, manages, together, conflicts) {
  return { desc, when, limits, reportsTo, manages, together, conflicts: conflicts || [] };
}

Контент: для каждого из 73 узлов заполняется из нормативки:

  • when — триггер активации (фаза, событие, контекст вызова)
  • limits — запреты, READ-ONLY политики, обязательные фильтры, hard-rule условия

Источники нормативки для контента:

  • Pravila §12 (hard rule инвокаций), §13 (UI-пул)
  • CLAUDE.md §3.1/3.2/3.3/3.4 (фазы и активация инструментов)
  • PSR_v1 R6/R10/R11/R14 (фильтры, координация, pipelines)
  • Tooling §3.1–3.4 (команды и режимы использования)
  • lefthook.yml (stage/glob для jobs)
  • .claude/settings.json (триггеры хуков)

Рендеринг в showLegend(): после ld-desc устанавливаются ld-when и ld-limits:

document.getElementById('ld-when').textContent = details.when || '—';
document.getElementById('ld-limits').textContent = details.limits || 'без особых ограничений';

Финальная структура legend panel

После рефакторинга панель содержит 7 секций в строгом порядке:

  1. Заголовок узла + категория-бадж
  2. Что делает
  3. Когда используется (новое)
  4. Ограничения (новое)
  5. Кому подчиняется
  6. Кто подчиняется ему
  7. С кем работает одновременно
  8. Конфликты (только если есть)

Технология

  • vis.js Network 9.1.9 (CDN), без изменений.
  • Файл docs/automation-graph.html — единственное место правок.
  • Spec, plan, NODES/EDGES/NODE_DETAILS — все правки внутри <script> тега.

Ограничения

  • При первом открытии граф занимает ~2400×2400px при fit-to-view; на 1920px viewport узлы внешнего кольца становятся мельче. Это компромисс за читаемую иерархию.
  • При physics.enabled = false нет анимации stabilization — узлы появляются сразу в финальной позиции. Это плюс для понимания, минус для эффекта «оживления» графа.
  • Контент полей when / limits — авторский, основанный на нормативке на момент 2026-05-14. При обновлении CLAUDE.md/Pravila/PSR_v1/Tooling — содержимое требует ручной актуализации.
  • Узлы можно перетаскивать мышкой при включённой физике («Расшевелить»); при physics: disabled drag работает, но узлы не пружинят на место.