feat(knowledge): detect potential-conflict pairs (agents' KB #4, detection half)#224
Merged
Merged
Conversation
…ction half) Route-the-findings: turn the nightly lint from a passive report into action + routed escalations. This half adds DETECTION; surfacing-at-retrieval is the next PR. The KB only FLAGS 'too similar to comfortably coexist' pairs — it does NOT judge whether they're a redundancy to merge or a real contradiction. That judgment needs live context the nightly job lacks, so it belongs to the consuming agent (the established principle; and an LLM contradiction-judge here would be the killed self-evolving-memory-compiler pattern). Hence a new mechanical :potential_conflict link type, distinct from :contradicts (which asserts a known disagreement). - ArticleLink: + :potential_conflict relationship_type (string column, no migration). - ArticleLinkingWorker (forward, incremental): per article it already runs nearest; now ALSO creates a :potential_conflict link for any neighbor >= the conflict threshold (config :knowledge_conflict_threshold, default 0.93), alongside the ambient :relates_to. Type-aware dedup so the two link kinds don't crowd each other. - KnowledgeLintWorker (existing-corpus backstop): a bounded nightly sweep promotes pre-existing :relates_to links whose stored similarity_score >= the threshold to also carry :potential_conflict — no new embedding calls, cycles the corpus over nights (cap :knowledge_lint_max_conflict_promotions, default 500), idempotent. Reports conflicts_promoted in the lint audit event. #1's gate keeps the published corpus de-duplicated going forward, so these flagged pairs are mostly shrinking legacy — low noise when surfaced at retrieval (next PR). Tests (+5): forward detection (flag >= threshold, none below); promotion sweep (promote >= threshold, leave below, idempotent). Full gate green (3042 tests).
mkreyman
added a commit
that referenced
this pull request
Jun 30, 2026
…s' KB #4, surfacing half) (#225) The detection half (#224) creates :potential_conflict links; this makes them travel with the search result so the consuming agent — the one with live context — trips over them and resolves them. - get_article JSON: + a flattened, actionable `potential_conflicts` field per article (peer article_id/title/similarity), derived from the already-loaded link graph. An agent reading an article now sees its 'too similar to coexist' peers directly, instead of digging through incoming/outgoing_links. Empty list when none. - Knowledge.list_potential_conflicts/2: the tenant-wide review queue — every flagged pair, highest-overlap first (most likely a true duplicate), paginated, tenant-scoped. - API: GET /api/v1/knowledge/conflicts (agent+), so a consuming agent or human can pull the whole queue and act. - MCP v2.26.0: knowledge_conflicts tool (agent key); knowledge_get now carries potential_conflicts automatically (flows through the API). Also fixed a stale knowledge_drafts doc that still claimed an over-max limit is rejected-400 (it has clamped since the pagination work). The KB only flags; every tool/field repeats that the caller decides redundancy-vs- contradiction. Tests (+6 Elixir, +2 MCP): list ordering/pagination/isolation, the get field (populated + empty), the endpoint, and the MCP plumbing. Full gate green (3048 tests, dialyzer, credo; 52 MCP tests).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Route-the-findings: turn the nightly lint from a passive report into action + routed escalations. This PR is the DETECTION half; surfacing-at-retrieval is the next PR.
Principle
The KB only flags "too similar to comfortably coexist" pairs — it does not judge whether they're a redundancy to merge or a real contradiction. That judgment needs live context the nightly job lacks, so it belongs to the consuming agent. (An LLM contradiction-judge here would be the killed self-evolving-memory-compiler pattern.) Hence a new mechanical
:potential_conflictlink type, distinct from:contradicts(which asserts a known disagreement).Changes
ArticleLink— new:potential_conflictrelationship_type (string column → no migration).ArticleLinkingWorker(forward, incremental) — per article it already runsnearest; now also creates a:potential_conflictlink for any neighbor ≥ the conflict threshold (:knowledge_conflict_threshold, default 0.93), alongside the ambient:relates_to. Type-aware dedup so the two kinds don't crowd each other out.KnowledgeLintWorker(existing-corpus backstop) — a bounded nightly sweep promotes pre-existing:relates_tolinks whose storedsimilarity_score≥ the threshold to also carry:potential_conflict. No new embedding calls; cycles the corpus over nights (cap:knowledge_lint_max_conflict_promotions, default 500); idempotent. Reportsconflicts_promotedin the lint audit event.#1's gate keeps the published corpus de-duplicated going forward, so these flagged pairs are mostly shrinking legacy — low noise when surfaced at retrieval (next PR).
Tests (+5)
Forward detection (flag ≥ threshold, none below the threshold); promotion sweep (promote ≥ threshold, leave below alone, idempotent). Full gate green: format, credo, dialyzer, 3042 tests, 0 failures.