# Understanding the ContextGraph state_at() Method in Semantica

> Explore Semantica's ContextGraph state_at() method. Get a temporal snapshot of your graph at any timestamp, filtering nodes and edges by validity windows. Learn more today.

- Repository: [Semantica /semantica](https://github.com/semantica-agi/semantica)
- Tags: deep-dive
- Published: 2026-09-13

---

**The `ContextGraph.state_at()` method returns a temporal snapshot of the entire graph at a specific timestamp, filtering nodes and edges by their validity windows without mutating the live graph structure.**

The `state_at()` method enables time-travel queries within the `semantica-agi/semantica` repository's ContextGraph implementation. This functionality supports auditing, retraction workflows, and "what-if" analyses by reconstructing the graph state as it existed at any historical moment.

## How ContextGraph state_at() Works

### Timestamp Normalization

The method accepts **flexible input formats** including ISO 8601 strings, Unix epoch integers, and Python `datetime` objects. Internally, `state_at()` normalizes all inputs to timezone-naive UTC `datetime` objects to ensure consistent temporal comparisons across different input types.

### Validity Window Filtering

`state_at()` filters graph elements using the same logic as `ContextNode.is_active()` and `ContextEdge.is_active()`. Only nodes and edges whose `valid_from` and `valid_until` properties contain the requested timestamp appear in the results. According to the source code in [`semantica/context/context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py), this validation occurs at lines 30-48 for nodes and lines 93-111 for edges.

### Decision-Aware Serialization

The method handles **decision-type nodes** specially, collecting them into a dedicated `decisions` list while preserving decision-specific properties such as `category`, `scenario`, `reasoning`, `outcome`, and `confidence`. The final output structure includes `nodes`, `edges`, `decisions`, and convenience aliases `entities` and `relationships` for downstream JSON serialization.

## Practical Examples for ContextGraph state_at()

### Basic Snapshot with ISO Strings

Query the graph state using a standard ISO 8601 timestamp to retrieve active nodes and edges at that specific moment:

```python
from semantica.context import ContextGraph

g = ContextGraph()
g.add_node("A", "entity", content="Alice", valid_from="2023-01-01", valid_until="2024-01-01")
g.add_node("B", "entity", content="Bob",   valid_from="2024-01-01")
g.add_edge("A", "B", "knows", valid_from="2023-06-01")

snapshot = g.state_at("2023-07-15T00:00:00Z")
print(snapshot["nodes"])      # → contains A, not B

print(snapshot["edges"])      # → contains the edge A‑B

```

### Unix Epoch and Datetime Objects

Pass Unix timestamps or aware/naive `datetime` objects directly to `state_at()`:

```python
import datetime as dt

# Using a datetime object (aware or naive)

snapshot = g.state_at(dt.datetime(2023, 7, 15, tzinfo=dt.timezone.utc))

# Using a Unix epoch (seconds since 1970‑01‑01)

snapshot = g.state_at(1689465600)   # same moment as above

```

### Querying Decision History

Inspect decisions that were valid at specific points in time for auditing purposes:

```python
decision_id = g.record_decision(
    category="loan",
    scenario="first‑time homebuyer",
    reasoning="high credit score",
    outcome="approved",
    confidence=0.96,
    valid_from="2024-06-01",
    valid_until="2025-06-01"
)

# Snapshot before the decision becomes valid → no decision appears

print(g.state_at("2024-01-01")["decisions"])   # []

# Snapshot after the decision is active → appears in the decisions list

print(g.state_at("2024-07-01")["decisions"])

# → [{ "id": decision_id, "category": "loan", ... }]

```

### Serializing Snapshots for Storage

Export temporal snapshots to JSON for network transmission or persistent storage:

```python
import json

snapshot_json = json.dumps(g.state_at("2023-07-15T00:00:00Z"))

# The JSON can be stored, sent over the network, or re‑loaded later.

```

## Implementation Details

The core implementation of `state_at()` resides in [`semantica/context/context_graph.py`](https://github.com/semantica-agi/semantica/blob/main/semantica/context/context_graph.py) at lines 3728-3740. This method orchestrates the temporal filtering by invoking the validity checking logic defined in the same file.

Key supporting methods include:
- **`ContextNode.is_active()`**: Located at lines 30-48, determines if a node's validity window contains the target timestamp
- **`ContextEdge.is_active()`**: Located at lines 93-111, performs equivalent checks for edge relationships

The `state_at()` implementation preserves the live graph's mutable state while creating an immutable view, enabling safe concurrent access and historical analysis without locking the underlying data structures.

## Summary

- **Temporal snapshots**: `state_at()` reconstructs the graph as it existed at any specific timestamp without modifying the live graph.
- **Flexible inputs**: Accepts ISO strings, Unix epochs, and `datetime` objects, normalizing to UTC internally.
- **Validity filtering**: Uses `valid_from` and `valid_until` properties via `is_active()` checks to include only current elements.
- **Decision support**: Segregates decision nodes into a dedicated list with full metadata preservation for audit trails.
- **JSON-ready output**: Returns serializable dictionaries with `nodes`, `edges`, `decisions`, and convenience aliases.

## Frequently Asked Questions

### What timestamp formats does the ContextGraph state_at() method accept?

The method accepts ISO 8601 formatted strings, Unix epoch integers (seconds since 1970-01-01), and Python `datetime` objects. All formats are normalized internally to timezone-naive UTC datetimes to ensure consistent temporal querying across different input types.

### How does state_at() handle decision nodes differently from regular entities?

While standard nodes populate the `nodes` or `entities` lists, decision-type nodes are extracted into a separate `decisions` list that preserves decision-specific metadata including `category`, `scenario`, `confidence`, and `outcome`. This segregation enables efficient auditing and compliance reporting without scanning the entire node collection.

### Does calling state_at() modify the original ContextGraph?

No, `state_at()` performs a read-only operation that returns a new dictionary structure containing filtered copies of the graph elements. The live ContextGraph remains mutable and unaffected, allowing safe concurrent snapshots for "what-if" analysis and historical investigation.

### Can I use state_at() to audit retracted information?

Yes, because `state_at()` filters by validity windows, you can query timestamps before a retraction occurred to view the previously valid state. This capability supports compliance requirements and forensic analysis by maintaining access to historical truth even after elements are marked invalid via `valid_until` timestamps.