# Semantica ExplanationGenerator Implementation for Traceable Reasoning

> Discover Semantica's ExplanationGenerator implementation for traceable reasoning. Convert raw artifacts into auditable reports with its modular architecture and progress tracking.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: deep-dive
- Published: 2026-08-20

---

**Semantica's `ExplanationGenerator` converts raw reasoning artifacts into human-readable, auditable reports through a modular architecture built on structured dataclasses, type-specific dispatch methods, and integrated progress tracking.**

The `ExplanationGenerator` is the core component in the semantica-agi/semantica repository that transforms outputs from logical inference engines into transparent, explainable results. Located in [`semantica/reasoning/explanation_generator.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/explanation_generator.py), this class bridges the gap between machine reasoning and human understanding by capturing every step of the inference process with full traceability.

## Core Dataclasses for Structured Explanation Output

The implementation defines four layered dataclasses that create a complete audit trail from individual reasoning steps to final natural-language narratives.

### ReasoningStep: Atomic Logical Operations

The `ReasoningStep` dataclass captures a single logical move with complete provenance:

```python

# Defined in semantica/reasoning/explanation_generator.py, lines 44-55

@dataclass
class ReasoningStep:
    step_id: str
    description: str
    rule_applied: Optional[str]  # Reference to the rule or axiom used

    input_facts: List[Fact]
    output_fact: Fact
    confidence: float  # 0.0 to 1.0

    metadata: Dict[str, Any] = field(default_factory=dict)

```

Every field serves traceability: **rule_applied** links to source knowledge, **input_facts** and **output_fact** establish data lineage, and **confidence** enables uncertainty quantification throughout the chain.

### ReasoningPath: Complete Inference Chains

`ReasoningPath` aggregates multiple steps into a traversable sequence:

```python

# Defined in semantica/reasoning/explanation_generator.py, lines 57-66

@dataclass
class ReasoningPath:
    path_id: str
    steps: List[ReasoningStep]
    start_facts: List[Fact]
    final_conclusion: Fact
    total_confidence: float  # Aggregated from step confidences

    metadata: Dict[str, Any] = field(default_factory=dict)

```

This structure enables **backward tracing** from any conclusion to its foundational premises and **forward simulation** of how evidence propagates through rules.

### Justification and Explanation: Human-Readable Output

The `Justification` dataclass bundles structured evidence with natural-language interpretation, while the top-level `Explanation` object provides the complete deliverable:

```python

# Justification: lines 69-78

@dataclass
class Justification:
    conclusion: Fact
    reasoning_path: ReasoningPath
    supporting_evidence: List[Evidence]
    overall_confidence: float
    explanation_text: str  # Generated natural-language rationale

```

```python

# Explanation: lines 82-92

@dataclass
class Explanation:
    explanation_id: str
    explanation_type: Literal["inference", "proof", "abductive", "generic"]
    conclusion: Fact
    reasoning_path: Optional[ReasoningPath]
    justification: Optional[Justification]
    natural_language: str  # Full narrative summary

    metadata: Dict[str, Any] = field(default_factory=dict)

```

The **explanation_type** field explicitly tags the reasoning paradigm used, enabling downstream systems to apply appropriate trust models for forward chaining, deductive proofs, or abductive hypotheses.

## Initialization and Configuration

The generator supports runtime tuning via constructor parameters:

```python

# Constructor implementation: lines 95-128

def __init__(
    self,
    config: Optional[Dict[str, Any]] = None,
    *,
    generate_nl: bool = True,      # Enable natural-language generation

    detail_level: str = "standard",  # "minimal", "standard", or "detailed"

    progress_tracker: Optional[ProgressTracker] = None
):

```

The **progress_tracker** parameter wires observability into the explanation pipeline, emitting phase updates suitable for logging or UI progress bars.

## Main Entry Point: generate_explanation

The `generate_explanation` method implements polymorphic dispatch based on input type, routing to specialized private handlers:

| Input Type | Handler Method | Purpose |
|------------|---------------|---------|
| `InferenceResult` | `_explain_inference_result` (lines 30-73) | Forward-chaining rule applications |
| `Proof` | `_explain_proof` (lines 138-167) | Deductive reasoner output |
| `AbductiveExplanation` | `_explain_abductive` (lines 76-108) | Hypothetical reasoning from observations |
| Any other object | `_explain_generic` (lines 119-126) | Fallback with stringified representation |

Each handler follows a consistent pattern: extract structured data, build `ReasoningStep` objects, assemble into `ReasoningPath`, and conditionally invoke natural-language generation.

### Inference Result Explanation

For forward-chaining outputs from [`semantica/reasoning/reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/reasoner.py):

