Repository navigation
Description
Parent: codellm-devkit/.github#55 · Spec: docs/design/specs/2026-09-05-leg-1.5-bounded-queries-and-dataflow.md
Problem
Leg 1's end-to-end run against a live 970k-node graph found two things its 159 unit tests could not.
The enumerating accessors are unusably slow, and the cause is round-trip count rather than database load. Instrumented against odoo-slim-19.0.0:
| Accessor | Time | Result |
|---|---|---|
get_callables_overview() |
0.6s | 15,549 |
get_classes() |
347.6s | 1,642 |
get_symbol_table() |
381.7s | 1,626 |
get_call_graph_json() |
422s | — |
get_symbol_table issues 73,669 round trips for 1,626 modules — 45.3 queries per module at 4.9ms each. _module_full fans out per module, _class_full per class, _callable_full per callable. get_callables_overview proves the contrast: same graph, one query, 0.6s.
The dataflow graph is present and unreachable. The projection carries PY_DDG 5,134,655, PY_SUMMARY 453,398, PY_CFG_NEXT 247,906, PY_PARAM_IN 229,035, PY_CDG 139,065, PY_PARAM_OUT 133,267 — a complete SDG that no accessor exposes.
A third problem surfaced while specifying the fix: there is no way to name a node. locate(path, line) yields an id for a position, and nothing else does. PyCallsite, PyCallableParameter and BodyNode carry no id, so a caller wanting "the invoice_id parameter of PaymentPortal.invoice_transaction" cannot address it — and the body-node kinds a dataflow query needs as endpoints are dominated by synthetic vertices reachable only by ordinal.
Scope boundary
Bounded enumeration, addressing, and the graph queries taint is built from — slicing, reachability, paths. Not taint itself: sources, sinks and sanitizers remain leg 4 and remain the caller's to supply. Not Java or TypeScript (legs 2 and 3). Not sharded fetch, deliberately deferred until the fan-out is collapsed and re-measured.
Goals
- Collapse the N+1 fan-out with
collect()—get_symbol_tableandget_classesunder 10s, round-trip count single-digit - Scoping keywords on the enumerating accessors; drop
get_application_view's discarded work - Addressing layer — name→node resolution,
SliceNode, suffix matching, ambiguity raising with candidates - Per-callable
get_cfg/get_cdg/get_ddg -
slice_backward/slice_forward/backward_cone/reaches -
paths_between/call_paths_between/flows_to_call/flows_to_argument/describe
Caveats and known risks
can://URIs never reach the caller (E6). Measured basis: 86% of Odoo's 11,266 leaf callable names are unique, and parameter names are always unique within a callable. The remaining 14% are framework methods —__init__238,write220,create214 — which always needin_class=, and the error must make that obvious rather than dumping 220 candidates.- Ordinals never reach the caller (E7), including
flows_to_argument, which takes the callee's parameter name. - Ambiguity raises with candidates and never auto-picks (E8). Suffix matching on the dotted name is supported and deterministic; typo-tolerant matching is out of scope entirely.
- Addressing is step 3, ahead of every traversal step. Without it, steps 4–6 ship queries a caller can only invoke for positions it happened to get from
locate(). - Blocked-adjacent: LocateResult.node_id does not join to the graph's node ids #320 (the SDK's
node_iddoes not join to graph ids) and codeanalyzer-python#176 (BodyNodecarries no id). Neither blocks step 1 or 2; both bear on step 3. - Every step verifies against the live graph, not fixtures. Leg 1 shipped six accessors broken on every real graph through 159 green unit tests, because hand-written fixtures encode the author's model of the data and can only confirm it.
Definition of done
get_symbol_table()andget_classes()complete in under 10 seconds on the odoo graph; round-trip count asserted by an instrumented test.get_call_graph(roots=…, depth=…)returns a bounded subgraph.- A backward slice over a fixture equals the hand-computed node set exactly.
- A known source→sink flow returns a path matching hop for hop, including
varandprov. - No public signature or return type mentions a
can://URI; no accessor takes an ordinal. - An ambiguous name raises listing candidates; a unique name resolves without a scope argument.
- Every capped accessor reports
truncated; no cap is silent. - Every accessor is exercised against the live graph in the e2e suite.
Activity
python-sdk2.0 — a static-analysis front end for humans and agents .github#55rahlk commentedon Sep 6, 2026
Resolved by #323, merged into
release/2.0asb5a18b4(stacked on #322d4a855aand #3183b66778). Ships in2.0.0rc2once #328 (release gate) and #327 (codeanalyzer-python 1.4.1 scoping) land.