Compare each incoming memory with existing facts in the same authorized scope before storing it. Skip exact duplicates, merge complementary details, and supersede an older value only when the evidence establishes a correction or change. Preserve unresolved conflicts explicitly, and commit updates against an expected revision so concurrent agents cannot silently overwrite each other.
Give each fact an identity before comparing text
Suppose Claude Code records that the billing service deploys to staging on Tuesdays. Codex later records the same schedule in different words. A third session says Thursday is the new staging window. Appending all three leaves recall to decide whether two weekdays describe alternatives, history or a contradiction.
For a store you control, define a fact identity from workspace, audience, owner where applicable, subject, predicate and qualifiers. Here the subject is billing, the predicate is deployment window, and the environment is staging. Production needs a separate identity. Keep the value outside that identity so changing Tuesday to Thursday updates the same fact.
Store the original claim, source reference, observation time and effective time alongside the canonical value. A transcript uploaded today may describe last month's schedule. Resolve personal and shared scope before looking for matches; a private preference must not become a workspace rule because its wording resembles one. The personal and team memory guide covers that ownership boundary.
Separate duplicate detection from candidate retrieval
Start with exact comparison within that fact identity. Define a conservative normalization policy, such as normalizing line endings and trimming surrounding whitespace. Preserve negation, dates, units, environment names and case-sensitive identifiers. Removing punctuation from a hostname or dropping the word 'not' changes evidence rather than cleaning it.
A fingerprint can accelerate this check, but verify the stored normalized content before skipping a candidate. Distinguish repeated delivery of one extraction event from independent evidence that happens to state the same fact. The former should be idempotent; the latter may add a source reference without adding another recalled sentence.
For paraphrases, retrieve possible matches using subject aliases, predicate filters and optionally semantic similarity. Always compare the existing record with the candidate before deciding. 'Deploy Tuesday' and 'Do not deploy Tuesday' concern the same topic but require different outcomes. An empty nearest-neighbor result also does not prove novelty; check the canonical identity directly.
The Mem0 paper describes retrieving similar memories and selecting among ADD, UPDATE, DELETE and NOOP operations. Use that as a reference pattern for separating retrieval from mutation. The conflict rules below are a proposed application policy; similarity scores alone do not authorize replacement.
Make conflict resolution an explicit decision
Have the merger return a structured proposal containing the operation, target identifier, expected revision, proposed value, supporting sources and reason. Validate those fields before committing anything. A model may propose a relationship between claims; application code must enforce scope and allowed transitions.
- Duplicate: Tuesday staging deployment expressed twice keeps one current value. Add genuinely new provenance without duplicating the prose.
- Enrichment: 'Tuesday after integration tests pass' adds a condition. Retain Tuesday and the test requirement without inventing an exact time.
- Supersession: an authorized maintainer explicitly moves the window to Thursday, effective next week. End the old value's validity at that boundary and preserve it as history.
- Unresolved conflict: two equally authoritative sources disagree without a clear correction. Retain both claims, flag the conflict, and require verification before scheduling a deployment.
- Distinct fact: Thursday production deployment coexists with Tuesday staging deployment. Preserve both environment qualifiers.
Define authority by fact type. A person's explicit correction can update their own preference; an agent's guessed summary should not overwrite a maintained release policy. Repeated summaries of the same transcript are one evidence chain, not multiple independent votes. Arrival order and model confidence are insufficient reasons to prefer Thursday.
Commit against the revision that was actually compared
Keep model inference outside the database transaction, then perform a conditional write. Otherwise two agents can both read Tuesday, independently add different conditions, and let the last replacement erase the first. This illustrative PostgreSQL statement assumes an application-owned memory_facts table with one current row per canonical identity and a revision incremented by every writer:
UPDATE memory_facts
SET value_text = $1,
revision = revision + 1,
updated_at = CURRENT_TIMESTAMP
WHERE workspace_id = $2
AND scope_key = $3
AND fact_key = $4
AND revision = $5
RETURNING fact_key, value_text, revision;Bind the merged value and expected revision as parameters. Derive workspace and permitted scope from authentication. Enforce a unique constraint on (workspace_id, scope_key, fact_key); make those columns non-null. PostgreSQL's UPDATE documentation defines the conditional write and returned rows. Under Read Committed, PostgreSQL rechecks the condition after a competing updater commits. With the revision rule, a stale proposal returns no updated row.
On that result, reread within the authorized scope and recompute the merge; never retry the stale replacement blindly. For a new identity, PostgreSQL's INSERT ... ON CONFLICT DO NOTHING can arbitrate competing creation attempts using the unique constraint. If another writer wins, read its fact and compare again.
Commit the value change, revision history and extraction-event receipt in one transaction. Give each event a stable identifier scoped to its origin and memory namespace, backed by uniqueness. A retry after a lost response should return the committed result rather than run a second semantic merge.
Keep current recall compact without erasing the disagreement
Separate the current fact from its revisions and source evidence. Routine recall should return Thursday once it becomes effective, plus the date and relevant condition. A historical question about Tuesday should consult the earlier validity interval. Before the change takes effect, return Tuesday as current and Thursday as scheduled.
For an unresolved conflict, return a short conflict description with both sources instead of silently choosing whichever record ranks first. If the agent needs to schedule work, that response should make the missing confirmation visible. Keep historical and disputed records out of ordinary current-fact ranking unless the query needs them.
When a canonical value changes, refresh any search representation and invalidate cached recall for the affected revision. If indexing is asynchronous, validate retrieved identifiers against current rows before returning their text. Otherwise the merge can succeed while stale excerpts continue circulating. Source evidence and old revisions also need a defined deletion lifecycle; the retention and deletion guide addresses that follow-through.
How SPYN3 handles remembered updates
SPYN3's opt-in Memory & skills setting is off by default. Its remember tool merges into an existing memory file rather than appending duplicates: with a workspace-provided model key, a model merges; without one, exact duplicates are skipped. Reading needs call:tools, while memory writes need the separate write:memory permission. Personal and workspace paths separate ownership, every memory write is audit-logged, and recalled memory is labelled as recorded data, not instructions.
Test meaning preservation as well as duplicate counts
Build a fixture history around the deployment window and assert the final facts, provenance and recall payload. A smaller row count proves little if the merger removed an environment qualifier or converted a proposal into an approved policy.
- Deliver the same extraction event twice; expect one committed effect.
- Submit a paraphrase; expect one current fact with its meaning unchanged.
- Add the integration-test condition; expect that condition to survive later updates.
- Upload an older Tuesday transcript after Thursday is approved; expect no reversal.
- Introduce a production schedule; expect a separate fact.
- Race two enrichments against one revision; expect a conflict followed by recomputation that preserves both compatible details.
- Submit contradictory evidence without authority to resolve it; expect a visible unresolved state.
Run model-assisted cases repeatedly and measure false merges separately from missed duplicates. Replay the history in different arrival orders where effective times and authority stay fixed. The same approved schedule should emerge. Include a fresh agent session that asks for the next deployment window; inspect what recall actually supplies. The memory recall evaluation guide extends that check to downstream task outcomes.
Built for the next step
Keep context with the user, not the agent
Memory and skills behind the same endpoint as your tools, readable by any agent you connect.
Read the developer guideSPYN3 is a consolidated MCP layer: one hosted endpoint in front of every system you connect — MCP servers, Postgres, REST APIs, Google Drive — with tools foldered by source and read/write permissions per key. Switching agents means moving one URL. Free plan available; current capabilities are documented on the product facts page.
Sources
- Chhikara et al.: Mem0: Building Production-Ready AI Agents with Scalable Long-Term Memory — Section 2.1 separates extraction from comparison with similar memories and selection of ADD, UPDATE, DELETE or NOOP operations. Verified 27 Oct 2026
- PostgreSQL 16 documentation: UPDATE — Parameterized conditional UPDATE syntax, expressions using existing values, RETURNING and zero-row update behavior. Verified 27 Oct 2026
- PostgreSQL 16 documentation: Transaction Isolation — Read Committed updates wait for competing writers and re-evaluate WHERE conditions against the updated row. Verified 27 Oct 2026
- PostgreSQL 16 documentation: INSERT — ON CONFLICT DO NOTHING uses unique constraints or indexes to arbitrate conflicting inserts. Verified 27 Oct 2026
