Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Temporal Index

The temporal index is a graph, not a flat lookup table. It records every capture across four dimensions: URL, time, content hash, and crawl context. This enables queries like “show me every version of this page” or “what changed between these two crawls.”

CaptureInstant

Every capture is timestamped with a paired clock:

#![allow(unused)]
fn main() {
pub struct CaptureInstant {
    pub wall: DateTime<Utc>,    // Real-world time
    pub logical: u64,           // Monotonic counter within a crawl
}
}

Wall time records when the capture happened. Logical time records the ordering within a single crawl session, immune to clock drift.

IndexEntry

#![allow(unused)]
fn main() {
pub struct IndexEntry {
    pub url: Url,
    pub captured_at: CaptureInstant,
    pub content_hash: ContentHash,
    pub crawl_context: CrawlContextId,
}
}

Each entry represents one capture of one URL at one point in time, with a pointer (content hash) to the stored artifact.

Backends

InMemoryIndex

Uses BTreeMap for deterministic ordering. Suitable for testing and short-lived crawls.

#![allow(unused)]
fn main() {
let mut index = InMemoryIndex::new();
index.insert(entry);
let results = index.query(&IndexQuery::for_url(&url));
}

SqliteIndex

Persistent SQL-backed index with WAL mode for concurrent reads:

#![allow(unused)]
fn main() {
let mut index = SqliteIndex::open(Path::new("./output/index.sqlite"))?;
index.insert(entry)?;
let results = index.query(&IndexQuery::for_url(&url))?;
}

The schema includes a UNIQUE constraint on (url, wall_time, content_hash) to prevent duplicate entries.

Queries

IndexQuery supports multi-dimensional filtering:

  • By URL — all captures of a specific URL
  • By time range — all captures within a window
  • By content hash — find which URLs produced a specific blob
  • By crawl context — all captures from a specific crawl session

Results are ordered by captured_at (ascending), then URL string.

Use Cases

History — “Show me every version of https://example.com/ across all crawls”:

#![allow(unused)]
fn main() {
let history = index.query(&IndexQuery::for_url(&url))?;
for entry in &history {
    println!("{} -> {}", entry.captured_at.wall, entry.content_hash.as_hex());
}
}

Change Detection — Compare content hashes across captures to identify when a page changed.

Provenance — Every RAG chunk and embedding links back to an IndexEntry via source_url, captured_at, and source_hash.