Skip to content

feat(graph): add bi-temporal fact search - #28

Open
DivyamTalwar wants to merge 1 commit into
mainfrom
codex/temporal-graph-facts-20260824
Open

feat(graph): add bi-temporal fact search#28
DivyamTalwar wants to merge 1 commit into
mainfrom
codex/temporal-graph-facts-20260824

Conversation

@DivyamTalwar

Copy link
Copy Markdown
Owner

Why

JITMIND already writes t_observed, t_valid, and t_invalid onto extracted graph relations, but no public graph API could apply those timestamps during retrieval. Worse, a repeated (head, relation, tail) could overwrite the prior relation observation, erasing the history needed for time-travel answers.

What changed

  • stores each extracted relation as an immutable, idempotent observation keyed by source memory + triplet
  • adds typed GraphFact evidence with source memory/page and full temporal interval
  • adds GraphMemoryStore.query_facts(...) with entity, relation-type, namespace, valid-time, and observation-time filters
  • adds GraphRetriever.search_temporal(...) so temporal facts flow through the existing Hit contract
  • normalizes timestamps before executing parameterized Cypher and bounds result limits
  • documents valid-time versus observation-time semantics

Competitive rationale / provenance

Graphiti publicly models dynamic memory as episodes and facts whose valid_at / invalid_at fields can be filtered during fact search: https://github.com/getzep/graphiti and https://github.com/getzep/graphiti/blob/main/mcp_server/src/graphiti_mcp_server.py

This PR implements that missing capability using JITMIND's own Memory, Entity, and RELATION schema and adds an explicit observation-time gate. No Graphiti code was copied.

Evidence

  • python -m pytest -q42 passed
  • python -m compileall -q jitmind → pass
  • new tests verify normalized bi-temporal query parameters, namespace and invalidation predicates, stable-but-versioned relation IDs, invalid-input fail-fast behavior, and retrieval provenance

Evidence gap

The Cypher contract is tested through a deterministic driver boundary. A live Neo4j latency benchmark is intentionally not claimed because this runner has no authoritative production graph dataset or Neo4j deployment.

Review notes

This is an independent proposal targeting main; it does not depend on PR #27. Please keep it open for review and comparison.

Copy link
Copy Markdown
Owner Author

Verification checkpoint

  • Exact head: c15ea9bc592136c3b9f8cfdbc3fae4031357ae23
  • GitHub Actions CI run: 32663099122success
  • Matrix: Python 3.10 (97252122494), 3.11 (97252122517), and 3.12 (97252122401) all passed install, pytest, and compileall
  • Local suite: 42 passed

Semantics reviewed: relation observations are idempotent per source-memory triplet, later observations preserve history, valid intervals are start-inclusive/end-exclusive, and observation time is independently gated. Live Neo4j latency remains an explicit evidence gap; no performance claim is being made. This PR remains intentionally open and unmerged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant