Claims & Conflicts
The bi-temporal record store — point/interval claim queries, per-claim change-logs, and the conflict queue with manual resolution.
The bi-temporal record store exposes the two-axis history behind the Facts
layer: what was true in the world (valid) and when CortexDB knew it (recorded). It's the query
surface over triple-derived facts, plus the queue of detected contradictions.
Mode-gated, and derived — empty on a content-only self-host
The engine is gated by CORTEX_BITEMPORAL_MODE = off · shadow (default) · enforce. In
shadow (the default) it runs on every triple-derived fact, persists BITEMPORAL WAL events, and
detects conflicts without changing legacy Fact fields; in enforce, stated dates ground
valid_from/valid_to. Because the records derive from facts, they need enrichment — verified live
on a content-only instance, /v1/claims returns { records: [] } and /v1/conflicts returns
{ conflicts: [], next_cursor: null, total: 0 }. See Self-hosting defaults.
Claim queries
GET /v1/claims?scope=&subject=&predicate=&valid_as_of=&known_as_of= — the two-axis point query
("what was true at X, as known at Y"). Swap to interval-overlap mode with valid_during=start..end
and/or recorded_during=start..end. Response envelope: { records: [...] } (verified). scope alone is
accepted; subject/predicate narrow to one claim.
GET /v1/claims/history?scope=&subject=&predicate= — the full change-log of one claim: every valid
interval and every record-time correction, plus the conflicts touching it. Response (verified):
{ "claim": { "scope": "…", "subject": "…", "predicate": "…" }, "history": [], "conflicts": [] }Every validity boundary carries a basis
A finite valid_from/valid_to is either stated (the source asserted the world date — render
"on/since <date>") or observed (bounded by when CortexDB learned it — render "by <date>",
never "on"). This is how undated state changes stay honest.
Conflict queue
GET /v1/conflicts?scope=&status=open|all — the queue of competing values for the same claim.
Paginated envelope (verified): { conflicts: [...], next_cursor, total }.
GET /v1/conflicts/{id} — one conflict.
POST /v1/conflicts/{id}/resolve — manual resolution with mode pick (choose a value),
split (both hold over different validity windows), new_information (a later value supersedes),
or dismiss. Every resolution is an audited, append-only WAL event — the record store never
mutates in place. See Audit Trail.
See also
- Bi-temporal Model — the two time axes and supersession.
- GET /v1/facts — the derived Facts layer these records track.
- The MCP tools
list_conflicts/resolve_conflict/claim_historywrap these routes — see MCP Server.