Files
brain/docs/superpowers/specs/2026-06-21-graphify-tools-scope-design.md
T

7.0 KiB

Дизайн: scope авто-обновления графа под пост-сплит claude-brain

Дата: 2026-06-21 · Репозиторий: claude-brain (управляющий слой).

Цель

Привести scope инкрементального обнователя графа tools/graphify-safe-update.mjs в соответствие с пост-сплит реальностью проекта: индексировать прод-код управляющего слоя (tools/), перестать ссылаться на удалённый app/, и не засорять граф внутренностями тестов.

Контекст и проблема

Инкрементальный обнователь фильтрует изменённые файлы по списку разрешённых префиксов. Сейчас список — docs/, .claude/, app/. Последствия:

  • tools/ исключён — изменения прод-кода управляющего слоя (роутер/наставник/ судья/пол/замок) НЕ попадают в инкрементальное обновление графа. Узлы tools/ в графе замораживаются с последней полной сборки и дрейфуют от истины.
  • app/ мёртв — каталог удалён при разделении репозитория; префикс ссылается в пустоту.

Исторически широкий scope исключал tools/ ради защиты от раздутия графа. Та защита относилась к прежнему большому несистематизированному монорепо (каталог приложения ~3800 узлов + широкий рескан, тянувший зависимости). В текущем проекте этого нет: управляющий слой систематизирован (парные имя.mjs/имя.test.mjs), а обнователь использует узкий путь точечного AST-разбора по изменённым файлам, а не широкий рескан. Эмпирически: граф уже содержит tools/ при здоровом размере без раздутия.

Изменение: scope обнователя

Контракт. Список разрешённых префиксов становится docs/, .claude/, tools/ (добавлен tools/, удалён app/). Дополнительно из индексации исключаются тест-файлы по суффиксу .test.mjs — узлы тест-внутренностей (локальные переменные, заглушки) для навигации по графу являются шумом, не архитектурой.

Реализация (детерминированная, чистые функции).

  • Константа списка префиксов и список исключающих подстрок становятся экспортируемыми — чтобы новый контракт проверялся тестом напрямую, а не только через поведение CLI.
  • Исключающая подстрока .test.mjs добавляется в существующий список дисквалифицирующих подстрок; функция отбора по области уже отбрасывает путь, если он содержит любую такую подстроку (p.includes(ex)).
  • Поведенческий путь (точечный AST-разбор + слияние по стабильным идентификаторам) не меняется — меняется только множество файлов, попадающих в этот путь.

Крайние случаи и тесты

Тест-файл обнователя сейчас кодирует СТАРЫЙ контракт и должен быть переписан под новый (это нормальный разворот контракта по TDD):

  • Было (отменяется): «tools/... отвергается», «app/... сохраняется».
  • Стало (новые утверждения):
    • tools/<имя>.mjs (прод-код) — сохраняется;
    • tools/<имя>.test.mjsотбрасывается (исключение по .test.mjs);
    • app/...отбрасывается (вне нового scope);
    • docs/..., .claude/... — сохраняются (без регресса);
    • исключения по каталогам (node_modules/, vendor/, __pycache__/, .git/) — без регресса;
    • пустой ввод → пустой вывод.
  • Прямая проверка контракта: экспортируемый список префиксов содержит tools/ и не содержит app/.

Разделение код/документ по расширению (partitionByExtension) не меняется.

Амендмент ADR-017

Раздел «Стратегия обновлений» ADR-017 фиксировал исключение tools/ под прежний большой репозиторий. Внести амендмент: пометить ту мотивацию как историческую (контекст прежнего монорепо) и зафиксировать пост-сплит правило — tools/ входит в scope как прод-код управляющего слоя; *.test.mjs и удалённый app/ исключены. Решение об амендменте — владельца (зафиксировано на планировании 2026-06-21).

Критерий готовности

  • Экспортируемый список префиксов = ['docs/', '.claude/', 'tools/']; исключения содержат .test.mjs.
  • Переписанный тест-файл обнователя зелёный полным сводом (npx vitest run --config vitest.config.tools.mjs), без новых падений в остальном своде.
  • ADR-017 несёт амендмент с историческим примечанием и пост-сплит правилом scope.
  • Никаких изменений поведенческого пути разбора/слияния, кроме множества входных файлов.
[
  {"id":"vc-scopes","kind":"EXTRACTED","ref":"tools/graphify-safe-update.mjs","anchor":"const ALLOWED_SCOPES = ["},
  {"id":"vc-filter","kind":"EXTRACTED","ref":"tools/graphify-safe-update.mjs","anchor":"export function filterInScope("},
  {"id":"vc-adr","kind":"EXTRACTED","ref":"docs/adr/ADR-017-knowledge-graph-tooling.md","anchor":"Стратегия обновлений"}
]