Repository navigation
Description
Is your feature request related to a problem? Please describe.
codeanalyzer-go v0.2.0 (release, PR codellm-devkit/codeanalyzer-go#36) emits the full L3/L4 substrate in both projections: per-callable cfg/cdg/ddg at -a 3, and at -a 4 the interprocedural SDG — parameter vertices, param_in/param_out, per-call-site summary, VTA dispatch edges, library stand-ins and degraded[] — with --emit neo4j projecting the same graph at L4.
The SDK cannot consume any of it. #434 (#426's M7) delivered the L1/L2 facade only, and the models stop at L2. Two concrete failures, both verified against v0.2.0 output:
-
Current output does not parse at all.
GoType.kindisLiteral["struct", "interface"](cldk/models/go/models.py:203), but the analyzer emits four kinds. On a fixture withtype Celsius float64andtype Alias = int,GoAnalysis(**doc)raises:2 validation errors for GoAnalysis application.symbol_table.`k.go`.types.Alias.kind Input should be 'struct' or 'interface' [input_value='alias'] application.symbol_table.`k.go`.types.Celsius.kind Input should be 'struct' or 'interface' [input_value='defined']This is independent of L3/L4 — it blocks
-a 1output on any project declaring a defined type or an alias. -
L4 output parses, then silently drops the graph. A
-a 4document loads without error, butGoApplicationhas noparam_in/param_out/external_symbols/degraded, andGoBodyNodekeeps onlykind/span/callee/is_goroutine— noid,parent,of,is_deferred. A consumer gets a valid object with the dataflow missing, which is worse than a parse error.
Describe the solution you'd like
The L3/L4 consumer train for Go, mirroring what the Python backend already exposes. Scope is specified in codeanalyzer-go/docs/design/specs/v2-l3-l4-dataflow.md §7 (the analyzer-side decisions it builds on are in that repo's CLAUDE.md).
- Models (
cldk/models/go/): widenGoType.kindto all four kinds first, then add the L3 body fields (id,parent), the L4 vertex fields (of,is_deferred),summary, application-scopeparam_in/param_out,external_symbols(incl.receiverandbodystand-ins), anddegraded[].extra="ignore"per Relax the schema-v2 mirrors from extra="forbid" to extra="ignore" #386. - Accessors with the Python backend's names and signatures —
get_cfg,get_cdg,get_ddg,resolve_callable,resolve_value,slice_backward,slice_forward,paths_between,reaches,backward_cone,flows_to_call,flows_to_argument,taint,get_source,get_external_symbols— routed throughcommons/graphs.py,commons/resolve.py,commons/results.pyexactly ascldk/analysis/python/backend.pydoes. - Both backends: local
GoCodeanalyzer(subprocess + JSON → networkx) andGoNeo4jBackend(Cypher withnode_label="GoBodyNode",P="GO_"), with a parity contract test — both answer identically, miss paths included. - Gates:
_require_dataflowat level 3 (as the Java backend declares it), plus the port-connectivity probe — refuse slicing/taint when no dependence edge leaves anyformal_in. - Bump the pin:
pyproject.tomlstill hascodeanalyzer-go==0.1.0rc1; v0.2.0 is on PyPI.
Go-specific details that will bite (from §7):
- Never split a body-node id on its first
@— external ids contain/@external/before the vertex@. Strip the known callable-id prefix instead. of, notparameters[], resolves formals;formal_in:0is the receiver for a method.- Global names:
value_candidateturns<global>:example.com/lib::Vintoexample.com/lib.V, so alib.Vquery failssegment_match. Normalise the import path or match on/too. degraded[]is the honesty signal. Non-empty means part of the graph is approximated (range_func,unmapped_ssa, …), so the SDK must not certify "no flow" over it.- Known gap: global → global
summaryedges are omitted (L4: global → global summary edges are omitted; reverse for context-sensitive walks or finer wiring codeanalyzer-go#30). Reachability is unchanged, but depth-bounded walks (DEFAULT_DEPTH = 5) may stop short where the shortcut is gone.
Describe alternatives you've considered
- Fix only
GoType.kindand defer the rest — rejected as the end state, but it is the right first commit: it is the parse blocker and is independent of everything else. - Add L3/L4 to SDK: GoAnalysisBackend, Neo4j projection #426 — rejected: that issue's scope guard names the consumer surface "a later train", and its M7 (the L1/L2 facade) is what CLDK go #434 delivered.
- Taint in the analyzer — out of scope by the 2026-07-02 amendment (Level-3: native dataflow graphs (CFG/DFG/PDG/SDG) for Go codeanalyzer-go#3): the analyzer is a graph provider; client analyses are SDK queries (#229).
Additional context
Evidence that the substrate is real and worth consuming:
- 8 open-source Go apps complete
-a 4deterministically (-j 1=-j 16= rerun, byte-identical). Kubernetes: 748k lines, 38 s, 7.9 GB, 1.71M SDG nodes and 5.78M dependence edges. - The Neo4j snapshot's row counts equal the JSON's on all eight.
- An HTTP → SQL fixture is gated end to end: a handler's request parameter reaches
database/sql.DB.Query'squerythrough an interface call only VTA resolves, and unrelated pairs stay unreachable (TestGateL4_HTTPToSQLPath). That fixture is the natural first integration test fortaint. - 15 metamorphic relations pass with 0 violations on memos, nats-server, chi and the fixtures.
- Numbers:
codeanalyzer-go/docs/design/notes/l3-dataflow-metrics.md§ L4.
Caveat for large apps: --emit neo4j currently peaks at 21–25 GB on nats-server and Kubernetes (codellm-devkit/codeanalyzer-go#38), and analysis.json at -a 4 reaches 1.78 GB, which the local backend would load whole.
Activity
sinha108 commentedon Oct 30, 2026
Precision inherited from the shared walk. The Go accessors route through
commons/graphs.pylike Python's, so they inherit its context-insensitivity: a walk can enter a callee through one call site'sparam_inand leave through another'sparam_out(#437). Nothing to fix in the Go backend — noted here so the docstrings say what a path proves, and so consumers readTaintResult.exhausted/.unresolvedrather than treating a returned path as a feasible flow.#437 is also the gate on reinstating the global → global
summaryedges the analyzer omits (codellm-devkit/codeanalyzer-go#30).