```python

# _explain_inference_result: lines 30-73

def _explain_inference_result(self, result: InferenceResult) -> Explanation:
    # Build reasoning path from premises to conclusion

    steps = []
    for activation in result.rule_activations:
        step = ReasoningStep(
            step_id=self._generate_id(),
            description=f"Applied rule {activation.rule_name}",
            rule_applied=activation.rule_name,
            input_facts=activation.matched_facts,
            output_fact=activation.inferred_fact,
            confidence=activation.confidence * result.premise_confidence
        )
        steps.append(step)
    
    path = ReasoningPath(
        path_id=self._generate_id(),
        steps=steps,
        start_facts=result.input_facts,
        final_conclusion=result.conclusion,
        total_confidence=self._aggregate_confidence(steps)
    )
    
    # Generate natural language if enabled

    nl_text = self._nl_generator.summarize_path(path) if self.generate_nl else ""
    
    return Explanation(
        explanation_id=self._generate_id(),
        explanation_type="inference",
        conclusion=result.conclusion,
        reasoning_path=path,
        justification=None,  # Optional: can build later via justify_conclusion

        natural_language=nl_text
    )

```

### Proof Explanation

For deductive proofs from [`semantica/reasoning/deductive_reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/deductive_reasoner.py):

```python

# _explain_proof: lines 138-167

def _explain_proof(self, proof: Proof) -> Explanation:
    steps = []
    for proof_step in proof.steps:
        step = ReasoningStep(
            step_id=str(proof_step.step_number),
            description=proof_step.tactic_description,
            rule_applied=proof_step.axiom_or_theorem,
            input_facts=[proof_step.premise] if proof_step.premise else [],
            output_fact=proof_step.consequent,
            confidence=1.0  # Proofs have certainty unless fuzzy logic enabled

        )
        steps.append(step)
    
    # Similar path construction and NL generation...

```

The translation preserves the **tactic_description** from the proof assistant, maintaining the mathematical rigor of the original deduction.

### Abductive Explanation

For hypothetical reasoning from [`semantica/reasoning/abductive_reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/abductive_reasoner.py):

```python

# _explain_abductive: lines 176-208

def _explain_abductive(self, abduction: AbductiveExplanation) -> Explanation:
    # Reverse direction: observations → best hypothesis

    steps = []
    
    # Step 1: Observed facts

    steps.append(ReasoningStep(
        step_id="observation",
        description="Observed phenomena requiring explanation",
        rule_applied=None,
        input_facts=[],
        output_fact=Fact("Observations", value=abduction.observations),
        confidence=1.0
    ))
    
    # Steps 2..n: Competing hypotheses with plausibility scores

    for hypothesis in abduction.candidate_hypotheses:
        steps.append(ReasoningStep(
            step_id=f"hypothesis_{hypothesis.id}",
            description=f"Abduced explanation: {hypothesis.description}",
            rule_applied=hypothesis.abduction_rule,
            input_facts=hypothesis.explains_observations,
            output_fact=hypothesis.conclusion,
            confidence=hypothesis.plausibility
        ))
    
    # Final step: Selected best explanation

    steps.append(ReasoningStep(
        step_id="selection",
        description=f"Selected best explanation by {abduction.selection_criterion}",
        rule_applied=abduction.selection_criterion,
        input_facts=[h.conclusion for h in abduction.candidate_hypotheses],
        output_fact=abduction.best_hypothesis.conclusion,
        confidence=abduction.best_hypothesis.plausibility
    ))

```

This handler explicitly marks the **abductive leap** from observations to hypotheses, a critical transparency requirement for diagnostic and scientific reasoning systems.

## Progress Tracking Integration

All handlers report phase transitions to the optional progress tracker:

```python

# Lines 41-78 demonstrate the tracking pattern

self.progress_tracker.start_phase("Identifying reasoning type...")

# ... type detection ...

self.progress_tracker.start_phase("Generating explanation...")

# ... step construction ...

self.progress_tracker.record_success(explanation_id)

```

This observability layer ensures that long-running explanations on complex knowledge bases remain debuggable and user-responsive.

## Auxiliary Utility Methods

The class provides two convenience APIs for common access patterns:

### show_reasoning_path

Extracts only the structured path without narrative overhead:

```python

# Lines 129-145

def show_reasoning_path(self, reasoning_artifact) -> ReasoningPath:
    explanation = self.generate_explanation(reasoning_artifact)
    if explanation.reasoning_path is None:
        raise ValueError("No reasoning path available for this artifact type")
    return explanation.reasoning_path

```

### justify_conclusion

Builds a full `Justification` with aggregated evidence analysis:

