IBEX Harness
DocsBenchmarksBlogChangelogRoadmap
GitHub
IBEX Harness

Documentation

Architecture Decision RecordsADR-0002: Repository foundation bootstrapADR-0003: Branch protection and merge policyADR-0004: Protobuf and code generation policyADR-0005: Postgres migration strategyADR-0006: Auth protobuf contract (`ibex.auth.v1`)ADR-0007: Auth token validation implementationADR-0008: Security scanning and CI quality gatesADR-0009: Permission bitmap layoutADR-0010: Cryptography policyADR-0011: Proxy auth gRPC client and middlewareADR-0012: Proxy request normalization (OpenAI chat)ADR-0013: Proxy input validation and stable error envelopeADR-0014: Core domain migration sequencingADR-0015: Proxy rate limit skeleton (Phase 1)ADR-0016: Proxy agent identity verification (Phase 1)ADR-0017: Request ID and trace context strategy (Phase 1)ADR-0018: Graceful shutdown contract (Phase 1)ADR-0019: OpenTelemetry provider configuration (Phase 1)ADR-0020: Shared package boundaries — `packages/config` and `packages/apierror`ADR-0021: Prometheus Metric Catalog (Phase 1)ADR-0022: Health check contract (Phase 1)ADR-0023: Docs site architecture (Phase 1.5)ADR-0024: Benchmark data publishing modelADR-0025: LLM provider abstractionADR-0026: OpenAI client designADR-0027: Streaming dual-write strategyADR-0028: Auth cache designADR-0029: Token revocation propagation via Redis pub/subADR-0030: Directive versioning strategyADR-0031: System prompt injection strategyADR-0032: Session data model and retentionADR-0033: ClickHouse llm_traces schema and retentionADR-0034: Proxy overhead performance measurement methodologyADR-0035: Chat Idempotency-Key Redis dedupeADR-0038: Context assembly service design and gRPC contractADR-0039: Proxy Postgres ownership for session and directive storesADR-0040: Anthropic provider adapterADR-0041: Model capability registryADR-0042: Self-hosted OpenAI-compatible LLM adapterADR-0043: Tokenizer registry architectureADR-0044: Non-streaming response pipelineADR-0045: Streaming response transformationADR-0046: Embedder interface and profile registryADR-0047: Memory temporal validity foundationADR-0048: Memory multi-label categoriesADR-0049: Memory relationship graph readinessADR-0050: MCP server skeleton (transport, auth, audit)ADR-0051: Local LGTM observability stack (Phase 2.5 exit pull-forward)ADR-0052: Memory schema v2 expand (HNSW, quality columns)ADR-0053: Vector store abstraction and composite scoring v2ADR-0054: In-process Presidio PII detection in memoryADR-0055: Memory write-path exact and near-duplicate dedupADR-0056: Temporal-interval-aware conflict detectionADR-0057: Memory write-path persistence and orchestration
ADRs›ADR-0055: Memory write-path exact and near-duplicate dedup
ADRs

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

  1. Application-only lookup (no DB unique) — race windows on concurrent writes.
  2. Full unique on (org_id, agent_id, content_hash) — blocks soft-deleted / superseded rows from ever reusing a hash.
  3. Partial unique index on (org_id, agent_id, content_hash) where status = '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

  1. Add VectorStore.find_similar alias.
  2. Call existing VectorStore.search with min_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

  1. Pipeline stages: ExactDedupStage before EmbedStage; NearDedupStage after.
  2. Exact hit: no insert path, bump retrieval_count (+ last_retrieved_at), set ctx.stop, skip embed/near-dup; metric ibex_memory_dedup_total{result=exact_duplicate}.
  3. Near-dup: attach near_duplicate_candidates for 3.C.3; metrics near_duplicate / novel.
  4. Migration 000018_memories_content_hash_unique_active adds the partial unique index via CREATE UNIQUE INDEX CONCURRENTLY (same golang-migrate pattern as 000011).
  5. agent_id required for both dedup stages.
  6. 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?

Edit on GitHub

Last updated on

PreviousADR-0054: In-process Presidio PII detection in memoryNextADR-0056: Temporal-interval-aware conflict detection

On this page

  • Context
  • Options considered
  • 1) Exact-hash uniqueness
  • 2) Near-duplicate API surface
  • 3) Threshold semantics
  • 4) Hash input
  • Decision
  • Consequences
  • Addendum (2026-08-27)
0%