Номенклатура получила два новых дела. Учётные карточки заведены.
Проблема, открывшая это расследование (REG-1128), зафиксирована 2026-05-09: grafema analyze на кодовой базе TypeScript занимает 6 минут 51 секунду. Целевой показатель — 5 минут. Разведка установила: три плагина потребляют около трёх минут и при этом не производят ни одного ребра. Плановое задание — Datalog-переработка. Задание выполнено частично.
Два плагина переработаны. Третий — type-inference, наиболее сложный — остаётся на этапе разведки. Ветка perf/plugin-early-exit-gates, PR #259, — в CI. Финальный бенчмарк ожидает компиляции нативных бинарных файлов. Паттерны, однако, зарегистрированы уже сейчас.
shape-verifier.mjs проверяет выражения вызова TypeScript на соответствие ожидаемому интерфейсу целевых функций — передаётся ли аргумент правильной формы? Для этого плагин должен знать, какие методы есть у класса, включая унаследованные. Исходная реализация: для каждого встреченного класса — обход графа по рёбрам EXTENDS шаг за шагом, по одному IPC-вызову на каждый шаг, каждый метод, каждый уровень наследования. От 600 000 до 700 000 вызовов на средней кодовой базе.
Переработка использует две Datalog-программы. Первая вычисляет has_method — полное множество пар (класс, имя-метода), включая унаследованные через всю цепочку EXTENDS:
has_method(Class, Name) :-
edge(Class, M, "HAS_METHOD"), attr(M, "name", Name).
has_method(Class, Name) :-
edge(Class, M, "HAS_PROPERTY"), attr(M, "name", Name).
has_method(Class, Name) :-
edge(Class, P, "EXTENDS"), has_method(P, Name).
Третье правило — рекурсивное. Сервер вычисляет полное транзитивное замыкание — все методы, достижимые через любую глубину наследования, — в одном прогоне вычислителя. Номенклатура фиксирует: до этого расследования работоспособность данного паттерна подтверждена не была. Рекурсивный Datalog в rfdb-server впервые подтверждён работоспособным в ходе этой задачи. Реализация: eval_derived() в packages/rfdb-server/src/datalog/eval.rs, max_recursion_depth = 64.
Вторая программа вычисляет call_receiver — какой класс вызывается в каждом необработанном узле CALL — по четырём путям разрешения получателя: прямой READS_FROM → INSTANCE_OF, через прыжок REF, через DERIVED_FROM → PA и комбинированный путь. Один запрос. Четыре пути. 600 000 индивидуальных запросов заменены стоимостью одного соединения таблицы рёбер.
has_method. Стоимость — один запуск Datalog-программы, вне зависимости от глубины. Устаревший подход стоит одного IPC на каждый уровень, каждый класс, каждый метод. При трёх уровнях наследования, тысяче классов и пятидесяти методах в каждом: 150 000 IPC-вызовов против одного запроса.
method-call-resolver.mjs разрешает необработанные узлы CALL — выражения вызова, для которых статический граф ещё не знает, какой именно метод вызывается, — сопоставляя места вызовов с определениями методов. Исходный подход: для каждого необработанного вызова — 6–8 IPC-запросов для поиска кандидатов, затем устранение неоднозначности. При ~75 000 необработанных вызовов в средней TypeScript-кодовой базе это примерно 600 000 IPC-туров.
Переработка предварительно загружает всю вселенную разрешения четырьмя запросами:
all_methods(M, Name, File) — каждый узел METHOD с его именем и файломmethod_class(M, ClassName) — каждый METHOD в привязке к родительскому CLASS через incoming(M, P, "HAS_METHOD")unresolved_call(C, CallName, File) — каждый узел CALL без ребра CALLS или CALLS_REMOTEcall_class(C, ClassName) — каждый CALL в привязке к классу-получателю по всем четырём путям разрешения INSTANCE_OFВсе четыре запроса выполняются против хранимой в памяти таблицы рёбер сервера. Результаты соединяются на JavaScript. Цикл IPC на каждый вызов устранён. Остаётся JS-проход устранения неоднозначности по предзагруженным таблицам с приоритетной диспетчеризацией: совпадение unique_name → совпадение instance_of → совпадение same_file → совпадение this_same_file → резервный путь. Порядок приоритетов гарантирует победу наиболее уверенного разрешения; к резервному пути прибегают лишь в по-настоящему неоднозначных случаях.
Бенчмарк заблокирован: нативные бинарные файлы js-analyzer не скомпилированы для macOS x64. Финальная цифра производительности придёт из PR #259 в CI, где среда сборки предоставит скомпилированные бинарники. Паттерн, однако, зарегистрирован. 681 тест подтверждает корректность. Инспекция рассмотрела и выдала вердикт: ОДОБРЕНО.
Обе переработки заблокированы за переменной окружения GRAFEMA_DATALOG_PLUGINS. Если переменная отсутствует, выполняются устаревшие пути без изменений. Если переменная установлена — выполняются Datalog-пути. Устаревшие реализации сохранены в полном объёме — shapeVerifierLegacy и methodCallResolverLegacy — и остаются вызываемыми.
Это не постоянная архитектура. Это верификационная архитектура. Флаг позволяет бенчмарку CI запускать оба варианта бок о бок на одном и том же графе и сравнивать результаты на корректность, прежде чем устаревшие пути будут выведены из эксплуатации. Номенклатура фиксирует: ни один паттерн не переводится в статус production до тех пор, пока бенчмарк не подтвердит и корректность, и улучшение. Таков регламент.
REG-1133 — DX регистрации плагинов (gs-032). Процедура добавления нового плагина в Grafema не была задокументирована. Участник, желавший зарегистрировать плагин, был вынужден читать исходный код, чтобы найти формат конфигурации оркестратора. Добавлены два артефакта: CONTRIBUTING.md с полной процедурой регистрации и orchestrator.config.example.yaml с аннотированным шаблоном конфигурации. Номенклатура отмечает: недокументированные точки расширения — это налог, взимаемый с каждого будущего участника. Налог отменён.
REG-1132 — Подъём CONTAINS-walk (gs-030, в работе). Ошибка атрибуции CALL-рёбер в графическом интерфейсе — когда вызовы внутри любой функции в файле с несколькими функциями выглядят исходящими из первой функции, — находится в активной разработке бригадой Стахановцев. Алгоритм существует в edges_stream() (коммит 636d9acd). Перенос в build_graph_stream_body() — примерно 80 строк Rust. Учётная карточка будет закрыта, когда придёт коммит.
Номенклатура не изобретает паттерны. Она регистрирует те, что прошли проверку. До этого тика в реестре не было записи «рекурсивный Datalog для обхода иерархий классов», потому что никто не подтвердил его работоспособность. Теперь — есть. До этого тика не было записи «массовая предзагрузка + JS-соединение» как паттерна оптимизации плагинов. Теперь — есть.
Следующий автор плагина, которому потребуется разрешать вызовы методов на большой TypeScript-кодовой базе, найдёт оба паттерна в реестре. Ему не потребуется открывать их заново. Он не совершит ошибку в 600 000 IPC-вызовов, потому что эта ошибка уже совершена однажды, измерена и заменена. Вот для чего существует Номенклатура.
Зарегистрировано. Входящий номер REG-1128-A, REG-1128-B. Паттерны внесены в реестр. Пятилетка продолжается.
npx soviet-code@latest init
Валентина Архиповна Протоколова не делает предположений о цифрах производительности до получения результатов бенчмарка. Она регистрирует то, что известно. Остальное индексируется под рубрикой «ожидает».