> Full SurrealDB documentation index: https://surrealdb.com/docs/llms.txt

# Reconciliation and supersession

How entities are deduplicated and conflicts detected. Corrections are tracked with full history.

Extracted data is not written directly to memory. A **reconciliation** pass compares new extractions against what is already stored: matching entities, detecting conflicts, and deciding whether a new value replaces an old one or coexists alongside it.

## Reconciliation in brief

### Entity matching

SurrealDB Agent Memory attaches a new extraction to an existing entity by **exact composite key**. An entity's record id is **`[normalised_type, normalised_name]`**, and matching is a direct lookup on that id: either the record exists and the new attributes and relations land on it, or a new entity is created. There is no fuzzy, phonetic, or embedding-based matching on the write path - a name that normalises differently becomes a separate entity.

Keeping references together therefore depends on **extraction emitting a consistent name**. To support that, the extraction prompt is given the entities the Context already holds and instructed to reuse their exact names. Seeding the entities you care about before a bulk ingest measurably improves the odds that later mentions land on them.

**Type is half the identity** - the same name under two types is two entities that nothing merges. Supplied types are normalised into a closed vocabulary (`person`, `organisation`, `project`, `location`, `topic`, `product`, `policy`, `concept`, `event`, `agent`, `service`, `other`). Near-synonyms fold into it - `company`, `org`, and `organization` all become `organisation` - and a type outside the set becomes **`other`** rather than minting a new type. When you write entities directly, pick the type once and keep it stable, or a later write lands on a different record.

**Nicknames and alternative names** - because matching is exact, a referent named two ways produces two entities. `Matt` and `Matthew Cauldwell`, `IBM` and `International Business Machines`, a person referred to by first name in one document and in full in another: each pair is two records, each with its own attributes and its own supersession chains.

There is no alias field and no automatic merge. Three things help:

- **Seed canonical names first.** Create the entity under the name you want before ingesting, so it appears in the extraction prompt's known-entity list.
- **Normalise at the edge.** Map the variants you know about to one canonical name in your own pipeline, before the write.
- **Audit with [`POST /fsck`](/docs/agent-memory/reference/rest-api.md).** The `duplicates` check reports entity pairs above a cosine-similarity floor (default **`0.95`**) in the same scope. It reports candidates for you to act on; it does not merge them.

> [!NOTE]
> The `duplicates` check currently returns no candidates. It stays inactive until `fsck` can limit its results to the scopes the caller is allowed to read, so an empty result does not mean the Context has no duplicates. Until then, review the entity list yourself after a bulk ingest.

> [!NOTE]
> A **`same_as`** relation is an ordinary edge label, not an instruction to the reconciler. It records that two entities denote the same referent - useful when that is a fact the reader or agent learns at a particular moment, and gate-able with **`asOf`** - but the two entities stay separate, keep their own attributes, and are returned separately. Merging them is a decision for the layer above.

**Cross-language mentions** - the same concept in different languages (for example `skill_math` from an English conversation and `skill_matte` from a Swedish conversation) are usually stored as **separate relation labels** unless extraction or reconciliation maps them to the same entity and key. That is expected: labels carry language-specific semantics. Background **elaboration** may later link related entities. Labels cannot be constrained up front, but extraction is shown the labels already in use and told to reuse them where the meaning matches - see [Extraction vocabulary](/docs/agent-memory/tuning/ontology-grounding.md). SurrealDB Agent Memory does not automatically mint a meta-edge between every cross-language synonym.

### Attribute conflicts

When the same entity and key already have a value in the **same scope** and the new value differs, SurrealDB Agent Memory treats it as a conflict. What happens depends on where the existing value came from:

- **Experiential-only conflict** - the new value **supersedes** the old. The previous value is closed with a **`valid_until`** timestamp and remains in history.
- **Authoritative conflict** - curated knowledge (documents, operator upserts) is **not** modified. The user’s assertion is stored in experiential memory with full provenance, and the clash is surfaced (for example via **`uncertainty`** records). See [Authority when pillars meet](/docs/agent-memory/reasoning/authority-hierarchy.md).

