How Semantica's ContextGraph trace_decision_causality Method Works for Audit Trails

The trace_decision_causality method performs a thread-safe breadth-first search across PRECEDENT_FOR edges to reconstruct a complete causal chain of agent decisions, calculating cumulative confidence scores for full audit trail transparency.

Semantica, an open-source agentic framework maintained at semantica-agi/semantica, stores every agent decision as a node in a Context Graph linked by causal relationships. The trace_decision_causality method transforms this raw graph data into a structured audit trail that compliance systems and debuggers can consume directly.

Overview of Decision Causality Tracing

In semantica/context/context_graph.py, the ContextGraph class implements a provenance system where decisions are immutable nodes connected by typed edges. When an agent makes a decision that references previous reasoning, the record_decision helper (implemented in semantica/context/decision_recorder.py) creates a PRECEDENT_FOR edge (defined in semantica/context/decision_models.py) linking the new decision to its antecedents.

The trace_decision_causality(decision_id) method reverses this process. Starting from any decision node, it walks backward through causal edges to answer three critical audit questions: what happened, when it happened, and why it happened.

How trace_decision_causality Builds Audit Trails

The method executes a four-phase traversal algorithm under a re-entrant lock to ensure consistency during concurrent graph mutations.

Locating the Decision Node

The method first validates the input by checking self.nodes for the supplied decision_id. If the identifier does not exist, it raises a KeyError immediately. This validation ensures that audit queries fail fast rather than returning empty or misleading chains.

Traversing Causal Edges

Using a breadth-first search (BFS), the walker follows outgoing edges filtered by the causal relationship label (defaulting to PRECEDENT_FOR). The search continues until it encounters nodes with no further causal edges or reaches a configurable max_hops limit. This prevents runaway traversals on densely connected graphs while preserving the ability to retrieve deep historical context when needed.

Calculating Confidence Decay

For each hop in the chain, the method extracts:

  • Source and target node IDs
  • Edge type and weight (typically representing LLM confidence scores)
  • Edge metadata containing reasoning context
  • Cumulative confidence decay calculated as the running product of edge weights

The final overall_confidence value represents the multiplicative probability that the entire decision chain is valid, enabling quantitative risk assessment in compliance workflows.

Thread-Safe Execution

The entire traversal executes under self._lock, a re-entrant lock held by the ContextGraph instance. This guarantees that the returned audit trail represents a consistent snapshot even when other threads are actively recording new decisions or modifying graph topology.

Anatomy of the Audit Trail Output

The method returns a _CausalChain dictionary subclass (for backward compatibility) containing a structured hop list:

{
    "decision_id": "2c3f7b1e-...",
    "hops": [
        {
            "source": "2c3f7b1e-...",
            "target": "a7e4d2f9-...",
            "edge_type": "PRECEDENT_FOR",
            "weight": 0.88,
            "metadata": {"reasoning": "customer requested lower rate"},
            "confidence_decay": 0.88,
            "path": ["2c3f7b1e-...", "a7e4d2f9-..."],
        },
        {
            "source": "a7e4d2f9-...",
            "target": "5f1e2c3d-...",
            "edge_type": "PRECEDENT_FOR",
            "weight": 0.96,
            "metadata": {"reasoning": "good credit score"},
            "confidence_decay": 0.8448,  # 0.88 * 0.96

            "path": ["2c3f7b1e-...", "a7e4d2f9-...", "5f1e2c3d-..."],
        },
    ],
    "total_hops": 2,
    "overall_confidence": 0.8448,
}

Because the return type subclasses dict, existing code that iterates over chain["hops"] continues to function without modification.

Practical Implementation Example

The following example demonstrates recording interdependent loan approval decisions and retrieving their audit trail:

from semantica.context import ContextGraph

# Initialize graph with thread-safe locking

g = ContextGraph(advanced_analytics=False)

# Record initial decision (root of the chain)

decision_a = g.record_decision(
    category="loan_approval",
    scenario="first_homebuyer",
    reasoning="good credit score",
    outcome="approved",
    confidence=0.96,
    entities=["customer_123", "property_456"],
)

# Record subsequent decision citing precedent

decision_b = g.record_decision(
    category="loan_approval",
    scenario="refinance",
    reasoning="customer requested lower rate",
    outcome="approved",
    confidence=0.88,
    entities=["customer_123"],
    precedents=[decision_a],  # Creates PRECEDENT_FOR edge

)

# Generate audit trail for compliance review

causal_chain = g.trace_decision_causality(decision_b)

print(f"Audit trail for decision: {decision_b}")
for hop in causal_chain["hops"]:
    print(
        f"← {hop['source']} --{hop['edge_type']} ({hop['weight']})→ {hop['target']}"
    )
print(f"Overall confidence: {causal_chain['overall_confidence']:.4f}")

Output:


Audit trail for decision: 2c3f7b1e-...
← 2c3f7b1e-... --PRECEDENT_FOR (0.88)→ a7e4d2f9-...
← a7e4d2f9-... --PRECEDENT_FOR (0.96)→ 5f1e2c3d-...
Overall confidence: 0.8448

Why This Matters for Compliance and Debugging

Complete Provenance: Every node stores full reasoning, outcome, associated entities, and timestamps. Auditors can traverse from any decision back to its ultimate origin.

Temporal Validity: Nodes and edges support valid_from and valid_until attributes (parsed in semantica/context/context_graph.py lines 42-64), enabling time-windowed queries that show only decisions active at a specific moment.

Quantifiable Trust: The multiplicative confidence decay provides a numerical metric for automated risk assessment pipelines.

Scalable Investigation: The max_hops parameter allows investigators to balance between deep historical analysis and rapid high-level overviews.

Summary

  • trace_decision_causality in semantica/context/context_graph.py implements BFS traversal over PRECEDENT_FOR edges to reconstruct decision history.
  • The method returns a structured dictionary containing ordered hops with confidence decay calculations and edge metadata.
  • Thread-safety is guaranteed via a re-entrant lock held during the entire traversal.
  • The system supports temporal filtering through valid_from/valid_until attributes on nodes and edges.
  • Audit trails include quantitative confidence metrics calculated as the product of edge weights along the causal chain.

Frequently Asked Questions

What is the difference between trace_decision_causality and a simple graph query?

The trace_decision_causality method is a specialized walker that understands decision-specific semantics. Unlike a generic graph query, it automatically filters for causal edge types (such as PRECEDENT_FOR), calculates cumulative confidence decay across the path, and respects temporal validity windows. It also handles thread-safety internally via the graph's re-entrant lock, whereas raw graph queries would require manual synchronization.

How does Semantica handle concurrent modifications during audit trail generation?

The method acquires self._lock before accessing the internal self.nodes dictionary and maintains the lock throughout the BFS traversal. This ensures that even if other threads are recording new decisions or adding edges concurrently, the returned audit trail represents a consistent point-in-time snapshot of the graph state.

Yes. The trace_decision_causality method accepts a max_hops parameter that caps the BFS traversal depth. This prevents performance degradation on large graphs with deeply nested decision chains while still exposing the most recent and relevant causal history for debugging or compliance review.

What happens if a decision references multiple precedents?

The BFS walker follows all outgoing PRECEDENT_FOR edges from each node, creating branching paths in the audit trail. Each branch is recorded as a separate hop in the hops list with its own confidence decay calculation. The overall_confidence field represents the product of weights along the primary path, but investigators can examine individual hop metadata to understand divergent reasoning paths.

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 →