Plan (optional)
Spec: docs/design/specs/2026-08-27-v2-neo4j-projection.md — all design decisions, the full graph vocabulary, and the release plan live there.
Problem
--emit neo4j is refused at --schema v2 (CodeAnalyzer.analyzeV2, guard at src/main/java/com/ibm/cldk/CodeAnalyzer.java:379-382); the Neo4j projection consumes the v1 model only, so nothing L3 produces can reach a graph. Per the accepted spec this issue also flips --schema to default to v2 everywhere (json and neo4j) — a breaking CLI change shipping as 3.0.0 — and makes --emit schema always emit the v2 graph catalog (2.0.0).
Scope boundary
Projects the canonical v2 model; does not change the v2 JSON schema. --schema v1 retains the legacy JSON and legacy graph byte-identical to 2.4.x. python-sdk's compat change (pin bump + explicit --schema v1) is a separate work item on that repo, shielded meanwhile by its exact 2.4.1 pin. No L4 facts; J_PARAM_IN/OUT/J_SUMMARY are declared in the catalog only.
Goals
Caveats and known risks
- L3 body-node volume (~30k+ rows on a mid-size app): mitigated by the existing UNWIND batching (500/file, 1000/bolt).
- Same-label replacement means one app name holds one graph generation; mixed-version fleets writing the same DB must coordinate — accepted, stamped via
JApplication.schema_version.
- Python reference has two wipe bugs (lists removed
PY_HAS_CALLSITE, omits PY_HAS_BODY_NODE) — deliberately not copied; java's wipe includes J_HAS_BODY_NODE.
- Default flip breaks any caller parsing default stdout as v1 — that is the point of the major bump; release notes must say so.
Definition of done
Plan (optional)
Spec: docs/design/specs/2026-08-27-v2-neo4j-projection.md — all design decisions, the full graph vocabulary, and the release plan live there.
Problem
--emit neo4jis refused at--schema v2(CodeAnalyzer.analyzeV2, guard atsrc/main/java/com/ibm/cldk/CodeAnalyzer.java:379-382); the Neo4j projection consumes the v1 model only, so nothing L3 produces can reach a graph. Per the accepted spec this issue also flips--schemato default to v2 everywhere (json and neo4j) — a breaking CLI change shipping as 3.0.0 — and makes--emit schemaalways emit the v2 graph catalog (2.0.0).Scope boundary
Projects the canonical v2 model; does not change the v2 JSON schema.
--schema v1retains the legacy JSON and legacy graph byte-identical to 2.4.x. python-sdk's compat change (pin bump + explicit--schema v1) is a separate work item on that repo, shielded meanwhile by its exact2.4.1pin. No L4 facts;J_PARAM_IN/OUT/J_SUMMARYare declared in the catalog only.Goals
V2GraphProjector: pure(Analysis, appName) → GraphRowsper the spec vocabulary (JSymbol merge label, JBodyNode convergence, parameters_json/docstring flattening)J_HAS_BODY_NODE,J_CFG_NEXT(kind,_k),J_CDG,J_DDG(var,prov,_k);RowBuildergains the optional edge_kMERGE discriminant--emit neo4jat v2: full-depth forced (L3 + external symbols);-a/--graph-field-depthalongside it exit non-zero--schemadefault flips to v2; version to 3.0.0--emit schemaemits the 2.0.0 catalog; repo-rootschema.neo4j.jsonregenerated; conformance test byte-matches itCaveats and known risks
JApplication.schema_version.PY_HAS_CALLSITE, omitsPY_HAS_BODY_NODE) — deliberately not copied; java's wipe includesJ_HAS_BODY_NODE.Definition of done
codeanalyzer -i <app> --emit neo4j -o out/producesgraph.cypherthat loads into Neo4j 5 viacypher-shellwith zero errors, twice (idempotent)analysis.jsoncounts exact-set: modules, types, callables, body nodes,J_CALLS/J_CFG_NEXT/J_CDG/J_DDGedge counts (modulo containment edges)JCompilationUnit,JCallSite,JParameter,JCommentcount 0 for that app)--schema v1 --emit jsonand--schema v1 --emit neo4jbyte-identical to 2.4.x output on the same input-a 2 --emit neo4jexits non-zero with the depth-rule errorschema.neo4j.jsonbyte-matches--emit schema; every projected label/rel/prop is declared