How Semantica's ContextGraph Tracks Decision Provenance Using W3C PROV-O

Semantica tracks decision provenance using W3C PROV-O through three integrated components: ContextGraph.record_decision creates decision entities, ProvenanceEntry schema maps to PROV-O concepts, and ProvenanceManager.track_entity persists lineage with cryptographic integrity.

Semantica is an open-source framework for semantic AI systems that records every decision in a ContextGraph with full W3C PROV-O compliance. Decision provenance tracking ensures auditability, versioning, and lineage reconstruction for AI-driven outcomes. This article examines the implementation details, source file locations, and code patterns that make Semantica's provenance system production-ready.

The Three-Component Architecture

Semantica's provenance pipeline splits responsibility across distinct layers:

Component Source File Core Responsibility
ContextGraph.record_decision semantica/context/context_graph.py Creates decision records with normalized temporal bounds
ProvenanceEntry dataclass semantica/provenance/schemas.py Defines PROV-O field mappings
ProvenanceManager.track_entity semantica/provenance/manager.py Persists provenance with hash-chain integrity

Each component transforms raw decision data into standards-compliant provenance graphs that can be exported as RDF/Turtle for interoperability.

Recording Decisions in ContextGraph

The record_decision method in semantica/context/context_graph.py (lines 3174–3222) validates inputs, normalizes temporal data, and stores the decision.


# semantica/context/context_graph.py

def record_decision(
    self,
    category: str,
    scenario: str,
    reasoning: str,
    outcome: str,
    confidence: float,
    entities: Optional[List[str]] = None,
    decision_maker: Optional[str] = None,
    metadata: Optional[Dict[str, Any]] = None,
    valid_from: Optional[Union[str, int, float, datetime]] = None,
    valid_until: Optional[Union[str, int, float, datetime]] = None,
    **kwargs
) -> str:
    decision_id = str(uuid.uuid4())
    normalized_valid_from = _normalize_temporal_input(valid_from)
    normalized_valid_until = _normalize_temporal_input(valid_until)

    decision = {
        "id": decision_id,
        "category": category,
        "scenario": scenario,
        "reasoning": reasoning,
        "outcome": outcome,
        "confidence": confidence,
        "entities": entities or [],
        "decision_maker": decision_maker,
        "timestamp": datetime.utcnow().timestamp(),
        "valid_from": normalized_valid_from,
        "valid_until": normalized_valid_until,
        "metadata": metadata or {},
        **kwargs,
    }
    self._add_decision_to_graph(decision)
    return decision_id

Key operations performed:

  • UUID generation for immutable decision identification
  • Temporal normalization via _normalize_temporal_input (ISO-8601 conversion per semantica/utils/helpers.py lines 73–89)
  • Domain-time capture (valid_from, valid_until) distinct from system-time
  • Graph persistence through _add_decision_to_graph

The returned decision_id becomes the entity_id in the provenance layer.

ProvenanceEntry: The PROV-O Schema Mapping

The ProvenanceEntry dataclass in semantica/provenance/schemas.py (lines 36–66) implements the W3C PROV-O ontology as native Python types:

Field PROV-O Concept Semantic Purpose
entity_id prov:Entity The decision itself
entity_type rdf:type Classification (e.g., "decision")
activity_id prov:Activity The recording action
agent_id, agent_type prov:Agent Decision maker or system
role prov:hadRole Function in the activity
timestamp prov:generatedAtTime System-time of creation
valid_from / valid_until Domain extension Business-time validity
parent_entity_id prov:wasDerivedFrom Correction lineage
previous_version_id prov:specializationOf Version succession
checksum / previous_checksum Integrity extension Tamper detection

This schema design separates system-time (timestamp, prov:generatedAtTime) from domain-time (valid_from, valid_until), enabling retroactive corrections without destroying audit history.

Persisting Provenance with ProvenanceManager

The ProvenanceManager.track_entity method in semantica/provenance/manager.py (lines 66–84) bridges decision creation and PROV-O storage:


# semantica/provenance/manager.py – excerpt

def track_entity(self, entity_id: str, source: str, 
                 metadata: Optional[Dict[str, Any]] = None, **kwargs):
    agent_info = self._resolve_agent_kwargs(kwargs)
    activity_info = self._resolve_activity_kwargs(kwargs, "entity_tracking")
    
    entry = ProvenanceEntry(
        entity_id=entity_id,
        entity_type=kwargs.get("entity_type", "entity"),
        activity_id=activity_info["activity_id"],
        agent_id=agent_info["agent_id"],
        agent_type=agent_info["agent_type"],
        is_automated=agent_info["is_automated"],
        role=agent_info["role"],
        source_document=source,
        source_location=kwargs.get("source_location"),
        confidence=kwargs.get("confidence", 1.0),
        metadata=metadata or {},
        first_seen=utc_now_iso(),
        last_updated=utc_now_iso(),
        valid_from=kwargs.get("valid_from"),
        valid_until=kwargs.get("valid_until"),
    )
    return self._save_entry(entry)

