perf(model): one Joern invocation per query kind, not one per region

JVM startup dominated a scan: a call per region per family put a ten-line
file at 275s over three regions, and would have put a thousand regions at
roughly fifty hours. The queries themselves are milliseconds once the CPG
is loaded, so the cost was almost entirely process starts.

scan_repository() is now collect -> batch -> arbitrate. The three .sc
scripts accept a `requests` JSON map and answer all of them in one run,
keeping the single-request form so the committed measurements stay
reproducible byte-for-byte. Arbiters are untouched: each is handed a
CpgResult whose `run` returns its own prefetched rows.

The batcher builds parameters by calling request_params() extracted from
taint.py, dominance.py and config_value.py rather than reconstructing
them. A second copy that drifts from the arbiter's is the exact shape of
the five family-assumption bugs the predecessor spec spent a session
finding; there is now one definition per family and the batcher borrows
it.

Regions are also deduplicated by (path, function), collapsing the
nameless entry-point rows that were producing `model:injection:?:10`.

Measured on the same ten-line file: 275s -> 106s, three duplicate
findings -> one `model:injection:ping:10`, rung unchanged at
model_entailed. Gates byte-identical.

Server mode is recorded as task 2.3, deliberately sequenced after the
repository measurement: whether the remaining ~100s floor is worth a
process model, a weakened subprocess seam and a Scala-evaluating HTTP
endpoint depends on a build-time-to-query-time ratio only 2.2 produces.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
Marius Ciepluch
2026-09-09 07:57:35 +02:00
co-authored by Claude Opus 5
parent e67f3ee2f0
commit c35426e186
13 changed files with 412 additions and 76 deletions
+34
View File
@@ -116,3 +116,37 @@ def test_an_unsupported_language_yields_no_region() -> None:
from openultrasast.model.regions import regions_for
assert regions_for([], [_target(path="x.rb", language="ruby")]) == ()
def test_nameless_entry_points_do_not_duplicate_a_file_already_covered() -> None:
"""The mapper can emit several entry points for one file, some with no function name.
On a ten-line Flask file it produced three: `ping`, and two nameless ones. Turning each into a region
scanned the same file three times and multiplied the Joern invocations by three for no new coverage.
A nameless entry point is the file; if a named region already covers that file, it adds nothing.
"""
from openultrasast.model.regions import regions_for
entries = [
_entry(function="ping", access="public"),
_entry(function=None, access="local-only"),
_entry(function=None, access="public"),
]
regions = regions_for(entries, [_target()])
assert len(regions) == 1
assert regions[0].function == "ping"
def test_a_file_with_only_nameless_entry_points_still_gets_one_region() -> None:
from openultrasast.model.regions import regions_for
regions = regions_for([_entry(function=None), _entry(function=None)], [_target()])
assert len(regions) == 1 and regions[0].function is None
def test_two_named_handlers_in_one_file_are_two_regions() -> None:
"""Deduping must not collapse genuinely distinct handlers."""
from openultrasast.model.regions import regions_for
regions = regions_for([_entry(function="a"), _entry(function="b")], [_target()])
assert sorted(r.function for r in regions) == ["a", "b"]