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
ConflictDetectorinconflict_detector.pyto find value, type, relationship, temporal, and logical conflicts across source-grouped entities - Resolution uses
ConflictResolverinconflict_resolver.pywith strategies: voting, credibility-weighted, most-recent, first-seen, highest-confidence, manual, or expert review - Provenance via
SourceTrackerenables 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →