# How ContextGraph.record_decision() Integrates with Causal Relationship Tracking in Semantica

> Discover how ContextGraph.record_decision() integrates with causal relationship tracking in Semantica. Learn to reconstruct influence chains through explicit graph traversal.

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

---

**ContextGraph.record_decision() creates Decision nodes that serve as anchors for causal edges added via add_causal_relationship(), enabling trace_decision_causality() to reconstruct influence chains through explicit graph traversal.**

The Semantica AGI framework provides sophisticated decision tracking through its `ContextGraph` class, where `ContextGraph.record_decision()` serves as the foundational method for persisting decision metadata. This functionality integrates seamlessly with causal relationship tracking to map how decisions influence one another over time. Understanding this integration is essential for building explainable AI systems that can trace decision provenance through directed causal chains.

## The Decision Recording Pipeline

At the core of the integration is the transformation of decision data into graph-native structures.

### Creating Decision Nodes with record_decision()

In [`semantica/context/context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py) (lines 3083-3130), the `record_decision()` method instantiates a `ContextNode` with type `"Decision"` and populates its properties with the decision's metadata. The method generates a unique UUID for the decision and delegates node insertion to `_add_internal_node()`.

```python
decision_id = str(uuid.uuid4())
node = ContextNode(
    node_id=decision_id,
    node_type="Decision",
    content=decision.scenario,
    properties={
        "category": decision.category,
        "reasoning": decision.reasoning,
        "outcome": decision.outcome,
        "confidence": decision.confidence,
        "timestamp": normalized_timestamp.isoformat(),
        "decision_maker": decision.decision_maker,
        **metadata,
    },
    valid_from=decision.valid_from,
    valid_until=decision.valid_until,
)
self._add_internal_node(node)

```

This node creation establishes the necessary graph entity that subsequent causal operations reference.

### Decision Node Structure and Properties

The properties dictionary captures comprehensive decision context including **category**, **reasoning**, **outcome**, and **confidence** scores. Temporal boundaries are enforced through `valid_from` and `valid_until` fields, enabling time-aware causal analysis. The `entities` field links decisions to specific domain objects, creating connection points for heuristic causal inference when explicit edges are absent.

## Establishing Causal Relationships Between Decisions

Once decisions exist as nodes, the graph supports explicit causal linkage through a dedicated API.

### The add_causal_relationship() Method

Located at lines 2643-2670 in [`context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/context_graph.py), `add_causal_relationship()` validates that source and target IDs reference existing decision nodes before creating a directed `ContextEdge`. The method accepts relationship types from the canonical set defined in `_CAUSAL_EDGE_TYPES`: `CAUSED`, `INFLUENCED`, and `PRECEDENT_FOR`.

```python
edge = ContextEdge(
    source_id=source_decision_id,
    target_id=target_decision_id,
    edge_type=relationship_type,  # "CAUSED", "INFLUENCED", or "PRECEDENT_FOR"

    weight=1.0,
    metadata={"recorded_at": datetime.utcnow().isoformat()},
)
self._add_internal_edge(edge)

```

The edge is persisted via `_add_internal_edge()`, making it available for subsequent traversal operations.

### Causal Edge Types and Validation

The integration enforces **strong typing** for causal relationships. Before edge creation, the system verifies both endpoints exist in the internal `_decisions` registry. This validation ensures causal chains only connect actual decision nodes, preventing spurious links to other entity types like observations or hypotheses.

## Traversing Causal Chains with trace_decision_causality()

The retrieval mechanism completes the integration by consuming the nodes and edges created by the previous steps.

### Building the Reverse Causal Index

The `trace_decision_causality()` method (lines 3453-3505) begins by constructing a reverse index of all explicit causal edges. It iterates through `_CAUSAL_EDGE_TYPES` and maps target decision IDs to their incoming edges using a `defaultdict(list)` structure.

```python
incoming_causal_edges = defaultdict(list)
for edge_type in _CAUSAL_EDGE_TYPES:
    for edge in self.edge_type_index.get(edge_type, []):
        if edge.source_id in self._decisions:
            incoming_causal_edges[edge.target_id].append(edge)

```

