Documentation

Locked facts

Locked Facts

A locked fact is a value Mnemix surfaces to an agent forever — until a higher-priority source supersedes it. It's the primitive that stops drift: the opening balance the agent can't misreport, the package version it can't silently bump, the caller's name it can't forget on turn 40.

If a human confirmed it once, Mnemix surfaces it forever. Forgetting is failure.

What makes a fact "locked"

Three things, all required:

  1. A value — structured JSON ({"model":"voyage-4-lite","dims":1024}, {"amount":-49.98}).
  2. Evidence — provenance recorded with the fact. You cannot lock a fact without it.
  3. An addressentity_id (who/what the fact is about) + fact_key (which fact). That's how the gate and the context packer look it up.

Schema

The substrate table (as shipped in the live migrations):

| Column | Type | Description | | :--- | :--- | :--- | | ref_id | uuid | Primary key. | | tenant_id | uuid | RLS isolation. | | entity_id | text | What the fact is about (acct_acme, repo_mnemix, a caller id). | | fact_key | varchar(255) | Fact identifier (embedder.canonical, opening_balance.2025-08-01). | | fact_value | jsonb | The fact data. | | valid_range / tx_range | tstzrange | The bi-temporal windows — when it was true, and when Mnemix believed it. GiST-indexed. | | supersedes_ref_id | uuid | Self-reference to the fact this one replaced. |

Writing facts — supersession, never UPDATE

Facts are written through supersession-safe stored procedures — assert_fact (new fact) and evolve_fact (replace a value while preserving history). When a fact changes, the substrate does not UPDATE the value:

  1. Bound the old fact — close its valid_range at the supersession moment.
  2. Insert the new fact — its valid_range opens where the old one closed.
  3. Link them — the new row's supersedes_ref_id points at the old row.
test_runner = "jest"     valid: [2025-01-01, 2026-05-29)        ◀── superseded by ─┐
test_runner = "vitest"   valid: [2026-05-29, ∞)   ← active                          │
                                                       supersedes_ref_id ───────────┘

This guarantees any historical audit can reconstruct the exact state of the world at a moment:

SELECT fact_value FROM locked_facts
WHERE entity_id = 'repo_mnemix' AND fact_key = 'test_runner'
  AND valid_range @> '2026-03-01T00:00:00Z'::timestamptz;
-- → "jest"   (what was true in March, even though it's "vitest" now)

See Bi-temporal Validity for the full time model.

Locked facts surface in agent context

The context packer is designed to inject a LOCKED FACTS YOU MUST HONOR block into agent context for the relevant entities (Weld A — the mechanism that makes remembering automatic). The agent sees test_runner = vitest every turn; when it proposes import { describe } from "jest", the gate's test_runner_consistency rule blocks it.

Facts over the API

There is no public facts REST surface yet — fact writes go through the substrate's stored procedures via the ingestion paths, and fact reads surface inside context packets. A direct facts API (lock / resolve / audit-chain) is on the beta roadmap; the docs will gain real request/response examples when it ships. Any older draft showing facts CLI subcommands or facts REST calls predates this correction and doesn't exist.

See also