SurrealDB Agent Memory does **not** use last-write-wins. Concurrent updates reconcile in **one ACID transaction** per write; cross-provenance clashes become **`uncertainty`**, same-stream updates **supersede** when confidence allows, and writes below the **confidence floor** cannot silently overwrite stronger beliefs.

### Confidence floor

Each Context configures **`config.reconciliation.confidence_floor`** (default **`0.7`**). On a same-provenance conflict, SurrealDB Agent Memory supersedes the prior value only when the new extraction’s confidence is at or above the floor **and** at or above the existing record’s confidence. Otherwise both values stay live and an **`uncertainty`** is recorded - a low-confidence extraction cannot erase an established high-confidence fact.

### Scope-aware coexistence

Different scopes may legitimately hold different values for the same key - an org default and a user override, or the same person in two organisations. Conflict detection runs **within one scope**. Cross-scope differences are independent records, not supersessions.

### Invalidation

When a user explicitly negates a fact (“I no longer work there”, “forget my old address”), reconciliation **closes** matching active attributes with **`valid_until`** rather than deleting them. History and audit trails stay intact.

## The supersession chain

When a fact changes over time, SurrealDB Agent Memory keeps a **chain** of values - each link records what it replaced and what replaced it. Only the **current** head of the chain is returned by default queries; earlier values remain available for history and point-in-time reads.

Example: Alice’s role moves from COO → CEO → CTO. Each step opens a new value with **`valid_from`** set to the correction time and closes the previous one with **`valid_until`**. Nothing is erased.

## Querying current and historical state

Use the public API rather than ad hoc database queries:

- **Current beliefs** - **`POST /query`** or **`GET /profile`** for a scope; entity GETs return active attributes.
- **History for one key** - **`GET /api/v1/{context_id}/entities/{type}/{name}/history/{key}`** returns the supersession chain.
- **Point in time** - entity reads accept **`asOf`**, **`atInstant`**, **`validFrom`**, and **`validUntil`** query parameters. See [Tri-temporal model](/docs/agent-memory/architecture/tri-temporal-model.md) and the [REST API](/docs/agent-memory/reference/rest-api.md).

## Correction versus coexistence

**Correction** - same scope, new value replaces old reality (role change, corrected name). Supersession applies.

**Coexistence** - same key, different scopes, both valid in their contexts. Neither record supersedes the other.

### Unresolved relation objects

When reconciliation cannot resolve a relation’s object entity, it materialises a placeholder typed **`unknown`** so the stated fact is not dropped from recall. These placeholders may not auto-merge with a later properly typed extraction until a maintenance sweep reconciles them.

## History by default - and forget when you need removal

For **corrections and supersession**, SurrealDB Agent Memory keeps a full chain of past values. Nothing is erased: earlier beliefs stay in the store so you can audit, recover from a bad correction, or answer “what did we believe in January?”

Data can still be removed. When someone asks to forget something, SurrealDB Agent Memory supports two distinct levels:

| Intent | What happens | Typical use |
| --- | --- | --- |
| **Stop using this in the agent** (default) | Matching memories are **expired** - they no longer appear in recall, query, profile, or chat context, but remain stored for audit and point-in-time review. | “Forget my old job”, entity delete, routine privacy tidying. |
| **Remove it for compliance** (explicit opt-in) | The same match is **permanently erased**, including correction history for the affected entities. | Right-to-erasure requests, retention policy enforcement. |
| **Erase a whole scope subtree** | Everything tagged under a scope path is **hard-deleted** across memory and knowledge. | GDPR-style deletion for a user or team branch. |

Default forget and entity delete are **soft**: the agent behaves as if the information is gone, while operators can still inspect what was retired. Compliance paths require an explicit **`purge`** flag on **`POST /forget`**, or **`POST /scopes/forget`** for subtree erasure - both need the **`memory:forget`** grant on the relevant scope. Audit traces may still record that a forget operation ran, without retaining the forgotten content itself.

See [Forgetting memories](/docs/agent-memory/operations/forget.md) for request shapes and CLI equivalents.
