You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Canonical vs analyzer vocabulary drift — the cpg models parse, but several canonical fields land EMPTY on real data
Surfaced by F2 (#240) whole-branch review: the cldk/models/cpg/ models are faithful to the keystone (canonical-schema.md § Part II), and they PARSE real codeanalyzer-python + cants output cleanly — but because they use extra="allow", several fields the analyzers emit under NON-keystone names get silently absorbed into model_extra while the canonical field they should populate stays at its empty default. F3's per-language views (#241) are specified against the canonical names, so they will return empty results on real data until this is reconciled.
Evidence is the committed fixtures tests/resources/cpg/{py-a4,ts-a4}.json (real --eager analyzer output).
Genuine drift (canonical field ends up empty)
Canonical (keystone)
Analyzer actually emits
Consequence
Node.base_types + Node.interfaces
base_classes (py+ts), implements_types (ts)
.base_types/.interfaces always empty; supertype info in model_extra
Node.fields
attributes (py)
.fields empty for Python; also sits OUTSIDE the durable-id validator
Node.metrics ({cyclomatic})
flat cyclomatic_complexity (py+ts)
.metrics always empty
callable of: "$ret"
of: "<return>" (py)
token mismatch on synthetic return vertices
callable kind: "method"
kind: "function" for class methods (py)
kind-filter for methods misses Python methods
Sanctioned / expected (NOT drift — note for consumers)
ddg prov: ["reaching-defs"] (ts) is a SANCTIONED additive token (chore: formalize reaching-defs ddg prov token (+ python-sdk lockstep) codeanalyzer-typescript#32; SDK already accepts it via open prov: List[str]). BUT any confidence mapping keyed on ssa/points-to (F7's _ddg_tier) must map reaching-defs → structural, or it misclassifies every TS ddg edge as unresolved. (Already an F7 carry-forward.)
external_symbols (py) / synthesized_callables (ts) at application scope are unmodeled extras (schema-contract sanctions the eventual shift); call_graph edges can reference ids that don't join into the modeled tree — F3/F7 id-joins must tolerate a missed join.
The nesting question (keystone datum for the F2 nested-types rollup)
Keystone Part II defines type.nesting: {parent?, is_local?} and does NOT define a types{} container on type nodes — canonical nesting is FLAT (module.types + a nesting.parent pointer). Yet codeanalyzer-python emits empty types: {} stubs on type/callable nodes. Resolution should add Node.nesting (canonical) and challenge the analyzer's types{} stubs, NOT add a Node.types container.
For each genuine-drift row: either the analyzers conform to the keystone name (like the #98 edge-key/identity/containment fixes), OR the keystone is amended to adopt the analyzer's name. This is a vocabulary reconciliation across the keystone + codeanalyzer-python + codeanalyzer-typescript + the SDK. Blocks F3 (#241) — F3's views must not ship kind-filters and .base_types/.fields/.metrics accessors against fields that are empty on real data. Part of epic #238.
Canonical vs analyzer vocabulary drift — the cpg models parse, but several canonical fields land EMPTY on real data
Surfaced by F2 (#240) whole-branch review: the
cldk/models/cpg/models are faithful to the keystone (canonical-schema.md § Part II), and they PARSE real codeanalyzer-python + cants output cleanly — but because they useextra="allow", several fields the analyzers emit under NON-keystone names get silently absorbed intomodel_extrawhile the canonical field they should populate stays at its empty default. F3's per-language views (#241) are specified against the canonical names, so they will return empty results on real data until this is reconciled.Evidence is the committed fixtures
tests/resources/cpg/{py-a4,ts-a4}.json(real--eageranalyzer output).Genuine drift (canonical field ends up empty)
Node.base_types+Node.interfacesbase_classes(py+ts),implements_types(ts).base_types/.interfacesalways empty; supertype info inmodel_extraNode.fieldsattributes(py).fieldsempty for Python; also sits OUTSIDE the durable-id validatorNode.metrics({cyclomatic})cyclomatic_complexity(py+ts).metricsalways emptyof: "$ret"of: "<return>"(py)kind: "method"kind: "function"for class methods (py)Sanctioned / expected (NOT drift — note for consumers)
prov: ["reaching-defs"](ts) is a SANCTIONED additive token (chore: formalize reaching-defs ddg prov token (+ python-sdk lockstep) codeanalyzer-typescript#32; SDK already accepts it via openprov: List[str]). BUT any confidence mapping keyed onssa/points-to(F7's_ddg_tier) must mapreaching-defs→ structural, or it misclassifies every TS ddg edge as unresolved. (Already an F7 carry-forward.)external_symbols(py) /synthesized_callables(ts) at application scope are unmodeled extras (schema-contract sanctions the eventual shift);call_graphedges can reference ids that don't join into the modeled tree — F3/F7 id-joins must tolerate a missed join.The
nestingquestion (keystone datum for the F2 nested-types rollup)Keystone Part II defines
type.nesting: {parent?, is_local?}and does NOT define atypes{}container on type nodes — canonical nesting is FLAT (module.types+ anesting.parentpointer). Yet codeanalyzer-python emits emptytypes: {}stubs on type/callable nodes. Resolution should addNode.nesting(canonical) and challenge the analyzer'stypes{}stubs, NOT add aNode.typescontainer.Decision needed (designing-cldk-changes territory)
For each genuine-drift row: either the analyzers conform to the keystone name (like the #98 edge-key/identity/containment fixes), OR the keystone is amended to adopt the analyzer's name. This is a vocabulary reconciliation across the keystone + codeanalyzer-python + codeanalyzer-typescript + the SDK. Blocks F3 (#241) — F3's views must not ship kind-filters and
.base_types/.fields/.metricsaccessors against fields that are empty on real data. Part of epic #238.