feat(schema): body nodes and parameters carry their id in analysis.json - #165
Merged
Conversation
codeanalyzer-python 1.4.1 (#180, design #176) stamps `id` on every body node — `<callable-id>@<local>`, the same value the Neo4j projection merges the node on — and on every parameter — `<callable-id>@formal_in:<i>`, the L4 formal_in vertex that carries it, emitted as a forward reference below level 4. The shared vocabulary promises both. TypeScript emitted neither, and the composition rule lived in two private `fq` copies (build/neo4j/project.ts, dataflow/attach.ts). `globalOrdinal` in schema/ids.ts is now the single definition; both `fq`s delegate to it. `stampBodyIds` runs after each body emitter: at the end of the L1 emitter per callable, and once over every callable at the end of applyDataflow (L4 writes actual_in/out into CALLER bodies, so a per-callee stamp would miss them). Two agreement tests pin the property against the OTHER projection rather than a hand-typed string: every body node's id equals the projected :TSBodyNode key for that callable, and every parameters[i].id equals the @formal_in:i vertex id with `of` naming the parameter. Mutation-checked: skipping the stamp and changing the separator each fail the tests. Additive; SCHEMA_VERSION stays 2.0.0 (#144). schema.neo4j.json is unchanged — :TSBodyNode already carried id as its key, and parameters are not graph nodes.
This was referenced Sep 6, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #164. Parity with codeanalyzer-python 1.4.1's #180 (design in its #176).
Python now stamps an
idon every body node inanalysis.json—<callable-id>@<local>, the same value its Neo4j projection merges the node on — and on every parameter —<callable-id>@formal_in:<i>, the L4formal_invertex that carries it, emitted as a forward reference below level 4. The sharedvocabulary.mdpromises both. TypeScript emitted neither.What this adds
TSBodyNode.idon every body node at every level, andTSCallableParameter.idon every parameter at every levelfqcopies (build/neo4j/project.tsanddataflow/attach.ts).globalOrdinalinschema/ids.tsis now the single implementation; both delegate to it.stampBodyIdsruns after each body emitter — at the end of the L1 emitter per callable, and once over every callable at the end ofapplyDataflow. The second is deliberately not per-callee: L4 writesactual_in/actual_outvertices into caller bodies, so a per-callee stamp would miss them.Verification
idequals the set of projected:TSBodyNodekeys for that callable; everyparameters[i].idequals the@formal_in:ivertex's id, with the vertex'sofnaming the parameter. Plus an L1 test that call nodes and parameters carry ids before any dataflow exists.@separator each fail the testsbun testgreen; container tests run (the projection'sfqnow delegates);schema.neo4j.jsonunchanged —:TSBodyNodealready carriedidas its merge key and parameters aren't graph nodesSCHEMA_VERSIONstays2.0.0(chore(schema)!: collapse the schema version back to 2.0.0 #144); decision recorded in.claude/SCHEMA_DECISIONS.mdNote on the test's shape
Because both projections now share one definition, an agreement test alone can't detect a defect in
globalOrdinal— both sides would move together. The L4 test therefore also pins the literal@formal_in:<i>shape, and the L3 test asserts a call node'sidis never itscallee. That's the same trade python made.