Skip to content

feat(neo4j)!: schema v2 graph projection; v2 becomes the default schema (3.0.0) - #201

Merged
rahlk merged 1 commit into
mainfrom
feat/issue-198-v2-neo4j-projection
Aug 28, 2026
Merged

feat(neo4j)!: schema v2 graph projection; v2 becomes the default schema (3.0.0)#201
rahlk merged 1 commit into
mainfrom
feat/issue-198-v2-neo4j-projection

Conversation

@rahlk

@rahlk rahlk commented Aug 27, 2026

Copy link
Copy Markdown
Collaborator

Closes #198. Implements the base relabel + L3 overlay of #182 (L1/L2 families + J_CFG_NEXT/J_CDG/J_DDG); the L4 SDG overlay (J_PARAM_*/J_SUMMARY, declared-only in the catalog here) remains for after L4. Implements docs/design/specs/2026-08-27-v2-neo4j-projection.md.

What

  • V2GraphProjector — pure (Analysis, appName) → GraphRows, projecting the v2 model onto the 2.0.0 graph vocabulary (python-parity: JSymbol merge label over JType/JCallable/JExternal; JBodyNode keyed on the global ordinal replaces call-site nodes; parameters_json/docstring flattening; J_CFG_NEXT/J_CDG/J_DDG overlay edges with the _k MERGE discriminant).
  • V2SchemaCatalog — declarative 2.0.0 contract, derived uniqueness constraints; --emit schema now always emits it; repo-root schema.neo4j.json regenerated.
  • RowBuilder/GraphRows/writers gain the optional edge _k discriminant (a conditional's true/false CFG pair, one DDG dependence per (var, prov)); CypherWriter/BoltWriter MERGE on {_k: row.k} for keyed groups.
  • Cross-generation replacement: the wipe/prune traversal spans v1 and v2 containment (J_HAS_UNIT|J_HAS_MODULE + union DESCENDANTS incl. J_HAS_BODY_NODE) and sweeps orphaned degree-0 symbols (v1's import-materialized bodyless JType stubs). Bolt diff/prune handles both generations and scopes pruning to the app anchor.

Breaking (3.0.0)

  • --schema defaults to v2 for json and neo4j; --schema v1 selects the legacy shapes (v1 node/edge cypher statements unchanged; the shared DDL/wipe preamble gained the v2 union, required for replacement in both directions).
  • --emit neo4j at v2 is always full depth (forces L3 + external symbols); -a/--graph-field-depth alongside it exit non-zero (keystone depth rule, python Fix Issue 113: call graph is missing edges to implementations of interfaces. Merge to v1.X.X. #119 parity).
  • --emit schema always emits the 2.0.0 catalog.

python-sdk is shielded by its exact codeanalyzer-java == "2.4.1" pin; its compat PR (bump + explicit --schema v1) is separate work per the spec's release plan.

Verification

  • Full suite green except CodeAnalyzerIntegrationTest (pre-existing Testcontainers/Docker env failure, identical on main).
  • New V2Neo4jSchemaConformanceTest: every projected label/rel/prop declared; body-node convergence pinned (no JCompilationUnit/JCallSite/JParameter/JComment rows); keyed overlay edges; wipe coverage.
  • E2E against Neo4j 5 (this repo as input, 30223 nodes / 158704 rels): cypher-shell loads clean; v1 load → v2 load leaves 0 v1 leftovers (including the orphaned import stubs); reloading is idempotent (counts unchanged); graph counts equal the same run's analysis.json exact-set for modules (156), callables (1199), body nodes (18265), cfg (8473), cdg (3031), ddg (5465); J_CALLS/JExternal counts equal the emitting run's rows exactly (cross-run RTA jitter of ±36 edges exists between separate analyses — pre-existing WALA behavior, not projection loss).
  • Traversal sanity: JApplication→J_HAS_MODULE→J_DECLARES→J_HAS_METHOD→J_HAS_BODY_NODE→J_RESOLVES_TO returns resolved callees; CFG edge kinds distribute as expected (fallthrough/true/false/return).

Adds the canonical schema v2 → Neo4j projection (graph contract 2.0.0),
mirroring codeanalyzer-python's vocabulary with J/J_ namespacing:
V2GraphProjector (pure Analysis → GraphRows), V2SchemaCatalog, and the L3
CPG overlay (J_HAS_BODY_NODE, J_CFG_NEXT/J_CDG/J_DDG with the _k MERGE
discriminant). Per the convergence spec there are no call-site/parameter/
comment nodes: call sites are :JBodyNode rows, parameters flatten to
parameters_json, javadoc collapses to docstring.

Breaking (3.0.0):
- --schema defaults to v2 everywhere; --schema v1 selects the legacy JSON
  and legacy graph (v1 node/edge statements unchanged).
- --emit neo4j at v2 is always full depth (forces L3 + external symbols);
  -a/--graph-field-depth alongside it exit non-zero.
- --emit schema always emits the 2.0.0 catalog; schema.neo4j.json
  regenerated as the v2 artifact.

The wipe/prune traversal spans both generations (J_HAS_UNIT|J_HAS_MODULE +
union DESCENDANTS) and sweeps orphaned degree-0 symbols, so a v2 push
replaces a same-app v1 graph completely — verified against Neo4j 5:
v1 load → v2 load leaves 0 v1 leftovers, reload is idempotent
(30223 nodes / 158704 rels unchanged), and graph counts equal the run's
analysis.json exact-set for modules/callables/body/cfg/cdg/ddg.

Spec: docs/design/specs/2026-08-27-v2-neo4j-projection.md

Closes #198
@rahlk
rahlk requested review from georgesafta and sinha108 August 27, 2026 17:52
@rahlk
rahlk merged commit 085b8d5 into main Aug 28, 2026
@rahlk
rahlk deleted the feat/issue-198-v2-neo4j-projection branch August 28, 2026 18:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(neo4j)!: schema v2 graph projection; v2 becomes the default schema (3.0.0)

2 participants