Status: Living reference
Scope: What each KnowCode parser extracts today, and the explicit
limitations a user or downstream step can rely on. This matrix is maintained
directly as the single source of truth referenced by the release gate; it
supersedes the Step 07 snapshot in the archived
hardening blueprint,
which is kept for history only. It is enforced by the cross-language integrity
gates in tests/unit/indexing/ and tests/unit/parsers/, and the exact
fixture contracts in tests/fixtures/parser_contracts/.
The parser and graph invariants themselves live in ADR 1. Anything not listed as supported here is either an explicit limitation below or outside the committed fixtures.
- Supported means a committed fixture or gate proves exact extraction,
location, and graph-identity behavior through
GraphBuilder, not only direct parser output. - Limitation means the construct is either not extracted or extracted
incompletely, and the gap is visible (reported through
ParseResult.errorsor documented here) rather than silently lost. Silent loss is a defect, not a limitation.
Every relationship endpoint is exactly one of:
| Classification | Form |
|---|---|
| Internal | <canonical-file>::<qualified-name> |
| External | external::<namespace>::<symbol> |
| Unresolved | unresolved::<language>::<file>::<scope>::<symbol> |
Legacy pseudo-namespaces (type::, trait::, ::method::, ::data::) are
invalid and rejected by the gates. A parser may emit a transient ref::<name>
placeholder for a reference it cannot fully qualify at parse time;
GraphBuilder._resolve_references links it to a local entity when one exists.
Committed fixtures and the mixed-language merge contain no lingering ref:: or
invalid endpoints.
Scoping note: this endpoint contract is enforced for the hardened parsers
above (JS/TS, Python, Vue, Rust) and the mixed-language gate fixture. The Java
parser predates it and still emits non-canonical forms — see its limitations
below; the mixed-language fixture contains no .java file, so the gates do
not cover it.
Duplicate declarations in one file never produce duplicate entity IDs: the
parser keeps the first and reports the dropped collision. Since ADR 11
(module-scoped qualified names, BL-9), top-level declarations are module-scoped
and no name collision with the file's MODULE entity arises; every tree-sitter
parser, including Java and Vue, emits the MODULE entity via _module_scope
(src/knowcode/parsers/base.py:122, vue_parser.py:128-134).
Supported:
- Classes, functions, arrow functions, and function-valued variable declarations.
- TypeScript interfaces, type aliases, and enums (extracted as
classentities until the shared entity-kind schema expands). - Named and default
exportdeclarations, unwrapped through one shared dispatch path. extendsfor simple identifiers, member expressions, and the explicitly supported complex grammar forms; nonlocal bases become unresolved references.- Module entity, containment, and call edges.
Limitations:
.tsxJSX bodies are reported as tree-sitter syntax errors, becauseTypeScriptParseruses the plaintypescriptgrammar (no TSX); tree-sitter error recovery still yields partial extraction, but the entity set is not guaranteed beyond the module entity..jsxfiles route toJavaScriptParser, whosejavascriptgrammar accepts JSX and extracts normally — JSX tags are not extracted as entities in either case. JSX-free TypeScript in a.tsxfile parses and extracts normally.- TypeScript interfaces, aliases, and enums share the
classentity kind. - Duplicate top-level declarations are deduped and reported (Step 07); the synthetic module entity is exempt so a Java-style filename match does not false-trigger.
Supported:
- Nested classes, nested functions, async nested functions, with lexical
qualified names (
Outer.Inner,Outer.method.local). - Decorators on classes, functions, and methods; entity location and source begin at the first decorator.
- Module
AssignandAnnAssignproduce one variable entity per simple bound name, including each name in chained or tuple assignment. - Scoped call resolution: a call resolves to the lexical scope that owns it and never leaks across nested definition boundaries.
- Imports (external) and inheritance.
Reference resolution goes beyond lexical scope (BL-31→BL-34): the graph
classifies import-bound references with repository knowledge, binds stated
receiver types — constructor calls, annotated parameters and assignments,
self/cls attributes, in-file factories — and types module-scope bindings,
literals, and qualified factory returns (8572c33, ec330f2, d9021c0).
Preflight splits the remaining unresolved evidence by hole class (979f399).
Limitations:
- A syntax error fails the whole file (
ast.parseraises); there is no partial extraction. The failure is visible inParseResult.errorsand deterministic. - Module-local (non-module-scope) assignments are intentionally not entities.
Supported:
- Attribute-order-insensitive SFC section scanning with exact byte/line offsets; malformed or unclosed sections are reported.
- Composition API (
<script setup>) and Options API; script content parsed with the JS or TS parser and rebased into the.vuefile. - Template bindings (
v-model,@eventhandlers), emitted events, CSSv-bind(), imports, and composables, resolved through a per-component symbol table. Templatev-bind:/:directives are not extracted — only the CSSv-bind()form in<style>is. - Exact declaration lines and source snippets.
Limitations:
v-model.trimand other.modifierforms drop the binding edge.- Quoted
data()keys ("count": 0) and array-formdefineProps(['title'])produce no entity. - Generic
defineEmits<{ (e: 'save'); (e: 'cancel') }>()captures only the first event. - An
importstatement inside a block comment still registers. _get_component_namelowercases interior capitals, soMyButton.vueyields the entityMybuttonwhile importers yieldexternal::vue_component::MyButton— this blocks future cross-file resolution until normalized.- A component pairing a plain
<script>with<script setup>indexes only the setup block; the plain block's Options API declarations are missing and reported. - Duplicate Options API method keys or
data()keys silently keep the first declaration (not reported); template-binding name collisions are reported. - Relationship identity is
(source, target, kind, binding_type); the shared fixture helper keys on(source, target, kind), so two legitimate edges that differ only bybinding_typeare both retained but cannot yet be expressed in one fixture.
Supported:
- Structs, enums, traits, inherent and trait
implblocks, methods, generics, and qualified trait paths. - Lexical module-scope reference resolution: a bare name declared once resolves to its entity; qualified or foreign paths become scoped unresolved references.
- Calls for local functions and
Type::methodnaming a same-scope method; imports fromusetrees (includingself, grouped, andasforms).
Limitations:
const,static, and type aliases are extracted with no containment edge, so they are unreachable by graph traversal.- Trait bodies contribute no entities; default methods and required signatures are missing.
- Associated
const/typeitems insideimplblocks are skipped. - Import-aware external trait classification is not performed, so a trait
reached through an imported path (
use std::fmt;thenimpl fmt::Display) is unresolved rather than external. - Structs, enums, traits, and type aliases share the
classentity kind. - A field and a method on the same type can collide on the
Type.namequalified-name scheme; the collision is dropped and reported.
Supported:
- Classes and interfaces (both
classentities), methods and constructors (bothmethodentities), with containment edges from the file module. - Imports as
IMPORTSedges;extends/implementssuperclasses asINHERITSedges viaref::placeholders resolved against local entities byGraphBuilder. - Calls: method invocations (
foo.bar(...), barebar(...)) andnew Foo()constructor calls, emitted asCALLSedges viaref::placeholders.
Limitations (pre-hardening parser; not covered by the endpoint gates):
- Endpoint forms predate ADR 1:
imports emit
external::<dotted.name>(e.g.external::java.util.List) instead ofexternal::<namespace>::<symbol>, and internal IDs are still minted with local f-strings rather than the shared normalization helpers. They are no longer barefile::namestrings, though: declarations root in the file's module scope (java_parser.py:95uses_module_scope), so a top-levelClassNameand the file's MODULE entity no longer collide on one ID. ref::placeholders without a matching local entity linger in the graph instead of becomingunresolved::endpoints (emitted atjava_parser.py:111,222,235for superclass, call, and constructor targets).- Nested method invocations can emit duplicate
CALLSedges (the cursor walk re-visits a parent invocation after its children). - Class fields, enum declarations, and annotation declarations are not
extracted;
packagenames are not part of qualified names.
Supported:
- One
DOCUMENTentity per file (first paragraph as docstring) and oneSECTIONentity per ATX heading (#–######), withCONTAINSrelationships following heading nesting, heading levels in metadata, and exact section line ranges. - Headings inside fenced code blocks are deliberately skipped.
Limitations:
- Setext headings (underlined with
===/---) are not detected — only ATX#headings are. - Section IDs are slugified titles; duplicate heading titles collide on one ID (the first wins after graph dedupe).
Supported:
- Mirrors the Markdown parser: one
DOCUMENTentity plus oneSECTIONentity per heading with aCONTAINShierarchy. Heading detection uses the shared RST adornment scanner (prose_chunker._scan_rst_headings), so section levels stay consistent between the graph and the retrieval index.
Limitations:
- Inherits the Markdown shape: no cross-references, directives, or role markup; only section structure is extracted.
Supported:
- One
DOCUMENTentity per file plus oneCONFIG_KEYentity per mapping key at any nesting depth (dotted qualified names), withCONTAINSrelationships following key nesting, value type and a bounded value preview in metadata.yaml.safe_loadwith parse errors visible and deterministic.
Limitations:
- Keys only: scalar/list values contribute a preview, never entities; a non-mapping root (list or scalar) yields only the document entity.
- Key line numbers use a textual search heuristic and can misattribute on duplicate keys, keys inside multiline strings, or commented-out keys that look real.
| Invariant | Gate |
|---|---|
Exact entities/relationships/locations through GraphBuilder |
test_graph_builder_references.py::test_graph_builder_matches_fixture_contract (parametrized over every fixture) |
| Unique entity IDs; collisions reported | test_graph_integrity_gates.py::test_duplicate_declarations_never_produce_duplicate_entity_ids |
| Mixed-language merge has no invalid/dangling endpoints | test_graph_integrity_gates.py::test_mixed_language_merge_has_no_invalid_or_dangling_endpoints |
| Output independent of scan order | test_graph_integrity_gates.py::test_mixed_language_graph_is_independent_of_scan_order |
| Malformed input is visible and deterministic | tests/unit/parsers/test_parser_negative_fixtures.py |
Extension dispatch (.tsx, .jsx, Vue TS) |
tests/unit/parsers/test_parser_extension_dispatch.py |