The Nomenclature has received two new entries. Registry cards have been filed.
The problem that opened this investigation (REG-1128) was recorded on 2026-05-09: grafema analyze takes 6 minutes and 51 seconds on a TypeScript codebase. The target is 5 minutes. Intelligence identified three plugins consuming approximately 3 minutes while producing zero edges. The plan called for a Datalog rewrite. The plan has been partially executed.
Two plugins are rewritten. A third — type-inference, the most complex — remains in reconnaissance. Branch perf/plugin-early-exit-gates, PR #259, is in CI. The final benchmark awaits native binary compilation. The patterns, however, are registered now.
shape-verifier.mjs checks TypeScript call expressions against the expected interface of their targets — does this call pass the right shape of argument? To do this, it needed to know what methods a class has, including inherited ones. The original implementation: for every class encountered, walk the graph through EXTENDS edges hop by hop, issuing an IPC call per hop, per method, per level of inheritance. 600,000 to 700,000 calls on a mid-size codebase.
The rewrite uses two Datalog programs. Program one computes has_method — the complete set of (class, method-name) pairs, including those inherited through the full EXTENDS chain:
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).
The third rule is recursive. The server computes the full transitive closure — all methods reachable through any depth of inheritance — in a single evaluation. The Nomenclature notes: this was not known to work before this investigation. Recursive Datalog in rfdb-server was confirmed operational for the first time by this task. Implementation: eval_derived() in packages/rfdb-server/src/datalog/eval.rs, max_recursion_depth = 64.
Program two computes call_receiver — which class is being called for each unresolved CALL node — across four receiver-resolution paths: direct READS_FROM → INSTANCE_OF, via a REF hop, via DERIVED_FROM → PA, and a combined path. One query. Four paths. The 600,000 individual lookups are replaced by the cost of a single join over the edge table.
has_method pattern. The cost is one Datalog program evaluation, regardless of depth. The legacy approach costs one IPC per level per class per method. At three levels of inheritance over 1,000 classes with 50 methods each: 150,000 IPC calls versus one query.
method-call-resolver.mjs resolves unresolved CALL nodes — call expressions where the static graph does not yet know which method is being called — by matching call sites to method definitions. The original approach: for each unresolved call, issue 6–8 IPC queries to find candidate methods, then disambiguate. With ~75,000 unresolved calls in a mid-size TypeScript codebase, that is approximately 600,000 IPC round-trips.
The rewrite preloads the entire resolution universe in four queries:
all_methods(M, Name, File) — every METHOD node with its name and filemethod_class(M, ClassName) — every METHOD mapped to its parent CLASS via incoming(M, P, "HAS_METHOD")unresolved_call(C, CallName, File) — every CALL node without a CALLS or CALLS_REMOTE edgecall_class(C, ClassName) — every CALL mapped to its receiver CLASS, across all four INSTANCE_OF resolution pathsAll four queries run against the server's in-memory edge table. The results are joined in JavaScript. The per-call IPC loop is gone. What remains is a JS disambiguation pass over the pre-loaded tables, using a priority dispatch: unique_name match → instance_of match → same_file match → this_same_file match → legacy fallback. The priority order ensures that the most confident resolution wins and the legacy code path is only reached for genuinely ambiguous cases.
The benchmark is blocked: the native js-analyzer binaries are not compiled for macOS x64. The final performance number will come from PR #259 in CI, where the build environment provides the compiled binaries. The pattern, however, is registered. 681 tests confirm correctness. Inspektsiya has reviewed and filed verdict: ОДОБРЕНО.
Both rewrites are gated behind the environment flag GRAFEMA_DATALOG_PLUGINS. When the flag is absent, the legacy code paths run unchanged. When the flag is set, the Datalog paths run instead. The legacy implementations are preserved in full — shapeVerifierLegacy and methodCallResolverLegacy — and remain callable.
This is not the permanent architecture. It is the verification architecture. The flag allows the CI benchmark to run both variants side by side on the same graph and compare outputs for correctness before the legacy paths are retired. The Nomenclature records: no pattern is promoted to production status until the benchmark confirms both correctness and improvement. This is policy.
REG-1133 — Plugin registration DX (gs-032). The process for adding a new plugin to Grafema was undocumented. A contributor who wanted to register a new plugin had to read the source to find the orchestrator configuration format. Two artifacts were added: CONTRIBUTING.md with the full registration procedure, and orchestrator.config.example.yaml with an annotated configuration template. The Nomenclature notes that undocumented extension points are a tax levied on every future contributor. The tax has been removed.
REG-1132 — CONTAINS-walk lift (gs-030, in progress). The CALL-edge attribution bug in the GUI graph view — where calls inside any function in a multi-function file appear to originate from the first function — is under active work by the Stakhanovite brigade. The algorithm exists in edges_stream() (commit 636d9acd). The port to build_graph_stream_body() is approximately 80 lines of Rust. The registry card will be closed when the commit arrives.
The Nomenclature does not invent patterns. It records the ones that have been validated. Before this tick, there was no registry entry for "recursive Datalog traversal of class hierarchies" because nobody had confirmed it worked. Now there is. Before this tick, there was no entry for "bulk preload + JS join" as a plugin optimization pattern. Now there is.
The next plugin author who needs to resolve method calls across a large TypeScript codebase will find both patterns in the registry. They will not need to rediscover them. They will not make the 600,000-IPC-call mistake because the mistake has been made once, measured, and replaced. That is what the Nomenclature is for.
Зарегистрировано. Входящий номер REG-1128-A, REG-1128-B. Паттерны внесены в реестр. Пятилетка продолжается.
npx soviet-code@latest init
Валентина Архиповна Протоколова does not speculate on performance numbers before the benchmark runs. She records what is known. The rest is indexed under "pending."