What memory validity invariants must survive a base model upgrade that changes embedding semantics?
**Date of Record:** 2026 October 27 **Scope:** Applies when an agentic session stores memory as embeddings (semantic memory, RAG context, or vector-indexed notes) using a base model's embedding function, and the base model is upgraded such that its embedding function produces vectors in a semantically incompatible space. Does not apply to sessions using strictly immutable embedding functions, or where memory is stored in non-embedding form.
Core Distinction
The separation between **memory content preservation** (the stored memories were not lost during upgrade) and **memory retrievability preservation** (the stored memories can still be retrieved with equivalent semantics under the new embedding function). Relying on content preservation creates the **Embedding Semantic Gap**: the memories are all present in the vector store, but their embeddings were generated by the old model, and the new model's query embeddings no longer align with the old vectors, so retrieval returns wrong or irrelevant memories.
What Was Observed
In memory-based agent architectures, failing to account for embedding semantic shift produces three primary failure modes:
- **Retrieval Quality Collapse:** The agent queries "relevant context for customer X" and the vector store returns irrelevant memories because the query embedding is in the new space, and the stored vectors are in the old space.
- **Silent Semantic Drift:** The agent retrieves memories that were semantically similar under the old model but are semantically unrelated under the new model, and the agent acts on them as if they were relevant.
- **Full Rebuild Requirement:** Detecting the semantic shift requires re-embedding all memories, which is expensive, and if the session did not plan for it, it must either accept degraded retrieval or take a long outage.
Recorded Elements
- **`memory_embedding_model_signature`:** For each stored memory, the cryptographic signature of the embedding model version that produced its vector, allowing the session to identify which memories need re-embedding.
- **`embedding_semantic_compatibility_receipt`:** A cryptographic proof that two embedding model versions produce compatible vector spaces (e.g., "v2 is a strict extension of v1 with the first 1536 dimensions preserved"), allowing selective re-embedding.
- **`query_embedding_reconciliation_receipt`:** For queries under the new model, the exact translation or adaptation applied to make the query comparable to old-version memories (e.g., truncating dimensions, or re-projecting through an adapter).
- **`re_embedding_progress_receipt`:** For the re-embedding operation, the cryptographic proof of which memories have been re-embedded, which remain on the old model, and the schedule for completion.
Condition of Validity
* **Applies when:** Memory is stored as embeddings, the embedding model can be upgraded, and the upgrade can change embedding semantics. * **Does not apply when:** Memory is stored in raw text/token form, or the embedding function is strictly immutable.
Decision Boundary
- **Has the base model's embedding function changed?** If no, standard memory retrieval applies. If yes, proceed.
- **Does the `embedding_semantic_compatibility_receipt` show that old and new embeddings are compatible?** If yes, the memories are retrievable without re-embedding. If no, the memories are semantically drifted.
- **Is the `query_embedding_reconciliation_receipt` applied for new queries?** If no, the session must apply reconciliation before querying old memories.
- **Conversely, when can the session ignore embedding semantic shift?** Only when the memory system is strictly rebuilt from scratch on upgrade, or the memory usage is tolerant to semantic shift (e.g., exploratory search).
Operational Effect
- **Retrieval Quality Preservation:** Ensures the agent can still retrieve relevant memories despite model upgrade.
- **Migration Planning:** Provides a clear signal for when full re-embedding is required vs. when reconciliation is sufficient.
- **Silent Drift Detection:** Prevents the agent from acting on irrelevant memories that were retrieved due to semantic drift.
from dataclasses import dataclass
from enum import Enum, auto
import hashlib
import json
class MemoryValidityVerdict(Enum):
NO_UPGRADE = auto()
COMPATIBLE_RETRIEVAL = auto()
RECONCILIATION_REQUIRED = auto()
FULL_REEMBEDDING_REQUIRED = auto()
@dataclass(frozen=True)
class MemoryState:
old_embedding_model: str
current_embedding_model: str
compatibility_receipt: str | None
reconciliation_receipt: str | None
reembedding_complete: bool
@dataclass(frozen=True)
class MemoryPolicy:
require_reconciliation: bool
require_reembedding: bool
@dataclass(frozen=True)
class MemoryManifest:
verdict: MemoryValidityVerdict
directive: str
manifest_digest: str
class MemoryEmbeddingGuard:
@staticmethod
def _hash(data: str) -> str:
return hashlib.sha256(data.encode("utf-8")).hexdigest()
@classmethod
def evaluate_memory(
cls, state: MemoryState, policy: MemoryPolicy
) -> MemoryManifest:
# Gate 1: No upgrade
if state.old_embedding_model == state.current_embedding_model:
digest = cls._hash(json.dumps({
"model": state.current_embedding_model,
"status": "NO_UPGRADE"
}, sort_keys=True))
return MemoryManifest(
verdict=MemoryValidityVerdict.NO_UPGRADE,
directive=f"PROCEED: No model upgrade, memories valid.",
manifest_digest=digest
)
# Gate 2: Compatibility
if state.compatibility_receipt:
digest = cls._hash(json.dumps({
"old": state.old_embedding_model,
"new": state.current_embedding_model,
"compatibility": state.compatibility_receipt
}, sort_keys=True))
return MemoryManifest(
verdict=MemoryValidityVerdict.COMPATIBLE_RETRIEVAL,
directive=f"PROCEED: Old memories compatible with new model.",
manifest_digest=digest
)
# Gate 3: Reconciliation
if policy.require_reconciliation and state.reconciliation_receipt:
digest = cls._hash(json.dumps({
"old": state.old_embedding_model,
"new": state.current_embedding_model,
"reconciliation": state.reconciliation_receipt
}, sort_keys=True))
return MemoryManifest(
verdict=MemoryValidityVerdict.RECONCILIATION_REQUIRED,
directive=f"PROCEED: Reconciliation applied. Semantics preserved.",
manifest_digest=digest
)
# Gate 4: Re-embedding required
if state.reembedding_complete:
digest = cls._hash(json.dumps({
"model": state.current_embedding_model,
"reembedding": "COMPLETE"
}, sort_keys=True))
return MemoryManifest(
verdict=MemoryValidityVerdict.FULL_REEMBEDDING_REQUIRED,
directive=f"PROCEED: Re-embedding complete, memories valid under new model.",
manifest_digest=digest
)
return MemoryManifest(
verdict=MemoryValidityVerdict.FULL_REEMBEDDING_REQUIRED,
directive=f"HALT: Memories under {state.old_embedding_model}, current is {state.current_embedding_model}. Re-embed required.",
manifest_digest=cls._hash(f"REEMBED_NEEDED:{state.current_embedding_model}")
)