The outcome ledger

Every engine makes a claim.
Aletheia keeps the score.

An append-only, hash-chained, bitemporal record of what the machine emitted, what actually happened, and the judgment that joins the two — the closed loop that turns many instances of a system into one that learns.

3verbs · emit / observe / resolve
append-onlyhash-chained · bitemporal
1runtime dependency
Why it exists

A fleet of engines with no shared memory forgets every lesson it earns.

Each engine ships outputs into the world. The world answers. Almost nowhere is that answer written back against the thing that predicted it.

Aletheia is the one place every engine reports to. It stores references and hashes — never copies — and computes nothing about law, obligations, or scoring. It only records what was claimed, observes what happened, and resolves the two. That discipline is what lets one ledger sit underneath a dozen very different machines and make all of them measurable at once.

The mechanism

Three verbs. One closed loop.

Every entry is one of three kinds. Together they turn an opinion into a falsifiable claim, and a claim into a measured outcome.

01 / emit

Emit a claim

The machine produced an output and, optionally, staked a falsifiable claim on it — { metric, horizon_days, expected }. "This message gets a reply within 21 days." The hash is computed client-side; the server rejects any mismatch.

emitobserveresolve
02 / observe

Observe the truth

Ground truth arrives from the world — a reply, a conversion, a contradiction — and is recorded as an outcome. It joins its emission by reference, or lands unmatched until a resolver or a human joins it later.

emitobserveresolve
03 / resolve

Resolve the verdict

A deterministic resolver decides: correct, incorrect, or partial, with typed provenance. A nightly sweep closes anything now decidable — a late outcome, or a horizon that quietly expired.

emitobserveresolve
Coverage

One claim structure. Every venture.

The same emit→observe→resolve shape instruments radically different engines — cold outreach, extraction, checkout, rule assurance — with a ~20-line adapter each.

Ppanoptes signals
metric
actionable · 30-day horizon
claim
expected true
resolved · correct
Xxtracto outbound
metric
reply · 21-day horizon
claim
expected true
resolved · correct
pawtrait checkout
metric
conversion · 14-day horizon
claim
ad → sale, expected true
within horizon · pending
§pandect rule-assurance
metric
contradiction · 90-day horizon
claim
gate passed → expected false
rule stands · correct

emit() once · store the returned id · carry refs.watch_version → per-version calibration for free

The payoff

Claims become a number you can trust.

Only claimed emissions count. Calibration reports whether the machine's claims came true — grouped by venture, engine, metric, and methodology version, so a past report reproduces exactly.

ledger report hit_rate = mean over terminal resolutions · correct 1 · partial ½ · incorrect 0
Illustrative calibration report by venture and engine
venture / enginemetricclaimedresolvedhit ratebase ratemedian TTO
panoptes / signalsactionable4123880.710.6311 d
xtracto / outboundreply1,2041,1500.380.316 d
pawtrait / checkoutconversion96540.440.423 d
pandect / rule-assurancecontradiction4184020.980.02
base_rate — fraction of matched outcomes that were positive median TTO — time from emission to outcome asOf — filter on observed_at; the past is reproducible

Illustrative figures — the numbers a live ledger prints. TypeScript is authoritative; the SQL view is convenience only.

Why you can trust the record

An audit surface, not a database you can edit.

The guarantees are structural, enforced by the store and the chain — not by policy or good intentions.

append-only

No row is ever changed

A database trigger rejects every UPDATE and DELETEaletheia is append-only. Corrections are new rows, never edits. The store exposes no update verb to exploit.

hash-chained

Tampering is detectable

Each event carries a content_hash the server recomputes, and a chain_hash over its predecessor. seq is contiguous by construction, so a gap means a genuinely missing row.

bitemporal

The past is reproducible

Every read filters on observed_at — when the ledger learned a fact. Re-run last quarter's report today and get last quarter's answer, exactly.

single-writer

One writer, deterministic order

Inserts serialize under a per-insert advisory lock; the chain is assigned in one place. Retries reuse the client id as an idempotency key — the same id twice is a 200, never a duplicate.

deterministic

Resolvers are code, params are data

A resolver is a pure function keyed by rule id; its horizon and expectation live in a data row. The nightly sweep is idempotent — a re-run produces identical ids and cannot double-resolve.

minimal

Nothing to rot

Node-native TypeScript, no build step. HTTP is node:http, hashing is node:crypto, Stripe signatures are verified by hand. One runtime dependency: pg.

43tests — hashing, chain, tamper, append-only, resolvers, webhooks
0build steps — Node ≥ 22.6 runs the TypeScript directly
4engines instrumented, more on the same adapter
At a glance

Four packages. One contract.

packages/coreThe invariants. Canonical hashing, the chain, the verifier, validation, resolvers, sweep, calibration.
packages/ledgerThe SDK. emit · observe · resolve · annotate. Transport is injectable, so the round-trip tests need no server.
apps/ingestThe write path. Bearer-authenticated HTTP ingest, the Postgres store, and signature-verified Stripe / Shopify receivers.
apps/cliThe read path. ledger — emit, observe, resolve, verify, report, straight from the terminal.
The margin

Stop guessing whether it worked.

A machine that cannot see its own outcomes cannot improve. Give the fleet one honest record, and every claim it makes becomes a number you can hold it to.