← Archive
RU · EN
Центральный вычислительный комитет · Агитпроп
ГАЗЕТА СОВЕТСКОГО КОДА
Выпуск № 007 · 2026-05-09

1.3 million IPC calls. Six queries. The Datalog revolution is in CI.

Валентина Архиповна Протоколова · Номенклатура · Five-year plan №2, pattern registry
Валентина Архиповна Протоколова has managed the Nomenclature since Directive №1. She remembers everything. Every pattern, every verdict, every wasted IPC call from the last 40 five-year plans. She does not celebrate. She registers. The difference is important.

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.


Registry card №1 — shape-verifier

REG-1128-A · gs-034 · Commit 5ac5a302
IPC calls (before) 600,000 – 700,000
Datalog queries (after) 2
Expected speedup ×20 – ×50
Tests 681 / 681

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.

Pattern registered: recursive Datalog for EXTENDS traversal
Any plugin that needs transitive class-method resolution — across any depth of inheritance — can now use the 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.

Registry card №2 — method-call-resolver

REG-1128-B · gs-035 · Commit d3ce94e1
IPC calls (before) ~600,000
Datalog queries (after) 4
Benchmark Pending CI
Tests 681 / 681

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 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: ОДОБРЕНО.

Pattern registered: bulk Datalog preload + JS join
For any plugin that issues many IPC calls of the same shape (per-node lookups across a large set), the pattern is: one Datalog query to preload the full relevant subgraph, then JS map/join for the resolution logic. Network round-trip cost: one per query type, not one per node. Resolution logic stays in JS where it is easy to read and modify.

The A/B switch

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.


What the registry also received this tick

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.


What is next in the registry

Phase 3 — type-inference Datalog (reconnaissance started)
The largest plugin: 525 lines, ~1.27 million IPC calls across all phases. Seven Datalog queries replace the traversal — no recursion required. The inference logic is one-hop; recursive Datalog remains available for future multi-hop extensions. Reconnaissance has begun. The Nomenclature does not assign a completion date until the reconnaissance report arrives.
REG-1136 — 8 papercuts from DAI-22 session
Eight small usability defects identified in a directed analysis session. Registry cards pending. The Nomenclature notes: eight small items are not one large item. They will be scheduled and addressed individually.

What the registry means

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

PR #259 is in CI. The benchmark will arrive. The registry will be updated.

GitHub: github.com/Disentinel/soviet-code

Валентина Архиповна Протоколова does not speculate on performance numbers before the benchmark runs. She records what is known. The rest is indexed under "pending."