```python

# Lines 146-167

def justify_conclusion(
    self,
    conclusion: Fact,
    reasoning_path: ReasoningPath,
    evidence_sources: Optional[List[Evidence]] = None
) -> Justification:
    supporting_evidence = evidence_sources or self._gather_evidence(reasoning_path)
    
    return Justification(
        conclusion=conclusion,
        reasoning_path=reasoning_path,
        supporting_evidence=supporting_evidence,
        overall_confidence=self._compute_overall_confidence(reasoning_path, supporting_evidence),
        explanation_text=self._nl_generator.justify(reasoning_path, supporting_evidence) 
            if self.generate_nl else ""
    )

```

This method supports **adversarial audit scenarios** where external evidence must be cross-referenced against the internal reasoning chain.

## Complete Usage Example

```python
from semantica.reasoning import ExplanationGenerator, Reasoner
from semantica.reasoning.deductive_reasoner import DeductiveReasoner

# Forward-chaining inference with full traceability

reasoner = Reasoner()
inference = reasoner.run_rules(rules=security_rules, facts=network_events)

generator = ExplanationGenerator(
    generate_nl=True,
    detail_level="detailed",
    progress_tracker=console_tracker  # Logs to stdout/structured logging

)

# Generate complete explanation

explanation = generator.generate_explanation(inference)

print(f"Explanation ID: {explanation.explanation_id}")
print(f"Type: {explanation.explanation_type}")
print(f"\nNatural Language Summary:\n{explanation.natural_language}")

# Iterate through structured reasoning chain

for step in explanation.reasoning_path.steps:
    print(f"\n  Step {step.step_id}: {step.description}")
    print(f"    Rule: {step.rule_applied}")
    print(f"    Confidence: {step.confidence:.3f}")
    print(f"    Inputs: {[f.predicate for f in step.input_facts]}")
    print(f"    Output: {step.output_fact.predicate}")

# Create formal justification for compliance reporting

justification = generator.justify_conclusion(
    conclusion=inference.conclusion,
    reasoning_path=explanation.reasoning_path
)
print(f"\nCompliance Report:\n{justification.explanation_text}")

```

## Architectural Files in the Explanation Pipeline

| File | Role in Traceable Reasoning |
|------|----------------------------|
| [`semantica/reasoning/explanation_generator.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/explanation_generator.py) | Core implementation with all dataclasses and generation logic |
| [`semantica/reasoning/reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/reasoner.py) | Produces `InferenceResult` objects for forward-chaining explanations |
| [`semantica/reasoning/deductive_reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/deductive_reasoner.py) | Provides `Proof` objects with theorem/axiom references |
| [`semantica/reasoning/abductive_reasoner.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/abductive_reasoner.py) | Generates `AbductiveExplanation` with plausibility-ranked hypotheses |
| [`semantica/utils/progress_tracker.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/utils/progress_tracker.py) | Observability infrastructure for long-running explanations |

## Summary

- **Structured dataclasses** (`ReasoningStep`, `ReasoningPath`, `Explanation`) create complete audit trails from raw inference to human-readable output
- **Polymorphic dispatch** via `generate_explanation` handles forward chaining, deductive proofs, and abductive reasoning through specialized private methods
- **Confidence propagation** at every step enables uncertainty-aware explanation and risk assessment
- **Optional natural-language generation** produces compliance-ready narratives without sacrificing structured traceability
- **Progress tracking integration** makes explanation generation observable for production deployments

## Frequently Asked Questions

### What makes Semantica's explanations "traceable"?

Every `ReasoningStep` explicitly records the **rule applied**, **input facts**, **output fact**, and **confidence score**. This creates a directed acyclic graph from any conclusion back to its foundational premises, satisfying audit requirements for high-stakes AI decisions.

### Can I disable natural language generation for performance?

Yes. Pass `generate_nl=False` to the `ExplanationGenerator` constructor. The generator will still produce complete `Explanation` objects with structured `ReasoningPath` data, skipping the NL summarization step entirely.

### How does the generator handle different reasoning types?

The `generate_explanation` method inspects the input object's type and dispatches to one of four private handlers: `_explain_inference_result` for forward chaining, `_explain_proof` for deductive proofs, `_explain_abductive` for hypothetical reasoning, or `_explain_generic` as a fallback. Each handler constructs appropriate `ReasoningStep` representations for its reasoning paradigm.

### Where are the explanation dataclasses defined?

All core dataclasses—`ReasoningStep`, `ReasoningPath`, `Justification`, and `Explanation`—are defined in [`semantica/reasoning/explanation_generator.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/reasoning/explanation_generator.py) at lines 44-92 according to the source code structure.