af15f24de7
Узлы rector/php_insights/backend_patterns/nightowl теперь в панелях описания (nd()) и теплокарте использования (NODE_META, uses:0 новые). Дополняет 5d82fdd (NODES/EDGES/ NODE_SECTION в data.js). Browser-smoke: 141 узел, NODE_META+NODE_DETAILS у всех 4, 0 JS-ошибок. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2528 lines
227 KiB
HTML
2528 lines
227 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Система автоматизации Лидерры</title>
|
||
<script src="https://unpkg.com/vis-network@9.1.9/standalone/umd/vis-network.min.js"></script>
|
||
<script src="automation-graph-data.js"></script>
|
||
<style>
|
||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||
body { background: #0d0d1a; color: #fdf6e3; font-family: 'Segoe UI', system-ui, sans-serif; height: 100vh; display: flex; flex-direction: column; overflow: hidden; }
|
||
|
||
/* ── Toolbar ── */
|
||
#toolbar { background: #073642; border-bottom: 1px solid #586e75; padding: 8px 12px; display: flex; align-items: center; gap: 10px; flex-shrink: 0; }
|
||
#toolbar h1 { font-size: 14px; color: #93a1a1; white-space: nowrap; margin-right: 6px; }
|
||
#search { background: #002b36; border: 1px solid #586e75; color: #fdf6e3; border-radius: 5px; padding: 5px 10px; font-size: 13px; width: 220px; outline: none; }
|
||
#search:focus { border-color: #268bd2; }
|
||
#search::placeholder { color: #586e75; }
|
||
.btn { background: #073642; border: 1px solid #586e75; color: #93a1a1; border-radius: 5px; padding: 5px 12px; font-size: 12px; cursor: pointer; transition: all 0.15s; }
|
||
.btn:hover { background: #0d4a5a; color: #fdf6e3; border-color: #839496; }
|
||
#btn-clear { margin-left: auto; }
|
||
|
||
/* ── Main area ── */
|
||
#main { flex: 1; display: flex; overflow: hidden; }
|
||
|
||
/* ── Graph canvas ── */
|
||
#network { flex: 1; background: #1e1e2e; }
|
||
#network canvas { background: #1e1e2e; }
|
||
|
||
/* ── Legend panel ── */
|
||
#legend-panel { width: 300px; min-width: 300px; background: #002b36; border-left: 1px solid #586e75; overflow-y: auto; padding: 16px; display: none; flex-direction: column; gap: 14px; position: relative; }
|
||
#legend-handle {
|
||
position: absolute; left: 0; top: 0;
|
||
width: 6px; height: 100%;
|
||
cursor: col-resize;
|
||
background: transparent;
|
||
transition: background 0.15s;
|
||
z-index: 10;
|
||
}
|
||
#legend-handle:hover, #legend-handle.dragging { background: #0d4a5a; }
|
||
#legend-panel.visible { display: flex; }
|
||
#legend-close { align-self: flex-end; background: none; border: none; color: #586e75; font-size: 18px; cursor: pointer; line-height: 1; padding: 0; }
|
||
#legend-close:hover { color: #fdf6e3; }
|
||
#legend-title { font-size: 15px; font-weight: 600; color: #fdf6e3; overflow-wrap: break-word; }
|
||
#legend-edge-title { font-size: 15px; font-weight: 600; color: #fdf6e3; overflow-wrap: break-word; line-height: 1.4; }
|
||
#legend-category { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; }
|
||
.legend-section { background: #073642; border-radius: 6px; padding: 10px 12px; }
|
||
.legend-section h4 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: #839496; margin-bottom: 6px; }
|
||
.legend-section p { font-size: 13px; color: #eee8d5; line-height: 1.5; }
|
||
.legend-section ul { list-style: none; display: flex; flex-direction: column; gap: 4px; }
|
||
.legend-section li { font-size: 12px; color: #eee8d5; line-height: 1.4; }
|
||
.legend-section li span.cond { color: #839496; font-style: italic; }
|
||
.conflict-item { border-radius: 4px; padding: 6px 8px; margin-top: 4px; }
|
||
.conflict-item .cname { font-weight: 600; font-size: 12px; }
|
||
.conflict-item .cdesc { color: #eee8d5; font-size: 11px; margin-top: 2px; line-height: 1.4; }
|
||
#legend-no-conflicts { font-size: 12px; color: #586e75; }
|
||
|
||
/* ── Category legend footer ── */
|
||
#cat-legend { background: #073642; border-top: 1px solid #586e75; padding: 7px 14px; display: flex; flex-wrap: wrap; gap: 12px; flex-shrink: 0; }
|
||
.cat-item { display: flex; align-items: center; gap: 5px; font-size: 11px; color: #839496; }
|
||
.cat-dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0; }
|
||
/* .cat-item interactive states (Task 1) — separate from layout rule above to keep concerns split */
|
||
.cat-item {
|
||
cursor: pointer;
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
transition: background 0.12s, box-shadow 0.12s;
|
||
user-select: none;
|
||
}
|
||
.cat-item:hover { background: rgba(255,255,255,0.05); }
|
||
.cat-item.active {
|
||
background: rgba(253,246,227,0.12);
|
||
box-shadow: inset 0 0 0 1px rgba(253,246,227,0.4);
|
||
color: #fdf6e3;
|
||
}
|
||
|
||
/* ── Паспорт узла (iter6) ── */
|
||
#passport-section p { font-size: 12px; color: #eee8d5; line-height: 1.6; }
|
||
#passport-section p .pp-k { color: #839496; }
|
||
|
||
/* ── Кнопки режимов в футере (iter6) ── */
|
||
.cat-ctl-sep { width: 1px; align-self: stretch; background: #586e75; margin: 0 4px; }
|
||
.cat-ctl {
|
||
background: #002b36; border: 1px solid #586e75; color: #93a1a1;
|
||
border-radius: 4px; padding: 2px 8px; font-size: 11px; cursor: pointer;
|
||
transition: background 0.12s, box-shadow 0.12s; user-select: none;
|
||
}
|
||
.cat-ctl:hover { background: #0d4a5a; color: #fdf6e3; }
|
||
.cat-ctl.active {
|
||
background: rgba(253,246,227,0.12);
|
||
box-shadow: inset 0 0 0 1px rgba(253,246,227,0.4);
|
||
color: #fdf6e3;
|
||
}
|
||
|
||
/* ── Панель «Разделы» (функциональная квалификация) ── */
|
||
#legend-sections-content { display: flex; flex-direction: column; gap: 10px; }
|
||
#legend-sections-title { font-size: 15px; font-weight: 600; color: #fdf6e3; }
|
||
.sect-bucket-h { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: #b58900; font-weight: 600; margin: 8px 0 2px; }
|
||
.sect-row { background: #073642; border-radius: 6px; padding: 7px 10px; }
|
||
.sect-row.sect-empty { opacity: 0.5; }
|
||
.sect-name { font-size: 12px; color: #eee8d5; font-weight: 600; }
|
||
.sect-name .sect-id { color: #839496; font-weight: 400; }
|
||
.sect-cnt { font-size: 11px; color: #839496; }
|
||
.sect-empty-mark { font-size: 11px; color: #586e75; font-style: italic; margin-top: 3px; }
|
||
.sect-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }
|
||
.sect-chip { font-size: 10px; color: #93a1a1; background: #002b36; border: 1px solid #586e75; border-radius: 3px; padding: 1px 5px; cursor: pointer; }
|
||
.sect-chip:hover { background: #0d4a5a; color: #fdf6e3; }
|
||
|
||
/* ── Панель «Хотелки» (отложенный backlog развития мозга) ── */
|
||
#legend-wishlist-content { display: flex; flex-direction: column; gap: 10px; }
|
||
#legend-wishlist-title { font-size: 15px; font-weight: 600; color: #fdf6e3; }
|
||
.wish-row { background: #073642; border-radius: 6px; padding: 8px 10px; border-left: 3px solid #586e75; }
|
||
.wish-row.wish-next { border-left-color: #859900; }
|
||
.wish-row.wish-blocked { border-left-color: #b58900; }
|
||
.wish-row.wish-idea { border-left-color: #586e75; }
|
||
.wish-head { font-size: 12px; color: #eee8d5; font-weight: 600; }
|
||
.wish-head .wish-id { color: #839496; font-weight: 400; }
|
||
.wish-status { font-size: 11px; margin-top: 3px; }
|
||
.wish-note { font-size: 11px; color: #93a1a1; margin-top: 4px; line-height: 1.5; }
|
||
.wish-sect { font-size: 10px; color: #586e75; margin-top: 4px; }
|
||
.wish-legend { font-size: 10px; color: #586e75; display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div id="toolbar">
|
||
<h1>🗺 Лидерра — карта автоматизации</h1>
|
||
<input id="search" type="text" placeholder="Поиск узла…" autocomplete="off">
|
||
<button class="btn" id="btn-freeze">❄ Зафиксировать</button>
|
||
<button class="btn" id="btn-unfreeze">▶ Расшевелить</button>
|
||
<button class="btn" id="btn-reset">⊙ Сбросить вид</button>
|
||
<button class="btn" id="btn-clear">✕ Снять выделение</button>
|
||
</div>
|
||
|
||
<div id="main">
|
||
<div id="network"></div>
|
||
<div id="legend-panel">
|
||
<div id="legend-handle" title="Перетащи, чтобы изменить ширину"></div>
|
||
<button id="legend-close">×</button>
|
||
|
||
<div id="legend-node-content">
|
||
<div id="legend-title">—</div>
|
||
<div id="legend-category"></div>
|
||
<div class="legend-section" id="passport-section">
|
||
<h4>📇 Паспорт узла</h4>
|
||
<p><span class="pp-k">Внедрён:</span> <span id="ld-since">—</span></p>
|
||
<p><span class="pp-k">Последнее изменение:</span> <span id="ld-changed">—</span></p>
|
||
<p><span class="pp-k">Раздел:</span> <span id="ld-section">—</span></p>
|
||
<p><span class="pp-k">Использований за 7 дней:</span> <span id="ld-uses">—</span></p>
|
||
<p id="ld-dup-row" style="display:none;"><span class="pp-k">Дубль:</span> <span id="ld-dup">—</span></p>
|
||
</div>
|
||
<div class="legend-section"><h4>Что делает</h4><p id="ld-desc">—</p></div>
|
||
<div class="legend-section"><h4>Когда используется</h4><p id="ld-when">—</p></div>
|
||
<div class="legend-section"><h4>Ограничения</h4><p id="ld-limits">—</p></div>
|
||
<div class="legend-section"><h4>Кому подчиняется</h4><ul id="ld-reports"></ul></div>
|
||
<div class="legend-section"><h4>Кто подчиняется ему</h4><ul id="ld-manages"></ul></div>
|
||
<div class="legend-section"><h4>С кем работает одновременно</h4><ul id="ld-together"></ul></div>
|
||
<div class="legend-section" id="conflicts-section">
|
||
<h4>⚡ Конфликты</h4>
|
||
<div id="ld-conflicts"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="legend-edge-content" style="display:none;">
|
||
<div id="legend-edge-title">—</div>
|
||
<div class="legend-section"><h4>Источник запроса</h4><p id="le-from">—</p></div>
|
||
<div class="legend-section"><h4>Конечный получатель</h4><p id="le-to">—</p></div>
|
||
<div class="legend-section"><h4>Тип связи</h4><p id="le-type">—</p></div>
|
||
<div class="legend-section"><h4>Когда срабатывает</h4><p id="le-when">—</p></div>
|
||
<div class="legend-section"><h4>Что передаёт</h4><p id="le-transfers">—</p></div>
|
||
<div class="legend-section"><h4>Обязательность</h4><p id="le-mandatory">—</p></div>
|
||
<div class="legend-section"><h4>Регламент</h4><p id="le-rule">—</p></div>
|
||
</div>
|
||
|
||
<div id="legend-sections-content" style="display:none;">
|
||
<div id="legend-sections-title">📂 Разделы деятельности Лидерры</div>
|
||
<div class="legend-section">
|
||
<p>Узлы карты распределены по функциональным разделам. Пустые разделы — будущие домены «мозга», под которые в карте dev-автоматики ещё нет узлов (playbook не наполнен).</p>
|
||
</div>
|
||
<div id="sect-list"></div>
|
||
</div>
|
||
|
||
<div id="legend-wishlist-content" style="display:none;">
|
||
<div id="legend-wishlist-title">💡 Хотелки — отложенный backlog</div>
|
||
<div class="legend-section">
|
||
<p>Отложенные «хотелки» развития мозга и портала — то, что решили сделать позже, чтобы не забыть. Источник правды — массив WISHLIST в этом HTML-файле; новая хотелка = новый объект.</p>
|
||
<div class="wish-legend"><span>▶ к работе</span><span>⏸ ждёт зависимости</span><span>💭 идея</span></div>
|
||
</div>
|
||
<div id="wish-list"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- data-filter-key атрибуты потребляются SECTION 8 (interactive highlighting) -->
|
||
<div id="cat-legend">
|
||
<div class="cat-item" data-filter-key="group:rules"><div class="cat-dot" style="background:#268bd2"></div>Правила</div>
|
||
<div class="cat-item" data-filter-key="group:plugins"><div class="cat-dot" style="background:#859900"></div>Плагины</div>
|
||
<div class="cat-item" data-filter-key="group:skills_sp"><div class="cat-dot" style="background:#6c71c4"></div>Скилы Superpowers</div>
|
||
<div class="cat-item" data-filter-key="group:skills_proj"><div class="cat-dot" style="background:#d33682"></div>Скилы проекта</div>
|
||
<div class="cat-item" data-filter-key="group:hooks"><div class="cat-dot" style="background:#2aa198"></div>Хуки</div>
|
||
<div class="cat-item" data-filter-key="group:agents"><div class="cat-dot" style="background:#b58900"></div>Агенты</div>
|
||
<div class="cat-item" data-filter-key="group:mcp"><div class="cat-dot" style="background:#cb4b16"></div>MCP-серверы</div>
|
||
<div class="cat-item" data-filter-key="group:lefthook"><div class="cat-dot" style="background:#dc322f"></div>Lefthook jobs</div>
|
||
<div class="cat-item" data-filter-key="group:memory"><div class="cat-dot" style="background:#586e75"></div>Memory files</div>
|
||
<div class="cat-item" data-filter-key="group:ruflo"><div class="cat-dot" style="background:#555555; border:1px dashed #888888"></div>🔇 ruflo (изолирован 18.05)</div>
|
||
<div class="cat-item" data-filter-key="conflict:RED"><div class="cat-dot" style="background:#ff5f57; border:1px dashed #ff5f57"></div>🔴 Не закрыт правилом</div>
|
||
<div class="cat-item" data-filter-key="conflict:BLACK"><div class="cat-dot" style="background:#888888; border:1px dashed #888888"></div>⚫ Возник на практике</div>
|
||
<div class="cat-item" data-filter-key="conflict:GREEN"><div class="cat-dot" style="background:#859900; border:1px dashed #859900"></div>🟢 Закрыт правилом</div>
|
||
<span class="cat-ctl-sep"></span>
|
||
<button class="cat-ctl" id="cat-ctl-heat" title="Подсветить узлы по числу вызовов за 7 дней">🔥 По использованию</button>
|
||
<button class="cat-ctl" id="cat-ctl-dup" title="Подсветить явные пары дублей (D1–D5, D7)">⧉ Дубли</button>
|
||
<button class="cat-ctl" id="cat-ctl-sect" title="Показать функциональные разделы и распределение узлов по ним">📂 Разделы</button>
|
||
<button class="cat-ctl" id="cat-ctl-wish" title="Показать отложенные хотелки — backlog развития мозга и портала">💡 Хотелки</button>
|
||
</div>
|
||
|
||
<script>
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 1: NODES
|
||
// ════════════════════════════════════════════════════
|
||
|
||
// RADII, pos() — moved to automation-graph-data.js
|
||
|
||
// NODES — moved to automation-graph-data.js
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 2: EDGES
|
||
// ════════════════════════════════════════════════════
|
||
// CONFLICT_TYPES, E, CONFLICT — moved to automation-graph-data.js
|
||
|
||
// EDGES — moved to automation-graph-data.js
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 3: NODE DETAILS
|
||
// ════════════════════════════════════════════════════
|
||
// CATEGORY_LABELS — moved to automation-graph-data.js
|
||
|
||
function nd(desc, when, limits, reportsTo, manages, together, conflicts) {
|
||
// Backward-compat: old 5-arg signature was nd(desc, reportsTo, manages, together, conflicts).
|
||
// If 2nd arg is an array, treat as old-style call and shift args.
|
||
if (Array.isArray(when)) {
|
||
return {
|
||
desc,
|
||
when: '',
|
||
limits: '',
|
||
reportsTo: when,
|
||
manages: limits,
|
||
together: reportsTo,
|
||
conflicts: (manages || []),
|
||
};
|
||
}
|
||
return { desc, when: when || '', limits: limits || '', reportsTo, manages, together, conflicts: conflicts || [] };
|
||
}
|
||
|
||
const NODE_DETAILS = {
|
||
// ── ПРАВИЛА ──────────────────────────────────────
|
||
pravila: nd(
|
||
'Главный свод правил работы Клода — кто чем командует, что запрещено, какие обязательные действия.',
|
||
'Действует всегда — Клод читает его при старте каждой сессии.',
|
||
'§12 Superpowers — hard-rule уровня 0 цепочки приоритетов: скил инвокируется первым, §9 «Отступления» не применяется, economy-режим §12 не отменяет. Расходимость с другими документами — нарушение §7.',
|
||
[],
|
||
[
|
||
{ name: 'CLAUDE.md', cond: 'подчинён, уровень 2a в цепочке приоритетов' },
|
||
{ name: 'PSR_v1', cond: 'подчинён, уровень 3 в цепочке приоритетов' },
|
||
{ name: 'плагин Superpowers', cond: '§12 обязывает запускать скил первым' },
|
||
{ name: 'Все компоненты', cond: 'через цепочку приоритетов §1' }
|
||
],
|
||
[{ name: 'CLAUDE.md', cond: 'оба читаются при старте сессии' }],
|
||
[{ name: 'ruflo Queen', desc: 'iter4–iter5: нормативка декларировала ruflo Queen-led routing уровнем −1 (overlord) — расходилось с рантаймом (рой idle, 0 задач). Реколлаж 16.05.2026 (Pravila v1.16 / CLAUDE.md v2.2 / PSR_v1 v3.2 / Tooling v2.2) привёл нормативку к факту: ruflo переописан в advisory/automation-подсистему, уровень −1 убран. Конфликт «декларация ≠ рантайм» закрыт.', type: 'GREEN' }]
|
||
),
|
||
claude_md: nd(
|
||
'Оперативная карта проекта — технологии, команды, фазы, 7-уровневая цепочка приоритетов (§1, уровни 0–6) и §3.5 — ruflo как advisory/automation-подсистема, ссылки на документы.',
|
||
'Читается при старте каждой сессии; обновляется при новом инструменте или новой фазе.',
|
||
'Править можно только через скил `/claude-md-management:claude-md-improver` или `:revise-claude-md` (правило §5 п.10). Прямые Edit/Write блокируются хуком предупреждения.',
|
||
[{ name: 'Pravila', cond: 'всегда подчинён (уровень 2a)' }],
|
||
[
|
||
{ name: 'Tooling v2.15', cond: 'ссылается как на реестр инструментов' },
|
||
{ name: 'плагин claude-md-management', cond: 'правило §5 п.10 — единственный канал правок' }
|
||
],
|
||
[
|
||
{ name: 'Pravila', cond: 'оба читаются при старте сессии' },
|
||
{ name: 'Tooling', cond: 'оба — оперативные карты уровня 2' }
|
||
],
|
||
[{ name: 'PSR_v1', desc: 'Правило §5 п.10 запрещает прямые правки, но PSR_v1 это явно не повторяет — есть риск Edit без скила', type: 'GREEN' }]
|
||
),
|
||
psr_v1: nd(
|
||
'Правила совместной работы плагинов — кто с кем работает, какая процедура обязательна. R0 — головной фильтр выбора плагинов (с реколлажа 16.05.2026 снова на вершине стека, не sub-policy под ruflo).',
|
||
'При выборе UI-инструмента (плагин Frontend Design против плагина UI UX Pro Max против MCP-сервера 21st Magic), при координации парных плагинов, при включении дополнительного MCP (внешнего сервиса-инструмента Claude) вне основных фаз.',
|
||
'Обязательное правило R14.5: плагины UI UX Pro Max, 21st Magic, Frontend Design — нельзя использовать одновременно. Обязательное правило R6.0 (фильтр стека) и R6.1 (палитра Forest) — нужно соблюдать при UI-выводе плагинов.',
|
||
[{ name: 'Pravila', cond: 'подчинён, уровень 3 в цепочке' }],
|
||
[
|
||
{ name: 'плагин Superpowers + плагин Frontend Design', cond: 'координирует как пару плагинов' },
|
||
{ name: 'плагин UI UX Pro Max', cond: 'R14.3: включается только через процедуру' },
|
||
{ name: 'MCP-сервер 21st Magic', cond: 'R14.4: включается только через процедуру' }
|
||
],
|
||
[{ name: 'CLAUDE.md', cond: 'обе — оперативные карты, правятся согласованно' }],
|
||
[{ name: 'CLAUDE.md', desc: 'CLAUDE.md §5 п.10 требует править только через скил claude-md-management, а PSR_v1 это ограничение не повторяет — риск прямых Edit', type: 'GREEN' }]
|
||
),
|
||
tooling: nd(
|
||
'Реестр 80 позиций — 60 формализованных инструментов + 20 ruflo-плагинов; §4.10 — ruflo как advisory/automation-подсистема. Когда что использовать, команды установки, конфликты.',
|
||
'При выборе инструмента для фазы (нулевая документация / первая backend / вторая frontend / третья перед запуском в боевую среду), при добавлении нового инструмента, при обновлении версий.',
|
||
'При прямом конфликте с CLAUDE.md побеждает CLAUDE.md (оперативная карта уровня 2a). Любая правка требует синхронизации с CLAUDE.md §3.',
|
||
[
|
||
{ name: 'Pravila', cond: 'уровень 2b — оперативная карта рядом с CLAUDE.md' },
|
||
{ name: 'CLAUDE.md', cond: 'при прямом конфликте побеждает CLAUDE.md' }
|
||
],
|
||
[],
|
||
[{ name: 'CLAUDE.md', cond: 'обе — оперативные карты, правятся синхронно' }]
|
||
),
|
||
|
||
// ── ПЛАГИНЫ ──────────────────────────────────────
|
||
superpowers: nd(
|
||
'Плагин поведения Клода — 14 скилов для тестов, отладки, планирования, параллельной работы.',
|
||
'При творческих, отладочных, тестовых и многошаговых задачах: скил brainstorming (продумать варианты) / скил TDD (разработка через тесты — failing test first) / скил systematic-debugging / скил verification-before-completion (обязательная проверка готовности) / скил writing-plans / скил parallel-work / скил worktree / скил finishing-PR (запрос на слияние кода) / скил subagent-driven-development / скил writing-skills (карта типов в §12.2 Pravila).',
|
||
'§12 Superpowers — hard-rule уровня 0 цепочки приоритетов: скил инвокируется первым. Единственная отмена — явная просьба заказчика «не используй superpowers сейчас» на текущее действие; §9 «Отступления» к §12 не применяется; economy-режим §12 не отменяет.',
|
||
[
|
||
{ name: 'Pravila §12', cond: 'обязательное правило: скил запускается первым' },
|
||
{ name: 'PSR_v1', cond: 'координирует как пару с плагином Frontend Design' }
|
||
],
|
||
[{ name: 'Все 14 скилов Superpowers', cond: 'содержит' }],
|
||
[{ name: 'плагин Frontend Design', cond: 'пара — работают вместе при UI-задачах' }],
|
||
[{ name: 'хук economy-mode', desc: 'Режим экономии 100% теоретически может «сэкономить» запуск скила — §12 (hard-rule уровня 0) economy-режим не отменяет.', type: 'GREEN' }]
|
||
),
|
||
fd_plugin: nd(
|
||
'Плагин знаний о UI — Vue, Vuetify, доступность (accessibility), паттерны компонентов для Лидерры.',
|
||
'При UI/UX задачах — компоненты, экраны, паттерны взаимодействия; в паре с плагином Superpowers (даёт процесс).',
|
||
'Фильтр стека R6.0: срезать React/Tailwind/shadcn/JSX в Vue 3 + Vuetify 3. Обязательное правило палитры Forest R6.1 для цветов, шрифтов и иконок.',
|
||
[{ name: 'PSR_v1', cond: 'R5: подчинён как часть пары плагинов' }],
|
||
[],
|
||
[{ name: 'плагин Superpowers', cond: 'пара — Frontend Design даёт UI-знания, Superpowers даёт процесс' }],
|
||
[
|
||
{ name: 'плагин UI UX Pro Max', desc: 'Правило PSR_v1 R14.5: нельзя одновременно — оба включены в настройках, но должны чередоваться', type: 'GREEN' },
|
||
{ name: 'MCP-сервер 21st Magic', desc: 'Правило PSR_v1 R14.5: нельзя одновременно с Frontend Design — оба потенциально доступны', type: 'GREEN' }
|
||
]
|
||
),
|
||
upm: nd(
|
||
'Резервная библиотека UI — 50+ стилей, 161 палитра, 99 правил-подсказок UX. Только по процедуре.',
|
||
'Только по процедуре PSR_v1 R14.3: запасной вариант к плагину Frontend Design ИЛИ «третий вариант» в архитектурном решении.',
|
||
'R14.5: нельзя одновременно с плагином Frontend Design / MCP-сервером 21st Magic. Фильтр стека R6.0 и обязательное правило палитры Forest R6.1 — обязательны. Проверка доступности Pa11y (автопроверка accessibility — доступности) перед выкаткой.',
|
||
[{ name: 'PSR_v1', cond: 'R14.3: включается только через процедуру, не сам по себе' }],
|
||
[],
|
||
[],
|
||
[{ name: 'плагин Frontend Design', desc: 'Правило PSR_v1 R14.5: нельзя одновременно — UI UX Pro Max как материал, Frontend Design как решатель; риск смешать роли', type: 'GREEN' }]
|
||
),
|
||
claude_md_mgmt: nd(
|
||
'Единственный разрешённый способ править CLAUDE.md — через скил claude-md-improver или revise-claude-md.',
|
||
'При любой правке CLAUDE.md (новая фаза, новый инструмент, смена версии, новые особенности — всё через скил).',
|
||
'Правило PSR_v1 R10.1 блок 1 (инфраструктурная категория). Внутри процедуры продолжают действовать §4 правил Клода (синхронизация Pravila + Tooling).',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 Блок 1: инфраструктурная категория' }],
|
||
[{ name: 'CLAUDE.md', cond: 'правило §5 п.10: единственный канал правок' }],
|
||
[{ name: 'скил q-item-add', cond: 'скил делегирует правки CLAUDE.md через этот плагин' }]
|
||
),
|
||
hookify_plugin: nd(
|
||
'Плагин создания хуков — анализирует разговоры и предлагает новые автоматизации в виде хуков.',
|
||
'При запросе «давай повесим хук на это поведение» или после серии повторяющихся ошибок — анализ через агента conversation-analyzer.',
|
||
'PSR_v1 R10.1 блок 1 #58 (authoring-tooling). HK1 hard-rule: только по явному /hookify, не проактивно; перед генерацией хука — обязательный pre-check на коллизию с зарегистрированными хуками settings.json; перезапись 6-компонентной economy/skill-discipline архитектуры запрещена. ADR-010.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1 #58: authoring-tooling, HK1 pre-check (ADR-010)' }],
|
||
[{ name: 'агент hookify:conversation-analyzer', cond: 'запускает анализ разговоров' }],
|
||
[{ name: 'агент hookify:conversation-analyzer', cond: 'плагин и агент работают в паре' }],
|
||
[
|
||
{ name: 'хук pre-claude-warn', desc: 'Закрыто правилом HK1 (ADR-010): hookify — только по явному /hookify, перед генерацией хука обязательный pre-check на коллизию с существующими хуками settings.json; перезапись 6-компонентной economy/skill-discipline архитектуры запрещена', type: 'GREEN' }
|
||
]
|
||
),
|
||
|
||
// ── A6 ARCHITECTURE-TOOLING (17.05.2026) ─────────
|
||
adr_kit: nd(
|
||
'Плагин ADR (Architecture Decision Records) — фиксация закрытых архитектурных решений в docs/adr/ (формат Nygard, 7 секций) + декларативный энфорсер adr-judge.',
|
||
'При фиксации архитектурного решения — стек, паттерн, граница слоёв; ADR-NNN в docs/adr/. Открытые вопросы — не сюда, они в реестре Открытые_вопросы.',
|
||
'Правило PSR_v1 R10.1 блок 1 (architecture-tooling, off-phase). adr-judge врезан в lefthook pre-commit job 9 — декларативный regex без --llm, 0 вызовов Claude API. init/install-hooks НЕ запускаются (конфликт-аудит AK1/AK2). Не UI → вне фильтров R6.0/R6.1/R14. Tooling §4.11, CLAUDE.md §3.3 #36.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: architecture-tooling' }, { name: 'Tooling', cond: '§4.11 #36 — реестр' }],
|
||
[{ name: 'lefthook job 9 (adr-judge)', cond: 'врезан как pre-commit проверка Enforcement-блоков' }],
|
||
[{ name: 'docs/adr/', cond: 'хранилище ADR — ADR-000/001/002' }]
|
||
),
|
||
arch_patterns: nd(
|
||
'Скил-плагин — справочник архитектурных паттернов (Clean / Hexagonal / layered architecture, Domain-Driven Design). Knowledge-only, не решатель.',
|
||
'При архитектурном вопросе «какой паттерн подходит» — playbook паттернов; код не генерирует, файлы не правит.',
|
||
'Правило PSR_v1 R10.1 блок 1 (architecture-tooling, off-phase). Knowledge-only — без хуков и машинерии. Не UI → вне фильтров R6.0/R6.1/R14. Tooling §4.13, CLAUDE.md §3.3 #38.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: architecture-tooling' }, { name: 'Tooling', cond: '§4.13 #38 — реестр' }],
|
||
[],
|
||
[]
|
||
),
|
||
mermaid_skill: nd(
|
||
'Вендоренный standalone-скил (.claude/skills/mermaid/) — генерирует исходник Mermaid-диаграмм (23 типа, включая C4/architecture). Рендера mmdc/Chromium не требует.',
|
||
'При построении C4/архитектурной диаграммы — результат в docs/architecture/ (Mermaid рендерится на GitHub нативно).',
|
||
'Вендорен — не плагин, не marketplace, не подсистема (конфликт-аудит CC1: иммунен к потере апстрима). lefthook markdownlint+cspell исключают .claude/skills/mermaid/** (MK1). Tooling §4.12, CLAUDE.md §3.3 #37.',
|
||
[{ name: 'Tooling', cond: '§4.12 #37 — реестр' }],
|
||
[],
|
||
[{ name: 'docs/architecture/', cond: 'C4-диаграммы → c4-context.md' }]
|
||
),
|
||
deptrac: nd(
|
||
'Composer dev-dependency deptrac/deptrac v4.6.1 (BSD-3) — статический анализ направления зависимостей между слоями App\\ (Controller/Service/Model/Job/…). Чистый PHP, 0 вызовов LLM.',
|
||
'Архитектурный fitness-гейт: проверяет, что код не нарушает границы слоёв. Конфиг app/deptrac.yaml (13 слоёв) + ruleset; запускается автоматически как lefthook pre-commit job 10 на staged app/**/*.php.',
|
||
'Правило PSR_v1 R10.1 блок 1 note (architecture-tooling, off-phase — composer dev-dep, не marketplace-плагин). Первый прогон 0 нарушений → baseline-файл не нужен (red-green доказан). Не UI → вне фильтров R6.0/R6.1/R14. Tooling §4.18, CLAUDE.md §3.3 #43.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1 note: architecture-tooling' }, { name: 'Tooling', cond: '§4.18 #43 — реестр' }],
|
||
[{ name: 'lefthook job 10 (deptrac)', cond: 'врезан как pre-commit гейт направления зависимостей' }],
|
||
[{ name: 'docs/architecture/', cond: 'mermaidjs-форматтер → c4-component-layers.md' }]
|
||
),
|
||
|
||
// ── A4 DESIGN-TOOLING (17.05.2026) ──────────────
|
||
mcp_figma: nd(
|
||
'MCP Figma (#44) — DEFERRED, precondition: Figma-аккаунт. Extract-only (ADR-006): извлечение токенов/variables из источника дизайна. FD #30 остаётся единственным UI-решателем.',
|
||
'При наличии Figma-аккаунта и нужде извлечь дизайн-токены/variables напрямую из Figma-файла.',
|
||
'DEFERRED — не установлен, требует Figma-аккаунт (Б-1). Не UI-решатель → вне R6.0/R6.1/R14. Extract-only, не генерирует UI-решения. PSR_v1 R10.1 блок 3.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 3: design-tooling (DEFERRED)' }],
|
||
[],
|
||
[{ name: 'Frontend Design', cond: 'FD остаётся единственным UI-решателем; Figma MCP — только источник токенов' }]
|
||
),
|
||
mcp_icons: nd(
|
||
'MCP Universal Icons (#45) — поиск/вставка SVG-иконок, 10 коллекций включая Lucide. Tools search_icons/get_icon. SVG framework-neutral (R6.0).',
|
||
'При поиске иконки из коллекции Lucide или других (Heroicons, Tabler, Phosphor и др.) — получить SVG-исходник для вставки в Vue-компонент.',
|
||
'SVG framework-neutral — результат нужно обернуть в Vue-компонент вручную. R6.0 фильтр не блокирует (SVG — не React/Tailwind). Lucide — branded иконочный стек проекта (CLAUDE.md §2). PSR_v1 R10.1 блок 3.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 3: design-tooling' }],
|
||
[],
|
||
[{ name: 'Frontend Design', cond: 'FD использует результат поиска как материал при UI-задачах' }]
|
||
),
|
||
design_plugin: nd(
|
||
'Плагин Design (#46, Anthropic Verified) — дизайн-критика, a11y-аудит дизайн-уровня, UX-копирайт, research synthesis. Pre-code (ADR-006); Pa11y остаётся техническим a11y SoT.',
|
||
'При дизайн-критике макета или компонента, при UX-анализе flow, при написании UX-копирайта, при synthesis пользовательских исследований.',
|
||
'Pre-code инструмент (ADR-006) — не генерирует финальный код, даёт дизайн-рекомендации. Pa11y остаётся техническим a11y SoT (§5 п.3). Не UI-решатель в смысле PSR_v1 R14 → вне R14 pipeline. PSR_v1 R10.1 блок 1.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: design-tooling' }],
|
||
[],
|
||
[{ name: 'Frontend Design', cond: 'Design plugin — pre-code критика; FD — post-spec UI-решатель; разные фазы' }]
|
||
),
|
||
|
||
// ── C9 PROJECT-MANAGEMENT-TOOLING (17.05.2026) ──
|
||
ccpm: nd(
|
||
'Vendored-скил CCPM: PRD→эпик→GitHub-issue→код с трассируемостью. Раздел C9 опирается также на reuse — GitHub MCP (issues/Projects v2) + Superpowers writing-plans + q-item-add.',
|
||
'При создании PRD, декомпозиции на эпики/задачи, связывании с GitHub Issues — стек CCPM + GitHub MCP + writing-plans.',
|
||
'Вендорен в .claude/skills/ccpm/ (C9 project-management-tooling, off-phase). Раздел C9. Tooling #41, CLAUDE.md §3.3 #41.',
|
||
[{ name: 'Tooling', cond: '§4.16 #41 — реестр' }],
|
||
[],
|
||
[{ name: 'GitHub MCP', cond: 'CCPM использует GitHub Issues/Projects v2 как source-of-truth' }]
|
||
),
|
||
product_mgmt: nd(
|
||
'Плагин Anthropic (product-management@knowledge-work-plugins): PRD/роадмап/метрики — product-strategy церемонии.',
|
||
'При написании PRD, обновлении роадмапа, анализе метрик продукта — skills product-management плагина.',
|
||
'Правило PSR_v1 R10.1 блок 1 (project-management-tooling, off-phase). Не UI → вне фильтров R6.0/R6.1/R14. Tooling #42, CLAUDE.md §3.3 #42.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: project-management-tooling' }, { name: 'Tooling', cond: '§4.17 #42 — реестр' }],
|
||
[],
|
||
[]
|
||
),
|
||
|
||
// ── D3 AUDIT-SECURITY (17.05.2026) ───────────────
|
||
tob_skills: nd(
|
||
'Marketplace-плагин Trail of Bits (`trailofbits/skills`) — курированный субсет 8 audit-плагинов: `differential-review`, `audit-context-building`, `supply-chain-risk-auditor`, `insecure-defaults`, `sharp-edges`, `static-analysis`, `variant-analysis`, `agentic-actions-auditor`. Глубокие on-demand аудит-кампании. Раздел D3. Tooling #39, off-phase audit-security.',
|
||
'При глубоком аудите безопасности: diff-ревью, supply-chain риски зависимостей, поиск вариантов уязвимостей, статический анализ (SARIF). Глубокие кампании — не inline SAST.',
|
||
'Правило PSR_v1 R10.1 блок 1 (audit-security, off-phase). Граница TB1: Semgrep MCP (#25) = inline SAST, ToB = глубокие on-demand кампании. CC-BY-SA-4.0 — не вендорено, лицензионный триггер TB4 не применяется. Не UI → вне R6.0/R6.1/R14. Tooling §4.14, CLAUDE.md §3.3 #39.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: audit-security' }, { name: 'Tooling', cond: '§4.14 #39 — реестр' }],
|
||
[],
|
||
[{ name: 'MCP: semgrep', cond: 'TB1: граница — Semgrep inline SAST, ToB глубокие кампании' }],
|
||
[{ name: 'MCP: semgrep', desc: 'TB1: граница разграничена регламентом — Semgrep = inline SAST в процессе работы, Trail of Bits = глубокие аудит-кампании по запросу. Параллельное использование разрешено при разных сценариях.', type: 'GREEN' }]
|
||
),
|
||
sec_guidance: nd(
|
||
'Anthropic-плагин (`security-guidance@claude-plugins-official`, Anthropic Verified) — один блокирующий PreToolUse-хук, inline-предупреждения уязвимостей при правке кода (8 контентных правил + 1 path-правило). При первом за сессию совпадении уязвимого паттерна в файле — sys.exit(2), блокирует правку (одноразовый speed-bump, retry проходит). Раздел D3. Tooling #40.',
|
||
'Активен автоматически при каждом Write/Edit/MultiEdit — при уязвимом паттерне печатает предупреждение и блокирует первую такую правку файла за сессию; повторная попытка проходит.',
|
||
'Правило PSR_v1 R10.1 блок 1 (audit-security, off-phase). SG1: 5-й PreToolUse-хук, блокирующий (sys.exit 2), одноразовый per «файл+правило» за сессию — economy/ruflo-цепочка не нарушается, +~34 мс/правку. SG2: Windows-починка — bundled hooks.json зовёт python3 (нет в PATH), решено python3.exe-шимом в каталоге Python. Не UI → вне R6.0/R6.1/R14. Tooling §4.15, CLAUDE.md §3.3 #40.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: audit-security' }, { name: 'Tooling', cond: '§4.15 #40 — реестр' }],
|
||
[],
|
||
[{ name: 'скил security-review', cond: 'оба — D3 audit-security; sec_guidance inline, sk_security_review ручной' }]
|
||
),
|
||
sk_security_review: nd(
|
||
'Кастомизированная Anthropic-команда `/security-review` — копия в `.claude/commands/security-review.md` с проектным FP-фильтром (RLS / ПДн / economy-хуки). Раздел D3. D3 #2.',
|
||
'При ручном security-review кода или PR — запуск `/security-review` с проектным контекстом для фильтрации ложных срабатываний.',
|
||
'Проектный FP-фильтр: RLS-политики / ПДн-поля / economy-хуки — не считаются уязвимостями. Раздел D3.',
|
||
[{ name: 'Tooling', cond: 'D3 #2 — проектная кастомизация' }],
|
||
[],
|
||
[{ name: 'sec_guidance', cond: 'оба D3 audit-security; sec_guidance — inline warn, security-review — ручной аудит' }, { name: 'audit-portal', cond: 'sk_audit_portal оркеструет security-review как фазу аудита' }]
|
||
),
|
||
sk_audit_portal: nd(
|
||
'Проектный скил — 14-фазный портальный аудит (дистилляция аудитов #1/#2/#3). Покрывает: PHP/Vue статический анализ, RLS, a11y, coverage, зависимости, secrets. Раздел D3.',
|
||
'При проведении полного аудита портала — запуск 14 фаз последовательно с документированием находок P0/P1/P2/P3.',
|
||
'Раздел D3. Оркеструет несколько инструментов: sk_security_review, Trail of Bits Skills, regression-скил. Находки фиксируются в docs/superpowers/audits/.',
|
||
[{ name: 'Tooling', cond: 'D3 — проектный аудит-скил' }],
|
||
[{ name: 'скил security-review', cond: 'оркеструет как security-фазу аудита' }, { name: 'Trail of Bits Skills', cond: 'оркеструет для глубоких кампаний' }, { name: 'скил regression', cond: 'использует на фазе тестов' }],
|
||
[{ name: 'скил security-review', cond: 'пара в D3 audit-security' }]
|
||
),
|
||
|
||
// ── A3 INTEGRATION-TOOLING (17.05.2026) ──────────
|
||
ag_apidocs: nd(
|
||
'Агент claude-flow — генерирует OpenAPI-спеку REST API по роутам и контроллерам Laravel. Pattern learning. 0 установки — агент доступен в сессии.',
|
||
'При фиксации контракта REST API: генерация/обновление OpenAPI-спеки группы эндпоинтов. Результат — docs/api/.',
|
||
'Sub-агент claude-flow — узел карты, но без отдельного номера в реестре Tooling Прил. Н (реестр — plugin-grain; 11 agent-узлов карты так же без Tooling-номеров). Не UI → вне фильтров R6.0/R6.1/R14.',
|
||
[{ name: 'CLAUDE.md', cond: '§3.3 — упомянут при #47 openapi-mcp' }],
|
||
[],
|
||
[{ name: 'MCP: openapi', cond: 'генерирует спеку → openapi-mcp отдаёт её как MCP-ресурс' }]
|
||
),
|
||
mcp_openapi: nd(
|
||
'MCP-сервер (npm, stdio) — отдаёт OpenAPI-спеку как MCP-ресурс/тулы; introspection своей и чужих API при интеграционной разработке.',
|
||
'При работе с интеграциями (API/вебхуки) — обращение к структуре OpenAPI-спеки из сессии Claude. READ-ONLY introspection.',
|
||
'Правило PSR_v1 R10.1 блок 3 (integration-tooling, off-phase — 9-я подкатегория). stdio-режим, без port-conflict. Не UI → вне фильтров R6.0/R6.1/R14. Tooling §4.22 #47, CLAUDE.md §3.3 #47.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 3: integration-tooling' }, { name: 'Tooling', cond: '§4.22 #47 — реестр' }],
|
||
[],
|
||
[{ name: 'docs/api/', cond: 'источник OpenAPI-спеки' }]
|
||
),
|
||
|
||
// ── A11 ML-AI-TOOLING (17.05.2026) ──────────────
|
||
claude_api: nd(
|
||
'Скил сборки AI-фич на Anthropic SDK (prompt-кэш). Reuse — раздел A11 опирается также на context7 MCP (доки) и Sentry MCP (LLM-наблюдаемость).',
|
||
'При разработке AI-фич на Anthropic API / Claude SDK — скил задаёт паттерны prompt-кэша, batch-запросов, tool use.',
|
||
'Reuse-узел раздела A11 (ml-ai-tooling). claude-api — встроенный скил Claude Code, не нумерованная Tooling-позиция; регистрация — Tooling «built-in skills» + PSR_v1 R10.1 блок 2. В A11 — reuse-слой (CLAUDE.md §6). Не UI → вне фильтров R6.0/R6.1/R14.',
|
||
[{ name: 'Tooling', cond: 'built-in skill — PSR_v1 R10.1 блок 2 (reuse)' }],
|
||
[],
|
||
[{ name: 'context7 MCP', cond: 'документация Anthropic SDK' }, { name: 'Sentry MCP', cond: 'LLM-наблюдаемость (off-phase reuse)' }]
|
||
),
|
||
promptfoo: nd(
|
||
'npm-CLI eval LLM-промптов: ассерты, регрессия, red-team. Запуск вручную/CI — не в хуках (платные LLM-вызовы).',
|
||
'При разработке и проверке AI-промптов — запуск test-suite promptfoo вручную или в CI. Никогда в pre-commit хук (ML1: платные вызовы).',
|
||
'Правило PSR_v1 R10.1 блок 1 note (ml-ai-tooling, off-phase). npm devDependency, тяжёлый (~1090 пакетов). Не UI → вне фильтров R6.0/R6.1/R14. Tooling §4.23 #48, CLAUDE.md §3.3 #48.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: ml-ai-tooling' }],
|
||
[{ name: 'ML1', cond: 'никогда в хук/pre-commit — платные LLM-вызовы' }],
|
||
[]
|
||
),
|
||
data_scientist: nd(
|
||
'Vendored-скил: классический ML-воркфлоу — выбор алгоритма, feature engineering, оценка модели.',
|
||
'При ML-задаче (выбор алгоритма, feature engineering, валидация модели) — knowledge-only playbook без генерации кода.',
|
||
'Вендорен в .claude/skills/data-scientist/ (ML3 — lefthook markdownlint+cspell исключают через job-exclude). Knowledge-only, не решатель. Не UI → вне фильтров R6.0/R6.1/R14. Tooling §4.24 #49, CLAUDE.md §3.3 #49.',
|
||
[{ name: 'Tooling', cond: '§4.24 #49 — реестр' }],
|
||
[],
|
||
[]
|
||
),
|
||
|
||
// ── C10 BUSINESS-PROCESS (17.05.2026) ────────────
|
||
ops_plugin: nd(
|
||
'Плагин Anthropic operations — 9 скилов бизнес-процессов: документирование, оптимизация, change-management, capacity-планирование.',
|
||
'При работе с бизнес-процессом — документировать процесс, спланировать change-request, рассчитать capacity. Marketplace-плагин, 0 lifecycle-хуков.',
|
||
'Правило PSR_v1 R10.1 блок 1 (business-process, off-phase). Marketplace `operations@knowledge-work-plugins` v1.2.0, тот же marketplace что #42/#46. Не UI → вне фильтров R6.0/R6.1/R14. Tooling §4.26 #51, CLAUDE.md §3.3 #51.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: business-process' }],
|
||
[{ name: 'OPS1', cond: 'process-doc → Mermaid-исходник; рендер за mermaid' }, { name: 'OPS5', cond: 'generic ↔ self-authored stack-grounded скилы' }],
|
||
[{ name: 'mermaid', cond: 'рендер диаграмм процесса' }]
|
||
),
|
||
process_modeling: nd(
|
||
'Self-authored скил: моделирование to-be бизнес-процесса — BPMN 2.0, карты процессов, RACI, state-машины.',
|
||
'При проектировании бизнес-процесса — выбрать артефакт (BPMN/swimlane/journey/RACI), построить модель. Рендер делегируется скилу mermaid.',
|
||
'Свой project-скил в .claude/skills/process-modeling/ (не вендоренный → линтуется, конфликт-аудит LINT1). Не UI → вне фильтров R6.0/R6.1/R14. Tooling §4.27 #52, CLAUDE.md §3.3 #52.',
|
||
[{ name: 'Tooling', cond: '§4.27 #52 — реестр' }],
|
||
[{ name: 'BPMN1', cond: 'нотация process-modeling ≠ mermaid рендер' }],
|
||
[{ name: 'mermaid', cond: 'рендер BPMN/диаграмм' }, { name: 'process-analysis', cond: 'as-is ↔ to-be пара' }]
|
||
),
|
||
process_analysis: nd(
|
||
'Self-authored скил: анализ as-is бизнес-процесса — discovery из кода Laravel, узкие места, трассировка, метрики.',
|
||
'При вскрытии существующего процесса — реконструировать из routes/jobs/audit-логов, найти узкие места, посчитать KPI.',
|
||
'Свой project-скил в .claude/skills/process-analysis/ (не вендоренный → линтуется, LINT1). Не UI → вне фильтров R6.0/R6.1/R14. Tooling §4.28 #53, CLAUDE.md §3.3 #53.',
|
||
[{ name: 'Tooling', cond: '§4.28 #53 — реестр' }],
|
||
[{ name: 'PA1', cond: 'процессные узкие места ≠ runtime (perf-analyzer)' }],
|
||
[{ name: 'process-modeling', cond: 'as-is ↔ to-be пара' }]
|
||
),
|
||
|
||
// ── DISCOVERY-TOOLING (18.05.2026) ────────────
|
||
discovery_interview: nd(
|
||
'Self-authored скил: структурированное интервью-discovery до проектирования — FEATURE (JTBD-интервью заказчика) + SYSTEM (ориентация по мета-слою проекта).',
|
||
'При расплывчатом проблемном запросе — провести JTBD-интервью, отдать discovery-brief в brainstorming; при «сориентируй по проекту» — синтез по карте/CLAUDE.md/MEMORY/Открытые_вопросы/Tooling.',
|
||
'Свой project-скил в .claude/skills/discovery-interview/ (не вендоренный → линтуется, LINT1). Не UI → вне фильтров R6.0/R6.1/R14. Триггер-eval 20/20. Tooling §4.30 #55, CLAUDE.md §3.3 #55, ADR-009.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1 note: discovery-tooling' }, { name: 'Tooling', cond: '§4.30 #55 — реестр' }],
|
||
[{ name: 'DI2', cond: 'разрез по слою-источнику с process-analysis (ADR-009)' }],
|
||
[{ name: 'process-analysis', cond: 'граница: app-код ↔ голова заказчика/мета-слой' }, { name: 'brainstorming', cond: 'хэндофф FEATURE-brief' }]
|
||
),
|
||
|
||
// ── FINANCE-TOOLING C6+C7 (20.05.2026, ADR-012) ──
|
||
finance_plugin: nd(
|
||
'Marketplace-плагин (Anthropic): финансы/бухгалтерия — сверка, variance-анализ, US-GAAP-отчётность, закрытие периода, проводки. 8 скилов.',
|
||
'При учётно-финансовой работе C7 (и сверке/variance для C6). РФ: reconciliation/variance ✅; US-GAAP-скилы ⚠️; SOX ❌; warehouse-MCP DEFERRED.',
|
||
'plugin finance@knowledge-work-plugins (enabledPlugins). Категория finance-tooling, homed C7. Не UI → вне R6/R14. Tooling §4.36 #61, CLAUDE.md §3.3 #61, ADR-012.',
|
||
[{ name: 'Tooling', cond: '§4.36 #61 — реестр' }],
|
||
[{ name: 'FIN2', cond: 'SOX not-applicable РФ' }, { name: 'FIN3', cond: 'граница с operations #51' }],
|
||
[{ name: 'ru-tax-accounting', cond: 'РФ-специфика поверх US-механики' }]
|
||
),
|
||
billing_audit: nd(
|
||
'Self-authored скил: аудит денежных инвариантов биллинга Лидерры — сумма (bcmath), идемпотентность, tier-резолюция, дрейф reconcile, charge_source.',
|
||
'При правке/ревью кода Billing — проверить денежную корректность начисления.',
|
||
'Свой project-скил .claude/skills/billing-audit/ (линтуется, LINT1). Не UI → вне R6/R14. Tooling §4.37 #62, CLAUDE.md §3.3 #62, ADR-012.',
|
||
[{ name: 'Tooling', cond: '§4.37 #62 — реестр' }],
|
||
[{ name: 'FIN5', cond: 'объект ≠ process-*/D3/ru-tax' }],
|
||
[{ name: 'Pest', cond: 'инварианты через тесты' }, { name: 'Boost', cond: 'модели биллинга' }]
|
||
),
|
||
ru_tax: nd(
|
||
'Self-authored скил: РСБУ/НК РФ контекст для выручки Лидерры — НДС/УСН, налоговая база, налогооблагаемое событие, выгрузки бухгалтеру.',
|
||
'При «как учесть/обложить по РФ» — перевод billing-выручки (выход C6) в учётно-налоговый контекст C7.',
|
||
'Свой project-скил .claude/skills/ru-tax-accounting/ (линтуется, LINT1). Закрывает РФ-gap US-плагина finance. Не UI → вне R6/R14. Tooling §4.38 #63, CLAUDE.md §3.3 #63, ADR-012.',
|
||
[{ name: 'Tooling', cond: '§4.38 #63 — реестр' }],
|
||
[{ name: 'FIN6', cond: '≠ finance plugin/billing-audit/D1/D2' }],
|
||
[{ name: 'billing-audit', cond: 'выручка C6 → налог.база C7' }, { name: 'finance plugin', cond: 'US-механика' }]
|
||
),
|
||
|
||
// ── A1 BACKEND-TOOLING (20.05.2026, ADR-013) ──
|
||
rector: nd(
|
||
'Composer dev-dep (Rector + rector-laravel): авто-рефакторинг и version-upgrade PHP-кода — dead-code, code-quality наборы, апгрейды под версию Laravel.',
|
||
'При «обнови/почини/рефактори backend-код», апгрейде Laravel-версии, удалении мёртвого кода. Запуск manual/CI (composer rector / rector:fix).',
|
||
'Composer dev-dep, app/rector.php (deadCode+codeQuality conservative). manual/CI — НЕ блокирующий lefthook (dry-run baseline 16 файлов). Не UI → вне R6/R14. Tooling §4.39 #64, CLAUDE.md §3.3 #64, ADR-013.',
|
||
[{ name: 'Tooling', cond: '§4.39 #64 — реестр' }],
|
||
[{ name: 'BT1', cond: '↔ Pint трансформация vs стиль' }, { name: 'BT2', cond: '↔ Larastan чинит vs находит' }, { name: 'BT3', cond: '↔ deptrac vs граф слоёв' }],
|
||
[{ name: 'PHP Insights', cond: 'backend-quality chain L14' }, { name: 'Larastan', cond: 'L14 типы' }]
|
||
),
|
||
php_insights: nd(
|
||
'Composer dev-dep: метрики качества кода — complexity / architecture / maintainability (cyclomatic, code smells, распределение архитектуры).',
|
||
'При «оцени качество/сложность кода», «где код запутан», в портальном аудите. on-demand/CI (composer insights).',
|
||
'Composer dev-dep, app/config/insights.php (SyntaxCheck removed — Windows-краш, style-ось off — владелец Pint). on-demand/CI — НЕ блокирующий (BT9). Не UI → вне R6/R14. Tooling §4.40 #65, CLAUDE.md §3.3 #65, ADR-013.',
|
||
[{ name: 'Tooling', cond: '§4.40 #65 — реестр' }],
|
||
[{ name: 'BT4', cond: 'style/code оси off — уникум complexity+architecture' }, { name: 'BT9', cond: 'не блокирующий — без четверного гейта' }],
|
||
[{ name: 'Rector', cond: 'backend-quality chain L14' }, { name: 'Larastan', cond: 'L14 типы' }]
|
||
),
|
||
backend_patterns: nd(
|
||
'Self-authored скил: backend-конвенции Лидерры — слоистость controller→service→job, RLS-aware Eloquent, деньги bcmath/LedgerService, идемпотентные джобы, partition-aware запросы.',
|
||
'При «как писать backend в Лидерре», «паттерн контроллера/сервиса/джоба», scaffolding новой backend-фичи.',
|
||
'Свой project-скил .claude/skills/laravel-backend-patterns/ (линтуется, LINT1). Не UI → вне R6/R14. Tooling §4.41 #66, CLAUDE.md §3.3 #66, ADR-013.',
|
||
[{ name: 'Tooling', cond: '§4.41 #66 — реестр' }],
|
||
[{ name: 'BT5', cond: '≠ architecture-patterns #38 (generic)' }, { name: 'BT6', cond: '≠ billing-audit #62 (аудит)' }],
|
||
[{ name: 'billing-audit', cond: '«как писать» ↔ «аудит денег»' }, { name: 'Boost', cond: 'Eloquent-контекст' }]
|
||
),
|
||
nightowl: nd(
|
||
'Self-hosted runtime-телеметрия (laravel/nightwatch + nightowl-agent): коррелированный трейс request↔job↔query↔cache в свой PostgreSQL. DEFERRED.',
|
||
'DEFERRED — при появлении Linux/боевого сервера (Б-1). Сейчас не маршрутизировать (нет pcntl/posix на Windows, OSS без MCP, hosted = 152-ФЗ).',
|
||
'DEFERRED pending-слот (как Sentry #34 / Figma #44 / Jupyter #50). Spike docs/backend/nightowl-spike.md. Не UI → вне R6/R14. Tooling §4.42 #67, CLAUDE.md §3.3 #67, ADR-013.',
|
||
[{ name: 'Tooling', cond: '§4.42 #67 — реестр' }],
|
||
[{ name: 'BT7', cond: '↔ Sentry трейс vs ошибки' }, { name: 'BT8', cond: '↔ Pail/Boost трейс vs tail/снапшот' }],
|
||
[{ name: 'Sentry', cond: 'трейс ↔ ошибки (ADR-013)' }]
|
||
),
|
||
|
||
// ── СКИЛЫ SUPERPOWERS ────────────────────────────
|
||
sk_brainstorm: nd(
|
||
'Продумывает задачу вместе с заказчиком, формулирует варианты A/B/C и согласует дизайн до написания кода.',
|
||
'При творческой задаче — новая фича, непростой рефакторинг, дизайн-решение; ДО любого кода или плана.',
|
||
'Обязательно явное «Approved» от заказчика до перехода к скилу writing-plans. Запрет: нельзя запускать скилы реализации до утверждения дизайна.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) для творческих задач' }],
|
||
[],
|
||
[{ name: 'скил writing-plans', cond: 'вызывается сразу после brainstorming для создания плана' }]
|
||
),
|
||
sk_tdd: nd(
|
||
'Ведёт разработку через написание падающего теста до кода: сначала RED (тест провален), потом GREEN (тест проходит). TDD (разработка через тесты — failing test first).',
|
||
'При любом новом боевом коде — backend (Pest) и frontend (Vitest).',
|
||
'Падающий тест пишется ДО реализации; формулировка «код должен работать» без проверенного теста — нарушение правила §12.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) для любого нового кода' }],
|
||
[],
|
||
[{ name: 'скил executing-plans', cond: 'TDD встроен в каждый шаг плана выполнения' }]
|
||
),
|
||
sk_debug: nd(
|
||
'Системная отладка: минимум 3 гипотезы, опровержение каждой реальной проверкой до того, как править код — никаких «должно работать».',
|
||
'При неожиданном поведении, падении теста, ошибке во время работы, неожиданном выводе.',
|
||
'Минимум 3 гипотезы. Опровержение через реальные команды и тесты, а не «логика подсказывает». Никаких «попробую исправить» без подтверждённой причины.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) при неожиданном поведении' }],
|
||
[],
|
||
[{ name: 'MCP-сервер redis', cond: 'используется для отладки очередей Redis' }]
|
||
),
|
||
sk_wplans: nd(
|
||
'Создаёт детальный план реализации с полным кодом, командами и шагами по 2-5 минут.',
|
||
'После скила brainstorming (творческая задача) или сразу для многошаговой (≥3 шагов) технической задачи.',
|
||
'Никаких заглушек (TBD, TODO, «add validation»). Каждый шаг — реальный код или команда. Покрытие спецификации обязательно.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) для многошаговых задач (≥3 шагов)' }],
|
||
[],
|
||
[{ name: 'скил executing-plans или скил subagent-driven', cond: 'план передаётся в один из них для выполнения' }]
|
||
),
|
||
sk_eplans: nd(
|
||
'Выполняет готовый план шаг за шагом, отмечает чекбоксы, делает коммиты после каждого шага.',
|
||
'После скила writing-plans (если выбрано выполнение в текущей сессии); альтернатива — скил subagent-driven-development в той же сессии.',
|
||
'Каждый шаг отмечается галочкой, коммиты не объединяются — атомарно по одному за шаг (Pravila §4.2).',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'скил writing-plans', cond: 'получает план от writing-plans' }, { name: 'скил subagent-driven-development', cond: 'альтернатива — зависит от выбора пользователя' }]
|
||
),
|
||
sk_verify: nd(
|
||
'Обязательная проверка перед заявлением «готово»: запускает тесты, видит реальный вывод, никаких предположений.',
|
||
'Перед любым заявлением «готово»/«passed»/«closed»/«merged» — обязательно (правило §12 + экономия 0% как жёсткое требование).',
|
||
'Реальный запуск, не «должно пройти». Вывод тестов виден полностью. Выборочные результаты запрещены («tests pass» = ровно столько, сколько действительно прошло).',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }, { name: 'Pravila §12', cond: 'обязательное правило (см. §12) перед любым заявлением «готово»' }],
|
||
[],
|
||
[{ name: 'MCP-сервер laravel-boost', cond: 'запросы к БД для проверки данных' }]
|
||
),
|
||
sk_parallel: nd(
|
||
'Разбивает независимые задачи на параллельные потоки с изоляцией через git worktrees (отдельные рабочие копии репозитория).',
|
||
'При нескольких независимых рабочих фронтах одновременно (CTO-задача + Plan-задача + audit-fix).',
|
||
'Изоляция через worktree обязательна — никакого «работаю в одной директории на 3 ветках сразу». Иначе риск конфликта файлов и веток.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'скил worktree', cond: 'parallel-work использует worktree для изоляции' }],
|
||
[{ name: 'MCP-сервер playwright', desc: 'Профили per-cwd hash (квирк #95) → worktrees получают разные mcp-chrome-{hash} директории, не конфликтуют. Same-dir parallel — редкий runtime, регулируется Pravila §15.2 claim', type: 'GREEN' }]
|
||
),
|
||
sk_worktree: nd(
|
||
'Создаёт изолированную копию репозитория (worktree) для рискованной или параллельной работы.',
|
||
'При параллельной работе нескольких задач или при рискованной работе (рефакторинг с возможным откатом, ветка экспериментов).',
|
||
'Очистка через ExitWorktree обязательна. Не оставлять забытые worktree — захламляют файловую систему.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'скил parallel-work', cond: 'worktree — инструмент для parallel-work' }]
|
||
),
|
||
sk_pr: nd(
|
||
'Чеклист финальной готовности PR (запроса на слияние кода): тесты, документация, чистота кода, проверки перед push.',
|
||
'Перед `gh pr create` или `git push` в общую ветку — обязательная проверка готовности.',
|
||
'Проверки перед push (job gitleaks в lefthook по всей истории + job lychee) — не обходить через `--no-verify`. Pravila §4.2.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'MCP-сервер github', cond: 'создаёт PR (запрос на слияние кода) через GitHub' }, { name: 'lefthook (job-набор перед push)', cond: 'запускает job gitleaks + job lychee' }]
|
||
),
|
||
sk_subagent: nd(
|
||
'Запускает суб-агентов для крупных задач — каждый в отдельном контексте без накопленного шума.',
|
||
'При выполнении плана в той же сессии ИЛИ при делегировании поиска/анализа большого объёма.',
|
||
'Суб-агент в режиме экономии 0%: запрашивать полный сырой вывод, а не сводку — решения принимать самому.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }],
|
||
[
|
||
{ name: 'агент Explore', cond: 'запускает для поиска по кодовой базе' },
|
||
{ name: 'агент general-purpose', cond: 'запускает для сложных задач' },
|
||
{ name: 'агент Plan', cond: 'запускает для архитектурного планирования' }
|
||
],
|
||
[{ name: 'скил writing-plans', cond: 'subagent-driven — основной способ выполнения планов' }]
|
||
),
|
||
sk_wskills: nd(
|
||
'Создаёт новые скилы по стандартному шаблону: файл SKILL.md, заголовочный блок (frontmatter), описание процесса.',
|
||
'При формализации повторяющегося процесса в переиспользуемый скил (после 2-3 примеров одинаковой работы).',
|
||
'Шаблон SKILL.md, заголовочный блок (name, description, when_to_use, allowed-tools), описание процесса с DOT-диаграммой.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'агент plugin-dev:skill-reviewer', cond: 'агент проверяет созданный скил' }]
|
||
),
|
||
sk_spreview: nd(
|
||
'Проверяет документ-спецификацию на полноту, противоречия, заглушки и объём работ.',
|
||
'После скила writing-plans на отдельном этапе ДО реализации — для крупных планов с несколькими задачами.',
|
||
'Самопроверка прямо в скиле brainstorming достаточна для небольшой спецификации; для крупных — отдельный запуск этого скила.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'скил brainstorming', cond: 'spec-review вызывается в конце brainstorming после записи спека' }]
|
||
),
|
||
sk_coderev: nd(
|
||
'Систематический разбор кода — безопасность, тесты, архитектура, соответствие правилам.',
|
||
'Перед слиянием PR (запроса на слияние кода); после крупной серии коммитов; при подготовке к релизу; при подозрении на регрессию (возврат к старому багу).',
|
||
'Без выборочности: разбор всех изменений, а не только подозрительных. SAST (статический анализ кода на уязвимости, через MCP-сервер semgrep) включается обязательно.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[{ name: 'MCP-сервер semgrep', cond: 'SAST-проверка при ревью кода' }]
|
||
),
|
||
sk_elements: nd(
|
||
'Улучшает написание текстов и документации — ясность, лаконичность, без воды.',
|
||
'При написании спецификации/плана/CHANGELOG/описания PR (запроса на слияние кода) — для общения с командой.',
|
||
'Без воды. Без «легко», «просто», «всего лишь». Каждое утверждение измеримо.',
|
||
[{ name: 'плагин Superpowers', cond: 'содержит' }],
|
||
[],
|
||
[]
|
||
),
|
||
|
||
// ── СКИЛЫ ПРОЕКТА ────────────────────────────────
|
||
sk_rls: nd(
|
||
'7-шаговый чеклист RLS (защита строк по тенанту) для новой таблицы: tenant_id, ENABLE RLS (включение защиты строк), политики, права для 5 ролей, CHANGELOG, проверка через squawk, дымовой тест (быстрая проверка функциональности).',
|
||
'При создании новой таблицы в db/schema.sql ИЛИ при правках существующих политик RLS (защиты строк по тенанту).',
|
||
'Права для 5 ролей обязательны (crm_app_user / crm_app_admin / crm_supplier_worker BYPASSRLS (право обходить защиту строк — для системных задач) / crm_readonly / crm_migrator). Запись в CHANGELOG_schema.md обязательна.',
|
||
[{ name: 'Tooling §3.2', cond: 'использует squawk (#15) и команды grep' }],
|
||
[],
|
||
[{ name: 'MCP-сервер laravel-boost', cond: 'SQL запросы к schema.sql для проверки' }],
|
||
[{ name: 'агент rls-reviewer', desc: 'граница задана регламентом (spec 2026-05-16): скил — ручная проверка одной названной таблицы + живой дымовой тест; агент — разбор diff/ветки/PR. См. секцию «Граница с агентом rls-reviewer» в SKILL.md.', type: 'GREEN' }]
|
||
),
|
||
sk_qitem: nd(
|
||
'Добавляет новый открытый вопрос в реестр Открытые_вопросы_v8_3.md с обновлением счётчиков §0 и версии.',
|
||
'При появлении нового открытого вопроса (Биз-/CTO-/Ю-/Диз-/DO-/OPEN-) — формальная запись в реестр.',
|
||
'Категория (Биз-/CTO-/...) обязательна. Связанные документы (CLAUDE.md/Pravila/PSR_v1/Tooling) — синхронизируются.',
|
||
[],
|
||
[],
|
||
[{ name: 'плагин claude-md-management', cond: 'скил делегирует правку CLAUDE.md через плагин (правило §5п.10 в нормативке)' }]
|
||
),
|
||
|
||
// ── ХУКИ ─────────────────────────────────────────
|
||
hk_pre_claude: nd(
|
||
'Блокирует прямое редактирование CLAUDE.md — срабатывает на Edit/Write по этому файлу.',
|
||
'PreToolUse (перед каждым вызовом инструмента) — перед каждым Edit/Write, фильтр путей нацелен на CLAUDE.md.',
|
||
'Обход запрещён. Единственный способ редактировать — плагин claude-md-management (правило §5п.10 в нормативке).',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук PreToolUse' }],
|
||
[],
|
||
[],
|
||
[{ name: 'плагин hookify', desc: 'плагин hookify динамически создаёт новые хуки PreToolUse — может перезаписать или конкурировать с этим хуком', type: 'RED' }]
|
||
),
|
||
hk_post_md: nd(
|
||
'После каждого Edit .md-файла запускает markdownlint --fix автоматически.',
|
||
'PostToolUse (после каждого вызова инструмента) — после Edit/Write на *.md (кроме корневого CLAUDE.md, чтобы не зациклить).',
|
||
'Не правит CLAUDE.md (исключён из фильтра путей). При неисправимой ошибке (например, битая ссылка) — предупреждение, не блокировка.',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук PostToolUse' }],
|
||
[],
|
||
[{ name: 'job markdownlint в lefthook', cond: 'дублируют задачу: хук — в сессии, lefthook — при коммите' }]
|
||
),
|
||
hk_post_schema: nd(
|
||
'После правки db/schema.sql напоминает обновить db/CHANGELOG_schema.md.',
|
||
'PostToolUse (после каждого вызова инструмента) — после Edit/Write на `db/schema.sql`.',
|
||
'Напоминание, не блокировка. Дисциплина ведения CHANGELOG_schema — на разработчике (§4.2 Pravila).',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук PostToolUse' }],
|
||
[],
|
||
[{ name: 'job squawk в lefthook', cond: 'оба реагируют на изменения SQL' }]
|
||
),
|
||
hk_session: nd(
|
||
'При старте каждой сессии подгружает CLAUDE.md, Pravila и ключевые memory-файлы в контекст.',
|
||
'SessionStart (при старте сессии) — единожды при инициализации сессии Claude Code.',
|
||
'Список memory-файлов фиксированный — для расширения править настройку хука. Не читает 80+ квирков целиком — выборочно по релевантности.',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук SessionStart' }],
|
||
[
|
||
{ name: 'память user_profile', cond: 'читает' },
|
||
{ name: 'память feedback_environment', cond: 'читает' },
|
||
{ name: 'память project_state', cond: 'читает' },
|
||
{ name: 'память feedback_superpowers_hard_rule', cond: 'читает' },
|
||
{ name: 'память feedback_plugin_paired_stack', cond: 'читает' }
|
||
],
|
||
[]
|
||
),
|
||
hk_economy: nd(
|
||
'Перед каждым промптом разбирает «экономия X%» и выставляет режим строгости (0% = максимальное качество, 100% = по умолчанию).',
|
||
'UserPromptSubmit (перед отправкой промпта пользователя) — ищет шаблон /экономия\\s*(\\d+)%/.',
|
||
'§12 Superpowers — hard-rule уровня 0, economy-режим §12 НЕ отменяет ни на каком уровне. Действует только на текущую задачу — следующий промпт разбирается заново.',
|
||
[{ name: '.claude/settings.json', cond: 'описан как хук UserPromptSubmit' }],
|
||
[],
|
||
[],
|
||
[{ name: 'плагин Superpowers (§12)', desc: 'Экономия=100% теоретически может «сэкономить» вызов скила — §12 (hard-rule уровня 0) economy-режим не отменяет ни на каком уровне (Pravila §12.4).', type: 'GREEN' }]
|
||
),
|
||
|
||
// ── АГЕНТЫ ───────────────────────────────────────
|
||
ag_pest: nd(
|
||
'Разбирает падения тестов Pest --parallel: отличает настоящую ошибку от известных квирков (73/77 и др.; квирк 72 устранён 16.05.2026 — commit 0fa1a73).',
|
||
'При падении Pest --parallel ИЛИ при дымовом тесте (быстрой проверке функциональности) только из подкаталога (как в аудите Phase 3 SyncSupplierProjectsJobTest).',
|
||
'READ-ONLY (только чтение — только читает код, ничего не правит). Каждую гипотезу подтверждает реальным запуском, а не «похоже на квирк».',
|
||
[{ name: 'CLAUDE.md §6', cond: 'описывает когда вызывать' }],
|
||
[],
|
||
[{ name: 'MCP-сервер redis', cond: 'читает Redis для отладки квирка 72 (гонка supplier:session)' }],
|
||
[
|
||
{ name: 'MCP-сервер redis', desc: 'Квирк 72 (гонка с кэшем Redis при Pest --parallel из подкаталога) устранён 16.05.2026 — commit 0fa1a73, array-стор в тестах. Конфликт закрыт.', type: 'GREEN' },
|
||
{ name: 'демон ruflo', desc: 'Worker-jitter фонового демона ruflo (PM2) усиливает частоту Pest-квирков 73/77. Квирк 72 устранён 16.05 — его jitter больше не усиливает. На baseline-регрессии — `pm2 stop ruflo-daemon` (квирк #93, переоценён).', type: 'BLACK' }
|
||
]
|
||
),
|
||
ag_rls: nd(
|
||
'Проверяет миграции на соответствие RLS (защите строк по тенанту) — 7 пунктов чеклиста с реальными командами, только чтение.',
|
||
'При создании/правке миграции в db/migrations/ ИЛИ при правке db/schema.sql ИЛИ при ревью PR (запроса на слияние кода) с изменениями БД.',
|
||
'READ-ONLY (только чтение — только Read/Grep/Glob/Bash) — код не пишет. Не замена скилу rls-check — у них разные сценарии.',
|
||
[{ name: 'CLAUDE.md', cond: 'описывает в §6 и в директории агентов' }],
|
||
[],
|
||
[{ name: 'MCP-сервер laravel-boost', cond: 'SQL запросы к db/schema.sql' }],
|
||
[{ name: 'скил rls-check', desc: 'граница задана регламентом (spec 2026-05-16): агент — разбор diff/ветки/PR со статическим 7-пунктовым чеклистом; скил — ручная проверка одной названной таблицы + живой дымовой тест. См. секцию «Граница со скилом /rls-check» в rls-reviewer.md.', type: 'GREEN' }]
|
||
),
|
||
ag_statusline: nd(
|
||
'Настраивает строку состояния Claude Code через правку файла настроек.',
|
||
'При запросе пользователя «настрой строку состояния» — редкая разовая задача.',
|
||
'Правит только секцию statusline в settings.json, другие части файла не трогает.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
ag_guide: nd(
|
||
'Отвечает на вопросы про API Claude Code, SDK, MCP-серверы (внешние сервисы-инструменты Claude), хуки, slash-команды.',
|
||
'При вопросе про возможности Claude Code/SDK/API — «Can Claude...», «How do I...», «Does Claude...».',
|
||
'READ-ONLY (только чтение): ищет в документации, код не правит. Не для отладки кода — только вопросы о платформе.',
|
||
[],
|
||
[],
|
||
[{ name: 'MCP-сервер github', cond: 'при необходимости ищет примеры в репозитории' }]
|
||
),
|
||
ag_explore: nd(
|
||
'Быстрый поиск файлов по шаблону имени или по символу — только чтение, без анализа.',
|
||
'При точечном поиске — найти файл по имени или сделать grep по символу/ключевому слову.',
|
||
'Не для свободного исследования. Не для ревью/аудита (читает отрывки, теряет контекст за пределами окна чтения).',
|
||
[{ name: 'скил subagent-driven-development', cond: 'запускается для задач поиска' }],
|
||
[],
|
||
[]
|
||
),
|
||
ag_general: nd(
|
||
'Универсальный агент для сложных многошаговых исследований — с полным набором инструментов.',
|
||
'При сложных многошаговых задачах исследования или написания кода, когда агента Explore не хватает (нужен анализ, не только поиск).',
|
||
'Полный набор инструментов — может писать код. Дороже Explore по токенам.',
|
||
[{ name: 'скил subagent-driven-development', cond: 'запускается для основных задач' }],
|
||
[],
|
||
[]
|
||
),
|
||
ag_plan: nd(
|
||
'Архитектор: разрабатывает планы реализации, находит критичные файлы, разбирает компромиссы.',
|
||
'При архитектурном планировании задачи из нескольких компонентов (не для мелкого рефакторинга).',
|
||
'READ-ONLY (только чтение — без Edit/Write/NotebookEdit). Возвращает план, сам его не реализует.',
|
||
[{ name: 'скил subagent-driven-development', cond: 'запускается для архитектурных задач' }],
|
||
[],
|
||
[{ name: 'скил writing-plans', cond: 'агент Plan и скил writing-plans решают похожую задачу в разных контекстах' }]
|
||
),
|
||
ag_hookify: nd(
|
||
'Разбирает транскрипты диалогов и ищет поведение, которое стоит предотвратить хуком.',
|
||
'При триггере /hookify без аргументов ИЛИ при запросе «look back at this conversation, what mistakes to prevent».',
|
||
'READ-ONLY (только чтение — только Read+Grep). Рекомендует хуки, сам их не создаёт — передаёт в плагин hookify.',
|
||
[],
|
||
[],
|
||
[{ name: 'плагин hookify', cond: 'агент передаёт рекомендации в плагин' }]
|
||
),
|
||
ag_pcreator: nd(
|
||
'Создаёт настройку новых агентов по описанию от пользователя.',
|
||
'При запросе «create an agent that...» — генерация agent.md по описанию функциональности.',
|
||
'Только инструменты Write/Read. Созданного агента сам не проверяет — передаёт в агент plugin-validator.',
|
||
[],
|
||
[],
|
||
[{ name: 'агент plugin-dev:plugin-validator', cond: 'валидатор проверяет созданного агента' }]
|
||
),
|
||
ag_pvalid: nd(
|
||
'Проверяет структуру плагина на корректность — plugin.json, инструменты, манифест.',
|
||
'После создания/правки plugin.json или компонентов плагина — превентивная проверка.',
|
||
'READ-ONLY (только чтение — Read/Grep/Glob/Bash). Сам не правит — выдаёт список нарушений.',
|
||
[],
|
||
[],
|
||
[{ name: 'агент plugin-dev:agent-creator', cond: 'валидатор и создатель работают в паре' }]
|
||
),
|
||
ag_skreview: nd(
|
||
'Оценивает качество написанного скила — описание, ход работы, примеры, лучшие практики.',
|
||
'После создания/правки скила через скил writing-skills — превентивное ревью.',
|
||
'READ-ONLY (только чтение — Read/Grep/Glob). Не правит — выдаёт рекомендации.',
|
||
[],
|
||
[],
|
||
[{ name: 'скил writing-skills', cond: 'skill-reviewer проверяет то, что создал writing-skills' }]
|
||
),
|
||
|
||
// ── MCP-СЕРВЕРЫ ──────────────────────────────────
|
||
mcp_pw: nd(
|
||
'Управляет браузером — снимает скриншоты, кликает, заполняет формы для smoke- и a11y-тестов.',
|
||
'При визуальной проверке прототипов (фаза 0), при a11y smoke (axe-core), при UI integration smoke.',
|
||
'Не для боевых пользователей. Профиль persistent кэшируется per-cwd hash (квирк #95 в memory) → разные worktrees получают разные mcp-chrome-{hash} директории и не конфликтуют. Конфликт остаётся только при same-dir parallel (две Claude-сессии в одной dir одновременно вызывают browser).',
|
||
[{ name: 'CLAUDE.md §3.1 #2', cond: 'активен с фазы 0' }],
|
||
[],
|
||
[{ name: 'SessionStart хук', cond: 'используется для визуальной проверки прототипов' }],
|
||
[{ name: 'parallel-work скил', desc: 'Профили per-cwd hash → worktrees не конфликтуют (квирк #95). Same-dir parallel регулируется Pravila §15.2 claim в CURRENT.md', type: 'GREEN' }]
|
||
),
|
||
mcp_gh: nd(
|
||
'GitHub API — читает/создаёт PR, issues, коммиты, ветки в репозитории CoralMinister/lidpotok.',
|
||
'При работе с PR/issues, при поиске в репозитории, при создании PR через скил finishing-pr.',
|
||
'Не делать push в main без явного одобрения. Pravila §4: атомарные коммиты, не объединять их через MCP.',
|
||
[{ name: 'CLAUDE.md §3.1 #3', cond: 'активен с фазы 0' }],
|
||
[],
|
||
[{ name: 'finishing-pr скил', cond: 'создаёт PR через этот MCP' }]
|
||
),
|
||
mcp_boost: nd(
|
||
'Laravel Boost — SQL-запросы к dev-БД, схема таблиц, журналы ошибок, поиск по документации Laravel.',
|
||
'С первой фазы (старт backend) и далее — при SQL-запросах, поиске в документации Laravel, работе с моделями Eloquent.',
|
||
'**READ-ONLY к prod** — `.env.production` не должен попадать в локальный конфиг. Не использовать правила-подсказки Inertia/Livewire/Tailwind/Filament.',
|
||
[{ name: 'CLAUDE.md §3.2 #10', cond: 'активен с фазы 1, доступ к prod только на чтение' }],
|
||
[],
|
||
[{ name: 'ag_rls агент', cond: 'rls-reviewer использует Boost для SQL' }, { name: 'sk_rls скил', cond: 'rls-check использует Boost' }]
|
||
),
|
||
mcp_semgrep: nd(
|
||
'SAST (статический анализ кода на уязвимости) — ищет уязвимости, XSS (внедрение JS), SQLi (внедрение SQL), нарушения правил по шаблонам.',
|
||
'На третьей фазе проекта (перед запуском в боевую среду) — при просмотре кода через скил code-review и при автозапуске проверок CI (continuous integration) перед выпуском новой версии.',
|
||
'Настройка в .semgrep.yml. Ложные срабатывания документируются прямо в коде.',
|
||
[{ name: 'CLAUDE.md §3.4 #25', cond: 'третья фаза — перед запуском в боевую среду' }],
|
||
[],
|
||
[{ name: 'скил code-review', cond: 'MCP-сервер semgrep используется при разборе кода' }]
|
||
),
|
||
mcp_sentry: nd(
|
||
'Читает ошибки из self-hosted Sentry в Yandex Cloud — события, стектрейсы, метрики. READ-ONLY (только чтение).',
|
||
'При расследовании ошибок боевой среды во время работы (после развёртывания Б-1).',
|
||
'**READ-ONLY** (org:read/project:read/event:read). Ждёт развёртывания инстанса Sentry по Б-1 (зависит от регистрации ООО).',
|
||
[{ name: 'CLAUDE.md §3.3 #34', cond: 'вне основных фаз (для отладки во время работы); ждёт развёртывания Sentry по Б-1' }],
|
||
[],
|
||
[]
|
||
),
|
||
mcp_redis: nd(
|
||
'Читает Redis/Memurai — ключи, очереди, кэш для отладки гонок (race conditions). СТРОГО READ-ONLY.',
|
||
'При отладке очередей Redis (Pest --parallel квирки 73/77), при анализе инвалидации кэша.',
|
||
'**СТРОГО READ-ONLY** — никаких DEL/FLUSHDB/SET/LPUSH из Claude (только GET/KEYS/LIST). Источник Anthropic устарел — миграция post-MVP.',
|
||
[{ name: 'CLAUDE.md §3.3 #35', cond: 'вне основных фаз (для отладки во время работы); PSR_v1 R10.1 блок 3' }],
|
||
[],
|
||
[{ name: 'pest-parallel-debugger агент', cond: 'агент использует для квирка 72 (гонка в Redis)' }],
|
||
[{ name: 'агент pest-parallel-debugger', desc: 'Квирк 72 (гонка с кэшем Redis при Pest --parallel из подкаталога) устранён 16.05.2026 — commit 0fa1a73. Конфликт закрыт.', type: 'GREEN' }]
|
||
),
|
||
mcp_21st: nd(
|
||
'Генератор стартовых шаблонов UI-компонентов через LLM. Активация только через процедуру R14.4.',
|
||
'Только через процедуру PSR_v1 R14.4: предпроверка из 9 условий (брендовый App*? есть аналог в Vuetify? есть уже существующий компонент?).',
|
||
'R14.5: не запускать параллельно с FD/UPM. Обязательны: JSX→Vue, Tailwind→utility, shadcn→Vuetify. Pa11y a11y на готовом виде.',
|
||
[{ name: 'PSR_v1 R14.4', cond: 'строгая предпроверка: 9 условий перед активацией' }],
|
||
[],
|
||
[],
|
||
[{ name: 'Frontend Design', desc: 'PSR_v1 R14.5: нельзя параллельно — 21st как генератор материала, FD как решатель; риск смешать роли и нарушить R6 (фильтр стека)', type: 'GREEN' }]
|
||
),
|
||
|
||
// ── LEFTHOOK JOBS ─────────────────────────────────
|
||
lh_gitleaks: nd(
|
||
'Ищет ПДн (персональные данные), токены и API-ключи в файлах, готовых к коммиту. Если находит — коммит блокируется.',
|
||
'Перед каждым коммитом — проверяет только те файлы, что добавлены через `git add`.',
|
||
'Обход через `--no-verify` запрещён (правило §4.2 Pravila). Находка = блокирующая ошибка, не предупреждение. Известные ложные срабатывания — в файл `.gitleaksignore`.',
|
||
[{ name: 'lefthook.yml', cond: 'задача №1 в наборе перед коммитом, без параллельного запуска' }],
|
||
[],
|
||
[{ name: 'lefthook:gitleaks pre-push', cond: 'версия для push сканирует всю историю' }]
|
||
),
|
||
lh_mdlint: nd(
|
||
'Проверяет и авто-исправляет стиль файлов Markdown перед коммитом.',
|
||
'Перед каждым коммитом, когда в нём есть файлы `.md`.',
|
||
'Настройки в `.markdownlint-cli2.cjs`. Авто-исправление включено (исправленные файлы авто-сохраняются обратно в коммит).',
|
||
[{ name: 'lefthook.yml', cond: 'задача №2 в наборе перед коммитом' }],
|
||
[],
|
||
[{ name: 'PostToolUse:markdownlint-fix хук', cond: 'делают одно и то же — хук сразу после правки, lefthook при коммите' }]
|
||
),
|
||
lh_cspell: nd(
|
||
'Проверяет орфографию в `.md` файлах по словарю `cspell-words.txt`.',
|
||
'Перед каждым коммитом, когда в нём есть файлы `.md`.',
|
||
'Словарь: `cspell-words.txt`. Кириллица — в нижнем регистре. Не обходить через `--no-verify` — добавлять валидные слова в словарь.',
|
||
[{ name: 'lefthook.yml', cond: 'задача №3 в наборе перед коммитом' }],
|
||
[],
|
||
[]
|
||
),
|
||
lh_stylelint: nd(
|
||
'Линтует CSS в HTML-прототипах (`web/v8/*.html`).',
|
||
'Перед каждым коммитом, когда в нём есть файлы `.html`/`.css`.',
|
||
'Настройки Stylelint в `.stylelintrc`. Устаревшие свойства (например `word-break: break-word`) блокируют коммит.',
|
||
[{ name: 'lefthook.yml', cond: 'задача №4 в наборе перед коммитом' }],
|
||
[],
|
||
[]
|
||
),
|
||
lh_pint: nd(
|
||
'Авто-форматирует код PHP по PSR-стандарту (стиль кода PHP). Исправленные файлы авто-сохраняются обратно в коммит.',
|
||
'Перед каждым коммитом — на каждый файл `.php` в директории `app/`.',
|
||
'Авто-исправление включено. Настройки в `app/pint.json`.',
|
||
[{ name: 'lefthook.yml', cond: 'задача №5 в наборе перед коммитом, корень `app/`' }],
|
||
[],
|
||
[]
|
||
),
|
||
lh_larastan: nd(
|
||
'Статический анализ PHP (Larastan, уровень L9) — находит ошибки типов выше базового уровня.',
|
||
'Перед каждым коммитом, когда в нём есть файлы `.php` в `app/`.',
|
||
'Базовый уровень `phpstan-baseline.neon` зафиксирован — новые ошибки блокируют коммит. Не повышать базовый уровень без обоснования.',
|
||
[{ name: 'lefthook.yml', cond: 'задача №6 в наборе перед коммитом, корень `app/`' }],
|
||
[],
|
||
[{ name: 'MCP: laravel-boost', cond: 'Boost даёт контекст типов через IDE-подсказки' }]
|
||
),
|
||
lh_squawk: nd(
|
||
'Линтер SQL-миграций — проверяет безопасные шаблоны (без блокировки таблиц, параллельный CREATE INDEX и т.п.).',
|
||
'Перед каждым коммитом, когда в нём есть файлы миграций (`database/migrations/*.php` или `db/*.sql`).',
|
||
'Настройки в `squawk.toml`. Небезопасные миграции (`ALTER TABLE ADD COLUMN NOT NULL DEFAULT`) запрещены без явной метки `-- squawk-ignore`.',
|
||
[{ name: 'lefthook.yml', cond: 'задача №7 в наборе перед коммитом, фильтр путей `*.sql`' }],
|
||
[],
|
||
[{ name: 'Tooling #15 squawk', cond: 'соответствует записи §3.2 в Tooling' }]
|
||
),
|
||
lh_eslint: nd(
|
||
'Линтует файлы Vue/TypeScript в `app/resources/js/`.',
|
||
'Перед каждым коммитом, когда в нём есть файлы `.vue`/`.ts`/`.tsx` в `app/`.',
|
||
'Flat-config ESLint 10 + plugin-vue 10. Обход через `--no-verify` запрещён. Ошибки блокируют коммит, предупреждения допустимы.',
|
||
[{ name: 'lefthook.yml', cond: 'задача №8 в наборе перед коммитом, корень `app/`' }],
|
||
[],
|
||
[]
|
||
),
|
||
lh_gitleaks2: nd(
|
||
'Полный скан всей истории коммитов на секреты — строже задачи перед коммитом.',
|
||
'pre-push (перед `git push` на удалённый репозиторий) — сканирует историю новых коммитов целиком.',
|
||
'Обход через `--no-verify` запрещён (правило §4.2 Pravila). На больших push (200+ коммитов) занимает 30+ секунд.',
|
||
[{ name: 'lefthook.yml', cond: 'задача в наборе перед push' }],
|
||
[],
|
||
[{ name: 'lefthook:gitleaks', cond: 'версия для push строже: проверяет всю историю, а не только staged' }]
|
||
),
|
||
lh_lychee: nd(
|
||
'Проверяет все ссылки в `.md` файлах на битые (`docs/**/*.md`, `db/**/*.md`, корневые `*.md`).',
|
||
'pre-push (перед `git push`) — проверяет ссылки во всех `.md` файлах репозитория.',
|
||
'Внешние ссылки проверяются с таймаутом 10 секунд; при отсутствии интернета — ошибка. Настройки в `lychee.toml`. Обход через `--no-verify` запрещён.',
|
||
[{ name: 'lefthook.yml', cond: 'задача в наборе перед push' }],
|
||
[],
|
||
[{ name: 'CLAUDE.md', cond: 'проверяет ссылки в CLAUDE.md в том числе' }]
|
||
),
|
||
|
||
// ── MEMORY FILES ─────────────────────────────────
|
||
mem_user: nd(
|
||
'Профиль заказчика: Дмитрий, Windows Server 2022, VSCode, русский язык, путь к проекту.',
|
||
'Читается при старте каждой сессии через хук SessionStart — для языка и предпочтений.',
|
||
'Не содержит секретов. При смене заказчика — переписать полностью.',
|
||
[],
|
||
[],
|
||
[{ name: 'SessionStart хук', cond: 'читается при старте каждой сессии' }]
|
||
),
|
||
mem_comm: nd(
|
||
'Стиль общения: короткие команды («а», «б», «делай»), варианты A/B/C, явная фиксация переоткрытий.',
|
||
'Читается при работе с заказчиком — чтобы соответствовать его стилю общения.',
|
||
'Это не код, а правила коммуникации. Корректировки — только через явный отзыв заказчика.',
|
||
[],
|
||
[],
|
||
[{ name: 'memory:user_profile', cond: 'дополняет профиль заказчика' }]
|
||
),
|
||
mem_env: nd(
|
||
'80+ квирков (особенностей) окружения: специфика Windows Server, баги инструментов, обходные пути.',
|
||
'При неожиданном поведении — сначала проверить memory:env на известный квирк.',
|
||
'Не дублировать — добавлять только новые квирки. Счётчик квирков актуализируется в `project_state.md`.',
|
||
[],
|
||
[],
|
||
[
|
||
{ name: 'pest-parallel-debugger агент', cond: 'квирки 73/77 используются агентом' },
|
||
{ name: 'SessionStart хук', cond: 'читается при старте' }
|
||
]
|
||
),
|
||
mem_sp: nd(
|
||
'Правило §12 (hard-rule уровня 0) + архитектура хука economy из 6 компонентов — дисциплина вызова скилов.',
|
||
'При работе со скилами — для соответствия обязательному правилу §12 Pravila.',
|
||
'Описывает архитектуру хука economy (6 компонентов) — менять только при изменении самого хука.',
|
||
[],
|
||
[],
|
||
[{ name: 'economy-mode хук', cond: 'memory описывает архитектуру хука' }]
|
||
),
|
||
mem_plugins: nd(
|
||
'Правила парного стека плагинов, MCP-серверы для отладки, уровневая структура PSR_v1.',
|
||
'При работе с плагинами FD/UPM/21st/Sentry/Redis MCP — для уровневого разделения по PSR_v1.',
|
||
'Синхронизируется с PSR_v1 — изменения в memory только если изменился сам PSR_v1.',
|
||
[],
|
||
[],
|
||
[{ name: 'PSR_v1', cond: 'memory отражает актуальные версии PSR_v1' }]
|
||
),
|
||
mem_state: nd(
|
||
'Текущее состояние проекта: ветка, тесты (Pest/Vitest), последние коммиты, активные задачи.',
|
||
'Читается при старте сессии — для быстрого контекста; обновляется после крупных вех.',
|
||
'Может устаревать — перечитать при сомнении. Не доверять данным старше 2-3 дней без проверки.',
|
||
[],
|
||
[],
|
||
[{ name: 'SessionStart хук', cond: 'читается при старте для быстрого контекста' }],
|
||
[{ name: 'память ruflo', desc: 'Два хранилища памяти не синхронизированы: проектные `memory/*.md` (16 файлов) и база ruflo `.swarm/memory.db`. Фактически память ruflo почти пуста — MCP-сервер репортит 0 записей (+2 тестовых призрака от alpha-бага HNSW #1122). Recall-хук срабатывает на каждый промпт, но извлекать ему почти нечего.', type: 'BLACK' }]
|
||
),
|
||
mem_phase1: nd(
|
||
'Стратегия фазы 1: нативный стек Windows без Docker, расширение pg_partman заменено Artisan-задачей в cron.',
|
||
'При работе с инфраструктурой фазы 1 (PG/Redis/PHP-CLI нативно на Windows).',
|
||
'Стратегия зафиксирована до закрытия блокера Б-1 (Managed PG в Yandex Cloud) или 6 месяцев — пересмотр указан в файле.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_archive: nd(
|
||
'Карта источников истины: версии всех 13+ ключевых документов проекта.',
|
||
'При вопросах «какая версия документа X» или «где источник истины для Y».',
|
||
'Синхронизируется с §0 CLAUDE.md. Изменения в memory — только если изменился §0 CLAUDE.md.',
|
||
[],
|
||
[],
|
||
[{ name: 'CLAUDE.md', cond: 'memory синхронизирует версии с §0 CLAUDE.md' }]
|
||
),
|
||
mem_github: nd(
|
||
'Репозиторий GitHub CoralMinister/lidpotok: HEAD, хуки, правила push.',
|
||
'При работе с GitHub — push, PR, операции с ветками.',
|
||
'Не делать `push --force` на main (предупреждение в Pravila). Хуки перед push обязательны.',
|
||
[],
|
||
[],
|
||
[{ name: 'MCP: github', cond: 'MCP и memory дополняют друг друга для работы с GitHub' }]
|
||
),
|
||
mem_handoff: nd(
|
||
'Дизайн-передача от Платона: что из `liderra_v8_handoff/` используем, что нет.',
|
||
'При UI/дизайн-задачах — для разделения «брендбук используем» vs «состав фич — по ТЗ v8.5».',
|
||
'Передача — только дизайн/токены/компоненты. Функционал и состав экранов — НЕ из передачи (берём из ТЗ).',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_audit: nd(
|
||
'Полный аудит портала 13.05.2026: 38 находок, вердикт жёлтый, 10 отложенных вопросов закрыты.',
|
||
'При вопросах про аудит или его последствия (Q.DEFER, распределение P0/P1/P2).',
|
||
'Это снимок состояния — не редактировать при последующих аудитах, создавать новые memory-файлы.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_supplier: nd(
|
||
'Прогресс интеграции с поставщиком лидов (планы 1-5): задачи, коммиты, блокеры.',
|
||
'При работе с интеграцией поставщика (планы 1-5) — для текущего состояния и блокеров.',
|
||
'Блокеры (Б-1, доступы) — внешние, не разрешаются силами Claude. Только отслеживание.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_brain: nd(
|
||
'Claude Brain v1.0 — отдельный репозиторий «мозга», тег `brain-v1.0`, скрипт `install.sh`.',
|
||
'При работе с репозиторием brain или скриптом `install.sh` для синхронизации потребителей.',
|
||
'Push на репозиторий brain в GitHub заблокирован (вопрос 8.2). Не пытаться push без разрешения.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_redesign: nd(
|
||
'Редизайн Quiet Luxury: 20 коммитов, базовый CSS + composables + переписанный AppSidebar.',
|
||
'При работе с редизайном портала (frontend, AppSidebar, базовый CSS).',
|
||
'Бэклог итерации I2 — в §15 спека, 10 пунктов отложены. Не реализовывать пункты I2 без явного запроса.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
mem_devindices: nd(
|
||
'Dev Element Indices — временная фича обратной связи для разработки; к удалению в продакшене.',
|
||
'При работе с dev-фидбеком (например «1030 измени цвет») — для соответствия номер → элемент.',
|
||
'**ВРЕМЕННАЯ** — заказчик прямо сказал «уберём в конечном релизе». Не вкладываться в долгосрочную инфраструктуру.',
|
||
[],
|
||
[],
|
||
[]
|
||
),
|
||
|
||
// ── RUFLO ОРКЕСТРАТОР (фактический реколлаж iter5) ──
|
||
ruflo_queen: nd(
|
||
'Queen оркестратора ruflo v3.7.0-alpha.38 — стратегическая «королева» роя hive-mind (топология hierarchical-mesh, консенсус byzantine). С реколлажа 16.05.2026 (CLAUDE.md §3.5, Tooling §4.10) — advisory/automation-подсистема, не entry-point: рой работает параллельно, Клод — напрямую.',
|
||
'Запускается только по триггеру queen/королева в промпте (Pravila §14 — hard-rule маршрутизации). Без триггера рой простаивает — Клод работает напрямую.',
|
||
'Фактическая инспекция рантайма 15.05.2026: Queen активна (term 1, нагрузка 0), но за всё время — 0 задач, 0 раундов консенсуса, 0 общей памяти. Реколлаж 16.05.2026 привёл нормативку к этому факту — ruflo переописан в advisory/automation-подсистему, декларация уровня −1 убрана. Alpha-версия, LLM API-ключей нет.',
|
||
[
|
||
{ name: 'Pravila §14', cond: 'queen-триггер — hard-rule маршрутизации задачи через Queen' },
|
||
{ name: 'CLAUDE.md §3.5 / Tooling §4.10', cond: 'нормативно описан как advisory/automation-подсистема' }
|
||
],
|
||
[
|
||
{ name: '10 воркеров hive-mind', cond: 'координирует рой — все 10 простаивают' },
|
||
{ name: 'каталог агентов ruflo', cond: 'ruflo init высыпал в .claude/agents/ — не задействовано' },
|
||
{ name: 'slash-команды ruflo', cond: 'ruflo init высыпал в .claude/commands/ — не задействовано' },
|
||
{ name: 'плагины ruflo', cond: 'установлено 0 из ~20 в реестре' }
|
||
],
|
||
[
|
||
{ name: 'memory:project_ruflo_integration', cond: 'memory-файл документирует интеграцию' },
|
||
{ name: 'ruflo MCP', cond: 'MCP-сервер экспонирует инструменты управления роем' }
|
||
],
|
||
[{ name: 'Pravila', desc: 'iter4–iter5: нормативка декларировала ruflo Queen-led routing уровнем −1 (overlord над всей иерархией) — расходилось с рантаймом (рой idle, 0 задач, 0 раундов консенсуса). Реколлаж 16.05.2026 (Pravila v1.16 / CLAUDE.md v2.2 / PSR_v1 v3.2 / Tooling v2.2) привёл нормативку к факту: ruflo переописан в advisory/automation-подсистему, уровень −1 убран. Конфликт «декларация ≠ рантайм» закрыт.', type: 'GREEN' }]
|
||
),
|
||
ruflo_workers: nd(
|
||
'Рабочие агенты роя hive-mind ruflo — 10 штук. Все одного типа (generic worker), без специализации. На карте до iter5 рисовались 9 «ролей» (Архитектор/Кодер/…) — таких ролей в рантайме не существует.',
|
||
'По задумке — Queen раздаёт воркерам подзадачи. Фактически — ни разу.',
|
||
'Инспекция рантайма 15.05.2026: 10 воркеров, все в статусе «простаивает» (idle), у каждого 0 выполненных задач. LLM API-ключей нет → реальная агентская работа невозможна. Последний рой запущен с тестовой задачей «ответь словом READY и ничего не меняй».',
|
||
[{ name: 'ruflo Queen', cond: 'подчинены — Queen-led иерархия hive-mind' }],
|
||
[],
|
||
[]
|
||
),
|
||
ruflo_daemon: nd(
|
||
'Фоновый демон ruflo под управлением PM2 (процесс `ruflo-daemon`). По расписанию запускает 5 воркеров: map (каждые 15 мин), audit (10 мин), optimize (15 мин), consolidate (30 мин), testgaps (20 мин). Переживает перезагрузку через планировщик задач Windows.',
|
||
'Работает постоянно в фоне.',
|
||
'Инспекция рантайма 15.05.2026: воркеры audit / optimize / testgaps пытаются запустить `claude` и КАЖДЫЙ РАЗ падают с ошибкой «файл не найден» (spawn claude ENOENT) — результат пустой (за сутки: audit 29 запусков, optimize 19, testgaps 14 — все пустые). Журнал демона при этом помечает их «успешными» — расхождение метрики и факта. Локально работают только воркеры map и consolidate (без вызова `claude`). Worker-jitter усиливает частоту Pest-квирков 73/77 (квирк 72 устранён 16.05) — на baseline-регрессии нужно `pm2 stop ruflo-daemon`.',
|
||
[],
|
||
[],
|
||
[{ name: 'память ruflo', cond: 'воркер consolidate обращается к хранилищу' }],
|
||
[{ name: 'агент pest-parallel-debugger', desc: 'Worker-jitter фонового демона ruflo (PM2) усиливает частоту Pest-квирков 73/77. Квирк 72 устранён 16.05 (commit 0fa1a73) — его jitter больше не усиливает. На baseline-регрессии — `pm2 stop ruflo-daemon` (квирк #93, переоценён).', type: 'BLACK' }]
|
||
),
|
||
ruflo_mcp: nd(
|
||
'MCP-сервер ruflo (внешний сервис-инструмент Клода) — отдельный процесс `ruflo mcp start`, режим stdio, 7-й сервер в `.mcp.json`. Экспонирует ~210 инструментов (агенты / память / рой / хуки / нейросеть и др.).',
|
||
'Инструменты доступны Клоду постоянно. Это единственная по-настоящему рабочая точка интеграции ruflo — через неё и собрана фактическая инспекция 15.05.2026.',
|
||
'Клод НЕ обязан вызывать ruflo-инструменты — отсюда статус ruflo как параллельной подсистемы, а не overlord. Память, опрашиваемая через MCP, почти пуста (0 записей). Alpha-версия.',
|
||
[],
|
||
[],
|
||
[
|
||
{ name: 'ruflo Queen', cond: 'экспонирует инструменты управления роем' },
|
||
{ name: 'память ruflo', cond: 'читает/пишет через инструменты memory_*' }
|
||
]
|
||
),
|
||
ruflo_memory: nd(
|
||
'Хранилище памяти ruflo — файл базы `.swarm/memory.db` (SQLite через sql.js) + векторный индекс HNSW с реальными embeddings Xenova/all-MiniLM-L6-v2 (384 измерения).',
|
||
'Должно накапливать факты между сессиями; recall-хук и MCP-инструменты обращаются к нему.',
|
||
'Инспекция рантайма 15.05.2026: MCP-сервер репортит 0 записей. В базе — 2 тестовых «призрака» (h7-fixed-verify, hook-e2e) от alpha-бага HNSW #1122 (`memory delete` убирает строку, но не вектор). Проектные `memory/*.md` (16 файлов) в неё не проиндексированы. Наполняется только вручную через `ruflo memory store`.',
|
||
[],
|
||
[],
|
||
[
|
||
{ name: 'ruflo MCP', cond: 'MCP читает/пишет через инструменты memory_*' },
|
||
{ name: 'хук recall', cond: 'recall-хук запускает поиск по памяти' },
|
||
{ name: 'демон ruflo', cond: 'воркер consolidate обращается к памяти' }
|
||
],
|
||
[{ name: 'memory:project_state', desc: 'Два хранилища памяти не синхронизированы: проектные `memory/*.md` (16 файлов) и база ruflo `.swarm/memory.db`. Фактически память ruflo почти пуста — MCP-сервер репортит 0 записей (+2 тестовых призрака от alpha-бага HNSW #1122). Recall-хук срабатывает на каждый промпт, но извлекать ему почти нечего.', type: 'BLACK' }]
|
||
),
|
||
ruflo_recall_hook: nd(
|
||
'Хук типа UserPromptSubmit, зарегистрирован в `.claude/settings.json` — скрипт `tools/ruflo-recall-hook.mjs`. На каждый промпт пользователя запускает `ruflo memory search` и подмешивает топ-3 найденных записи в контекст. Единственный хук ruflo, реально вшитый в сессию Claude Code.',
|
||
'Перед каждым промптом пользователя.',
|
||
'Срабатывает «мягко» (fail-open): при ошибке/таймауте — пустой инжект, промпт не блокируется. Хук работает (виден в системных напоминаниях этой сессии), но память ruflo почти пуста — извлекать почти нечего (recall возвращает 2 тестовых призрака). У самого ruflo есть 26-27 внутренних хуков, но в `.claude/settings.json` вшит только этот один.',
|
||
[],
|
||
[],
|
||
[{ name: 'память ruflo', cond: 'запускает поиск по памяти ruflo' }]
|
||
),
|
||
ruflo_agents_catalog: nd(
|
||
'Каталог определений агентов, который `ruflo init` высыпал в `.claude/agents/` — 100 файлов в 23 категориях (core, consensus, sparc, github, v3, flow-nexus, optimization, sublinear, templates и др.). Из них 98 — от ruflo, 2 — проектные (rls-reviewer, pest-parallel-debugger).',
|
||
'Определения видны Claude Code как доступные типы суб-агентов.',
|
||
'Статичные файлы-заготовки. «ruflo использует каталог» — нет: воркеры роя безымянные generic, у демона свой набор воркеров. Каталог просто лежит.',
|
||
[{ name: 'ruflo Queen', cond: 'высыпан установкой ruflo init' }],
|
||
[],
|
||
[]
|
||
),
|
||
ruflo_commands: nd(
|
||
'Slash-команды, которые `ruflo init` высыпал в `.claude/commands/` — 88 файлов (категории sparc, github, hooks, analysis, automation, optimization, monitoring).',
|
||
'Доступны как slash-команды Claude Code.',
|
||
'Статичные файлы. Это ближайший аналог «скилов» у ruflo — но НЕ Claude Code скилы; в `.claude/skills/` ruflo не положил ничего (там только 2 проектных скила). Команды лежат, в работе проекта не задействуются.',
|
||
[{ name: 'ruflo Queen', cond: 'высыпаны установкой ruflo init' }],
|
||
[],
|
||
[]
|
||
),
|
||
ruflo_plugins: nd(
|
||
'Плагины ruflo. В IPFS-реестре оркестратора заявлено ~20 плагинов. Установлено — 0.',
|
||
'Никогда — ни один плагин не подключён.',
|
||
'Фактически: папки `.claude-flow/plugins/` не существует, ни один плагин не установлен. `ruflo plugins list` зависает на IPFS-discovery (реестр недоступен — Pinata/Cloudflare не отвечают). Отдельно: Claude Code скилов ruflo не привнёс — в `.claude/skills/` только 2 проектных (rls-check, q-item-add). Прямой ответ на вопрос «какие плагины и скилы использует ruflo»: ноль и ноль.',
|
||
[{ name: 'ruflo Queen', cond: 'часть установки ruflo' }],
|
||
[],
|
||
[]
|
||
),
|
||
mem_ruflo: nd(
|
||
'Memory-файл `project_ruflo_integration` — история ruflo big-bang (установка, нормативная инверсия, активация рантайма) и alpha-баги.',
|
||
'При работе с ruflo — для контекста интеграции и известных alpha-багов.',
|
||
'Снимок на 15.05.2026. iter5 карты опирается на фактическую инспекцию рантайма, а не только на этот файл.',
|
||
[],
|
||
[],
|
||
[{ name: 'ruflo Queen', cond: 'документирует ruflo-интеграцию' }]
|
||
),
|
||
|
||
// ── АУДИТ-АКТУАЛИЗАЦИЯ 16.05.2026 ────────────────
|
||
skill_creator: nd(
|
||
'Плагин Anthropic для создания новых скилов — eval-driven подход: датасеты сценариев, train/test split, бенчмарк-цикл.',
|
||
'При формализации повторяющегося процесса в скил с проверяемым выводом (генерация кода, преобразование файлов).',
|
||
'Включён в настройках (~/.claude/settings.json). Для discipline-скилов (TDD-типа) предпочтительнее скил writing-skills плагина Superpowers — у них разные философии.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1 #56: authoring-tooling (ADR-010)' }],
|
||
[],
|
||
[{ name: 'скил writing-skills', cond: 'обе создают скилы — skill-creator eval-driven, writing-skills через TDD' }]
|
||
),
|
||
claude_setup: nd(
|
||
'Плагин Anthropic — рекомендатель автоматизаций (claude-automation-recommender): анализирует репозиторий и советует, какие MCP-серверы, скилы, хуки, суб-агентов добавить.',
|
||
'При настройке/ревизии автоматизации проекта — «чего не хватает в тулчейне».',
|
||
'Включён в настройках (~/.claude/settings.json). Рекомендации — совещательные, решение за заказчиком.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1 #59: dev-support — рекомендации фильтруются R0/R10.1 (CCS1, ADR-010)' }],
|
||
[],
|
||
[]
|
||
),
|
||
plugin_dev: nd(
|
||
'Плагин Anthropic для разработки плагинов Claude Code — 7 скилов (структура плагина, разработка скилов / агентов / хуков / команд, интеграция MCP, настройки).',
|
||
'При создании или правке плагина и его компонентов.',
|
||
'Включён в настройках. Содержит 3 агента, уже представленные на карте (agent-creator / plugin-validator / skill-reviewer).',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1 #57: authoring-tooling — только для marketplace-плагинов, не для вендоренного/self-authored (PD1, ADR-010)' }],
|
||
[
|
||
{ name: 'агент plugin-dev:agent-creator', cond: 'входит в плагин' },
|
||
{ name: 'агент plugin-dev:plugin-validator', cond: 'входит в плагин' },
|
||
{ name: 'агент plugin-dev:skill-reviewer', cond: 'входит в плагин' }
|
||
],
|
||
[]
|
||
),
|
||
context7: nd(
|
||
'Плагин Anthropic — актуальная документация библиотек / фреймворков / API через MCP-инструменты query-docs и resolve-library-id.',
|
||
'При вопросах по библиотеке / фреймворку / SDK / CLI — синтаксис API, конфигурация, миграция версий. Предпочтительнее веб-поиска для документации библиотек.',
|
||
'Включён в настройках. Не для рефакторинга / отладки бизнес-логики / ревью — только документация.',
|
||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1 #60: dev-support — первый выбор для документации библиотек; WebFetch/WebSearch как fallback (CTX1, ADR-010)' }],
|
||
[],
|
||
[]
|
||
),
|
||
hk_self_check: nd(
|
||
'Хук SessionStart — economy-self-check.py: при старте сессии восстанавливает уровень экономии из файла состояния и проверяет согласованность.',
|
||
'SessionStart — единожды при инициализации сессии.',
|
||
'Часть архитектуры economy-хука из 6 компонентов (memory feedback_superpowers_hard_rule). §12 economy-режим не отменяет.',
|
||
[{ name: '~/.claude/settings.json', cond: 'хук SessionStart (user-level)' }],
|
||
[],
|
||
[{ name: 'хук economy-mode', cond: 'оба — часть системы экономии' }]
|
||
),
|
||
hk_skill_marker: nd(
|
||
'Хук PreToolUse на вызов Skill — skill-marker.py: фиксирует факт инвокации скила в состоянии сессии (пара со skill-check).',
|
||
'PreToolUse, matcher Skill — перед каждым вызовом скила.',
|
||
'Часть пары skill-marker / skill-check — runtime-энфорсмент §12 (скил инвокируется первым).',
|
||
[{ name: '~/.claude/settings.json', cond: 'хук PreToolUse (user-level)' }],
|
||
[],
|
||
[{ name: 'хук skill-check', cond: 'пара: marker фиксирует вызов скила, check проверяет' }]
|
||
),
|
||
hk_skill_check: nd(
|
||
'Хук PreToolUse на Edit/Write/MultiEdit — skill-check.py: проверяет, был ли инвокирован подходящий скил перед правкой кода (§12 дисциплина).',
|
||
'PreToolUse, matcher Edit|Write|MultiEdit.',
|
||
'Пара со skill-marker. Энфорсит §12 — нельзя править код, минуя обязательный скил.',
|
||
[{ name: '~/.claude/settings.json', cond: 'хук PreToolUse (user-level)' }],
|
||
[],
|
||
[{ name: 'хук skill-marker', cond: 'пара skill-marker / skill-check' }]
|
||
),
|
||
hk_state_guard: nd(
|
||
'Хук PreToolUse на Edit/Write/MultiEdit/Bash/Agent — economy-state-guard.py: ловит обходы режима экономии (в т.ч. Bash-обход Edit и наследование суб-агентами).',
|
||
'PreToolUse, matcher Edit|Write|MultiEdit|Bash|Agent.',
|
||
'Часть системы экономии из 6 компонентов. Закрывает bypass-пути (Bash вместо Edit, суб-агенты).',
|
||
[{ name: '~/.claude/settings.json', cond: 'хук PreToolUse (user-level)' }],
|
||
[],
|
||
[{ name: 'хук economy-mode', cond: 'оба — система экономии' }]
|
||
),
|
||
hk_postcompact: nd(
|
||
'Хук PostCompact — economy-postcompact.py: после компактификации сессии переинжектит состояние режима экономии в контекст.',
|
||
'PostCompact — после сжатия истории сессии.',
|
||
'Часть системы экономии из 6 компонентов — гарантирует, что режим переживает компакт.',
|
||
[{ name: '~/.claude/settings.json', cond: 'хук PostCompact (user-level)' }],
|
||
[],
|
||
[]
|
||
),
|
||
hk_verifier: nd(
|
||
'Хук Stop — агент-верификатор (модель Sonnet 4.6): после ответа проверяет соответствие режиму экономии — заявления «готово» без тестов, правки без тестов, выборочные результаты.',
|
||
'Stop — после каждого ответа Claude (кроме тривиальных Q&A-ходов).',
|
||
'Решение decision:block при нарушении. На уровне экономии 5 — short-circuit {compliant:true}. Стоит денег (вызовы Sonnet).',
|
||
[{ name: '~/.claude/settings.json', cond: 'хук Stop типа agent (user-level)' }],
|
||
[],
|
||
[{ name: 'скил verification-before-completion', cond: 'верификатор энфорсит то, что требует скил' }]
|
||
),
|
||
hk_ruflo_queen: nd(
|
||
'Хук UserPromptSubmit — ruflo-queen-hook.mjs: при триггер-словах queen/королева в промпте инжектит жёсткую директиву маршрутизации задачи через ruflo Queen (Pravila §14).',
|
||
'UserPromptSubmit — перед каждым промптом; срабатывает на queen / королева.',
|
||
'Энфорсит §14 Pravila (hard-rule). Перед платным спавном роя — превью. Зарегистрирован в project .claude/settings.json.',
|
||
[
|
||
{ name: '.claude/settings.json', cond: 'хук UserPromptSubmit (project-level)' },
|
||
{ name: 'Pravila §14', cond: 'энфорсит queen-триггер' }
|
||
],
|
||
[],
|
||
[{ name: 'ruflo Queen', cond: 'хук маршрутизирует queen-задачи на Queen' }]
|
||
),
|
||
sk_regression: nd(
|
||
'Проектный скил /regression — единый прогон регрессии: Pest --parallel + Vitest + сборка, парсинг результатов (JSON-first для pest --parallel, см. квирк 94).',
|
||
'Перед коммитом/пушем или при запросе полной регрессии — единая сводка по тестам.',
|
||
'Реализация — .claude/skills/regression/ (SKILL.md + run.mjs + run.test.mjs). parsePest: JSON.parse строки {"tool":"pest"}, regex — fallback.',
|
||
[],
|
||
[],
|
||
[{ name: 'агент pest-parallel-debugger', cond: 'при падениях Pest --parallel передаёт разбор агенту' }]
|
||
),
|
||
mem_audit_b: nd(
|
||
'Memory-файл audit_B_status — статус и находки аудитов D и B (закрыты, 6 коммитов, 34/34 RLS после хотфикса).',
|
||
'При вопросах про аудиты D / B — историческая запись, аудит не запускать повторно.',
|
||
'Снимок-история. Не редактировать — новые аудиты в новые файлы.',
|
||
[], [], []
|
||
),
|
||
mem_audit_c: nd(
|
||
'Memory-файл audit_C_pending — аудит C, полностью реализован 07.05 (4 коммита).',
|
||
'При вопросах про аудит C — историческая запись, не запускать повторно.',
|
||
'Снимок-история. Детали — реестр §13.10, CHANGELOG §Y.',
|
||
[], [], []
|
||
),
|
||
mem_suppliercrm: nd(
|
||
'Memory-файл supplier_crm — бизнес-модель поставщика лидов crm.bp-gr.ru: B1/B2/B3 = платформы-источники, проекты = каналы, сделки = лиды, 14 статусов.',
|
||
'При работе с интеграцией поставщика — для доменной модели.',
|
||
'Доменное описание, синхронизировано со схемой Лидерры.',
|
||
[], [], []
|
||
),
|
||
mem_audit12: nd(
|
||
'Memory-файл full_audit_2026-05-12 — аудит портала 12.05 + post-audit + закрытия Q.DEFER.003/004.',
|
||
'При вопросах про аудит 12.05 и его последствия.',
|
||
'Снимок-история. Содержит уроки про axe-core race-condition и mis-attribution квирка 72.',
|
||
[], [], []
|
||
),
|
||
mem_audit14: nd(
|
||
'Memory-файл full_audit_2026-05-14 — аудит портала #3 (14 фаз, 26 находок, вердикт зелёный).',
|
||
'При вопросах про аудит #3 от 14.05.',
|
||
'Снимок-история. Не редактировать при последующих аудитах.',
|
||
[], [], []
|
||
),
|
||
mem_sprint1: nd(
|
||
'Memory-файл sprint1_p0_closure — закрытие 5 P0 UI-находок аудита (DealsView, Kanban DnD, BulkActionsBar, Admin-экраны).',
|
||
'При вопросах про Sprint 1 / P0-фиксы портала.',
|
||
'Снимок-история спринта. 10 атомарных коммитов.',
|
||
[], [], []
|
||
),
|
||
mem_sprint2: nd(
|
||
'Memory-файл sprint2_p1_progress — Sprint 2 P1 wave 1: планы A (Auth) / B (Settings) / C (Billing) — закрыты и запушены.',
|
||
'При вопросах про Sprint 2 / P1-фиксы.',
|
||
'Снимок-история. Содержит коррекцию: SyncSupplierProjectsJobTest — реальный баг времени, не квирк 72.',
|
||
[], [], []
|
||
),
|
||
mem_sprint3: nd(
|
||
'Memory-файл sprint3_progress — Sprint 3 (P1 wave 2): под-планы 3A-3F, 3A-3D закрыты и запушены, 3E-3F в ожидании.',
|
||
'При вопросах про Sprint 3 / P1 wave 2.',
|
||
'Снимок-история, обновляется по ходу спринта.',
|
||
[], [], []
|
||
),
|
||
// ── 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' }],
|
||
[]
|
||
),
|
||
};
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 3.5: EDGE DETAILS (iter2 §5)
|
||
// ════════════════════════════════════════════════════
|
||
const edgeKey = (from, to) => from + '->' + to;
|
||
|
||
const EDGE_DETAILS = {
|
||
// ── ПРАВИЛА — иерархия ──────────────────────────
|
||
'pravila->claude_md': { type: 'подчиняет', when: 'всегда — CLAUDE.md уровень ниже Pravila', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §1 (уровень 1→2a)' },
|
||
'pravila->psr_v1': { type: 'подчиняет', when: 'всегда — PSR_v1 уровень 3 ниже Pravila', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §1 (уровень 1→3)' },
|
||
'claude_md->tooling': { type: 'документирует', when: 'при правке реестра инструментов', transfers: 'документация', mandatory: 'обязательно', rule: 'CLAUDE.md §0, §3 (ссылка на Прил. Н)' },
|
||
'pravila->superpowers': { type: 'подчиняет', when: 'задача попадает под карту §12.2 (14 типов)', transfers: 'контроль', mandatory: 'hard-block', rule: 'Pravila §12 (hard-rule уровня 0; скил первым, §9 не применяется)' },
|
||
|
||
// ── PSR_v1 координирует плагины ─────────────────
|
||
'psr_v1->superpowers': { type: 'координирует', when: 'paired-stack: процесс/решатель', transfers: 'контроль', mandatory: 'обязательно', rule: 'PSR_v1 R5 (paired stack ядро)' },
|
||
'psr_v1->fd_plugin': { type: 'координирует', when: 'paired-stack: процесс/решатель', transfers: 'контроль', mandatory: 'обязательно', rule: 'PSR_v1 R5 (paired stack ядро)' },
|
||
'psr_v1->upm': { type: 'координирует', when: 'вне основных фаз — активация через процедуру R14.3', transfers: 'контроль', mandatory: 'опционально', rule: 'PSR_v1 R10.1, R11.5, R14.3' },
|
||
'psr_v1->mcp_21st': { type: 'координирует', when: 'вне основных фаз — активация через процедуру R14.4', transfers: 'контроль', mandatory: 'опционально', rule: 'PSR_v1 R10.1, R14.4' },
|
||
'psr_v1->claude_md_mgmt': { type: 'координирует', when: 'инфраструктурный плагин для CLAUDE.md edits', transfers: 'контроль', mandatory: 'обязательно', rule: 'PSR_v1 R10.1 блок 1' },
|
||
|
||
// ── CLAUDE.md — документирует ──────────────────
|
||
'claude_md->mcp_boost': { type: 'документирует', when: 'фаза 1+ Laravel SQL/Eloquent/docs', transfers: 'документация', mandatory: 'рекомендуется', rule: 'CLAUDE.md §3.2 #10' },
|
||
'claude_md->mcp_sentry': { type: 'документирует', when: 'вне основных фаз — для отладки во время работы, ждёт Б-1', transfers: 'документация', mandatory: 'опционально', rule: 'CLAUDE.md §3.3 #34' },
|
||
'claude_md->mcp_redis': { type: 'документирует', when: 'вне основных фаз — Memurai только на чтение', transfers: 'документация', mandatory: 'опционально', rule: 'CLAUDE.md §3.3 #35' },
|
||
'claude_md->claude_md_mgmt': { type: 'документирует', when: 'единственный канал правок CLAUDE.md', transfers: 'документация', mandatory: 'hard-block', rule: 'CLAUDE.md §5 п.10' },
|
||
'claude_md->ag_pest': { type: 'документирует', when: 'агент для Pest TDD задач', transfers: 'документация', mandatory: 'рекомендуется', rule: 'CLAUDE.md §3 (агенты)' },
|
||
'claude_md->ag_rls': { type: 'документирует', when: 'агент для RLS-аудита и smoke-тестов', transfers: 'документация', mandatory: 'рекомендуется', rule: 'CLAUDE.md §3 (агенты)' },
|
||
|
||
// ── HOOKS — триггеры ────────────────────────────
|
||
'hk_pre_claude->claude_md': { type: 'триггерит', when: 'PreToolUse Edit/Write CLAUDE.md', transfers: 'проверка', mandatory: 'hard-block', rule: 'settings.json hooks (claude-md-management канал)' },
|
||
'hk_post_md->lh_mdlint': { type: 'триггерит', when: 'PostToolUse Edit *.md → markdownlint --fix', transfers: 'триггер', mandatory: 'обязательно', rule: 'settings.json hooks + lefthook' },
|
||
'hk_post_schema->claude_md': { type: 'триггерит', when: 'PostToolUse Edit db/schema.sql → напоминание sync', transfers: 'триггер', mandatory: 'обязательно', rule: 'settings.json hooks (§4.2 правил Claude)' },
|
||
'hk_session->mem_user': { type: 'триггерит', when: 'SessionStart инжектит memory-блок', transfers: 'данные', mandatory: 'обязательно', rule: 'settings.json hooks (memory inject)' },
|
||
'hk_session->mem_env': { type: 'триггерит', when: 'SessionStart инжектит memory-блок', transfers: 'данные', mandatory: 'обязательно', rule: 'settings.json hooks (memory inject)' },
|
||
'hk_session->mem_sp': { type: 'триггерит', when: 'SessionStart инжектит memory-блок', transfers: 'данные', mandatory: 'обязательно', rule: 'settings.json hooks (memory inject)' },
|
||
'hk_session->mem_plugins': { type: 'триггерит', when: 'SessionStart инжектит memory-блок', transfers: 'данные', mandatory: 'обязательно', rule: 'settings.json hooks (memory inject)' },
|
||
'hk_session->mem_state': { type: 'триггерит', when: 'SessionStart инжектит memory-блок', transfers: 'данные', mandatory: 'обязательно', rule: 'settings.json hooks (memory inject)' },
|
||
|
||
// ── SUPERPOWERS — содержит skills ───────────────
|
||
'superpowers->sk_brainstorm': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_tdd': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_debug': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_wplans': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_eplans': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_verify': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_parallel': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_worktree': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_pr': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_subagent': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_wskills': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_spreview': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_coderev': { type: 'содержит', when: 'plugin содержит skill', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12.2 (карта 14 типов)' },
|
||
'superpowers->sk_elements': { type: 'содержит', when: 'plugin содержит skill (using-superpowers)', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12 (старт сессии)' },
|
||
|
||
// ── SKILLS — последовательности ─────────────────
|
||
'sk_brainstorm->sk_wplans': { type: 'запускает', when: 'после brainstorming → writing-plans', transfers: 'триггер', mandatory: 'рекомендуется', rule: 'PSR_v1 R5 (paired-stack flow)' },
|
||
'sk_wplans->sk_eplans': { type: 'запускает', when: 'plan готов → executing-plans', transfers: 'триггер', mandatory: 'рекомендуется', rule: 'Superpowers process chain' },
|
||
'sk_wplans->sk_subagent': { type: 'альтернатива', when: 'если в текущей сессии — subagent-driven-development вместо executing', transfers: 'триггер', mandatory: 'опционально', rule: 'Superpowers process chain (in-session alt)' },
|
||
'sk_subagent->ag_explore': { type: 'запускает', when: 'параллельный поиск/исследование', transfers: 'триггер', mandatory: 'опционально', rule: 'subagent-driven-development (Task agent)' },
|
||
'sk_subagent->ag_general': { type: 'запускает', when: 'general-purpose subagent для независимых задач', transfers: 'триггер', mandatory: 'опционально', rule: 'subagent-driven-development (Task agent)' },
|
||
'sk_subagent->ag_plan': { type: 'запускает', when: 'агент планирования больших задач', transfers: 'триггер', mandatory: 'опционально', rule: 'subagent-driven-development (Task agent)' },
|
||
'sk_parallel->sk_worktree': { type: 'запускает', when: 'parallel agents требует изоляцию worktree', transfers: 'триггер', mandatory: 'рекомендуется', rule: 'PSR_v1 R5 (dispatching-parallel-agents)' },
|
||
'sk_rls->tooling': { type: 'читает', when: 'RLS-аудит сверяется с реестром инструментов', transfers: 'данные', mandatory: 'обязательно', rule: 'Tooling Прил. Н (squawk/Boost)' },
|
||
'sk_rls->mcp_boost': { type: 'запускает', when: 'RLS-смоук читает БД через Boost MCP', transfers: 'данные', mandatory: 'обязательно', rule: 'CLAUDE.md §3.2 #10 (Boost)' },
|
||
'sk_qitem->claude_md_mgmt': { type: 'запускает', when: 'правки реестра открытых вопросов → бамп CLAUDE.md', transfers: 'триггер', mandatory: 'обязательно', rule: 'CLAUDE.md §5 п.10 (единственный канал)' },
|
||
'claude_md_mgmt->claude_md': { type: 'запускает', when: 'skills claude-md-improver / revise-claude-md правят файл', transfers: 'контроль', mandatory: 'hard-block', rule: 'CLAUDE.md §5 п.10' },
|
||
|
||
// ── HOOKIFY — генерирует hooks ──────────────────
|
||
'ag_hookify->hookify_plugin': { type: 'запускает', when: 'агент hookify создаёт правила через plugin', transfers: 'триггер', mandatory: 'опционально', rule: 'hookify plugin docs' },
|
||
'hookify_plugin->hk_economy': { type: 'содержит', when: 'hookify сгенерировал economy hook', transfers: 'контроль', mandatory: 'обязательно', rule: 'Pravila §12 economy hook architecture' },
|
||
|
||
// ── АГЕНТЫ → MCP/инструменты ────────────────────
|
||
'ag_rls->mcp_boost': { type: 'запускает', when: 'RLS-аудит через Boost MCP', transfers: 'данные', mandatory: 'обязательно', rule: 'CLAUDE.md §3.2 #10' },
|
||
'ag_guide->mcp_gh': { type: 'запускает', when: 'агент гайдов работает с GitHub issues/PR', transfers: 'триггер', mandatory: 'опционально', rule: 'CLAUDE.md §3.1 #3 (GitHub MCP)' },
|
||
|
||
// ── LEFTHOOK jobs ───────────────────────────────
|
||
'lh_gitleaks->mem_plugins': { type: 'документирует', when: 'gitleaks-job описан в memory о плагинах', transfers: 'документация', mandatory: 'рекомендуется', rule: 'Tooling Прил. Н §8 (lefthook.yml)' },
|
||
'lh_larastan->mcp_boost': { type: 'запускает', when: 'Larastan job использует Boost для контекста', transfers: 'проверка', mandatory: 'обязательно', rule: 'lefthook.yml job + Boost' },
|
||
'lh_squawk->tooling': { type: 'читает', when: 'squawk-конфиг описан в реестре инструментов', transfers: 'документация', mandatory: 'обязательно', rule: 'Tooling Прил. Н #15' },
|
||
'lh_gitleaks2->lh_gitleaks': { type: 'альтернатива', when: 'второй gitleaks-job (pre-push) вариант pre-commit', transfers: 'проверка', mandatory: 'опционально', rule: 'lefthook.yml (дубль pre-push)' },
|
||
'lh_lychee->claude_md': { type: 'читает', when: 'lychee валидирует ссылки в CLAUDE.md и docs', transfers: 'проверка', mandatory: 'обязательно', rule: 'CLAUDE.md §4 + lefthook' },
|
||
|
||
// ── MEMORY → плагины/правила ────────────────────
|
||
'mem_env->ag_pest': { type: 'документирует', when: 'memory о квирках окружения нужен для Pest agent', transfers: 'данные', mandatory: 'рекомендуется', rule: 'memory/feedback_environment.md' },
|
||
'mem_plugins->psr_v1': { type: 'документирует', when: 'memory о парном стеке отражает PSR_v1', transfers: 'данные', mandatory: 'рекомендуется', rule: 'memory/feedback_plugin_paired_stack.md' },
|
||
'mem_archive->claude_md': { type: 'документирует', when: 'memory об архиве содержит refs на CLAUDE.md', transfers: 'данные', mandatory: 'рекомендуется', rule: 'memory/reference_archive.md' },
|
||
|
||
// ── MCP → агенты/skills ─────────────────────────
|
||
'mcp_pw->hk_session': { type: 'триггерит', when: 'Playwright MCP вызывается из SessionStart hook', transfers: 'триггер', mandatory: 'опционально', rule: 'settings.json hooks + Playwright' },
|
||
'mcp_gh->sk_pr': { type: 'запускает', when: 'finishing-a-development-branch использует gh-команды', transfers: 'триггер', mandatory: 'обязательно', rule: 'Superpowers finishing-a-development-branch' },
|
||
'mcp_boost->ag_rls': { type: 'запускает', when: 'Boost MCP отдаёт данные RLS-агенту', transfers: 'данные', mandatory: 'обязательно', rule: 'CLAUDE.md §3.2 #10' },
|
||
|
||
// ── КОНФЛИКТЫ (8 рёбер; 3 из них имеют ту же пару from/to, что и обычные — здесь объединены под одним ключом) ─
|
||
'sk_rls->ag_rls': { type: 'конфликт', when: 'граница задана: скил — по таблице, агент — по diff/ветке/PR', transfers: 'coverage', mandatory: 'опционально', rule: 'секции «Граница…» в SKILL.md + rls-reviewer.md (spec 2026-05-16)' },
|
||
'hookify_plugin->hk_pre_claude': { type: 'конфликт', when: 'hookify plugin генерирует hook — двойное owner-ship vs settings.json', transfers: 'coverage', mandatory: 'опционально', rule: 'нет регламента (plugin vs settings.json)' },
|
||
'mcp_pw->sk_parallel': { type: 'конфликт', when: 'Playwright и parallel-agents оба требуют изоляцию', transfers: 'coverage', mandatory: 'опционально', rule: 'GREEN: квирк #95 — профили per-cwd hash → worktrees не конфликтуют; same-dir parallel под Pravila §15.2 claim' },
|
||
'ag_pest->mcp_redis': { type: 'конфликт', when: 'Pest --parallel race на Redis cache (quirk 72/77)', transfers: 'coverage', mandatory: 'опционально', rule: 'CLAUDE.md §3.3 #35 (Redis MCP) — race остаётся вне регламента' },
|
||
'psr_v1->claude_md': { type: 'конфликт', when: 'PSR_v1 уровень 3 vs CLAUDE.md 2a — приоритет CLAUDE.md', transfers: 'контроль', mandatory: 'hard-block', rule: 'CLAUDE.md §1 (priority chain)' },
|
||
'upm->fd_plugin': { type: 'конфликт', when: 'UPM и FD оба претендуют на UI-решения', transfers: 'coverage', mandatory: 'hard-block', rule: 'PSR_v1 R14.5 (не параллельно)' },
|
||
'mcp_21st->fd_plugin': { type: 'конфликт', when: '21st Magic и FD оба генераторы UI', transfers: 'coverage', mandatory: 'hard-block', rule: 'PSR_v1 R14.5 (не параллельно)' },
|
||
'hk_economy->superpowers': { type: 'конфликт', when: 'economy-режим теоретически может «сэкономить» вызов скила — §12 (hard-rule уровня 0) economy не отменяет', transfers: 'контроль', mandatory: 'hard-block', rule: 'Pravila §12.4 (только явный «не используй»)' },
|
||
|
||
// ── RUFLO ОРКЕСТРАТОР — реколлаж (iter5 2026-05-15 + нормативный sync 2026-05-16) ──
|
||
'ruflo_queen->ruflo_workers': { type: 'подчиняет', when: 'hive-mind активен, но рой ни разу не получал задач', transfers: 'контроль', mandatory: 'опционально (рой idle)', rule: 'Tooling §4.10 (ruflo как advisory-подсистема)' },
|
||
'ruflo_queen->ruflo_agents_catalog': { type: 'артефакт', when: '`ruflo init` высыпал каталог в .claude/agents/', transfers: 'ничего (файлы лежат)', mandatory: 'не задействовано', rule: 'артефакт установки ruflo' },
|
||
'ruflo_queen->ruflo_commands': { type: 'артефакт', when: '`ruflo init` высыпал команды в .claude/commands/', transfers: 'ничего (файлы лежат)', mandatory: 'не задействовано', rule: 'артефакт установки ruflo' },
|
||
'ruflo_queen->ruflo_plugins': { type: 'артефакт', when: 'плагины ruflo — 0 установлено из ~20 в реестре', transfers: 'ничего', mandatory: 'не задействовано', rule: 'артефакт установки ruflo' },
|
||
'ruflo_mcp->ruflo_memory': { type: 'читает', when: 'MCP-инструменты memory_* обращаются к хранилищу', transfers: 'данные', mandatory: 'опционально', rule: 'Tooling §4.10' },
|
||
'ruflo_recall_hook->ruflo_memory': { type: 'читает', when: 'recall-хук на каждый промпт запускает `ruflo memory search`', transfers: 'данные', mandatory: '«мягко» (fail-open)', rule: '.claude/settings.json (UserPromptSubmit)' },
|
||
'ruflo_daemon->ruflo_memory': { type: 'читает', when: 'воркер consolidate демона обращается к памяти', transfers: 'данные', mandatory: 'опционально', rule: '.claude-flow daemon' },
|
||
'ruflo_mcp->ruflo_queen': { type: 'экспонирует', when: 'MCP-сервер отдаёт инструменты hive-mind_*/agent_*/swarm_*', transfers: 'инструменты', mandatory: 'опционально', rule: 'Tooling §4.10' },
|
||
'ruflo_queen->pravila': { type: 'конфликт', when: 'реколлаж 16.05.2026 привёл нормативку к рантайму — конфликт «декларация ≠ рантайм» закрыт', transfers: 'coverage', mandatory: 'закрыто', rule: 'Закрыто реколлажем: Pravila v1.16 / CLAUDE.md v2.2 / PSR_v1 v3.2 / Tooling v2.2' },
|
||
'pravila->ruflo_queen': { type: 'триггерит', when: 'триггер-слова queen/королева в промпте — задача маршрутизируется через ruflo Queen', transfers: 'триггер', mandatory: 'hard-rule', rule: 'Pravila §14 (queen/королева → hive-mind spawn)' },
|
||
'claude_md->ruflo_queen': { type: 'документирует', when: 'CLAUDE.md §3.5 описывает ruflo как advisory/automation-подсистему', transfers: 'документация', mandatory: 'рекомендуется', rule: 'CLAUDE.md §3.5' },
|
||
'psr_v1->ruflo_queen': { type: 'документирует', when: 'PSR_v1 §14 — cross-ref на queen-триггер Pravila §14', transfers: 'документация', mandatory: 'рекомендуется', rule: 'PSR_v1 §14' },
|
||
'tooling->ruflo_queen': { type: 'документирует', when: 'Tooling §4.10 — реестр ruflo как advisory/automation-подсистемы', transfers: 'документация', mandatory: 'рекомендуется', rule: 'Tooling §4.10' },
|
||
'mem_ruflo->ruflo_queen': { type: 'документирует', when: 'memory-файл хранит историю ruflo-интеграции', transfers: 'данные', mandatory: 'рекомендуется', rule: 'memory/project_ruflo_integration.md' },
|
||
'ruflo_memory->mem_state': { type: 'конфликт', when: 'два хранилища памяти не синхронизированы; память ruflo почти пуста', transfers: 'coverage', mandatory: 'опционально', rule: 'нет регламента синхронизации (alpha-баг HNSW #1122)' },
|
||
'ruflo_daemon->ag_pest': { type: 'конфликт', when: 'daemon worker-jitter усиливает частоту Pest-квирка 72', transfers: 'coverage', mandatory: 'опционально', rule: 'memory feedback_environment квирк #93' },
|
||
|
||
// ── 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' },
|
||
};
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 3.6: NODE META (iter6 → iter8 — даты, использование, дубли)
|
||
// ════════════════════════════════════════════════════
|
||
// Данные — фактический снимок: даты из git/changelog/mtime, счётчик uses —
|
||
// из разбора транскриптов сессий Claude Code за окно META_WINDOW.
|
||
// Методика и воспроизводимость — план iter6, Приложение А.
|
||
//
|
||
// iter8 (18.05.2026): окно расширено 09–16.05 → 09–18.05 (10 дней).
|
||
// Узлы интеграционных волн 17-18.05 (A6 / D3 / C9 / A4 / A3 / A11 / C10 / discovery /
|
||
// ADT) получают baseline 1 = факт интеграции (коммит + plan/spec/ADR + Tooling §4).
|
||
// Реальные вызовы (за пределами интеграций) не подсчитаны — транскрипты Claude Code
|
||
// не доступны как источник в репо. mcp_figma — uses=0, usesSrc='DEFERRED'.
|
||
// null сохраняется только для принципиально неизмеримых: правила, superpowers,
|
||
// hookify_plugin, ruflo_daemon, ruflo_memory, фоновые economy/skill-discipline
|
||
// хуки (hk_self_check / skill_marker / skill_check / state_guard / postcompact /
|
||
// verifier / ruflo_queen) и старые mem_* без активных Read-вызовов в окне.
|
||
const META_SNAPSHOT = '20.05.2026'; // дата генерации значений
|
||
const META_WINDOW = '09–20.05.2026'; // окно подсчёта использования (12 дней)
|
||
|
||
// uses: number — измеримый узел (0 = реально простаивал); null — измерить нельзя
|
||
// (узел-правило / плагин-обёртка / автономный демон / пассивное хранилище) → «нет данных».
|
||
// usesSrc: 'скил' | 'агент' | 'MCP' | 'хук' | 'memory-чтение' | 'коммиты' | 'инспекция' | 'интеграция' | 'DEFERRED' | '—'
|
||
const NODE_META = {
|
||
// ── ПРАВИЛА (4) — узлы-правила, напрямую не вызываются ──
|
||
pravila: { since: '06.05.2026', changed: '19.05.2026', uses: null, usesSrc: '—' },
|
||
claude_md: { since: '06.05.2026', changed: '19.05.2026', uses: null, usesSrc: '—' },
|
||
psr_v1: { since: '09.05.2026', changed: '19.05.2026', uses: null, usesSrc: '—' },
|
||
tooling: { since: '06.05.2026', changed: '19.05.2026', uses: null, usesSrc: '—' },
|
||
|
||
// ── ПЛАГИНЫ (5) ──
|
||
superpowers: { since: '09.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
fd_plugin: { since: '10.05.2026', changed: '—', uses: 1, usesSrc: 'скил' },
|
||
upm: { since: '10.05.2026', changed: '—', uses: 0, usesSrc: 'скил' },
|
||
claude_md_mgmt: { since: '10.05.2026', changed: '—', uses: 15, usesSrc: 'скил' },
|
||
hookify_plugin: { since: '—', changed: '18.05.2026', uses: null, usesSrc: '—' },
|
||
|
||
// ── СКИЛЫ SUPERPOWERS (14) — связка подключена 09.05.2026 ──
|
||
sk_brainstorm: { since: '09.05.2026', changed: '—', uses: 44, usesSrc: 'скил' },
|
||
sk_wplans: { since: '09.05.2026', changed: '—', uses: 54, usesSrc: 'скил' },
|
||
sk_eplans: { since: '09.05.2026', changed: '—', uses: 11, usesSrc: 'скил' },
|
||
sk_subagent: { since: '09.05.2026', changed: '—', uses: 33, usesSrc: 'скил' },
|
||
sk_tdd: { since: '09.05.2026', changed: '—', uses: 2, usesSrc: 'скил' },
|
||
sk_verify: { since: '09.05.2026', changed: '—', uses: 25, usesSrc: 'скил' },
|
||
sk_debug: { since: '09.05.2026', changed: '—', uses: 10, usesSrc: 'скил' },
|
||
sk_parallel: { since: '09.05.2026', changed: '—', uses: 3, usesSrc: 'скил' },
|
||
sk_worktree: { since: '09.05.2026', changed: '—', uses: 3, usesSrc: 'скил' },
|
||
sk_pr: { since: '09.05.2026', changed: '—', uses: 10, usesSrc: 'скил' },
|
||
sk_coderev: { since: '09.05.2026', changed: '—', uses: 1, usesSrc: 'скил' },
|
||
sk_spreview: { since: '09.05.2026', changed: '—', uses: 0, usesSrc: 'скил' },
|
||
sk_wskills: { since: '09.05.2026', changed: '—', uses: 0, usesSrc: 'скил' },
|
||
sk_elements: { since: '09.05.2026', changed: '—', uses: 0, usesSrc: 'скил' },
|
||
|
||
// ── СКИЛЫ ПРОЕКТА (2) — файлы добавлены в репозиторий 13.05.2026 ──
|
||
sk_rls: { since: '13.05.2026', changed: '—', uses: 0, usesSrc: 'скил' },
|
||
sk_qitem: { since: '13.05.2026', changed: '—', uses: 1, usesSrc: 'скил' },
|
||
|
||
// ── ХУКИ (5) ──
|
||
hk_session: { since: '—', changed: '—', uses: 67, usesSrc: 'хук' },
|
||
hk_economy: { since: '10.05.2026', changed: '—', uses: 276, usesSrc: 'хук' },
|
||
hk_pre_claude: { since: '13.05.2026', changed: '—', uses: 249, usesSrc: 'хук' },
|
||
hk_post_md: { since: '06.05.2026', changed: '—', uses: 1334, usesSrc: 'хук' },
|
||
hk_post_schema: { since: '13.05.2026', changed: '—', uses: 22, usesSrc: 'хук' },
|
||
|
||
// ── АГЕНТЫ (11) ──
|
||
ag_explore: { since: 'встроено в Claude Code', changed: '—', uses: 26, usesSrc: 'агент' },
|
||
ag_general: { since: 'встроено в Claude Code', changed: '—', uses: 512, usesSrc: 'агент' },
|
||
ag_plan: { since: 'встроено в Claude Code', changed: '—', uses: 0, usesSrc: 'агент' },
|
||
ag_pest: { since: '13.05.2026', changed: '—', uses: 2, usesSrc: 'агент' },
|
||
ag_guide: { since: 'встроено в Claude Code', changed: '—', uses: 4, usesSrc: 'агент' },
|
||
ag_statusline: { since: 'встроено в Claude Code', changed: '—', uses: 0, usesSrc: 'агент' },
|
||
ag_hookify: { since: '—', changed: '—', uses: 0, usesSrc: 'агент' },
|
||
ag_pcreator: { since: '—', changed: '—', uses: 0, usesSrc: 'агент' },
|
||
ag_pvalid: { since: '—', changed: '—', uses: 0, usesSrc: 'агент' },
|
||
ag_skreview: { since: '—', changed: '—', uses: 0, usesSrc: 'агент' },
|
||
ag_rls: { since: '13.05.2026', changed: '—', uses: 2, usesSrc: 'агент' },
|
||
|
||
// ── MCP-СЕРВЕРЫ (7) ──
|
||
mcp_21st: { since: '10.05.2026', changed: '—', uses: 0, usesSrc: 'MCP' },
|
||
mcp_pw: { since: '06.05.2026', changed: '—', uses: 706, usesSrc: 'MCP' },
|
||
mcp_gh: { since: '06.05.2026', changed: '—', uses: 0, usesSrc: 'MCP' },
|
||
mcp_boost: { since: '08.05.2026', changed: '—', uses: 73, usesSrc: 'MCP' },
|
||
mcp_redis: { since: '13.05.2026', changed: '—', uses: 0, usesSrc: 'MCP' },
|
||
mcp_sentry: { since: '13.05.2026', changed: '—', uses: 0, usesSrc: 'MCP' },
|
||
mcp_semgrep: { since: '10.05.2026', changed: '—', uses: 0, usesSrc: 'MCP' },
|
||
|
||
// ── LEFTHOOK JOBS (10) — uses ≈ число коммитов в окне, фильтр по типу файла ──
|
||
lh_mdlint: { since: '06.05.2026', changed: '—', uses: 232, usesSrc: 'коммиты' },
|
||
lh_cspell: { since: '06.05.2026', changed: '—', uses: 232, usesSrc: 'коммиты' },
|
||
lh_stylelint: { since: '06.05.2026', changed: '—', uses: 43, usesSrc: 'коммиты' },
|
||
lh_eslint: { since: '08.05.2026', changed: '—', uses: 120, usesSrc: 'коммиты' },
|
||
lh_lychee: { since: '06.05.2026', changed: '—', uses: 56, usesSrc: 'коммиты' },
|
||
lh_gitleaks: { since: '06.05.2026', changed: '—', uses: 514, usesSrc: 'коммиты' },
|
||
lh_gitleaks2: { since: '06.05.2026', changed: '—', uses: 56, usesSrc: 'коммиты' },
|
||
lh_pint: { since: '08.05.2026', changed: '—', uses: 134, usesSrc: 'коммиты' },
|
||
lh_larastan: { since: '08.05.2026', changed: '—', uses: 134, usesSrc: 'коммиты' },
|
||
lh_squawk: { since: '08.05.2026', changed: '—', uses: 19, usesSrc: 'коммиты' },
|
||
|
||
// ── MEMORY FILES (15) — uses = вызовы Read; changed = mtime файла ──
|
||
mem_user: { since: '07.05.2026', changed: '08.05.2026', uses: 0, usesSrc: 'memory-чтение' },
|
||
mem_comm: { since: '07.05.2026', changed: '08.05.2026', uses: 0, usesSrc: 'memory-чтение' },
|
||
mem_env: { since: '07.05.2026', changed: '15.05.2026', uses: 41, usesSrc: 'memory-чтение' },
|
||
mem_sp: { since: '09.05.2026', changed: '10.05.2026', uses: 1, usesSrc: 'memory-чтение' },
|
||
mem_plugins: { since: '09.05.2026', changed: '13.05.2026', uses: 9, usesSrc: 'memory-чтение' },
|
||
mem_handoff: { since: '08.05.2026', changed: '—', uses: 0, usesSrc: 'memory-чтение' },
|
||
mem_redesign: { since: '12.05.2026', changed: '—', uses: 0, usesSrc: 'memory-чтение' },
|
||
mem_devindices: { since: '12.05.2026', changed: '—', uses: 1, usesSrc: 'memory-чтение' },
|
||
mem_phase1: { since: '08.05.2026', changed: '—', uses: 1, usesSrc: 'memory-чтение' },
|
||
mem_state: { since: '07.05.2026', changed: '15.05.2026', uses: 73, usesSrc: 'memory-чтение' },
|
||
mem_brain: { since: '11.05.2026', changed: '—', uses: 1, usesSrc: 'memory-чтение' },
|
||
mem_supplier: { since: '10.05.2026', changed: '12.05.2026', uses: 13, usesSrc: 'memory-чтение' },
|
||
mem_audit: { since: '13.05.2026', changed: '—', uses: 3, usesSrc: 'memory-чтение' },
|
||
mem_archive: { since: '07.05.2026', changed: '15.05.2026', uses: 21, usesSrc: 'memory-чтение' },
|
||
mem_github: { since: '07.05.2026', changed: '15.05.2026', uses: 33, usesSrc: 'memory-чтение' },
|
||
|
||
// ── RUFLO ОРКЕСТРАТОР (9) — все внедрены big-bang'ом 15.05.2026 ──
|
||
// 🔇 ИЗОЛИРОВАН 18.05.2026 (Rec2 SYSTEM-аудита): hooks сняты из settings.json,
|
||
// MCP удалён из .mcp.json, PM2 daemon stopped+saved-empty. См. Pravila §14.9 /
|
||
// Tooling §4.10 / memory feedback_ruflo_isolated.md. uses=0 — реальные вызовы 0.
|
||
ruflo_queen: { since: '15.05.2026', changed: '18.05.2026', uses: 0, usesSrc: 'инспекция', isolated: true },
|
||
ruflo_plugins: { since: '15.05.2026', changed: '18.05.2026', uses: 0, usesSrc: 'инспекция', isolated: true },
|
||
ruflo_workers: { since: '15.05.2026', changed: '18.05.2026', uses: 0, usesSrc: 'инспекция', isolated: true },
|
||
ruflo_agents_catalog: { since: '15.05.2026', changed: '18.05.2026', uses: 0, usesSrc: 'инспекция', isolated: true,
|
||
dupNote: '100 определений агентов дублируют реестр агентов; каталог буквально содержит 2 проектных агента' },
|
||
ruflo_commands: { since: '15.05.2026', changed: '18.05.2026', uses: 0, usesSrc: 'инспекция', isolated: true,
|
||
dupNote: '88 slash-команд дублируют роль скилов — именованные вызываемые процедуры; команды инертны' },
|
||
ruflo_daemon: { since: '15.05.2026', changed: '18.05.2026', uses: 0, usesSrc: 'pm2 stopped+deleted', isolated: true },
|
||
ruflo_memory: { since: '15.05.2026', changed: '18.05.2026', uses: 0, usesSrc: 'не читается', isolated: true,
|
||
dupNote: 'дублирует роль 16 memory-файлов проекта — постоянная память между сессиями; ⚫-конфликт с project_state снят изоляцией' },
|
||
ruflo_mcp: { since: '15.05.2026', changed: '18.05.2026', uses: 36, usesSrc: 'MCP (был активен 15-17.05; снят 18.05)', isolated: true },
|
||
ruflo_recall_hook: { since: '15.05.2026', changed: '18.05.2026', uses: 220, usesSrc: 'хук (был активен 15-17.05; снят 18.05)', isolated: true },
|
||
|
||
// ── MEMORY +1 (артефакт ruflo big-bang) ──
|
||
mem_ruflo: { since: '15.05.2026', changed: '16.05.2026', uses: 18, usesSrc: 'memory-чтение' },
|
||
|
||
// ── АУДИТ-АКТУАЛИЗАЦИЯ 16.05.2026 + iter8 18.05.2026 ──
|
||
// ADT (18.05): baseline 1 = факт формализации в Tooling §4.31–4.35 + интеграционный коммит 515acb6.
|
||
skill_creator: { since: '11.05.2026', changed: '18.05.2026', uses: 1, usesSrc: 'интеграция' },
|
||
claude_setup: { since: '11.05.2026', changed: '18.05.2026', uses: 1, usesSrc: 'интеграция' },
|
||
plugin_dev: { since: '—', changed: '18.05.2026', uses: 1, usesSrc: 'интеграция' },
|
||
context7: { since: '—', changed: '18.05.2026', uses: 1, usesSrc: 'интеграция' },
|
||
// Фоновые economy/skill-discipline хуки — измерение требует доступа к user-level логам, не репо.
|
||
hk_self_check: { since: '10.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
hk_skill_marker: { since: '10.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
hk_skill_check: { since: '10.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
hk_state_guard: { since: '10.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
hk_postcompact: { since: '10.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
hk_verifier: { since: '10.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
hk_ruflo_queen: { since: '15.05.2026', changed: '18.05.2026', uses: 0, usesSrc: 'снят 18.05', isolated: true }, // 🔇 ИЗОЛИРОВАН (см. ruflo блок выше)
|
||
sk_regression: { since: '15.05.2026', changed: '—', uses: 2, usesSrc: 'скил' }, // verification в Sprint 1-6
|
||
mem_audit_b: { since: '08.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
mem_audit_c: { since: '07.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
mem_suppliercrm: { since: '10.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
mem_audit12: { since: '12.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
mem_audit14: { since: '14.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
mem_sprint1: { since: '15.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
mem_sprint2: { since: '15.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
mem_sprint3: { since: '16.05.2026', changed: '—', uses: null, usesSrc: '—' },
|
||
|
||
// ── A6 ARCHITECTURE-TOOLING 17.05.2026 (iter8: baseline 1 = факт интеграции) ──
|
||
adr_kit: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
arch_patterns: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
mermaid_skill: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
deptrac: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
|
||
// ── D3 AUDIT-SECURITY 17.05.2026 (iter8: baseline 1) ──
|
||
tob_skills: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
sec_guidance: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'хук' },
|
||
sk_security_review: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
sk_audit_portal: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
|
||
// ── C9 PROJECT-MANAGEMENT-TOOLING 17.05.2026 (iter8: baseline 1) ──
|
||
ccpm: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
product_mgmt: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
|
||
// ── A4 DESIGN-TOOLING 17.05.2026 (iter8: baseline 1, mcp_figma=0 DEFERRED) ──
|
||
mcp_figma: { since: '17.05.2026', changed: '—', uses: 0, usesSrc: 'DEFERRED' },
|
||
mcp_icons: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'MCP' },
|
||
design_plugin:{ since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
|
||
// ── A3 INTEGRATION-TOOLING (17.05.2026, iter8: baseline 1) ──
|
||
ag_apidocs: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
mcp_openapi: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
|
||
// ── A11 ML-AI-TOOLING (17.05.2026, iter8: baseline 1) ──
|
||
claude_api: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
promptfoo: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'CLI' },
|
||
data_scientist: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
|
||
// ── C10 BUSINESS-PROCESS (17.05.2026, iter8: baseline 1) ──
|
||
ops_plugin: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
process_modeling: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
process_analysis: { since: '17.05.2026', changed: '—', uses: 1, usesSrc: 'интеграция' },
|
||
|
||
// ── DISCOVERY-TOOLING (18.05.2026, iter8: factual в сессии) ──
|
||
// snapshot 2026-05-18-system-audit-brain.md (утро) + это интервью (вечер) + последующие вызовы
|
||
discovery_interview: { since: '18.05.2026', changed: '—', uses: 3, usesSrc: 'скил, factual' },
|
||
|
||
// ── FINANCE-TOOLING C6+C7 (20.05.2026) ──
|
||
finance_plugin: { since: '20.05.2026', changed: '—', uses: 0, usesSrc: 'новый узел' },
|
||
billing_audit: { since: '20.05.2026', changed: '—', uses: 0, usesSrc: 'новый узел' },
|
||
ru_tax: { since: '20.05.2026', changed: '—', uses: 0, usesSrc: 'новый узел' },
|
||
|
||
// ── A1 BACKEND-TOOLING (20.05.2026, ADR-013) ──
|
||
rector: { since: '20.05.2026', changed: '—', uses: 0, usesSrc: 'новый узел' },
|
||
php_insights: { since: '20.05.2026', changed: '—', uses: 0, usesSrc: 'новый узел' },
|
||
backend_patterns: { since: '20.05.2026', changed: '—', uses: 0, usesSrc: 'новый узел' },
|
||
nightowl: { since: '20.05.2026', changed: '—', uses: 0, usesSrc: 'новый узел (DEFERRED)' },
|
||
|
||
// ── 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)' },
|
||
};
|
||
|
||
// Явные парные дубли (Фича 3) — попадают в кнопку «⧉ Дубли».
|
||
const DUPLICATE_GROUPS = [
|
||
{ id: 'D1', pct: 90, members: ['hk_post_md', 'lh_mdlint'],
|
||
reason: 'оба запускают markdownlint --fix на .md — разница только в триггере (после правки в сессии против при коммите)' },
|
||
{ id: 'D2', pct: 85, members: ['lh_gitleaks', 'lh_gitleaks2'],
|
||
reason: 'оба — скан секретов gitleaks; pre-commit проверяет staged-файлы, pre-push — всю историю (надмножество)' },
|
||
{ id: 'D3', pct: 85, members: ['sk_rls', 'ag_rls'],
|
||
reason: 'оба — 7-пунктовая проверка RLS-соответствия; уже отмечено 🔴-конфликтом «нет регламента кто когда»' },
|
||
{ id: 'D4', pct: 80, members: ['sk_eplans', 'sk_subagent'],
|
||
reason: 'оба исполняют план writing-plans пошагово; разница — параллельная сессия против суб-агентов в текущей' },
|
||
{ id: 'D5', pct: 80, members: ['sk_wplans', 'ag_plan'],
|
||
reason: 'оба производят план задачи; скил writing-plans — inline с полным кодом, агент Plan — архитектурный набросок READ-ONLY' },
|
||
{ id: 'D7', pct: 80, members: ['ruflo_recall_hook', 'hk_session'],
|
||
reason: 'оба инжектят память в контекст Клода; recall-хук — на каждый промпт из базы ruflo, SessionStart — при старте из .md-файлов' },
|
||
];
|
||
|
||
// Производный индекс: nodeId -> { partner, pct, reason } — для рендера легенды и подсветки.
|
||
const DUP_BY_NODE = new Map();
|
||
DUPLICATE_GROUPS.forEach(g => g.members.forEach(m => {
|
||
const partner = g.members.find(x => x !== m);
|
||
DUP_BY_NODE.set(m, { partner, pct: g.pct, reason: g.reason });
|
||
}));
|
||
const DUP_NODE_SET = new Set(DUP_BY_NODE.keys()); // 12 узлов-членов парных дублей
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 3.5: ФУНКЦИОНАЛЬНЫЕ РАЗДЕЛЫ (функциональная квалификация)
|
||
// ════════════════════════════════════════════════════
|
||
// Разделы деятельности Лидерры. Каждый узел карты отнесён к одному разделу
|
||
// (NODE_SECTION). Часть разделов пока пустая — это бизнес-домены, под которые
|
||
// в карте dev-автоматики ещё нет узлов. Основа будущего «мозга»: 1 раздел =
|
||
// 1 playbook «как и что делать».
|
||
// SECTION_BUCKETS — moved to automation-graph-data.js
|
||
// SECTIONS — moved to automation-graph-data.js
|
||
// NODE_SECTION — moved to automation-graph-data.js
|
||
// NODE_SECTION_SECONDARY — moved to automation-graph-data.js
|
||
// Производные индексы для рендера панели и Паспорта.
|
||
const SECTION_BY_ID = new Map(SECTIONS.map(s => [s.id, s]));
|
||
const SECTION_NODES = new Map(SECTIONS.map(s => [s.id, []]));
|
||
NODES.forEach(n => {
|
||
const sid = NODE_SECTION[n.id];
|
||
if (sid && SECTION_NODES.has(sid)) SECTION_NODES.get(sid).push(n.id);
|
||
(NODE_SECTION_SECONDARY[n.id] || []).forEach(secId => {
|
||
if (SECTION_NODES.has(secId)) SECTION_NODES.get(secId).push(n.id);
|
||
});
|
||
});
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 3.5: WISHLIST — отложенный backlog (todo-лист хотелок)
|
||
// ════════════════════════════════════════════════════
|
||
// Редактируемый список отложенных «хотелок» развития мозга/портала.
|
||
// Добавить хотелку = добавить объект. status: 'next' | 'blocked' | 'idea'.
|
||
const WISH_STATUS = {
|
||
next: { emoji: '▶', label: 'к работе', color: '#859900' },
|
||
blocked: { emoji: '⏸', label: 'ждёт зависимости', color: '#b58900' },
|
||
idea: { emoji: '💭', label: 'идея', color: '#586e75' },
|
||
};
|
||
const WISHLIST = [
|
||
{ id: 'W1', status: 'next', section: 'E8',
|
||
title: 'K7-spike — починка embeddings ruflo',
|
||
note: 'Tensor.location / onnxruntime version sync. Гейт жизнеспособности моста claude-mem→ReasoningBank. ~1-2 ч, systematic-debugging, ≥3 гипотезы.' },
|
||
{ id: 'W2', status: 'blocked', section: 'E8',
|
||
title: 'Мост claude-mem → ReasoningBank',
|
||
note: 'Замкнутый self-learning loop: захват (claude-mem) → адаптер+LLM-трансформ → сток (ruflo memory) → recall. Gated на W1.' },
|
||
{ id: 'W3', status: 'blocked', section: 'E8',
|
||
title: 'claude-mem #1 — установка плагином',
|
||
note: 'Слой авто-захвата моста. Ставить как плагин (не npx — риск перезаписи settings.json). Роль решается после W1.' },
|
||
{ id: 'W4', status: 'blocked', section: 'E8',
|
||
title: 'Двухуровневый ремонтник моста',
|
||
note: 'Tier 1 — auto-heal операционки (рестарт демона, re-run h7-patch, retry). Tier 2 — circuit-breaker на семантику (halt, не чинить). Часть W2.' },
|
||
];
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 4: VIS INIT
|
||
// ════════════════════════════════════════════════════
|
||
// GROUPS — moved to automation-graph-data.js
|
||
|
||
const nodesDS = new vis.DataSet(NODES);
|
||
const edgesDS = new vis.DataSet(EDGES);
|
||
|
||
const network = new vis.Network(
|
||
document.getElementById('network'),
|
||
{ nodes: nodesDS, edges: edgesDS },
|
||
{
|
||
groups: GROUPS,
|
||
nodes: {
|
||
shape: 'dot',
|
||
borderWidth: 2,
|
||
borderWidthSelected: 3,
|
||
font: { multi: 'html' },
|
||
},
|
||
edges: {
|
||
smooth: { type: 'continuous', roundness: 0.5 },
|
||
selectionWidth: 2,
|
||
},
|
||
physics: {
|
||
enabled: false,
|
||
},
|
||
interaction: {
|
||
hover: true,
|
||
tooltipDelay: 400,
|
||
multiselect: false,
|
||
},
|
||
}
|
||
);
|
||
|
||
network.once('afterDrawing', () => {
|
||
network.fit({ animation: { duration: 600, easingFunction: 'easeInOutQuad' } });
|
||
});
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 5: LEGEND PANEL
|
||
// ════════════════════════════════════════════════════
|
||
function renderLegendItem(item) {
|
||
return `<li>${item.name}${item.cond ? ` <span class="cond">— ${item.cond}</span>` : ''}</li>`;
|
||
}
|
||
|
||
function showNodeLegend(nodeId) {
|
||
document.getElementById('legend-node-content').style.display = '';
|
||
document.getElementById('legend-edge-content').style.display = 'none';
|
||
document.getElementById('legend-sections-content').style.display = 'none';
|
||
document.getElementById('legend-wishlist-content').style.display = 'none';
|
||
const node = NODES.find(n => n.id === nodeId);
|
||
const details = NODE_DETAILS[nodeId];
|
||
const panel = document.getElementById('legend-panel');
|
||
|
||
if (!node || !details) { panel.classList.remove('visible'); return; }
|
||
|
||
document.getElementById('legend-title').textContent = node.label.replace(/\n/g, ' ');
|
||
|
||
const catLabel = CATEGORY_LABELS[node.group] || node.group;
|
||
const catColor = GROUPS[node.group] && GROUPS[node.group].color ? GROUPS[node.group].color.border : '#839496';
|
||
document.getElementById('legend-category').innerHTML =
|
||
`<span style="color:${catColor}; font-weight:600;">● ${catLabel}</span>`;
|
||
|
||
// ── Паспорт узла (iter6) ──
|
||
const meta = NODE_META[nodeId] || { since: '—', changed: '—', uses: null, usesSrc: '—' };
|
||
document.getElementById('ld-since').textContent = meta.since || '—';
|
||
document.getElementById('ld-changed').textContent = meta.changed || '—';
|
||
const _sec = NODE_SECTION[nodeId] ? SECTION_BY_ID.get(NODE_SECTION[nodeId]) : null;
|
||
const _secExtra = (NODE_SECTION_SECONDARY[nodeId] || [])
|
||
.map(id => SECTION_BY_ID.get(id)).filter(Boolean);
|
||
let _secText = _sec ? `${_sec.id} · ${_sec.label}` : '—';
|
||
if (_secExtra.length) _secText += ` (+${_secExtra.map(s => s.id).join(', ')})`;
|
||
document.getElementById('ld-section').textContent = _secText;
|
||
|
||
const usesEl = document.getElementById('ld-uses');
|
||
if (meta.uses === null || meta.uses === undefined) {
|
||
usesEl.textContent = 'нет данных (узел не вызывается напрямую)';
|
||
usesEl.style.color = '#586e75';
|
||
} else {
|
||
usesEl.innerHTML = `<b>${meta.uses}</b> <span style="color:#839496;">(${meta.usesSrc}) · срез ${META_WINDOW}</span>`;
|
||
usesEl.style.color = '';
|
||
}
|
||
|
||
// строка «Дубль» — парный дубль (DUPLICATE_GROUPS) либо ролевая заметка ruflo (dupNote)
|
||
const dupRow = document.getElementById('ld-dup-row');
|
||
const dupEl = document.getElementById('ld-dup');
|
||
const pair = DUP_BY_NODE.get(nodeId);
|
||
if (pair) {
|
||
const partnerNode = NODES.find(n => n.id === pair.partner);
|
||
const partnerLabel = partnerNode ? partnerNode.label.replace(/\n/g, ' ') : pair.partner;
|
||
dupEl.innerHTML = `⧉ <b>${partnerLabel}</b> (~${pair.pct}%) — ${pair.reason}`;
|
||
dupRow.style.display = '';
|
||
} else if (meta.dupNote) {
|
||
dupEl.innerHTML = `⧉ ${meta.dupNote}`;
|
||
dupRow.style.display = '';
|
||
} else {
|
||
dupRow.style.display = 'none';
|
||
}
|
||
|
||
document.getElementById('ld-desc').textContent = details.desc;
|
||
document.getElementById('ld-when').textContent = details.when || '—';
|
||
document.getElementById('ld-limits').textContent = details.limits || 'без особых ограничений';
|
||
|
||
const ldReports = document.getElementById('ld-reports');
|
||
ldReports.innerHTML = details.reportsTo.length
|
||
? details.reportsTo.map(renderLegendItem).join('')
|
||
: '<li style="color:#586e75; font-style:italic;">Не подчиняется никому</li>';
|
||
|
||
const ldManages = document.getElementById('ld-manages');
|
||
ldManages.innerHTML = details.manages.length
|
||
? details.manages.map(renderLegendItem).join('')
|
||
: '<li style="color:#586e75; font-style:italic;">Никто не подчиняется</li>';
|
||
|
||
const ldTogether = document.getElementById('ld-together');
|
||
ldTogether.innerHTML = details.together.length
|
||
? details.together.map(renderLegendItem).join('')
|
||
: '<li style="color:#586e75; font-style:italic;">Нет особых одновременных связей</li>';
|
||
|
||
const ldConflicts = document.getElementById('ld-conflicts');
|
||
if (details.conflicts && details.conflicts.length) {
|
||
const sorted = [...details.conflicts].sort((a, b) =>
|
||
(CONFLICT_TYPES[a.type] ? CONFLICT_TYPES[a.type].rank : 999) -
|
||
(CONFLICT_TYPES[b.type] ? CONFLICT_TYPES[b.type].rank : 999)
|
||
);
|
||
ldConflicts.innerHTML = sorted.map(c => {
|
||
const t = CONFLICT_TYPES[c.type] || CONFLICT_TYPES.RED;
|
||
return `<div class="conflict-item" style="background:${t.bg}">` +
|
||
`<div class="cname" style="color:${t.color}">${t.emoji} ${c.name}</div>` +
|
||
`<div class="cdesc">${c.desc}</div>` +
|
||
`</div>`;
|
||
}).join('');
|
||
} else {
|
||
ldConflicts.innerHTML = '<div id="legend-no-conflicts" style="font-size:12px;color:#586e75;">Конфликтов не выявлено</div>';
|
||
}
|
||
document.getElementById('conflicts-section').style.display = '';
|
||
|
||
panel.classList.add('visible');
|
||
}
|
||
|
||
function showEdgeLegend(edgeId) {
|
||
const edge = edgesDS.get(edgeId);
|
||
if (!edge) return;
|
||
|
||
const panel = document.getElementById('legend-panel');
|
||
document.getElementById('legend-node-content').style.display = 'none';
|
||
document.getElementById('legend-edge-content').style.display = '';
|
||
document.getElementById('legend-sections-content').style.display = 'none';
|
||
document.getElementById('legend-wishlist-content').style.display = 'none';
|
||
|
||
const fromNode = NODES.find(n => n.id === edge.from);
|
||
const toNode = NODES.find(n => n.id === edge.to);
|
||
if (!fromNode || !toNode) return;
|
||
|
||
const fromCat = CATEGORY_LABELS[fromNode.group] || fromNode.group;
|
||
const toCat = CATEGORY_LABELS[toNode.group] || toNode.group;
|
||
const fromColor = (GROUPS[fromNode.group] && GROUPS[fromNode.group].color) ? GROUPS[fromNode.group].color.border : '#839496';
|
||
const toColor = (GROUPS[toNode.group] && GROUPS[toNode.group].color) ? GROUPS[toNode.group].color.border : '#839496';
|
||
const edgeColor = (edge.color && edge.color.color) ? edge.color.color : '#586e75';
|
||
|
||
document.getElementById('legend-edge-title').innerHTML =
|
||
'<span style="color:' + fromColor + '">' + fromNode.label.replace(/\n/g, ' ') + '</span>' +
|
||
' <span style="color:' + edgeColor + '">→</span> ' +
|
||
'<span style="color:' + toColor + '">' + toNode.label.replace(/\n/g, ' ') + '</span>';
|
||
|
||
document.getElementById('le-from').innerHTML =
|
||
fromNode.label.replace(/\n/g, ' ') +
|
||
' <span style="color:' + fromColor + ';font-size:11px;text-transform:uppercase;">(' + fromCat + ')</span>';
|
||
document.getElementById('le-to').innerHTML =
|
||
toNode.label.replace(/\n/g, ' ') +
|
||
' <span style="color:' + toColor + ';font-size:11px;text-transform:uppercase;">(' + toCat + ')</span>';
|
||
|
||
const details = EDGE_DETAILS[edgeKey(edge.from, edge.to)];
|
||
if (details) {
|
||
document.getElementById('le-type').textContent = details.type;
|
||
document.getElementById('le-when').textContent = details.when;
|
||
document.getElementById('le-transfers').textContent = details.transfers;
|
||
document.getElementById('le-mandatory').textContent = details.mandatory;
|
||
document.getElementById('le-rule').textContent = details.rule;
|
||
} else {
|
||
['le-type','le-when','le-transfers','le-mandatory'].forEach(id =>
|
||
document.getElementById(id).textContent = '—');
|
||
document.getElementById('le-rule').textContent = 'Регламент не задокументирован';
|
||
}
|
||
|
||
panel.classList.add('visible');
|
||
}
|
||
|
||
// ── Панель «Разделы» — функциональная квалификация (3-й режим легенды) ──
|
||
function showSectionsLegend() {
|
||
document.getElementById('legend-node-content').style.display = 'none';
|
||
document.getElementById('legend-edge-content').style.display = 'none';
|
||
document.getElementById('legend-wishlist-content').style.display = 'none';
|
||
document.getElementById('legend-sections-content').style.display = '';
|
||
let html = '';
|
||
for (const bucket of SECTION_BUCKETS) {
|
||
html += `<div class="sect-bucket-h">${bucket.id}. ${bucket.label}</div>`;
|
||
for (const sec of SECTIONS.filter(s => s.bucket === bucket.id)) {
|
||
const nodeIds = SECTION_NODES.get(sec.id) || [];
|
||
const empty = nodeIds.length === 0;
|
||
html += `<div class="sect-row${empty ? ' sect-empty' : ''}">`;
|
||
html += `<div><span class="sect-name"><span class="sect-id">${sec.id}</span> ${sec.label}</span> <span class="sect-cnt">· ${nodeIds.length}</span></div>`;
|
||
if (empty) {
|
||
html += `<div class="sect-empty-mark">— пусто (playbook ещё не наполнен) —</div>`;
|
||
} else {
|
||
html += '<div class="sect-chips">' + nodeIds.map(id => {
|
||
const node = NODES.find(n => n.id === id);
|
||
const lbl = node ? node.label.replace(/\n/g, ' ') : id;
|
||
return `<span class="sect-chip" data-node="${id}">${lbl}</span>`;
|
||
}).join('') + '</div>';
|
||
}
|
||
html += '</div>';
|
||
}
|
||
}
|
||
document.getElementById('sect-list').innerHTML = html;
|
||
document.getElementById('legend-panel').classList.add('visible');
|
||
}
|
||
|
||
// ── Панель «Хотелки» — отложенный backlog (режим легенды) ──
|
||
function showWishlistLegend() {
|
||
document.getElementById('legend-node-content').style.display = 'none';
|
||
document.getElementById('legend-edge-content').style.display = 'none';
|
||
document.getElementById('legend-sections-content').style.display = 'none';
|
||
document.getElementById('legend-wishlist-content').style.display = '';
|
||
let html = '';
|
||
for (const w of WISHLIST) {
|
||
const st = WISH_STATUS[w.status] || WISH_STATUS.idea;
|
||
html += `<div class="wish-row wish-${w.status}">`;
|
||
html += `<div class="wish-head"><span class="wish-id">${w.id}</span> ${w.title}</div>`;
|
||
html += `<div class="wish-status" style="color:${st.color}">${st.emoji} ${st.label}</div>`;
|
||
html += `<div class="wish-note">${w.note}</div>`;
|
||
if (w.section) {
|
||
const sec = SECTION_BY_ID.get(w.section);
|
||
html += `<div class="wish-sect">Раздел: ${w.section}${sec ? ' · ' + sec.label : ''}</div>`;
|
||
}
|
||
html += '</div>';
|
||
}
|
||
document.getElementById('wish-list').innerHTML = html;
|
||
document.getElementById('legend-panel').classList.add('visible');
|
||
}
|
||
|
||
network.on('click', params => {
|
||
if (params.nodes.length === 1) {
|
||
const id = params.nodes[0];
|
||
// iter6 — в режиме heat/dup клик открывает паспорт, но не трогает подсветку режима
|
||
if (HIGHLIGHT.state.viewMode === null) {
|
||
HIGHLIGHT.setSelectedNode(id);
|
||
HIGHLIGHT.applyHighlight();
|
||
}
|
||
// Right panel still shows details of the clicked node (last-clicked, even after toggle-off)
|
||
showNodeLegend(id);
|
||
} else if (params.edges.length === 1) {
|
||
showEdgeLegend(params.edges[0]);
|
||
} else if (params.nodes.length === 0 && params.edges.length === 0) {
|
||
if (HIGHLIGHT.state.viewMode === null) {
|
||
HIGHLIGHT.setSelectedNode(null);
|
||
HIGHLIGHT.applyHighlight();
|
||
}
|
||
document.getElementById('legend-panel').classList.remove('visible');
|
||
}
|
||
});
|
||
|
||
document.getElementById('legend-close').addEventListener('click', () => {
|
||
document.getElementById('legend-panel').classList.remove('visible');
|
||
});
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 6: TOOLBAR
|
||
// ════════════════════════════════════════════════════
|
||
let highlightedNode = null;
|
||
|
||
document.getElementById('search').addEventListener('input', function () {
|
||
// Search is a separate mode — last-wins over highlight state
|
||
HIGHLIGHT.clearAll();
|
||
HIGHLIGHT.updateLegendVisuals();
|
||
const q = this.value.trim().toLowerCase();
|
||
if (!q) {
|
||
nodesDS.update(NODES.map(n => ({ id: n.id, borderWidth: 2, opacity: 1.0 })));
|
||
highlightedNode = null;
|
||
return;
|
||
}
|
||
const matches = NODES.filter(n => n.label.toLowerCase().includes(q));
|
||
const updates = NODES.map(n => {
|
||
const match = matches.some(m => m.id === n.id);
|
||
return {
|
||
id: n.id,
|
||
borderWidth: match ? 5 : 1,
|
||
opacity: match ? 1.0 : 0.25,
|
||
};
|
||
});
|
||
nodesDS.update(updates);
|
||
if (matches.length === 1) {
|
||
network.focus(matches[0].id, { scale: 1.4, animation: { duration: 500, easingFunction: 'easeInOutQuad' } });
|
||
showNodeLegend(matches[0].id);
|
||
highlightedNode = matches[0].id;
|
||
}
|
||
});
|
||
|
||
document.getElementById('btn-freeze').addEventListener('click', () => {
|
||
network.setOptions({ physics: { enabled: false } });
|
||
});
|
||
|
||
document.getElementById('btn-unfreeze').addEventListener('click', () => {
|
||
network.setOptions({
|
||
physics: {
|
||
enabled: true,
|
||
solver: 'forceAtlas2Based',
|
||
forceAtlas2Based: {
|
||
gravitationalConstant: -50,
|
||
centralGravity: 0.0,
|
||
springLength: 100,
|
||
springConstant: 0.02,
|
||
damping: 0.6,
|
||
avoidOverlap: 0.4,
|
||
},
|
||
},
|
||
});
|
||
});
|
||
|
||
document.getElementById('btn-reset').addEventListener('click', () => {
|
||
// (a) Restore radial positions
|
||
nodesDS.update(NODES.map(n => ({ id: n.id, x: n.x, y: n.y })));
|
||
// (b) Refit camera
|
||
network.fit({ animation: { duration: 600, easingFunction: 'easeInOutQuad' } });
|
||
});
|
||
|
||
document.getElementById('btn-clear').addEventListener('click', () => {
|
||
document.getElementById('search').value = '';
|
||
HIGHLIGHT.clearAll();
|
||
HIGHLIGHT.updateLegendVisuals();
|
||
HIGHLIGHT.applyHighlight();
|
||
nodesDS.update(NODES.map(n => ({ id: n.id, borderWidth: 2 }))); // reset borderWidth used by search-highlight
|
||
document.getElementById('legend-panel').classList.remove('visible');
|
||
highlightedNode = null;
|
||
});
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 7: RESIZE HANDLE + LOCALSTORAGE
|
||
// ════════════════════════════════════════════════════
|
||
const LEGEND_STORAGE_KEY = 'liderra-map-legend-width';
|
||
const LEGEND_MIN_W = 300, LEGEND_MAX_W = 900;
|
||
|
||
let redrawScheduled = false;
|
||
function applyLegendWidth(w) {
|
||
const clamped = Math.max(LEGEND_MIN_W, Math.min(LEGEND_MAX_W, w));
|
||
const panel = document.getElementById('legend-panel');
|
||
panel.style.width = clamped + 'px';
|
||
panel.style.minWidth = clamped + 'px';
|
||
if (typeof network !== 'undefined' && network && !redrawScheduled) {
|
||
redrawScheduled = true;
|
||
requestAnimationFrame(() => {
|
||
redrawScheduled = false;
|
||
network.redraw();
|
||
});
|
||
}
|
||
}
|
||
|
||
function restoreLegendWidth() {
|
||
let saved = 300;
|
||
try {
|
||
saved = parseInt(localStorage.getItem(LEGEND_STORAGE_KEY) || '300', 10);
|
||
} catch (e) { /* private mode or quota — keep default */ }
|
||
applyLegendWidth(saved);
|
||
}
|
||
|
||
(function setupResizeHandle() {
|
||
const handle = document.getElementById('legend-handle');
|
||
if (!handle) return;
|
||
let dragging = false;
|
||
handle.addEventListener('mousedown', e => {
|
||
dragging = true;
|
||
handle.classList.add('dragging');
|
||
document.body.style.userSelect = 'none';
|
||
e.preventDefault();
|
||
});
|
||
document.addEventListener('mousemove', e => {
|
||
if (!dragging) return;
|
||
const w = window.innerWidth - e.clientX;
|
||
applyLegendWidth(w);
|
||
});
|
||
document.addEventListener('mouseup', () => {
|
||
if (!dragging) return;
|
||
dragging = false;
|
||
handle.classList.remove('dragging');
|
||
document.body.style.userSelect = '';
|
||
const w = parseInt(document.getElementById('legend-panel').style.width, 10);
|
||
try { localStorage.setItem(LEGEND_STORAGE_KEY, String(w)); } catch (e) { /* private mode or quota */ }
|
||
});
|
||
})();
|
||
|
||
// ════════════════════════════════════════════════════
|
||
// SECTION 8: HIGHLIGHTING (legend filter + node focus)
|
||
// ════════════════════════════════════════════════════
|
||
const HIGHLIGHT = (function setupHighlight() {
|
||
const FILTER_GROUP_PREFIX = 'group:';
|
||
const FILTER_CONFLICT_PREFIX = 'conflict:';
|
||
const OPACITY_FOCUS = 1.0;
|
||
const OPACITY_FILTER = 0.55;
|
||
const OPACITY_DIM = 0.15;
|
||
const CONFLICT_EDGE_MIN_OPACITY = 0.85;
|
||
|
||
const state = {
|
||
selectedNode: null,
|
||
legendFilter: new Set(),
|
||
viewMode: null, // null | 'heat' | 'dup' — взаимоисключающие режимы (iter6)
|
||
};
|
||
|
||
// ── Теплокарта использования (iter6) — 4 яруса по NODE_META[id].uses ──
|
||
function heatOpacity(nodeId) {
|
||
const m = NODE_META[nodeId];
|
||
const u = m ? m.uses : null;
|
||
if (u === null || u === undefined) return 0.5; // нет данных — нейтрально
|
||
if (u >= 21) return 1.0; // часто
|
||
if (u >= 6) return 0.65; // иногда
|
||
if (u >= 1) return 0.35; // редко
|
||
return 0.12; // простаивает (uses === 0)
|
||
}
|
||
// Узлы верхнего яруса теплокарты получают акцентную рамку.
|
||
function heatBorderWidth(nodeId) {
|
||
if (state.viewMode !== 'heat') return 2;
|
||
const m = NODE_META[nodeId];
|
||
const u = m ? m.uses : null;
|
||
return (typeof u === 'number' && u >= 21) ? 4 : 2;
|
||
}
|
||
// Переключатель режима — toggle; включение режима гасит пофильтровую подсветку.
|
||
function setViewMode(mode) {
|
||
state.viewMode = (state.viewMode === mode) ? null : mode;
|
||
if (state.viewMode !== null) {
|
||
state.legendFilter.clear();
|
||
state.selectedNode = null;
|
||
}
|
||
}
|
||
|
||
// ── Pre-computed indices ──────────────────────────
|
||
const NODES_BY_ID = new Map();
|
||
const NEIGHBOURS = new Map();
|
||
const CONFLICT_ENDPOINTS = { RED: new Set(), BLACK: new Set(), GREEN: new Set() };
|
||
const CONFLICT_EDGE_TYPE = new Map();
|
||
|
||
NODES.forEach(n => {
|
||
NODES_BY_ID.set(n.id, n);
|
||
if (!NEIGHBOURS.has(n.id)) NEIGHBOURS.set(n.id, new Set());
|
||
});
|
||
|
||
edgesDS.get().forEach(edge => {
|
||
// Both directions — Q5; conflict edges count as connections — Q6
|
||
if (NEIGHBOURS.has(edge.from)) NEIGHBOURS.get(edge.from).add(edge.to);
|
||
if (NEIGHBOURS.has(edge.to)) NEIGHBOURS.get(edge.to).add(edge.from);
|
||
if (edge.dashes && edge.color && edge.color.color) {
|
||
for (const t of ['RED', 'BLACK', 'GREEN']) {
|
||
if (CONFLICT_TYPES[t].color === edge.color.color) {
|
||
CONFLICT_ENDPOINTS[t].add(edge.from);
|
||
CONFLICT_ENDPOINTS[t].add(edge.to);
|
||
CONFLICT_EDGE_TYPE.set(edge.id, t);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// ── Opacity computations ──────────────────────────
|
||
function computeNodeOpacity(nodeId) {
|
||
// Row 0: view-mode (iter6) — глобальная картина, поверх focus/filter
|
||
if (state.viewMode === 'heat') return heatOpacity(nodeId);
|
||
if (state.viewMode === 'dup') return DUP_NODE_SET.has(nodeId) ? OPACITY_FOCUS : OPACITY_DIM;
|
||
// Row 1: focus
|
||
if (state.selectedNode !== null) {
|
||
if (state.selectedNode === nodeId) return OPACITY_FOCUS;
|
||
const neigh = NEIGHBOURS.get(state.selectedNode);
|
||
if (neigh && neigh.has(nodeId)) return OPACITY_FOCUS;
|
||
}
|
||
// Row 2: idle
|
||
if (state.legendFilter.size === 0 && state.selectedNode === null) return OPACITY_FOCUS;
|
||
// Row 3: in filter?
|
||
const node = NODES_BY_ID.get(nodeId);
|
||
let inFilter = false;
|
||
if (node && state.legendFilter.has(FILTER_GROUP_PREFIX + node.group)) inFilter = true;
|
||
if (!inFilter) {
|
||
for (const t of ['RED', 'BLACK', 'GREEN']) {
|
||
if (state.legendFilter.has(FILTER_CONFLICT_PREFIX + t) && CONFLICT_ENDPOINTS[t].has(nodeId)) {
|
||
inFilter = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
if (inFilter) return state.selectedNode ? OPACITY_FILTER : OPACITY_FOCUS;
|
||
// Row 4: everything else
|
||
return OPACITY_DIM;
|
||
}
|
||
|
||
function computeEdgeOpacity(edge) {
|
||
const fromO = computeNodeOpacity(edge.from);
|
||
const toO = computeNodeOpacity(edge.to);
|
||
const baseline = Math.min(fromO, toO);
|
||
// Conflict edge directly selected via 🔴/⚫/🟢 in filter — boost to ≥0.85
|
||
const ctype = CONFLICT_EDGE_TYPE.get(edge.id);
|
||
if (ctype && state.legendFilter.has(FILTER_CONFLICT_PREFIX + ctype)) {
|
||
return Math.max(CONFLICT_EDGE_MIN_OPACITY, baseline);
|
||
}
|
||
return baseline;
|
||
}
|
||
|
||
function applyHighlight() {
|
||
const nodeUpdates = NODES.map(n => ({
|
||
id: n.id,
|
||
opacity: computeNodeOpacity(n.id),
|
||
borderWidth: heatBorderWidth(n.id), // 4 для верхнего яруса теплокарты, иначе 2 (iter6)
|
||
}));
|
||
const edgeUpdates = edgesDS.get().map(e => ({
|
||
id: e.id,
|
||
color: Object.assign({}, e.color || {}, { opacity: computeEdgeOpacity(e) }),
|
||
}));
|
||
nodesDS.update(nodeUpdates);
|
||
edgesDS.update(edgeUpdates);
|
||
}
|
||
|
||
// ── State manipulators ────────────────────────────
|
||
function toggleFilter(key) {
|
||
if (state.legendFilter.has(key)) state.legendFilter.delete(key);
|
||
else state.legendFilter.add(key);
|
||
}
|
||
|
||
function setSelectedNode(id) {
|
||
if (state.selectedNode === id) state.selectedNode = null; // toggle on repeat
|
||
else state.selectedNode = id;
|
||
}
|
||
|
||
function clearAll() {
|
||
state.selectedNode = null;
|
||
state.legendFilter.clear();
|
||
state.viewMode = null;
|
||
}
|
||
|
||
function updateLegendVisuals() {
|
||
document.querySelectorAll('#cat-legend .cat-item').forEach(item => {
|
||
const key = item.dataset.filterKey;
|
||
if (!key) return;
|
||
if (state.legendFilter.has(key)) item.classList.add('active');
|
||
else item.classList.remove('active');
|
||
});
|
||
const heatBtn = document.getElementById('cat-ctl-heat');
|
||
const dupBtn = document.getElementById('cat-ctl-dup');
|
||
if (heatBtn) heatBtn.classList.toggle('active', state.viewMode === 'heat');
|
||
if (dupBtn) dupBtn.classList.toggle('active', state.viewMode === 'dup');
|
||
}
|
||
|
||
// ── Legend click delegation ───────────────────────
|
||
document.getElementById('cat-legend').addEventListener('click', e => {
|
||
// iter6 — клик по кнопке режима heat/dup
|
||
const ctl = e.target.closest('.cat-ctl');
|
||
if (ctl) {
|
||
if (ctl.id === 'cat-ctl-sect') { showSectionsLegend(); return; }
|
||
if (ctl.id === 'cat-ctl-wish') { showWishlistLegend(); return; }
|
||
setViewMode(ctl.id === 'cat-ctl-heat' ? 'heat' : 'dup');
|
||
applyHighlight();
|
||
updateLegendVisuals();
|
||
return;
|
||
}
|
||
const item = e.target.closest('.cat-item');
|
||
if (!item || !item.dataset.filterKey) return;
|
||
toggleFilter(item.dataset.filterKey);
|
||
applyHighlight();
|
||
updateLegendVisuals();
|
||
});
|
||
|
||
// Expose API (closes over state)
|
||
return {
|
||
applyHighlight,
|
||
toggleFilter,
|
||
setSelectedNode,
|
||
clearAll,
|
||
updateLegendVisuals,
|
||
state, // exposed for debug only
|
||
};
|
||
})();
|
||
|
||
// Клик по чипу узла в панели «Разделы» — открыть паспорт узла + сфокусировать граф.
|
||
document.getElementById('sect-list').addEventListener('click', e => {
|
||
const chip = e.target.closest('.sect-chip');
|
||
if (!chip) return;
|
||
const id = chip.dataset.node;
|
||
if (HIGHLIGHT.state.viewMode === null) {
|
||
HIGHLIGHT.setSelectedNode(id);
|
||
HIGHLIGHT.applyHighlight();
|
||
}
|
||
network.focus(id, { scale: 1.2, animation: { duration: 500, easingFunction: 'easeInOutQuad' } });
|
||
showNodeLegend(id);
|
||
});
|
||
|
||
window.addEventListener('DOMContentLoaded', restoreLegendWidth);
|
||
</script>
|
||
</body>
|
||
</html>
|