# Semantica Ontology Validator Architecture: How SHACL Enforcement and Structural Validation Work

> Explore Semantica's ontology validator architecture. Learn how SHACL enforcement and structural validation work in this layered system.

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

---

**Semantica's ontology validator separates structural checks, symbolic reasoning, and SHACL constraint enforcement through a layered architecture centered in [`semantica/ontology/ontology_validator.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/ontology_validator.py).**

Semantica is an open-source AGI framework that generates and validates OWL ontologies programmatically. Understanding its **ontology validator and SHACL enforcement** internals helps developers debug constraint violations, extend validation logic, and integrate semantic checks into automated pipelines. This article breaks down the implementation as found in the `semantica-agi/semantica` repository.

## Core Data Models: SHACLViolation and SHACLValidationReport

The foundation of SHACL enforcement rests on two dataclasses that model validation outcomes.

### SHACLViolation

Each constraint failure becomes a `SHACLViolation` object with the following fields as defined in [`ontology_validator.py`](https://github.com/semantica-agi/semantica/blob/main/ontology_validator.py):

- `focus_node` – the RDF resource that failed validation
- `result_path` – the property path where the violation occurred
- `constraint` – the constraint type that was violated
- `severity` – `sh:Violation`, `sh:Warning`, or `sh:Info`
- `message` – the human-readable violation message
- `value` – the actual value that caused the violation
- `shape` – the SHACL shape that triggered the check

Crucially, the dataclass also stores **concrete constraint parameters extracted from the source shape**: `min_count`, `max_count`, `datatype`, and `class_`. This enrichment enables precise, context-aware error reporting that goes beyond generic SHACL messages.

### SHACLValidationReport

The `SHACLValidationReport` aggregates individual violations into a complete validation result:

| Property | Type | Purpose |
|----------|------|---------|
| `conforms` | `bool` | Whether the data graph satisfies all shapes |
| `violations` | `List[SHACLViolation]` | Critical constraint failures |
| `warnings` | `List[SHACLViolation]` | Non-critical issues (severity `sh:Warning`) |
| `infos` | `List[SHACLViolation]` | Informational notes |
| `violation_count` | `int` | Computed property for quick status checks |
| `warning_count` | `int` | Computed property for quick status checks |

The report provides three key methods:

- `summary()` – high-level status overview
- `explain_violations()` – generates plain-English explanations using the enriched constraint parameters
- `to_dict()` – serializes the entire report for API responses or logging

## The SHACL Engine: _run_pyshacl Function

All SHACL validation flows through `_run_pyshacl()` in [`semantica/ontology/ontology_validator.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/ontology_validator.py). This function implements a five-step pipeline:

1. **Parse graphs** using **rdflib** – loads both the data graph (ontology instance) and the shapes graph (SHACL constraints)
2. **Execute validation** via **pyshacl** – internally invokes the Jena SHACL validator through Python bindings
3. **Walk result graph** – traverses `sh:ValidationResult` nodes in the pyshacl output
4. **Extract constraint parameters** – pulls values like `sh:minCount`, `sh:datatype` from `sh:sourceShape` to populate `SHACLViolation` fields
5. **Build report** – constructs and returns a `SHACLValidationReport`

The function runs with `abort_on_first=False` and no inference, ensuring complete violation discovery without side effects on the input data.

## OntologyValidator: The Public Orchestration Layer

The `OntologyValidator` class serves as the primary entry point for Semantica's validation pipeline. It coordinates three distinct validation modes.

### Constructor Configuration

```python
OntologyValidator(
    reasoner='hermit',           # 'hermit', 'pellet', or 'auto'

    check_consistency=True,      # Run symbolic consistency check

    check_satisfiability=True,   # Check class satisfiability

    **kwargs                     # Additional reasoner options

)

```

The validator supports pluggable reasoners through an auto-selector mechanism, with **HermiT** and **Pellet** as built-in options.

### Validation Dispatch

The `validate(ontology)` method accepts either:

- A Python dictionary with `classes` and `properties` keys
- A path to an OWL file (loaded and parsed internally)

It returns a `ValidationResult` with flags for `valid`, `consistent`, and `satisfiable`, plus collected `errors` and `warnings`.

### Structural Integrity Checks

The `_validate_structure(ontology, result)` method enforces minimal ontology requirements:

```python
def _validate_structure(self, ontology, result):
    if 'classes' not in ontology:
        result.warnings.append("Missing 'classes' section")
    if 'properties' not in ontology:
        result.warnings.append("Missing 'properties' section")

```

Missing sections generate warnings but do not halt validation, allowing partial ontologies to pass through with annotations.

### Extensibility Hooks

The `check_constraint(constraint)` method provides a placeholder for ad-hoc **SPARQL-based validation rules**, enabling domain-specific constraints beyond standard SHACL.

## Complete Validation Workflow

Understanding how components interact clarifies integration points:

1. **Entry** – CLI or [`engine.py`](https://github.com/semantica-agi/semantica/blob/main/engine.py) calls `validate_ontology()` convenience wrapper
2. **Instantiation** – Creates `OntologyValidator` with configured reasoner
3. **Structure check** – `_validate_structure()` verifies required dictionary keys
4. **Symbolic reasoning** – Optional consistency and satisfiability checks (HermiT/Pellet)
5. **SHACL enforcement** – If shapes provided, `_run_pyshacl()` executes constraint validation
6. **Assembly** – `validate_ontology()` returns serializable dictionary for downstream consumption

## Key Source Files

| File | Responsibility |
|------|--------------|
| [`semantica/ontology/ontology_validator.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/ontology_validator.py) | Core validator, SHACL runner, all data models |
| [`semantica/ontology/ontology_generator.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/ontology_generator.py) | Injects `OntologyValidator` for generation-time sanity checks |
| [`semantica/ontology/engine.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/engine.py) | Workflow orchestration that can trigger SHACL validation |
| [`semantica/ontology/__init__.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/ontology/__init__.py) | Public API exports (`OntologyValidator`, `validate_ontology`) |

## Practical Usage Examples

### Basic Structural Validation

```python
from semantica.ontology import OntologyValidator

validator = OntologyValidator()
result = validator.validate({"classes": [], "properties": []})

print(result.valid)      # True

print(result.warnings)   # [] (no missing sections)

```

### Full SHACL Enforcement with Violation Analysis

```python
from semantica.ontology import _run_pyshacl

# data_ttl: ontology serialized as Turtle

# shacl_ttl: SHACL shapes defining constraints

report = _run_pyshacl(data_ttl, shacl_ttl)

print(f"Conforms: {report.conforms}")
print(f"Violations: {report.violation_count}")

# Generate human-readable explanations

report.explain_violations()
for v in report.violations:
    print(f"- {v.message} (expected {v.min_count}, found value {v.value})")

# Export for API response

json_report = report.to_dict()

```

## Summary

- **Semantica ontology validator** implements three-layer architecture: data models (`SHACLViolation`, `SHACLValidationReport`), execution engine (`_run_pyshacl`), and orchestration (`OntologyValidator`)
- **SHACL enforcement** relies on pyshacl wrapping Jena, with rdflib for graph parsing and enriched violation reporting through source shape introspection
- **Structural validation** guarantees minimum ontology completeness without blocking on warnings
- **Symbolic reasoning** integrates HermiT and Pellet via configurable reasoner selection
- **Extension points** include SPARQL-based constraint hooks and custom severity handling

## Frequently Asked Questions

### How does Semantica extract detailed constraint parameters from SHACL violations?

The `_run_pyshacl()` function traverses the `sh:sourceShape` of each `sh:ValidationResult` and extracts concrete values like `sh:minCount`, `sh:maxCount`, `sh:datatype`, and `sh:class`. These populate the `SHACLViolation` dataclass fields, enabling `explain_violations()` to generate messages like "expected at least 1 value, found 0" rather than generic failure notices.

### Can I use the validator without SHACL shapes?

Yes. The `OntologyValidator` performs structural checks and optional symbolic reasoning independently. Simply omit SHACL shape graphs when calling validation methods. The `validate()` method is designed to be modular—SHACL enforcement is an optional downstream step, not a hard dependency.

### What reasoners does Semantica support for ontology consistency checking?

The validator accepts `'hermit'`, `'pellet'`, or `'auto'` as `reasoner` parameter values. HermiT serves as the default. The implementation预留s extension points for `owlready2` integration, though the current codebase focuses on these two established reasoners for OWL-DL consistency and satisfiability analysis.

### Where does SHACL validation fit in the Semantica generation pipeline?

The `OntologyGenerator` class in [`ontology_generator.py`](https://github.com/semantica-agi/semantica/blob/main/ontology_generator.py) instantiates `OntologyValidator` for generation-time sanity checks. For full constraint enforcement, [`engine.py`](https://github.com/semantica-agi/semantica/blob/main/engine.py) workflows can invoke `_run_pyshacl()` directly after ontology serialization, ensuring shaped compliance before downstream consumption.