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-0056: Temporal-interval-aware conflict detection
ADRs

ADR-0056: Temporal-interval-aware conflict detection

Architecture decision record 0056 — interval-overlap-first conflict gating on near-dup candidates; auto-supersede without LLM; spaCy subject match; escalate only on overlap or missing validity.

ADR-0056: Temporal-interval-aware conflict detection

  • Status: Accepted
  • Date: 2026-08-27
  • Authors: IBEX Harness team
  • Milestone: 3.C.3 Temporal-interval-aware conflict detection

Context

Milestone planning text referred to “ADR-0042” for this decision. ADR-0042 is already taken (self-hosted OpenAI-compatible adapter). This record is ADR-0056.

Near-duplicate candidates from ADR-0055 must not all escalate to an LLM. Sequential facts (“prefers Python” in March → “switching to Go” in June) are supersedes, not contradicts. Temporal columns ship in ADR-0047; relationship types in ADR-0049.

Options considered

1) Similarity-only → LLM

Escalate every near-dup. Cheap to implement; wastes LLM budget and misclassifies sequential facts.

2) Interval-overlap-first (chosen)

  1. Same subject/attribute and non-overlapping half-open intervals and new.valid_from > candidate.valid_from → supersedes, zero LLM.
  2. Intervals overlap (or validity missing/unreliable) → escalate to LLM classifier.
  3. No overlap and subjects differ → no conflict.

3) Subject extraction

  1. Secondary LLM call — accurate but costs latency/budget on the write path.
  2. spaCy CNN (en_core_web_md, already admitted for PII / ADR-0054) — free, <5ms, self-hosted.

Decision: spaCy. Weak fixtures trigger follow-up, not an initial LLM subject extractor.

Decision

  1. Half-open intervals [valid_from, valid_until); NULL valid_until = open (+∞), per ADR-0047.
  2. Overlap iff a_from < coalesce(b_until, +∞) AND b_from < coalesce(a_until, +∞).
  3. Auto-supersede only when non-overlapping, newer valid_from, and subject keys match.
  4. Missing valid_from on either side → escalate (never silent skip).
  5. Escalation is a pluggable classifier (ConflictClassifier protocol). This milestone ships the seam + metrics; production LLM worker may land later. Tests inject a fake classifier for overlap fixtures.
  6. Status taxonomy: use existing CHECK values (superseded, merged_into). Do not invent pending_review without a migration — contradicts outcomes record a contradicts edge and leave review routing to a later write/API milestone.
  7. Pipeline order: … → near_dedup → conflict. Supersession persist requires the new memory id (post-insert helper); the stage records pending actions on WriteContext.
  8. Metrics: ibex_memory_conflicts_total{outcome} and ibex_memory_conflict_llm_calls_total (llm_call_made counter per detection run).

Consequences

  • Sequential-fact fixtures cost zero LLM calls.
  • Overlapping same-subject claims still escalate.
  • Full write HTTP API remains a later milestone; integration tests drive service + persist helpers directly (same pattern as 3.C.1 / 3.C.2).

Addendum (2026-08-27) — Persist and escalation durability

  1. Applying pending_supersede_targets after the new memory receives its DB id is owned by ADR-0057 / milestone 3.C.5.
  2. ESCALATE_PENDING is WriteContext-only in 3.C.3. Durable storage is an explicit deferral to 3.C.5: org-scoped table memory_conflict_escalations (not pending_review on memories.status, not a fake relationship type). Tracking: #620.
  3. Until 3.C.5 ships, a conflict-resolution worker has nothing queryable to poll for escalations — that gap is intentional and ticketed, not silent.

Was this page helpful?

Edit on GitHub

Last updated on

PreviousADR-0055: Memory write-path exact and near-duplicate dedupNextADR-0057: Memory write-path persistence and orchestration

On this page

  • Context
  • Options considered
  • 1) Similarity-only → LLM
  • 2) Interval-overlap-first (chosen)
  • 3) Subject extraction
  • Decision
  • Consequences
  • Addendum (2026-08-27) — Persist and escalation durability
0%