Reasoning

Temporal validity

How Spectron tracks when facts were true using valid_from and valid_until.

Facts change. Spectron records when each fact was true, not only what the current value is.

Every active attribute and relation carries a validity interval:

  • valid_from — when the fact became true (often the extraction or correction time; document facts may use an effective date from the source).

  • valid_until — when the fact ceased to be true. null means still valid.

Together these fields power current-state reads, point-in-time reconstruction, and full correction history. The broader picture — system time, known time, and valid time — is in Tri-temporal model.

Current state — default queries return attributes whose validity interval includes “now”.

Point in time — ask what was true on a past date (“what role did Alice hold in February 2025?”) using asOf or validity parameters on entity reads.

History — walk the supersession chain for a key to see every value it took, in order.

Temporal language in chat — when a turn says “I became CEO in January 2025”, “last week I moved to Berlin”, or “I used to live in Berlin”, extraction sets or adjusts validity bounds where it can. Relative phrases (“last week”, “three weeks ago”) resolve against the turn’s spoken time, not wall-clock ingest time — the same anchoring documents get from authored_at or caller-supplied observed_at / observedAt on ingest. Unresolved dates may become uncertainty records instead of guessed timestamps.

Closing a fact with valid_until is not the same as deleting it. The record stays in the store for audit and time-travel queries; it simply drops out of “what is true now”.

OperationDelete-and-replaceTemporal validity
Apply correctionOld value goneOld value closed; new value opened
Query current stateLatest record winsFilter by open validity interval
Query past stateOften impossibleFilter by interval containing the instant
Undo a bad correctionRestore from backupReopen prior value in the chain

Supersession tracks why a value changed (replaced by a newer belief). Temporal validity tracks when each value was active. A correction updates both: the old attribute gets valid_until and a link to its replacement; the new attribute gets valid_from and a link back. See Reconciliation and supersession.

Two situations set valid_until:

Correction — a conflicting new value supersedes the old one. The chain links old → new.

Expiry — a fact ends without a replacement (a promotion that lapses, a time-boxed assignment, an instruction that was revoked). valid_until is set directly — at extraction when temporal language supplies an end date, or via POST /forget / lifecycle operations when you expire memory explicitly.

Agents that ingest an entire canon at once — every chapter of a novel, every episode of a series, every film in a franchise — know things the user has not reached yet. That is a problem for:

  • Serial fiction — a reader on chapter 8 of Dr Jekyll and Mr Hyde must not learn that Hyde and Jekyll are the same person before the reveal page.

  • Episodic or franchise media — a viewer on The Empire Strikes Back in release order must not be told Vader is Luke's father before that scene; someone watching in chronological order (I → II → III) needs a different spoiler boundary entirely, as the spoiler for the viewer in this case is that Anakin becomes a villain.

  • Long-running book series — a Wheel of Time reader on book three should not get answers that depend on book twelve.

The fix is not to omit later material from ingest. Ingest everything, but stamp when each fact entered the reader's timeline, then query asOf the user's current position.

User positionOn ingestOn recall
"I've read up to page N"observed_at / observedAt per page or chapter (a synthetic timeline, not wall-clock)asOf = that page's stamp
"I'm on episode 5 of my chosen order"One stamp per episode in viewing order (release, chronological, or machete)asOf = stamp for episode 5
"Show me chapter 3 only"labels: ["chapter=3"] on uploadlabels: ["chapter=3"] (often with include: ["passages"])

asOf gates the knowledge graph — attributes and relations. A same_as edge between two characters only appears once the ingest stamp for the reveal page has passed. Earlier queries see separate entities with no link.

See the spoiler-safe narrative memory cookbook for franchises, non-chronological viewing orders, and page-by-page ingest recipes.

When each unit of a serial (page, chapter, episode, policy revision) should appear on a known-time axis distinct from when you ran the import, pass observed_at on POST /facts (or observedAt in document upload metadata). Spectron stamps derived facts with that instant as their known time (created_at), so asOf queries reconstruct what the system would have believed at that point in the narrative — not at bulk-import time.

  • GET /entities/{type}/{name} — active attributes for an entity; optional temporal query params on the request.

  • GET /entities/{type}/{name}/history/{key} — ordered supersession history for one key.

  • POST /query with asOf — belief-level recall at a past instant. asOf now gates relations as well as attributes: a relationship is visible only when its known time and validity interval include the requested instant.

Field-level schema detail lives in Data model and schema for operators who manage SurrealDB directly.

Was this page helpful?