Edges
The single relationship concept. Every edge, regardless of kind, carries:
| Attribute | Type | Required | Meaning |
|---|---|---|---|
edge |
EdgeKind | yes | discriminant, see below |
from |
EntityId | yes | source |
to |
EntityId | yes | primary target (best candidate if uncertain) |
provenance |
Provenance | yes | how we know |
anchor |
SourceAnchor | yes | where observed |
candidates |
EntityId[] | no | possible targets when dispatch is uncertain; non-empty iff resolution was ambiguous |
sourceFile |
string | no | disambiguates which declaration site produced the edge (C# partial classes, TS declaration merging) |
Rules
- Outgoing only, stored once. All inverse views — callers of X, subtypes of Y, importers of M, and
children(the inverse ofparent) — are derived in memory, never serialized. Onlyparentis a stored fact. - Closure:
fromandtomust resolve to a known entity or a stub — a tested property of every model. - No self-reference:
from ≠ to.
Edge kinds
| Kind | From → To | Extra attributes | Notes |
|---|---|---|---|
import |
Module → Module | First-class layer: the only relation reliable ≈100% across all languages, hence the granularity for cross-language comparison. Rust has two levels (mod, crate) | |
inheritance |
Type → Type | N edges for multiple inheritance (Python); optional MRO order left to profile notes | |
interfaceImplementation |
Type → Type (interface/trait/protocol) | declared (Java implements) or derived (Go, TS structural) depending on language. For Rust/Clojure the anchor is the reified impl block |
|
invocation |
Invocable → Invocable | candidates |
uncertain dispatch → provenance: dynamic-candidate + candidates list |
access |
Invocable → Structural | isRead: bool, isWrite: bool |
field/variable reads and writes; a compound assignment sets both |
reference |
Entity → Type | type usage that is none of the above (declarations, generics, casts) | |
annotationUse |
Entity → Type (annotation) | arguments: NamedArgument[] |
a written annotation on any entity, with its arguments. The dedicated kind carries the values and lets a consumer select annotation usages without guessing from the target’s kind — which a stub target cannot answer |
throws |
Invocable → Type (exception) | a written throw statement whose static exception type resolved; the anchor is the throw SITE. A declared propagation clause (Java throws E) is a plain reference, not this |
|
embedding |
Type → Type | Go struct { Base } — neither inheritance nor attribute (method promotion); dedicated relation |
|
traitUsage |
Type → Trait (PHP) | PHP use TraitX; — kept as a usage edge, never flattened into the class |
|
fileInclude |
CodeFile → CodeFile | PHP include/require — the only file-to-file dependency in the metamodel |
The order above is the order the header dictionary’s enum declares.
Relations: edges connect entities; are licensed per language profile (a profile lists which edge kinds its extractor can emit); carry a SourceAnchor and a Provenance.
Folded edges
Analyses do not read base edges directly: the analyzer folds them to --level module or --level type first, aggregating every base edge between two folded nodes into one arrow that carries the count, the set of base kinds and the set of provenances. A folded arrow is an inference about a group, not a written fact; what it aggregates is stated in every rendering.
Last updated on