How to Detect and Resolve Conflicting Facts in Semantica: A Complete Guide

Semantica resolves conflicting facts through a two-stage pipeline: the ConflictDetector identifies contradictions across five conflict types, then the ConflictResolver applies strategies like voting, credibility-weighted, or most-recent to select a single authoritative value.

When building knowledge graphs from multiple sources, you'll inevitably encounter conflicting facts—the same entity described differently by two or more sources. The Semantica framework handles this through a dedicated conflict management subsystem implemented in semantica/conflicts/. This guide covers the complete workflow from detection through resolution, with runnable code examples drawn directly from the source.

Conflict Detection Architecture

The detection stage happens in semantica/conflicts/conflict_detector.py. The ConflictDetector class evaluates entity collections for contradictions across five distinct families defined in the ConflictType enum.

The Five Conflict Types

Conflict Type Description Detection Method
Value Same property holds different values (e.g., name: "Acme Corp" vs "Acme Corporation") detect_value_conflicts()
Type Entity classified differently (e.g., Person vs Organization) detect_type_conflicts()
Relationship Conflicting connections to other entities detect_relationship_conflicts()
Temporal Date or time information disagrees detect_temporal_conflicts()
Logical Contradictory classifications or inferred properties detect_logical_conflicts()

The entry point detect_conflicts() runs all five detectors or you can invoke specific methods for targeted checks.

Provenance and Progress Tracking

Every detected conflict carries provenance metadata via SourceTracker (semantica/conflicts/source_tracker.py). This records:

  • Which document contributed the value
  • Page or section location
  • Confidence score from the extraction process
  • Source credibility for later resolution weighting

Large-scale detection remains responsive through ProgressTracker, which reports progress without blocking the main thread.

Conflict Resolution Strategies

Resolution happens in semantica/conflicts/conflict_resolver.py. The ConflictResolver accepts Conflict objects and applies one of several resolution strategies from the ResolutionStrategy enum.

Built-in Resolution Strategies

  • Voting — Simple majority wins; default strategy in pipeline mode
  • Credibility-weighted — Sources scored by SourceTracker.get_source_credibility(); higher-credibility sources dominate
  • Most-recent — Timestamp-based selection from provenance data
  • First-seen — Original value preserved as authoritative
  • Highest-confidence — Extraction confidence score determines winner
  • Manual — Flags conflict for human review
  • Expert — Routes to domain expert queue

Each resolution produces a ResolutionResult dataclass containing the chosen value, computed confidence, strategy used, and optional explanatory notes.

Practical Code Examples

Basic Detection and Resolution

from semantica.conflicts import ConflictDetector, ConflictResolver

# Entities from two sources disagreeing on company name

entities = [
    {"id": "c1", "name": "Acme Corp", "type": "Company", "source": "source_A"},
    {"id": "c1", "name": "Acme Corporation", "type": "Company", "source": "source_B"},
    {"id": "c2", "name": "Globex", "type": "Company", "source": "source_A"},
]

detector = ConflictDetector()
value_conflicts = detector.detect_value_conflicts(entities, property_name="name")
print(f"Detected {len(value_conflicts)} value conflict(s)")
resolver = ConflictResolver()
results = resolver.resolve_conflicts(value_conflicts)  # uses voting default

for r in results:
    print(f"{r.conflict_id} → {r.resolved_value} (confidence={r.confidence:.2f})")

Custom Per-Property Rules


# Configure credibility-weighted resolution for specific entity.property

resolver.set_resolution_rule("c1", "name", "credibility_weighted")

results = resolver.resolve_conflicts(value_conflicts)
for r in results:
    print(f"{r.conflict_id} → {r.resolved_value} via {r.resolution_strategy}")

Pipeline Integration

The cleanest approach for production use: enable automatic conflict handling in GraphBuilder (semantica/pipeline/pipeline_builder.py):

from semantica.pipeline.pipeline_builder import GraphBuilder

builder = GraphBuilder(resolve_conflicts=True)  # auto-creates detector + resolver

kg = builder.build_graph(entities)              # detection + resolution run internally

When resolve_conflicts=True, the builder instantiates both components, runs detection after graph assembly, and applies the configured resolution strategy (defaulting to voting if none specified).

Core Source Files

File Purpose
semantica/conflicts/conflict_detector.py ConflictDetector class, ConflictType enum, Conflict dataclass
semantica/conflicts/conflict_resolver.py ConflictResolver class, ResolutionStrategy enum, ResolutionResult
semantica/conflicts/source_tracker.py Provenance tracking and source credibility scoring
semantica/conflicts/progress_tracker.py Non-blocking progress reporting for large datasets
semantica/pipeline/pipeline_builder.py Orchestrates detection and resolution when resolve_conflicts=True

Summary

  • Detection uses ConflictDetector in conflict_detector.py to find value, type, relationship, temporal, and logical conflicts across source-grouped entities
  • Resolution uses ConflictResolver in conflict_resolver.py with strategies: voting, credibility-weighted, most-recent, first-seen, highest-confidence, manual, or expert review
  • Provenance via SourceTracker enables credibility-weighted decisions and audit trails
  • Pipeline mode with GraphBuilder(resolve_conflicts=True) automates the entire workflow

Frequently Asked Questions

How does Semantica determine which source is more credible?

Credibility comes from SourceTracker in source_tracker.py. Each tracked property includes a credibility score, either assigned manually during source configuration or learned from historical accuracy. The ConflictResolver._resolve_by_credibility() method weights votes by these scores, so a source with 0.9 credibility outweighs one with 0.3.

Can I use different resolution strategies for different entity types?

Yes. Call set_resolution_rule(entity_id, property_name, strategy) before resolution. This creates a lookup table that resolve_conflict() checks before applying defaults. For type-level rules, you'll need to iterate entities and apply rules programmatically—no built-in type-based routing exists in the current implementation.

What happens when no resolution strategy produces a clear winner?

Tie-breaking behavior depends on the strategy. Voting randomly selects among tied winners. Credibility-weighted falls back to first-seen if scores are identical. Highest-confidence uses temporal order. Set manual or expert resolution strategy to guarantee human review for edge cases rather than accepting arbitrary tie-breaks.

Does conflict detection work on existing graphs, or only during initial construction?

Both. ConflictDetector.detect_conflicts() accepts any collection of entities or graph dictionary—you can run detection on extracted entities before graph construction or on an existing knowledge graph by iterating its nodes. The pipeline integration in GraphBuilder simply automates this during build time.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →