Bi-Temporal Validity¶
memv tracks knowledge across two independent timelines. Based on Graphiti.
Two Timelines¶
| Timeline | Fields | Question it answers |
|---|---|---|
| Event time | valid_at / invalid_at |
When was this fact true in the world? |
| Transaction time | created_at / expired_at |
When did memv learn/record this? |
Example¶
A user says "I work at Anthropic" in January, then says "I just moved to OpenAI" in March.
| Statement | valid_at | invalid_at | created_at | expired_at |
|---|---|---|---|---|
| Works at Anthropic | Jan 1 | Mar 1 | Jan 1 | Mar 1 |
| Works at OpenAI | Mar 1 | None | Mar 1 | None |
- The Anthropic fact has
invalid_at=Mar 1(no longer true) andexpired_at=Mar 1(superseded) - The OpenAI fact has
invalid_at=None(still true) andexpired_at=None(current record)
Contradiction Handling¶
When predict-calibrate detects a contradiction, it doesn't delete the old fact. Instead:
- The old
SemanticKnowledgeentry getsexpired_atset to now - A new entry is created with the updated information
- Full history is preserved
Python
# Check if a knowledge entry is still current
knowledge.is_current() # expired_at is None
# Check if a fact was true at a specific time
knowledge.is_valid_at(datetime(2024, 2, 1))
Point-in-Time Queries¶
The bi-temporal model enables querying knowledge as it was at any moment:
Python
from datetime import datetime
# What did we know about user's job in January 2024?
result = await memory.retrieve(
"Where does user work?",
user_id="user-123",
at_time=datetime(2024, 1, 1),
)
# Show full history including superseded facts
result = await memory.retrieve(
"Where does user work?",
user_id="user-123",
include_expired=True,
)
Why Not Just Overwrite?¶
Overwriting loses information. With bi-temporal tracking:
- You can reconstruct what you knew at any point in time
- You can see how a user's situation evolved
- Debugging is easier — you can trace when and why knowledge changed
- Rollback is possible — superseded records still exist