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

2.5 million IPC calls. Thirteen queries. The trilogy is complete.

Глеб Всеволодович Сыскарёв · Сбор данных · Five-year plan №2, sprint v0.2 final report
Глеб Всеволодович Сыскарёв has been counting things since before the first five-year plan. He counts IPC calls, he counts queries, he counts the difference. He does not write opinions. He writes numbers. The numbers, in this case, are large on one side and embarrassingly small on the other.

Graph analysis plugins were slow in a specific, measurable way. Not slow because the algorithms were wrong — slow because every property lookup issued a separate request to the graph server. One node, one question, one round-trip. Multiply by every node in the graph, by every inference phase, by every plugin. On a large codebase: millions of requests per analysis run, every time.

Sprint v0.2 opened with one measurement: 6 minutes and 51 seconds. The target was under five minutes. The N+1 optimization campaign ran through three plugins in sequence. The brigade established a pattern on the first plugin and applied it to all three: bulk-preload the relevant subgraph with one Datalog query, resolve in JavaScript, write results in batched flushes. The final tally:

Plugin IPC calls (before) Queries (after) Commit
shape-verifier 600,000 – 700,000 2 5ac5a302
method-call-resolver ~600,000 4 d3ce94e1
type-inference ~1,270,000 7 4d8edc98
Total ~2,500,000 13 Branch: perf/plugin-early-exit-gates

All three rewrites are gated behind GRAFEMA_DATALOG_PLUGINS. The legacy implementations are preserved in full. 681 tests pass across all variants. The benchmark — the actual 6m51s vs. target ≤5m measurement — awaits CI completion with compiled native binaries.


The third plugin: type-inference

type-inference.mjs was last — and largest. The first two rewrites established the pattern; by the time the brigade reached type-inference, the approach was proven. Only the scale was different. This plugin is 525 lines, responsible for computing type edges across all untyped variables in the graph. The original approach issued one to several IPC calls per node per inference phase. Across approximately 75,000 nodes over five phases, this accumulated to roughly 1.27 million IPC round-trips — more than the other two plugins combined.

The rewrite replaces the per-node loop with seven Datalog queries. Each query preloads a complete resolution table; the result is joined in JavaScript. The seven queries, by phase:

Q1needs_inference(N) replaces ~350,000 IPC calls
Early-exit gate: identifies all nodes that actually require inference. Nodes that fail Q1 skip the remaining phases entirely. The single largest IPC reduction in the rewrite.
Q2infer_literal(N, TypeName)
Literal type mapping: number, string, boolean, null, undefined — resolved directly from node kind.
Q3infer_constructor(N, ClassName)
Direct constructor inference: new ClassName()INSTANCE_OF → ClassName.
Q4infer_import_ctor(N, ClassName)
Import binding constructor: resolves new X() where X arrives via an IMPORT edge.
Q5infer_annotation(N, TypeName)
TypeScript annotation forward-lookup: reads declared type annotations from the AST node.
Q6a+Q6bcall_needs_singleton(C, ClassName) · builtin_method(M, ClassName) replaces ~125,000 IPC calls
Global singleton resolution with deduplication: maps built-in method calls (console.log, Math.floor, etc.) to their canonical class. First-wins dedup by ClassName::MethodName eliminates duplicates from multi-file graphs.
Q7param_typed(P, TypeName) replaces ~180,000 IPC calls
Parameter type propagation: two paths — direct parameter annotation, and annotation via a REFERENCE hop.

Results from Q2 through Q4 are merged with first-wins priority in a single inferredVars Set. Write-backs are batched at 500 edges per flush — a pattern established in the first two rewrites. Inspection approved. The third rewrite was the hardest. It was also the most impactful.

Sprint v0.2 pattern: bulk preload everywhere
All three rewrites share one structure: one Datalog query to preload the relevant subgraph, one JS pass to join and resolve, one batch flush to write results. The cost of a "how many methods does this class have" question is now the cost of one query evaluation — not one IPC per class per method per level of inheritance. This is the only pattern Intelligence will log for this sprint. It applies to every future plugin that loops over nodes and asks the server questions.