The manager performs three critical functions:

  1. Checksum computation – SHA-256 hashes create an immutable chain (checksum, previous_checksum)
  2. Lineage linking – Connects to parent entities for corrections or versioning
  3. Backend abstraction – Supports in-memory or SQLite storage

Lineage retrieval via get_lineage (lines 752–782) traverses these links to reconstruct full provenance chains.

Complete Integration Example

from semantica.context import ContextGraph
from semantica.provenance import ProvenanceManager

# Initialize components

graph = ContextGraph()
prov_mgr = ProvenanceManager()

# Create decision in ContextGraph

decision_id = graph.record_decision(
    category="loan_approval",
    scenario="First-time home-buyer",
    reasoning="Excellent credit score",
    outcome="approved",
    confidence=0.95,
    entities=["customer_123", "property_456"],
    valid_from="2023-01-01",
    valid_until="2024-01-01",
    metadata={"risk_score": 0.2},
)

# Mirror to provenance layer

prov_mgr.track_entity(
    entity_id=decision_id,
    source="decision_log",
    metadata={
        "category": "loan_approval",
        "scenario": "First-time home-buyer",
        "outcome": "approved",
        "confidence": 0.95,
    },
    entity_type="decision",
    agent="automated_engine",
    activity="decision_recording",
)

# Export as W3C PROV-O RDF

turtle_output = prov_mgr.export_prov(decision_id)

The export_prov method (line 378) generates standards-compliant RDF for external provenance tools.

PROV-O Compliance Features

Semantica's implementation satisfies W3C PROV-O requirements while adding operational safeguards:

  • Entity-Activity-Agent pattern – Every decision traces to who (agent), what (activity), and the resulting entity
  • Derivation tracking – prov:wasDerivedFrom links corrected decisions to their predecessors
  • Specialization – prov:specializationOf handles versioning of the same logical decision
  • Temporal precision – Dual timestamping separates observation time from validity period
  • Cryptographic integrity – Hash chains detect tampering beyond standard PROV-O

Summary

  • ContextGraph.record_decision creates decision entities with UUIDs and normalized temporal bounds in semantica/context/context_graph.py
  • ProvenanceEntry maps 15+ fields to W3C PROV-O concepts (prov:Entity, prov:Activity, prov:Agent, prov:wasDerivedFrom) in semantica/provenance/schemas.py
  • ProvenanceManager.track_entity persists provenance with SHA-256 checksum chains and lineage linking in semantica/provenance/manager.py
  • The export_prov method produces interoperable RDF/Turtle for external provenance analysis
  • Temporal normalization utilities in semantica/utils/helpers.py ensure ISO-8601 compliance across all timestamps

Frequently Asked Questions

What is W3C PROV-O and why does Semantica use it?

W3C PROV-O is the ontology-based standard for provenance interchange on the web. Semantica adopts it to ensure decision audit records are interoperable with corporate governance tools, regulatory systems, and academic provenance research. The standard defines Entity, Activity, and Agent classes with relationships like wasDerivedFrom and generatedAtTime—all directly implemented in Semantica's ProvenanceEntry schema.

How does Semantica handle decision corrections without breaking audit trails?

Corrections create new entities linked via prov:wasDerivedFrom to the original. The parent_entity_id field in ProvenanceEntry establishes this derivation chain, while previous_version_id tracks versioning through prov:specializationOf. The original decision remains immutable; the new decision explicitly references its predecessor, enabling full lineage reconstruction without data loss.

Can Semantica export provenance for external compliance audits?

Yes, via ProvenanceManager.export_prov which generates W3C-compliant RDF/Turtle. The export includes all PROV-O entities, activities, agents, and relationships from a decision's lineage. This output validates against standard PROV-O validators and loads into tools like Provenance Explorer or corporate SIEM systems for regulatory reporting.

What storage backends does ProvenanceManager support?

In-memory and SQLite backends are built in, with extensible interfaces. The manager abstracts storage through a backend protocol, defaulting to SQLite for persistence across process restarts. The checksum and previous_checksum fields maintain integrity regardless of backend, enabling verification via verify_checksum even when data moves between systems.

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 →