I1002 — Relations are typed, inferred from stable identities, and never dangle
Give the graph typed relations — implements, documents, exposes, generated from, enforced by, tested by, benchmarked by, depends on, projects to, served at — inferred where a stable convention exists, declared where it does not, and resolved or refused.
DONE wave 1 · p0 · deep-work profile · parallel safe
Objective
Give the graph typed relations — implements, documents, exposes, generated from, enforced by, tested by, benchmarked by, depends on, projects to, served at — inferred where a stable convention exists, declared where it does not, and resolved or refused.
Why
A list of capabilities is an inventory; a graph of them is an architecture a person can navigate. The value is entirely in the edges, and an edge that points at nothing is worse than a missing one because it renders as an empty section instead of an error.
Current state
Relations exist implicitly in frontmatter references, capability tags, rule metadata and ADR related lists. Nothing resolves them into a common edge type, and nothing fails when one does not resolve.
Desired state
Every edge has a type, both ends resolve to a node, and an unresolvable edge fails generation with a message naming the declaration, the missing end and the correction.
Scope
- apps/majordomus-cli/src/graph.rs
Out of scope
- Inference by substring or title matching where a stable identity exists
- Requiring a contributor to restate a relation the metadata already implies
Dependencies
What waits on this
- I1005DONE The graph is a generated artifact with a schema and no unsafe field
- I1011READY The coverage matrix reports evidence, and never a green cell without one
- I1014BLOCKED The relation view reads the graph and holds no data of its own
- I1020BLOCKED The graph's health is answered by the doctor that already answers everything else
Acceptance criteria
- Each relation type is explicit, and the direction is part of its meaning
- Inference uses stable identities only, and an ambiguous case requires an explicit declaration instead of a guess
- A relation whose target does not exist fails generation, naming where it was declared and what is missing
- Tests cover malformed metadata, duplicate identities and dangling relations
Validation
- cargo test --workspace --all-features
- majordomus generate --check
Evidence required
- relations_resolve
- dangling_refused
Evidence
| covers | type | command | result | at commit |
|---|---|---|---|---|
| relations_resolve | test | cargo test --lib graph (apps/majordomus-cli) and unresolved_relations over this repository | the layer resolves cleanly: 778 objects, 0 unresolved references; edges cover depends_on, supersedes, put_in_force, related_to, runs, exercises, evidences, tracks and documents, each through a stable identity, a declared id or a repository-relative path | c5ecfa1 |
| dangling_refused | test | cargo test --lib graph::tests::a_reference_to_a_kind_we_hold_that_names_nothing_is_a_finding and a_finding_is_never_drawn_as_an_edge | a reference naming a kind this repository holds that resolves to nothing yields a finding with the file, the key, the reference and the correction, and no node or edge is drawn for it; a file or test outside the layer resolves to an external node and is not a finding | c5ecfa1 |
Risk
Strict resolution can make an unrelated documentation edit fail the build. The message has to be good enough that the failure is a five-second fix rather than an investigation.
Timeline
- started
- 2026-09-06T15:54:48Z
- verified
- —
- completed
- 2026-09-06T16:19:14Z
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I1002.yaml. Read it back with majordomus plan show I1002.