Status: Step 07 snapshot of the hardening blueprint
Scope: What each KnowCode parser extracts today, and the explicit
limitations a user or downstream step can rely on. This matrix 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/. It is the single
source of truth referenced by the release gate (blueprint Step 22).
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 (Step 07). The
synthetic per-file module entity (named after the file stem) is intentionally
excluded from that dedupe so a top-level declaration whose name matches the file
stem — notably a Java public class in ClassName.java — remains a redundant
wrapper that the graph merge resolves in favor of the declaration.
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.
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 rawfile::namestrings without the shared normalization helpers, soclassify_endpoint_idmarks them invalid. ref::placeholders without a matching local entity linger in the graph instead of becomingunresolved::endpoints.- 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 |