Skip to content

Neo4j projections: the application root drops the contractual can:// id in two of three analyzers, substituting an undefined name field #5

Description

@rahlk

Problem

The canonical schema gives the application root exactly one identity field:

Field Type Level Notes
id string 1 can://<lang>/<app> — the app segment disambiguates apps in one language.

No name field is defined on the root. Every analyzer honours this in analysis.json — but two of the three Neo4j projections drop id from the root node and substitute a non-contractual name.

Measured on live graphs, one per analyzer:

projection root label id name
codeanalyzer-python 1.4.x :PyApplication absent "odoo-slim-19"
codeanalyzer-java 3.0.x :JApplication absent "daytrader8"
codeanalyzer-typescript 1.3.0 :TSApplication "can://typescript/superset-frontend" absent

The JSON side is uniform and conformant in all three: application.id is can://java/daytrader8, can://typescript/platform, and so on, with no name anywhere. So this is a projection-only divergence, introduced independently in two analyzers.

Why it matters

Every other node in those same graphs is addressed by its can:// id — that is the whole basis of prefix scoping, and it is what lets one database hold several applications and several languages at once. The root is the one node that cannot be addressed that way in a Java or Python graph, so the SDK has to compensate per language:

JNeo4jBackend    MATCH (a:JApplication  {name: $app})           # non-contractual field
PyNeo4jBackend   MATCH (a:PyApplication {name: $app})           # non-contractual field
TSNeo4jBackend   MATCH (a:Application   {id:   $application_id}) # contractual

Three backends, one concept, two different anchors — decided by which analyzer emitted the graph rather than by the schema. That is the shape the parity clause exists to prevent: a term coined twice is permanently wrong, and here it was coined twice in the same direction and once in the other.

It also means a consumer cannot write one query against "the application root" that works across languages, even though the contract says it can.

Not a naming quibble

name is genuinely useful — it is the --app-name a caller passed, and reading it off the root is convenient. The problem is that it replaced id rather than joining it. The fix that costs nothing is to project both: id because the contract requires it and prefix scoping depends on it, name as the convenience it already is, on all three.

Suggested resolution

  • Project id on the application root in codeanalyzer-python and codeanalyzer-java.
  • Decide whether name becomes a contractual root field (in which case add it to the schema and to codeanalyzer-typescript) or stays an unspecified projection extra. Either is defensible; the current split is not.
  • Once id is present everywhere, the three SDK backends can share one anchor.

Filed here rather than on one analyzer because it is a contract question first and two analyzer changes second. Happy to open the analyzer-side issues once the contract call is made.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions