Relationships
Relationships are first-class typed edges between entities, not hard-coded foreign keys. They are stored as observations and snapshots, so multiple sources can contribute to the same edge, every edge carries full provenance, and the graph stays open-ontology and queryable.
Sits next to entities. Sources produce relationship observations the same way they produce entity observations; the relationship reducer composes them into a relationship snapshot.
Schema#
Relationship pattern
Core relationship types#
PART_OF (hierarchical containment, e.g. invoice_line_item PART_OF invoice). CORRECTS (corrections supersede originals). REFERS_TO (mentions / references). SETTLES (payment settles invoice). DUPLICATE_OF (entity dedupe). DEPENDS_ON (task ordering). SUPERSEDES (versioning). EMBEDS (container embeds reusable asset, e.g. blog post EMBEDS image).
Open ontology, not hard-coded hierarchies#
Neotoma does not hard-code parent-child columns or a fixed schema of edge types. Hierarchies emerge from edges, which means out-of-order ingestion, multiple parents, overlapping summaries, and corrections all compose without schema changes. New edge types can be introduced without migrating data.
Observation-snapshot pattern#
Each write to a relationship is an immutable observation that carries metadata and provenance. The reducer merges all observations for the same (source_entity, target_entity, type) into a single snapshot. The provenance map records, per metadata field, which observation produced which value, exactly the same shape as entity snapshots.
Queryable in both directions#
Relationships are first-class rows that can be queried by source entity, target entity, type, or metadata. Read paths support traversals (find all PART_OF children of an invoice) and reverse lookups (find every entity that REFERS_TO this contract). Same RLS rules apply, only relationships whose source/target you own are visible.
Invariants#
Every relationship satisfies the following constraints:
MUST
- Be stored as immutable observations + a deterministically computed snapshot
- Carry full provenance, every metadata field traces to the observation that set it
- Be typed (PART_OF / CORRECTS / REFERS_TO / SETTLES / DUPLICATE_OF / DEPENDS_ON / SUPERSEDES / EMBEDS, …)
- Respect source-ownership RLS on every read path
MUST NOT
- Be modeled as foreign keys on entity tables
- Be mutated in place, corrections and supersessions create new observations
- Be created without explicit source_entity_id, target_entity_id, and type
- Bypass the relationship reducer for ad-hoc snapshot writes
Related#
- Relationships subsystem doc , Types, graph patterns, query examples
- Observations , Underlying primitive each relationship observation builds on
- Entity merge , DUPLICATE_OF mechanics and merge handling
- Architectural decisions , Why relationships are first-class and the graph is open-ontology
Where to go next#
- All primitive record types , index of sources, interpretations, observations, relationships, and timeline events
- Architecture , how the primitives compose into Neotoma's deterministic state
- Terminology , canonical glossary of terms used across Neotoma docs