Part of #69.
Stage 1 — v2 schema foundation + L1
Introduce the v2 model layer, the can:// id builders, source-per-module + byte-offset spans, the L1 body (call nodes), the JSON envelope, and the Neo4j L1 re-key. After this stage, -a 1 emits a v2-shaped tree in both projections. max_level=1.
Branch: feat/v2-stage1-schema-l1
Tasks (bite-sized TDD, detailed in the plan):
- Byte-offset
Span model + line/col→byte helper (schema/py_schema.py).
can:// durable-id builders (schema/ids.py) — locks the name(argnames) param-encoding decision.
- v2 model layer —
BodyNode, split edge models (Cfg/Cdg/Ddg/Summary/ParamEdge), Analysis envelope; reshape PyApplication/PyModule/PyClass/PyCallable; dissolve PyProgramGraphs/PyFunctionGraphs/PySDGEndpoint/PySDGEdge/PyGraphNode/PyParamNode.
- Capture
source per module + byte-offset spans in the symbol-table builder; drop the per-node code field.
- Stamp
can:// ids across the tree (schema/assign_ids.py, returns signature→can://id).
- L1
body call nodes from call_sites (callee null; schema/l1_body.py).
- Emit the v2
Analysis envelope from the CLI; analyze() returns Analysis.
- Canonical-schema conformance gate helper + L1 assertion (
test/conftest_v2.py).
- Neo4j L1 re-key onto
can:// ids (two-projection agreement).
- Stale-v1 cache detection (rebuild instead of crash).
Gate (L1): -a 1 output round-trips the v2 models and passes assert_conformant(..., 1); symbol_table keys relative; get_method_body slices source via span bytes; cache reuse works and a stale v1 cache rebuilds; JSON callable ids == Neo4j merge keys.
Part of #69.
Stage 1 — v2 schema foundation + L1
Introduce the v2 model layer, the
can://id builders,source-per-module + byte-offset spans, the L1body(call nodes), the JSON envelope, and the Neo4j L1 re-key. After this stage,-a 1emits a v2-shaped tree in both projections.max_level=1.Branch:
feat/v2-stage1-schema-l1Tasks (bite-sized TDD, detailed in the plan):
Spanmodel + line/col→byte helper (schema/py_schema.py).can://durable-id builders (schema/ids.py) — locks thename(argnames)param-encoding decision.BodyNode, split edge models (Cfg/Cdg/Ddg/Summary/ParamEdge),Analysisenvelope; reshapePyApplication/PyModule/PyClass/PyCallable; dissolvePyProgramGraphs/PyFunctionGraphs/PySDGEndpoint/PySDGEdge/PyGraphNode/PyParamNode.sourceper module + byte-offset spans in the symbol-table builder; drop the per-nodecodefield.can://ids across the tree (schema/assign_ids.py, returnssignature→can://id).bodycall nodes fromcall_sites(calleenull;schema/l1_body.py).Analysisenvelope from the CLI;analyze()returnsAnalysis.test/conftest_v2.py).can://ids (two-projection agreement).Gate (L1):
-a 1output round-trips the v2 models and passesassert_conformant(..., 1);symbol_tablekeys relative;get_method_bodyslicessourcevia span bytes; cache reuse works and a stale v1 cache rebuilds; JSON callable ids == Neo4j merge keys.