Skip to content

Canonical vs analyzer vocabulary drift — several cpg fields land empty on real data (blocks F3 #241) #273

Description

@rahlk

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.

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/.metrics accessors against fields that are empty on real data. Part of epic #238.

Metadata

Metadata

Assignees

No one assigned

    Labels

    breakingBreaking Changes

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions