Skip to content

--emit neo4j (bolt) full-run orphan prune is global — wipes other applications' modules #45

Description

@rahlk

Summary

The incremental bolt writer's orphan-prune step (codeanalyzer/neo4j/bolt.py, bolt_writer, full-run branch) deletes any :PyModule whose file_key is not in the current emit, across the entire database — it is not scoped to the --app-name being emitted. So emitting application B detaches/deletes application A's modules, leaving an orphaned :PyApplication {name: "A"} with zero PY_HAS_MODULE edges.

Environment

  • codeanalyzer-python 0.2.0 (--emit neo4j --neo4j-uri ..., i.e. live Bolt push)

Root cause

# bolt.py, bolt_writer(), full_run branch:
present = list(by_module.keys())   # only THIS emit's module file_keys
s.run(
    "MATCH (m:PyModule) WHERE NOT m.file_key IN $present "
    "OPTIONAL MATCH (m)-[...]->(x) DETACH DELETE x, m ...",
    present=present,
)

present is global — every :PyModule in the DB is a prune candidate, with no filter tying m to the :PyApplication anchor being written.

Impact

A single Neo4j database cannot hold multiple applications populated via full-run --emit neo4j: each emit wipes the others' module subgraphs. Observed directly — after emitting app B, app A reports count{(a)-[:PY_HAS_MODULE]->()} = 0. This also makes it unsafe to run multiple projects' integration tests against one shared Neo4j instance.

Suggested fix

Scope the prune to the application being emitted, e.g. only prune modules reachable from this run's anchor:

MATCH (:PyApplication {name: $app})-[:PY_HAS_MODULE]->(m:PyModule)
WHERE NOT m.file_key IN $present
OPTIONAL MATCH (m)-[...]->(x)
DETACH DELETE x, m

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions