Graph Node Identity
Context¶
The canonical trace graph (ADR-0006 layer 1) grew two node sources: corpus documents, whose frontmatter-link edges originate from declared document IDs, and code/test artefacts, whose marker edges originate from file paths. Two identity schemes in one graph leave the join rule implicit — consumers must know which kind of node they are matching — and the question must be settled before the Rust Trace Engine freezes the contract.
Decision¶
Every node has exactly one id, chosen by one rule: the declared document ID when the source declares one, otherwise the repository-relative path.
Every node carries file as an attribute (for artefacts, file equals id).
Edges always reference node ids.
Artefact identity is deliberately path-based and therefore rename-unstable: the graph contains only facts declared in the corpus, and a Rust source file declares no identity beyond its location. Stability for artefacts comes from version control, not from invented names.
Alternatives Considered¶
- Status quo without a rule: rejected — the mixed model works today, but the join semantics stay implicit and every consumer re-derives them; an undocumented convention is the worst kind of contract.
- Synthetic artefact IDs (hashes, module paths): rejected — invented identities that appear nowhere in the corpus contradict the graph's lossless-facts principle and add collision and maintenance questions for marginal rename-stability.
- Two separate graphs (ontology links vs marker links): rejected — it breaks the single node-and-edge contract (REQ-03-01-05-04), coverage needs both halves together anyway, and it reintroduces the two-format problem ADR-0006 eliminated.
Consequences¶
- One join rule for all consumers: match on
id, readfilefor location. - The Rust Trace Engine inherits the rule; the conformance suite exercises it through the skeleton tests.
- Test functions can later become declared identities (child nodes of their file's artefact node) without breaking the rule — a declared name is a declared fact.
- Marker edges carry the attached test function's name as an attribute (
test), which is location context, not identity.