Correctness fixes: three problems that had waited long enough

Sprint v0.2 was not only about performance. Three bugs were in the queue — each independent, each with a known root cause, each a trap waiting for the next developer who ran into it. The brigade cleared all three alongside the N+1 campaign.


REG-1132: Wrong function attribution

The GUI graph view had a systematic misattribution that only appeared in multi-function files. Every CALL node inside any function appeared to originate from the first function in the file — not the one that actually contained it. A file with five functions would show all calls as coming from function one. The graph was structurally wrong in any file with more than one function, and had been for some time.

REG-1132 · http_server.rs · Inspection approved FIXED

The /api/graph-stream endpoint was not walking the CONTAINS parent chain — it was assigning every invisible node to the first visible node unconditionally.

The fix: approximately 33 lines of Rust in build_graph_stream_body(). A parent_of: HashMap<u128, u128> is built from CONTAINS edges (excluding synthetic layout-pack edges), then each invisible node walks the ancestry chain until it finds its correct visible container. If no ancestor is found, the original fallback behavior is preserved. The algorithm was already proven in edges_stream() — this was a port, not a discovery. Performance impact: approximately +2 seconds to graph-stream loading. The brigade assessed this as acceptable for correctness.


REG-1129: The server that wouldn't let go

grafema analyze --clear was supposed to shut down the server and start fresh. It did not. Every subsequent run after the first ended in ECONNREFUSED. The pattern was consistent: the process exited, the PID file and socket file stayed behind, and the next connect() call found them, concluded the server was already running, and refused to start a new one. It was not running. The files were lying.

REG-1129 · Inspection approved FIXED

shutdownServer() waited for the process to exit but did not delete the PID file or socket file. Two unlinkSync calls after _waitForPidExit — with try/catch for ENOENT — closed the loop. 21/21 tests pass.

grafema doctor · Inspection approved FIXED

grafema doctor now detects stale socket files and removes them automatically, returning a warn status with the message: "Stale socket removed. Run grafema analyze to restart server." Previously, a stale socket caused doctor to report an error with no remediation path. Intelligence notes: this is the same pattern as REG-1129. The server that used to leave its keys in the lock has learned to take them out.


REG-1133: Plugin registration required reading source code

Every developer who had ever added a new Grafema plugin had paid the same tax: read the orchestrator source code to discover the configuration format. There was no documentation. There was no example file. There was source code, and you read it. The tax was not large. It was not necessary.

REG-1133 · Plugin registration documentation RESOLVED

Adding a new plugin to Grafema now requires no source-reading. The setup workflow is two commands:

cp _ai/orchestrator.config.example.yaml _ai/orchestrator.config
sed -i "s|<GRAFEMA_ROOT>|$(pwd)|g" _ai/orchestrator.config

The full registration procedure is in CONTRIBUTING.md. The annotated configuration template is at _ai/orchestrator.config.example.yaml. Every future plugin author avoids the tax that every previous one paid.


The count

Sprint v0.2 opened with one measurement: 6 minutes and 51 seconds. It closes with four completed items, 681 passing tests, and a benchmark pending in CI. Intelligence does not predict benchmark results. It counts what is confirmed: 2.5 million IPC calls removed. Thirteen queries standing where they stood.

The graph is correct where it was wrong. The server shuts down where it did not. The plugin registration is documented where it was not. The measurement will follow from CI.

Разведка данных завершена. Итог: 2 500 000 IPC-вызовов ликвидировано. 13 запросов несут вахту. Ожидаем бенчмарка.
GRAFEMA_DATALOG_PLUGINS=shape-verifier,method-call-resolver,type-inference grafema analyze

Branch perf/plugin-early-exit-gates · PR #259 · CI running

GitHub: github.com/Disentinel/soviet-code

Глеб Всеволодович Сыскарёв filed this report at 23:45. He has already begun counting the next set of IPC calls.