Changelog
mempill follows semantic versioning. The first published release is 0.2.0, now live on crates.io and PyPI. See Installation for install instructions.
Unreleased
Section titled “Unreleased”- TypeScript bindings (napi-rs) — planned
- Vector search integration (sqlite-vec / pgvector) — planned
- True bi-temporal point-in-time read — a
valid_atparameter distinct fromas_of_tx_time, enabling “what did the engine believe was valid on date X?” queries — planned (v0.3). Today,as_of_tx_timerewinds both transaction time and valid-time selection simultaneously; a separatevalid_ataxis is not yet exposed. - Date precision / granularity — partial dates (
2020-03) currently normalize to the start of the period (2020-03-01); the filled day is a normalization placeholder, not asserted precision. Granularity-aware valid-time (rendering “March 2020” honestly rather than “March 1, 2020”) is planned (v0.3). - PostgreSQL TLS support — planned for a future minor release (NoTls only today)
- API/authoritative-source oracle reference implementation — planned
pdoc-generated Python API reference athttps://api.mempill.dev/python/— planned
0.2.0 — first published release
Section titled “0.2.0 — first published release”446 Rust + ~70 Postgres (feature-gated) + 135 Python tests · 0 warnings (clippy --all-targets -D warnings + missing_docs) · MSRV Rust 1.88 · Apache-2.0
Cross-adapter conformance: SQLite + PostgreSQL 16 + PostgreSQL 18.4 via testcontainers.
This release ships the full mempill stack end-to-end:
Rust core engine (mempill-core)
Section titled “Rust core engine (mempill-core)”EngineHandle<P, O, V>— the sole async entry point. Eight deterministic engine components C1–C8:- C1: Provenance Gate — validates and classifies provenance.
- C2: Canonical Fold — read-time belief computation (I8: canonical, never stored).
- C3: Conflict Detector — detects
Functionalcardinality conflicts. - C4: Reconciler — attempts deterministic conflict resolution.
- C5: Read Path (
query_memory,query_audit). - C6: Amplification Guard — blocks
RecallReEntryechoes. - C7: Adjudication Gate — oracle escalation when C4 cannot resolve.
- C8: Ledger — append-only audit log (I1: no UPDATE/DELETE).
- All port traits:
PersistencePort,OraclePort(withNoOpOracle),VectorPort(withNoOpVector). - Application use-cases:
IngestClaimUseCase,QueryMemoryUseCase,ReconcileUseCase,AuditUseCase,SubmitAdjudicationUseCase,SweepAdjudicationsUseCase. - Public DTOs:
IngestClaimRequest/Response,QueryMemoryRequest/Response,ReconcileRequest/Response,AuditQueryRequest/Response. mempill-types:ProvenanceLabel,Disposition(12-state),Cardinality,Confidence,Criticality,ValidTime,BeliefProjection,LedgerEntry,ClaimRef,AgentId.- 11 invariants enforced: I1 (append-only), I2 (low-conf → Contested), I3 (fold not stored), I5 (oracle proposal only), I7 (overlap → Contested), I8 (canonical fold), I9 (atomic commit), and others.
Facade crate (mempill)
Section titled “Facade crate (mempill)”cargo add mempillre-exportsmempill-core+mempill-sqlitefor the common embedded case.
SQLite adapter (mempill-sqlite)
Section titled “SQLite adapter (mempill-sqlite)”SqlitePersistenceStore,DefaultEnginetype alias.open_default(path),open_default_in_memory().- Mandatory PRAGMAs at connection open:
WAL + synchronous=FULL + foreign_keys=ON.
PostgreSQL adapter (mempill-postgres)
Section titled “PostgreSQL adapter (mempill-postgres)”PostgresPersistenceStoreimplementingPersistencePortviapostgres+r2d2connection pool (max 20 connections).open_postgres(conn_str, oracle, vector, config)andopen_postgres_with_oracle(...)constructors.PostgresEngine<O, V>type alias.- Per-agent write serialization:
pg_advisory_xact_lock(hashtext(agent_id)::bigint). - OCC belt-and-suspenders:
UNIQUE(agent_id, stream_seq)onledger_entries. requires_global_write_serialization()returnsfalse— no global application lock; true per-agent concurrency across agents sharing one database.- Schema embedded at compile time via
refinery::embed_migrations!; runs automatically on first connection. - Cross-adapter conformance harness (
run_persistence_conformance,run_oracle_conformance): SQLite and Postgres pass the same behavioral test suite. - Known limitation:
NoTlsonly — TLS planned for a future release. Do not expose the connection over an untrusted network.
Oracle resolution loop
Section titled “Oracle resolution loop”submit_adjudicationwithAffirm/Deny/Unknownverdicts — both SQLite and PostgreSQL adapters.- TTL on pending adjudications;
sweep_expired_adjudications()orphan sweep. EngineHandle::list_pending_adjudications(agent_id)— returns the durable pending queue with incumbent and challenger values decoded.PyOracleEngine.list_pending_adjudications(agent_id=...)— Python binding.
Valid-time succession
Section titled “Valid-time succession”ConflictType::Succession— when a new claim’s valid-time window starts after the incumbent’s ends, and both havevalid_time_confidence ≥ 0.7, the engine commits the new claim asCommittedCheap(notContested) and supersedes the old one cleanly.- Fold selects the claim whose valid-time window contains the query instant (now or
as_of_tx_time) —query_memoryreturns the temporally-correct belief without additional filtering by the caller. - Succession matrix test suite: now/past/boundary/gap/n-chain correctness, cross-adapter conformance (SQLite + Postgres 16 + Postgres 18).
- Overlapping windows →
Contested(no regression). - Low-confidence valid-time (
valid_time_confidence < 0.7) →Contested. - Claims without
valid_time→Contestedwhen conflicting. - Known limitation:
as_of_tx_timerewinds both transaction time and valid-time selection simultaneously. A future release will add a separatevalid_atparameter.
Bi-temporal history read
Section titled “Bi-temporal history read”history()(Rust facade) /history()(Python ergonomic tier) retrieves the full ordered claim timeline for a(subject, predicate)subject-line.- Returns
History/HistoryResultwithentries: Vec<HistoryEntry>(Rust) orentries: list[HistoryEntry](Python), ordered oldest→newest. - Each
HistoryEntrycarries:value,valid_from,valid_until,status(Current|Superseded),provenance,value_confidence,claim_ref. history().current()returns the singleCurrententry — guaranteed to agree withrecall()(same canonical fold).history().is_empty()— true when no claims exist for the subject-line.- Python
Historyis iterable:for e in history(engine, agent, subject, predicate). - Remaining limitation: point-in-time valid-time as-of (
valid_at) is still v0.3.history()always reflects the current epoch; separatevalid_atquerying is not yet exposed.
Python wheel (mempill-python)
Section titled “Python wheel (mempill-python)”- PyO3/maturin wheel (PyO3 0.29, Python ≥ 3.11, abi3).
mempill.open(path),mempill.open_in_memory(),mempill.open_oracle(path, oracle),mempill.open_oracle_in_memory(oracle).- Duck-typed oracle protocol:
request_adjudication(self, agent_id: str, request: dict) -> str. submit_adjudication({handle_id, verdict, evidence_provenance}).sweep_expired_adjudications().mempill.typesmodule:Disposition(12-statestrenum),ProvenanceLabel(factory),IngestClaimRequest,IngestClaimResponse,QueryMemoryRequest,QueryMemoryResponse,ReconcileRequest,ReconcileResponse,AuditQueryRequest,AuditQueryResponseTypedDicts.- Exception hierarchy:
MempillError,ValidationError,NotFoundError,ConflictError,StorageError,ConfigError,InternalError. - Toolchain: maturin 1.14.1, PyO3 0.29.
MCP adapter (mempill-mcp)
Section titled “MCP adapter (mempill-mcp)”- FastMCP stdio server (FastMCP, mcp 1.28, pinned
<2). Four tools:ingest_claim,query_memory,reconcile,audit. MEMPILL_AGENT_IDrequired environment variable.MEMPILL_DB_PATHoptional (in-memory if absent).status_reasonfield on non-committed dispositions.- Friendly provenance string normalisation (
"External:UserAsserted"etc.).
Demo (mempill-demo)
Section titled “Demo (mempill-demo)”- Console + LangGraph agents.
HumanOraclereference implementation — stateless duck-typed oracle; generates a UUID handle per conflict; engine stores all conflict state in the durable pending queue./reviewREPL command — interactive human-in-the-loop adjudication:c(hallenger) → Affirm,i(ncumbent) → Deny,abstain → Unknown,skip → defer.--selftestflag for non-interactive CI validation.- Verified: deferred conflicts survive engine restart (same
handle_idafter close+reopen).
Development history
Section titled “Development history”The following notes track internal milestones during development toward 0.2.0. They are recorded for historical context only — the authoritative current state is the 0.2.0 section above.
| Internal phase | Highlights | Rust tests at that point |
|---|---|---|
| Core engine + SQLite | 8 engine components, 12-state disposition model, port traits | 290 |
| Python wheel + MCP | PyO3 wheel, FastMCP adapter | — |
| PostgreSQL adapter | topology-b, cross-adapter conformance (SQLite + PG16 + PG18) | 311 |
| Oracle resolution loop + HITL | submit_adjudication, HumanOracle, /review REPL |
430 |
| Valid-time succession | ConflictType::Succession, fold fix, succession matrix tests |
461 |
| Additional coverage | Oracle conformance, edge cases, cleanup | 462 |
| Ergonomic Tier-1 API + Postgres test gating | remember/recall + enrichment; PG tests feature-gated |
424 default · 69 PG · 107 Python |
| Bi-temporal history read | history() / query_history; full timeline with Current/Superseded status |
443 default · ~70 PG · 135 Python |
| Publish-hardening (API guidelines + Cargo checklist) | #[non_exhaustive] enum sweep, facade types::/engine:: modules, leak removal, compiled doctest, missing_docs gate |
446 default · ~70 PG · 135 Python (current) |
License
Section titled “License”Apache-2.0. Note: a commercial licensing option is planned for future releases.