ADR-0055: Memory write-path exact and near-duplicate dedup
Architecture decision record 0055 — SHA-256 content_hash exact dedup before embed; near-dup candidates via VectorStore.search with cosine > 0.92; partial unique index on active rows.
ADR-0055: Memory write-path exact and near-duplicate dedup
- Status: Accepted
- Date: 2026-08-27
- Authors: IBEX Harness team
- Milestone: 3.C.2 Content and near-duplicate detection
Context
Track C write order is validate → PII → exact dedup → embed → near-dup →
conflict (3.C.3). Milestone 3.C.1 shipped the Stage seam and PII. Exact and near
checks must reuse Track B’s VectorStore (no bespoke ANN SQL), stay org/agent-scoped,
and leave conflict/merge policy to 3.C.3.
Options considered
1) Exact-hash uniqueness
- Application-only lookup (no DB unique) — race windows on concurrent writes.
- Full unique on
(org_id, agent_id, content_hash)— blocks soft-deleted / superseded rows from ever reusing a hash. - Partial unique index on
(org_id, agent_id, content_hash)wherestatus = 'active' AND deleted_at IS NULL.
Decision: (3). Matches “one live copy” while allowing 3.C.3 supersession / merge to free the hash for a replacement row.
2) Near-duplicate API surface
- Add
VectorStore.find_similaralias. - Call existing
VectorStore.searchwithmin_similarity= threshold.
Decision: (2). Avoids ABC churn; Track D may still wrap search later.
3) Threshold semantics
Milestone text: cosine > 0.92. search returns similarity >= min_similarity.
Decision: request min_similarity = threshold, then keep candidates with
similarity > threshold (strict). Default
IBEX_MEMORY_NEAR_DUPLICATE_SIM_THRESHOLD=0.92.
4) Hash input
Hash post-PII ctx.content (whitespace-collapsed, lowercased, SHA-256 hex).
Identical redacted payloads dedup; raw PII never enters the hash after redaction.
Decision
- Pipeline stages:
ExactDedupStagebeforeEmbedStage;NearDedupStageafter. - Exact hit: no insert path, bump
retrieval_count(+last_retrieved_at), setctx.stop, skip embed/near-dup; metricibex_memory_dedup_total{result=exact_duplicate}. - Near-dup: attach
near_duplicate_candidatesfor 3.C.3; metricsnear_duplicate/novel. - Migration
000018_memories_content_hash_unique_activeadds the partial unique index viaCREATE UNIQUE INDEX CONCURRENTLY(same golang-migrate pattern as000011). agent_idrequired for both dedup stages.- Exact hit always invokes
bump_retrieval(mandatory when a duplicate is found).
Consequences
- Concurrent exact writes are serialized by the unique index (second insert fails; write API in a later milestone must map that to the bump path).
- Conflict classification / merge remains out of scope (3.C.3).
- Operators can disable exact dedup via
IBEX_MEMORY_DEDUP_EXACT_ENABLED=false(hash still computed for later persist).
Addendum (2026-08-27)
Unique-violation → bump-retrieval → documented 409 DUPLICATE_CONTENT mapping for
POST /v1/memories is owned by ADR-0057
/ milestone 3.C.5
(#620).
Was this page helpful?
Last updated on