The data model
How the record holds together
A memory system is only as good as what it can say about the things it stores — that this claim replaced that one, that these four are about the same person, that this date was chosen over that one and here is why. Those are relationships, and a list cannot hold them.
This page is the shape of the store: the tables, the links between them, and what each link carries. It is the other half of the architecture page, which follows material through the pipeline. That one is about how things move. This one is about how they relate.
Readings
Meaning at the top, the claim in the middle, where it came from underneath. Reading downwards asks why the system believes something; reading upwards asks what it means and who can see it.
The drawing needs more width than this screen has, and shrunk to fit it would be a picture of a diagram rather than one. Every row it draws is in the list below, and every link it draws is in the record beneath that.
All 39 rows
Owner
Filing
Meaning
Beside the claim
The claim
Grounds
Material
Origin
8 bands, 39 rows. Choosing one shows what it connects to and why.
Reading it
Shape says what a row is
a claim, or something recorded beside one
memories · memory_versions · conflicts · tasks
a thing, and the links between things
entities · entity_aliases · relationships
a rule about who and what
users · spaces · space_collaborators
where it came from
evidence · documents · sources · conversations · conversation_messages
Colour says only what state it is in
Nothing on this page is coloured to look alive. A hue appears when a row carries a state-bearing column and reports its value, and nowhere else — so when two claims disagree, the disagreement is the only coloured thing in view.
- currentactive, confirmed, accepted, or the side a conflict was decided for
- helduncertain, open, invited but not accepted — known and not yet settled
- supersededreplaced, expired or ended. Still true of the past, so struck rather than removed
- contradictsthe one relation that disagrees: a passage cited against a claim
Every kind of link, and where it lives
A link is either a row in a table of its own, which can carry columns — a confidence, a role, a reason in words — or a foreign key on one of its two ends, which cannot. Almost every interesting thing on this page comes from that difference.
memories.user_id
foreign key
owns
Every owned table carries a user_id that cascades. Ownership is a foreign key rather than a column somebody has to remember to filter on.
space_memberships
link table
is filed in
A row, not a column, so one memory sits in several Spaces at once and carries a kind, a confidence and a reason in words for each. Copying the memory per Space would turn one fact into three that drift apart the first time any is corrected.
spaces.parent_space_id
foreign key
nests under
Reach, not permission. Asking for the parent can mean everything under it; a memory in a child Space is not thereby visible to everyone who can see the parent.
space_collaborators
link table
may read
Visibility, never ownership. Nothing is copied into the collaborator's account, so revoking is one timestamp and their conflict set never mixes with the owner's.
conversations.space_ids
foreign key
files into
An array on the conversation rather than a link table: the scope of a conversation is known when it starts, and every memory extracted from it inherits these.
conversation_messages.conversation_id
foreign key
is a turn of
Ordered by sequence, not by timestamp, because turns can arrive faster than a millisecond.
memory_entities
link table
is about
A junction, because “what else concerns this person” is asked as often as “who is this about”, and an array can only be walked one way. Carries the role and the words the source actually used.
entity_aliases
link table
is also called
The resolution lookup: who is known by this name. Confidence belongs to the alias, not to the entity.
relationships
link table
relates to
An edge between two entities with its own validity window, because a link outlives both ends: a thing stops being true without either entity changing.
relationship_memories
link table
was asserted by
A link with no memory has no grounds.
relationship_evidence
link table
is grounded by
One sentence, two claims: the observation that grounds a memory usually grounds the relationship extracted from the same words.
memory_evidence
link table
is grounded by
The relation lives on the pairing rather than on the observation, because the same passage can support one claim and contradict another.
evidence.document_id
foreign key
is a passage of
Required. A passage with no document is a quote from nowhere, which cannot be checked and therefore cannot ground anything.
evidence.source_id
foreign key
was seen through
Nullable, unlike the document: a connector can be removed while the material it produced stays checkable.
memory_sources
link table
came from
Association, which is not the same as citation. A memory merged from three sources may have evidence from only two — and the third is often the one that made it well-founded, since corroboration counts distinct origins.
memory_versions
link table
is a version of
Append-only. What it said before, what changed, and why.
memories.superseded_by
foreign key
was replaced by
The old row stays, keeps its evidence and its filing, and points at what replaced it. Overwriting would destroy the only record that the belief ever changed.
conflict_memories
link table
is a side of
A junction rather than two columns, because three sources can disagree three ways about one subject and a two-column shape would record that as three conflicts nobody can resolve together.
conflicts.winner_memory_id
foreign key
was decided for
Set null on delete: the record that a conflict happened outlives the row that won it.
tasks.memory_id
foreign key
came from
Four typed columns rather than one polymorphic pair, so the database can still check the reference. All four set null rather than cascade: a to-do outlives the transcript it was agreed in.
What this deliberately does not draw
A diagram is read as a claim about the system, so an absence is worth as much as a line. These are the four things it would have been easy to add and wrong to.
- memory_pins
- The table is real — (user_id, memory_id, pinned_at) — and it is left out because of who it belongs to rather than because it is small. A pin is one person’s opinion ABOUT a claim, not a property of the claim: the same memory is pinned for its owner and not for someone reading it through a shared Space. Everything drawn here is true for every reader of a row, and a pin is the one edge that would not be.
- A membership row for Universal
- Universal is the base layer rather than a Space. Every memory is in it, so a row saying so would be one row per memory carrying no information — and querying Universal is simply querying the user’s own memories.
- candidates, vectors, jobs, events and the rest of the machinery
- They are how material gets here and how it is retrieved, which is the pipeline the architecture page explains. This page is only about how the things that survive that pipeline relate to each other.
- What a collaborator may DO
- `space_collaborators.role` is real and this page draws the grant without it. A viewer reads a Space, an editor also files into it, an owner shares it onward — three different powers over the same edge, which is a second dimension this drawing has no way to carry: it distinguishes kinds of link by shape, and these are all one kind. The dashboard is where a role is read and changed.
The pipeline that produces all of this is on the architecture page, and the API that reads it is in the documentation.