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)
- Same subject/attribute and non-overlapping half-open intervals and
new.valid_from > candidate.valid_from→supersedes, zero LLM. - Intervals overlap (or validity missing/unreliable) → escalate to LLM classifier.
- No overlap and subjects differ → no conflict.
3) Subject extraction
- Secondary LLM call — accurate but costs latency/budget on the write path.
- 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
- Half-open intervals
[valid_from, valid_until);NULL valid_until= open (+∞), per ADR-0047. - Overlap iff
a_from < coalesce(b_until, +∞) AND b_from < coalesce(a_until, +∞). - Auto-supersede only when non-overlapping, newer
valid_from, and subject keys match. - Missing
valid_fromon either side → escalate (never silent skip). - Escalation is a pluggable classifier (
ConflictClassifierprotocol). This milestone ships the seam + metrics; production LLM worker may land later. Tests inject a fake classifier for overlap fixtures. - Status taxonomy: use existing CHECK values (
superseded,merged_into). Do not inventpending_reviewwithout a migration — contradicts outcomes record acontradictsedge and leave review routing to a later write/API milestone. - Pipeline order:
… → near_dedup → conflict. Supersession persist requires the new memory id (post-insert helper); the stage records pending actions onWriteContext. - Metrics:
ibex_memory_conflicts_total{outcome}andibex_memory_conflict_llm_calls_total(llm_call_madecounter 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
- Applying
pending_supersede_targetsafter the new memory receives its DB id is owned by ADR-0057 / milestone 3.C.5. ESCALATE_PENDINGis WriteContext-only in 3.C.3. Durable storage is an explicit deferral to 3.C.5: org-scoped tablememory_conflict_escalations(notpending_reviewonmemories.status, not a fake relationship type). Tracking: #620.- 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?
Last updated on