Skip to content

Epic: body nodes and parameters carry their id in analysis.json #56

Description

@rahlk

Spec: docs/design/specs/2026-09-05-body-node-id-in-analysis-json.md

Summary

Every body node and every parameters entry gains an id in analysis.json: the global ordinal <callable-id>@<local> that all three Neo4j projections already write as their body-node merge key. Schema impact: one additive field on two spine node shapes; schema_version stays 2.0.0; the graph contract is unchanged. This closes the gap where a node is addressable in Neo4j and anonymous in JSON, so the SDK stops recomposing the can:// grammar itself (python-sdk#320 composed it on signature and joins to nothing).

Affected repos

  • codeanalyzer-python — emits the field (codeanalyzer-python#176)
  • codeanalyzer-java — emits the field
  • codeanalyzer-typescript — emits the field
  • codeanalyzer-schema — spine BodyNode and Parameter gain id; each language schema and sample updated as its analyzer ships
  • python-sdk — pin bump only; the python model is re-exported from the analyzer; consumer fix is python-sdk#320

Design decisions

  • Spine field, not a python leaf: all three analyzers mint the same value for Neo4j and the grammar lives in the keystone, so a python-only field would put a spine concept under x-cldk.divergences.
  • id is stamped from the same function each projector uses for its Neo4j merge key, never re-derived at emit sites. The @ rule is on the local key: keys starting with @ concatenate, others get a @ separator.
  • parameters[i].id == <callable-id>@formal_in:<i> by list position. A forward reference below L4. Formal-vertex index order now equals parameters order, a contract each analyzer gates with an L4 test.
  • Scope guard, OUT: PyCallsite (legacy list #120 already folded into body nodes); class attributes and local variables (their Neo4j ids are signature-minted and being redone under 2026-09-02-prune-scope-on-can-id-prefix.md; revisit after that lands).

Release plan

  • codeanalyzer-python 1.5.0 first; it is the requesting analyzer and the only gate for python-sdk.
  • codeanalyzer-java 3.1.0 and codeanalyzer-typescript 1.3.0 on their own clocks; no analyzer reads another's output, so no lockstep among the three.
  • codeanalyzer-schema trails each analyzer release with the regenerated sample and closed schema.
  • python-sdk pins codeanalyzer-python==1.5.0; python-sdk#320 reads BodyNode.id in the local backend and b.id in Neo4j.

Definition of done (epic-level)

  • Every sub-issue closed and its gate green.
  • Per analyzer: parity test that body[k].id equals the Neo4j merge key for every k in a fixture; L4 test that body[parameters[i].id].of is parameters[i].name for every callable; monotonicity CI green.
  • codeanalyzer-schema scripts/check.py green with regenerated samples from the releases that emit the field.
  • python-sdk local and Neo4j backends return equal ids for the same node, asserted by a parity test.

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

    EpicCross-repo coordination epic

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions