How to Implement Decision Intelligence with Full Audit Trails and Causal Chain Tracking in Semantica-AGI
Implement decision intelligence with immutable audit trails and causal chain tracking by combining DecisionRecorder for persisting decisions, ProvenanceManager for hash-chained audit logs, and CausalChainAnalyzer for upstream/downstream impact analysis—all orchestrated through MCP tools in the Semantica-AGI framework.
Decision intelligence requires more than logging choices; it demands traceable provenance, queryable precedents, and analyzable causal relationships. The open-source Semantica-AGI repository (semantica-agi/semantica) provides production-ready Python components that bind these capabilities together through a knowledge-graph-backed architecture. This guide covers the complete implementation: recording decisions, validating schemas, traversing causal chains, and exporting tamper-evident audit logs.
Core Components for Decision Intelligence
Semantica-AGI's decision intelligence stack consists of five tightly-coupled modules:
| Capability | Core Module | Primary API | Purpose |
|---|---|---|---|
| Decision recording | semantica/context/decision_methods.py |
record_decision() / capture_decision_trace() |
Persists decisions with metadata and creates immutable trace events in the knowledge graph |
| Decision querying | semantica/context/decision_methods.py |
find_precedents() / query_decisions() |
Retrieves past decisions by semantic similarity or explicit filters |
| Causal-chain analysis | semantica/context/causal_analyzer.py |
CausalChainAnalyzer.get_causal_chain() |
Walks upstream/downstream relationships to surface root causes and downstream impacts |
| Audit-trail storage | semantica/provenance/manager.py |
ProvenanceManager.track_entity(), audit_log() |
Stores PROV-O-compatible entries with hash-chained checksums, exportable in multiple formats |
| Schema validation | semantica/mcp/schemas.py |
RECORD_DECISION JSON schema |
Enforces required fields: category, scenario, reasoning, outcome, confidence |
The Decision Lifecycle: From Recording to Immutable Audit
Understanding how a decision flows through the system is essential for proper integration. The lifecycle follows five stages:
- Client builds payload — conforming to the
RECORD_DECISIONschema defined inmcp/schemas.py - MCP tool invocation —
record_decisionhandler inmcp/tools/decisions.pyreceives the payload - DecisionRecorder persistence — creates a
Decisiondataclass and writes to the graph store - Trace event emission —
DECISION_RECORDEDevent triggers supplemental captures - Immutable chain creation —
_append_immutable_trace_events()generates hash-chainedDecisionTraceEventnodes
In mcp/tools/decisions.py, the tool handler directly invokes:
# https://github.com/semantica-agi/semantica/blob/main/mcp/tools/decisions.py
DECISION_TOOLS[0]["_handler"](args)
This delegates to the convenience wrapper record_decision() in semantica/context/decision_methods.py, which orchestrates both graph persistence and audit trail generation.
Recording Decisions with Full Provenance
The record_decision() function in semantica/context/decision_methods.py provides the primary interface. It accepts structured decision metadata and automatically initiates audit capture.
from semantica.context.decision_methods import record_decision
decision_id = record_decision(
graph_store=my_graph_store,
category="risk_assessment",
scenario="Evaluate credit risk for applicant #12345",
reasoning="FICO 680, recent delinquency flagged in 2023-Q2",
outcome="high_risk",
confidence=0.87,
entities=["applicant_12345", "credit_report_67890"],
decision_maker="risk_engine_v3",
)
print("Decision recorded:", decision_id)
Key parameters include:
category— taxonomic classifier for decision types (e.g.,loan_approval,deployment)scenario— natural-language description of the decision contextreasoning— explicit rationale (often LLM-generated or rule-derived)outcome— the resulting action or classificationconfidence— numeric certainty score (0.0–1.0)entities— linked knowledge-graph nodes that influenced this decisiondecision_maker— identifier for the responsible agent or system
The function returns a UUID that serves as the anchor for all subsequent audit and causal queries.
Building Immutable Audit Trails with Hash Chaining
The ProvenanceManager in semantica/provenance/manager.py guarantees tamper-evidence through cryptographic chaining. Each audit entry includes the SHA-256 hash of the previous entry, forming an append-only sequence that detects any modification.
from semantica.provenance.manager import ProvenanceManager
# Initialize with persistent SQLite backend
prov_mgr = ProvenanceManager(storage_path="audit.db")
# Export full audit trail in multiple formats
json_log = prov_mgr.audit_log(format="json")
csv_log = prov_mgr.audit_log(format="csv")
table_log = prov_mgr.audit_log(format="table")
The internal _save_entry() method computes:
# Conceptual flow within ProvenanceManager._save_entry()
current_hash = sha256(previous_hash + entry_content)
This hash chain ensures that even a single-character alteration anywhere in the history invalidates all subsequent entries—a critical property for compliance and forensic analysis.
Querying Precedents and Decision History
Decisions become intelligence when compared against historical patterns. The find_precedents() function supports semantic similarity search over past decision scenarios.
from semantica.context.decision_methods import find_precedents
precedents = find_precedents(
graph_store=my_graph_store,
scenario="Credit risk evaluation for self-employed applicant",
limit=5,
)
for decision in precedents:
print(f"{decision.decision_id}: {decision.outcome} (confidence: {decision.confidence})")
The match is performed via natural-language embedding similarity on the scenario field, optionally filtered by category, outcome, or date range through query_decisions().
Causal Chain Analysis: Upstream and Downstream Traversal
The CausalChainAnalyzer in semantica/context/causal_analyzer.py enables forensic investigation of how decisions propagate through systems. It supports three traversal directions:
- Upstream — identify root causes by following
derived_from_idandused_entitiesedges - Downstream — measure impact by following
has_trace_eventandused_entitiesedges - Both — full bidirectional exploration
from semantica.context.decision_methods import get_causal_chain
# Investigate what led to a critical decision
upstream_chain = get_causal_chain(
graph_store=my_graph_store,
decision_id=decision_id,
direction="upstream",
max_depth=3,
)
# Assess what this decision subsequently affected
downstream_chain = get_causal_chain(
graph_store=my_graph_store,
decision_id=decision_id,
direction="downstream",
max_depth=5,
)
# Full bidirectional analysis
full_chain = get_causal_chain(
graph_store=my_graph_store,
decision_id=decision_id,
direction="both",
max_depth=4,
)
for step in full_chain:
print(f"{step.decision_id}: {step.scenario} (impact score: {step.impact_score})")
The analyzer computes impact scores via analyze_decision_impact(), weighting downstream nodes by graph distance and outcome severity.
Automatic Integration via AgentContext
When decision_tracking is enabled in configuration, AgentContext (semantica/context/agent_context.py) automatically wires all decision intelligence services:
# https://github.com/semantica-agi/semantica/blob/main/semantica/context/agent_context.py
if self.config.get("decision_tracking"):
self._decision_recorder = DecisionRecorder(self.graph_store)
self._decision_query = DecisionQuery(self.graph_store)
self._causal_analyzer = CausalChainAnalyzer(self.graph_store)
self._policy_engine = PolicyEngine(self.graph_store)
This injection pattern allows any LLM-driven agent to access decision capabilities without manual service initialization:
# Within an AgentContext-enabled workflow
decision_id = record_decision(
graph_store=ctx.graph_store,
category="deployment",
scenario="Deploy v2.3 of the recommendation engine",
reasoning="Tests passed, p99 latency < 50ms, no critical errors in staging",
outcome="deployed",
confidence=0.99,
)
# Immediate causal analysis
chain = get_causal_chain(
graph_store=ctx.graph_store,
decision_id=decision_id,
direction="downstream",
max_depth=5,
)
Complete End-to-End Implementation
The following runnable example demonstrates all capabilities in sequence:
from semantica.context.decision_methods import (
record_decision,
find_precedents,
get_causal_chain,
analyze_decision_impact,
)
from semantica.provenance.manager import ProvenanceManager
# 1. Initialize provenance with persistent SQLite store
prov_mgr = ProvenanceManager(storage_path="audit.db")
# 2. Record a deployment decision with full metadata
decision_id = record_decision(
graph_store=prov_mgr.storage.graph_store,
category="deployment",
scenario="Deploy v2.3 of the recommendation engine to production",
reasoning="Integration tests passed; canary metrics healthy for 4 hours; rollback window confirmed with SRE",
outcome="deployed",
confidence=0.94,
entities=["service_recommendation_v2.3", "deployment_pipeline_prod"],
decision_maker="ci_cd_orchestrator",
)
# 3. Find similar past deployment decisions
similar_deployments = find_precedents(
graph_store=prov_mgr.storage.graph_store,
scenario="Deploy recommendation engine",
limit=3,
)
print(f"Found {len(similar_deployments)} precedents")
# 4. Get full causal chain (upstream dependencies + downstream effects)
full_chain = get_causal_chain(
graph_store=prov_mgr.storage.graph_store,
decision_id=decision_id,
direction="both",
max_depth=4,
)
# 5. Compute quantitative impact score
impact = analyze_decision_impact(
graph_store=prov_mgr.storage.graph_store,
decision_id=decision_id,
)
print(f"Downstream impact score: {impact.score}")
# 6. Export immutable audit log for compliance
audit_json = prov_mgr.audit_log(format="json")
with open("deployment_audit.json", "w") as f:
f.write(audit_json)
Key Source Files Reference
Summary
record_decision()persists decisions to the knowledge graph and initiates immutable audit capture via hash-chained trace eventsProvenanceManagerprovides tamper-evident storage with SHA-256 checksums and multi-format export (JSON/CSV/table)find_precedents()enables semantic similarity search over historical decisions for pattern recognitionget_causal_chain()traverses upstream (derived_from_id) and downstream (has_trace_event) relationships to surface root causes and impactsAgentContextautomatically injects all services whendecision_trackingis enabled, requiring zero boilerplate for LLM agents- Schema enforcement via
RECORD_DECISIONinmcp/schemas.pyguarantees data integrity at ingestion
Frequently Asked Questions
How does Semantica-AGI ensure audit logs cannot be tampered with?
The ProvenanceManager in semantica/provenance/manager.py computes a SHA-256 checksum for each audit entry that incorporates the previous entry's hash. This creates a cryptographic chain where modifying any historical entry invalidates all subsequent hashes, making tampering immediately detectable.
What graph relationships does CausalChainAnalyzer traverse?
CausalChainAnalyzer.get_causal_chain() follows derived_from_id and used_entities edges for upstream traversal (root cause analysis), and has_trace_event with used_entities for downstream traversal (impact analysis). These relationships are stored as labeled edges in the underlying knowledge graph.
Can decision schemas be customized for domain-specific requirements?
The base RECORD_DECISION schema in mcp/schemas.py enforces core fields (category, scenario, reasoning, outcome, confidence), but the Decision dataclass and DecisionRecorder accept arbitrary additional fields through the entities list and extensible metadata dictionaries. Domain extensions should subclass the schema validator while preserving required fields.
What storage backends support the audit trail?
ProvenanceManager supports both in-memory storage (for testing) and persistent SQLite via storage_path="audit.db". The ProvenanceStorage abstraction in semantica/provenance/manager.py can be extended for PostgreSQL, Neo4j, or other backends by implementing the _save_entry() and query interface contracts.
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 →