This index enables efficient O(1) lookup of causal predecessors during graph traversal.

### Explicit vs. Heuristic Causal Discovery

The tracing algorithm performs a **depth-first walk** starting from the target decision, prioritizing explicit edges from `incoming_causal_edges`. Each hop is recorded with its direction, type, and weight:

```python
hop = {
    "from": cause_id,
    "to": current_id,
    "type": edge.edge_type,
    "edge_weight": edge_weight,
}

```

Only when no explicit causal edges exist does the system fall back to **heuristic inference** based on shared entities or temporal proximity. This precedence guarantees that manually curated causal relationships override automated assumptions.

## Practical Implementation Example

The following example demonstrates the complete integration workflow: recording decisions, establishing causality, and tracing the resulting chain.

```python
from semantica.context import ContextGraph

# Initialize the graph

graph = ContextGraph()

# Record two related decisions

d1 = graph.record_decision(
    category="loan_approval",
    scenario="First-time homebuyer",
    reasoning="Excellent credit score",
    outcome="approved",
    confidence=0.96,
    entities=["customer_123"],
    decision_maker="analyst_1",
)

d2 = graph.record_decision(
    category="loan_approval",
    scenario="Refinance request",
    reasoning="Stable income, low LTV",
    outcome="approved",
    confidence=0.93,
    entities=["customer_123"],
    decision_maker="analyst_2",
)

# Establish explicit causal link

graph.add_causal_relationship(
    source_decision_id=d1,
    target_decision_id=d2,
    relationship_type="CAUSED",
)

# Retrieve causal chain

chain = graph.trace_decision_causality(d2)
print(chain)

```

**Output structure:**

```json
[
  {
    "from": "d1-uuid",
    "from_scenario": "First-time homebuyer",
    "to": "d2-uuid",
    "to_scenario": "Refinance request",
    "type": "CAUSED",
    "edge_weight": 1.0
  }
]

```

## Summary

- **ContextGraph.record_decision()** creates strongly-typed Decision nodes in [`semantica/context/context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py) (lines 3083-3130), storing comprehensive metadata as node properties.
- **add_causal_relationship()** (lines 2643-2670) validates decision nodes and creates directed edges with types `CAUSED`, `INFLUENCED`, or `PRECEDENT_FOR`.
- **trace_decision_causality()** (lines 3453-3505) builds a reverse index of explicit causal edges and performs depth-first traversal to reconstruct influence chains.
- The system prioritizes **explicit causal edges** over heuristic inference based on shared entities or timestamps.
- All operations maintain **temporal validity** through `valid_from` and `valid_until` attributes on decision nodes.

## Frequently Asked Questions

### What data structure does record_decision() use to store decision metadata?

The method stores metadata within a `ContextNode` object's **properties dictionary**, which includes fields like `category`, `reasoning`, `outcome`, `confidence`, and `timestamp`. These properties are indexed alongside the node's temporal bounds (`valid_from`, `valid_until`) to support time-aware causal queries.

### How does trace_decision_causality() prioritize causal relationships?

The method always prioritizes **explicit causal edges** created via `add_causal_relationship()`. It first builds a reverse index of edges with types in `_CAUSAL_EDGE_TYPES` (CAUSED, INFLUENCED, PRECEDENT_FOR) and traverses these before falling back to heuristic inference based on shared entities or temporal proximity.

### Can causal relationships be established between non-decision nodes?

No. The `add_causal_relationship()` method explicitly validates that both `source_decision_id` and `target_decision_id` exist in the internal `_decisions` registry. This constraint ensures that causal chains specifically map decision provenance rather than general entity relationships.

### Where are the core implementations of these methods located?

All three methods reside in [`semantica/context/context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py). The `record_decision()` implementation spans lines 3083-3130, `add_causal_relationship()` is at lines 2643-2670, and `trace_decision_causality()` occupies lines 3453-3505. Supporting data models are defined in [`semantica/context/decision_models.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/decision_models.py).