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

> Learn to detect and resolve conflicting facts in Semantica. Discover how our two-stage pipeline identifies and resolves contradictions using strategies like voting and credibility weighting.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: how-to-guide
- Published: 2026-08-15

---

**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`](https://github.com/semantica-agi/semantica/blob/main/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`](https://github.com/semantica-agi/semantica/blob/main/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`](https://github.com/semantica-agi/semantica/blob/main/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

```python
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)")

```

```python
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

```python

# 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`](https://github.com/semantica-agi/semantica/blob/main/semantica/pipeline/pipeline_builder.py)):

```python
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`](https://github.com/semantica-agi/semantica/blob/main/semantica/conflicts/conflict_detector.py) | `ConflictDetector` class, `ConflictType` enum, `Conflict` dataclass |
| [`semantica/conflicts/conflict_resolver.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/conflicts/conflict_resolver.py) | `ConflictResolver` class, `ResolutionStrategy` enum, `ResolutionResult` |
| [`semantica/conflicts/source_tracker.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/conflicts/source_tracker.py) | Provenance tracking and source credibility scoring |
| [`semantica/conflicts/progress_tracker.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/conflicts/progress_tracker.py) | Non-blocking progress reporting for large datasets |
| [`semantica/pipeline/pipeline_builder.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/pipeline/pipeline_builder.py) | Orchestrates detection and resolution when `resolve_conflicts=True` |

## Summary

- **Detection** uses `ConflictDetector` in [`conflict_detector.py`](https://github.com/semantica-agi/semantica/blob/main/conflict_detector.py) to find value, type, relationship, temporal, and logical conflicts across source-grouped entities
- **Resolution** uses `ConflictResolver` in [`conflict_resolver.py`](https://github.com/semantica-agi/semantica/blob/main/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`](https://github.com/semantica-agi/semantica/blob/main/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.