Skip to content

fix(neo4j): relationship-identity discriminant for DDG/CFG_NEXT edges#74

Closed
rahlk wants to merge 1 commit into
fix/issue-46-bolt-symbol-labelsfrom
fix/issue-70-edge-identity-discriminant
Closed

fix(neo4j): relationship-identity discriminant for DDG/CFG_NEXT edges#74
rahlk wants to merge 1 commit into
fix/issue-46-bolt-symbol-labelsfrom
fix/issue-70-edge-identity-discriminant

Conversation

@rahlk

@rahlk rahlk commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #70. Stacked on fix/issue-46-bolt-symbol-labels (PR #51) — the v2-chain tip that carries the CPG overlay this bug lives in; main (0.5.0) does not yet project DDG/CFG_NEXT and is unaffected.

A plain endpoint-pair MERGE (a)-[r:TYPE]->(b) collapses legitimately-distinct edges between one node pair: per-variable DDG edges (and the prov split), and a conditional's true/false CFG_NEXT pair. The live graph then materializes fewer dependence edges than the projection produced, with var/prov/kind props last-write-wins by push order. Found in codeanalyzer-python's stage-5 release gates (bolt count 106 != 109) and fixed there identically (codellm-devkit/codeanalyzer-python#98 batch, commit be1148e).

  • EdgeRow.key? discriminant; keyed families MERGE on (a)-[r:TYPE {_k: row.k}]->(b) in both writers (keyed vs unkeyed rows grouped separately).
  • DDG keyed per (var, prov); CFG_NEXT per kind; CDG/SUMMARY/PARAM_* stay plain.
  • _k declared in the schema catalog; schema.neo4j.json regenerated.
  • New test/neo4j-edge-identity.test.ts; full suite 107 pass / 5 skip, tsc --noEmit clean.

Suggested follow-up when convenient: a count-parity assertion in the container bolt test (relationships in DB == rows.edges.length) like the Python twin's, which is what caught this class of bug.

…#70)

A plain endpoint-pair MERGE collapses legitimately-distinct edges of one
type between the same two nodes: the DDG carries one edge per variable
(plus the prov split), and a conditional's true/false CFG_NEXT pair shares
its endpoints — the live graph silently materialized fewer dependence
edges than the projection produced, with var/prov/kind props last-write-wins.
Found in codeanalyzer-python during its v2 stage-5 gates (bolt count test
106 != 109) and fixed there the same way.

- EdgeRow gains an optional `key` discriminant; RowBuilder.edge passes it.
- bolt/cypher writers MERGE keyed families on `(a)-[r:TYPE {_k: row.k}]->(b)`
  and group keyed vs unkeyed rows separately.
- project(): DDG keyed per `(var, prov)`, CFG_NEXT per `kind`; CDG/SUMMARY/
  PARAM_* stay plain (their endpoint pairs are unique by construction).
- schema catalog declares `_k` on DDG/CFG_NEXT; schema.neo4j.json regenerated.
- test/neo4j-edge-identity.test.ts covers survival of per-var DDG rows, the
  keyed MERGE shape, and that undiscriminated families keep the plain MERGE.
@rahlk rahlk closed this Jul 15, 2026
@rahlk rahlk deleted the fix/issue-70-edge-identity-discriminant branch July 15, 2026 04:26
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.

1 participant