Skip to content

Fidelity

Every invariant DST proves is proven against the in-memory mock — so the honest question is always "and does the mock behave like the real engine?". This page is the measured answer, in two layers: the anomaly matrix (does the mock agree with real Postgres and Mongo on classic isolation phenomena, per level?) and the bug transfer (do the mock's verdicts on known bugs hold on the real engine?). Both are regenerated artifacts, never prose claims — just dst-fidelity and just dst-transfer re-run the differentials and rewrite the tables below.

DST fidelity matrix

Mock↔real verdict agreement for the isolation anomaly battery, per backend and IsolationLevel. = both backends produce the same verdict; = mock stricter (mock prevents, real permits — the false-confidence direction: simulation green, production bleeds); = mock weaker (mock permits, real prevents — the false-alarm direction: simulated violations reality cannot produce). A divergence is admissible only when a reviewed engine-scoped catalog entry explains it; an unexplained divergence fails the differential. There is deliberately no single agreement score.

Generated by just dst-fidelity — do not edit by hand.

mock ↔ postgres

Divergences — mock-stricter (▲): 0 · mock-weaker (△): 0 · unexplained: 0

case Adya READ_COMMITTED SNAPSHOT SERIALIZABLE
dirty_write G0 ✓ prevented ✓ prevented ✓ prevented
dirty_read G1a ✓ prevented ✓ prevented ✓ prevented
intermediate_read G1b ✓ prevented ✓ prevented ✓ prevented
non_repeatable_read G-single ✓ permitted ✓ prevented ✓ prevented
read_skew G-single ✓ permitted ✓ prevented ✓ prevented
phantom PMP ✓ permitted ✓ prevented ✓ prevented
write_skew G2-item ✓ permitted ✓ permitted ✓ prevented
predicate_write_skew G2 ✓ permitted ✓ permitted ✓ prevented
read_only_anomaly G2 ✓ permitted ✓ permitted ✓ prevented
lost_update G-single ✓ prevented ✓ prevented ✓ prevented
fresh_read_update ✓ permitted ✓ prevented ✓ prevented
duplicate_key_insert ✓ prevented ✓ prevented ✓ prevented
for_update_lost_update ✓ prevented ✓ prevented ✓ prevented

mock ↔ mongo

Divergences — mock-stricter (▲): 0 · mock-weaker (△): 4 · unexplained: 0

case Adya READ_COMMITTED SNAPSHOT
dirty_write G0 ✓ prevented ✓ prevented
dirty_read G1a ✓ prevented ✓ prevented
intermediate_read G1b ✓ prevented ✓ prevented
non_repeatable_read G-single △ mock permitted / real prevented (explained) ✓ prevented
read_skew G-single △ mock permitted / real prevented (explained) ✓ prevented
phantom PMP △ mock permitted / real prevented (explained) ✓ prevented
write_skew G2-item ✓ permitted ✓ permitted
predicate_write_skew G2 ✓ permitted ✓ permitted
read_only_anomaly G2 ✓ permitted ✓ permitted
lost_update G-single ✓ prevented ✓ prevented
fresh_read_update △ mock permitted / real prevented (explained) ✓ prevented
duplicate_key_insert ✓ prevented ✓ prevented
for_update_lost_update ✓ prevented ✓ prevented

Contract strengthenings (reviewed)

A Forze adapter prevents an anomaly the textbook contract permits — the only sanctioned way an observed verdict may deviate from the textbook, and the only thing that may explain a mock↔real divergence above.

anomaly level engine contract → observed source
lost_update READ_COMMITTED * permitted → prevented Berenson et al., A Critique of ANSI SQL Isolation Levels (P4, lost update)
non_repeatable_read READ_COMMITTED mongo permitted → prevented MongoDB manual, Read Concern & Transactions (WiredTiger snapshot semantics); asserted by the Mongo differential leg
read_skew READ_COMMITTED mongo permitted → prevented MongoDB manual, Read Concern & Transactions (WiredTiger snapshot semantics); asserted by the Mongo differential leg
phantom READ_COMMITTED mongo permitted → prevented MongoDB manual, Read Concern & Transactions (WiredTiger snapshot semantics); asserted by the Mongo differential leg
fresh_read_update READ_COMMITTED mongo permitted → prevented MongoDB manual, Read Concern & Transactions (WiredTiger snapshot semantics); asserted by the Mongo differential leg

Mechanism divergences (normalized, never verdict-level)

Surface differences between correct engines that the differential normalizes away before a verdict exists — listed for completeness; they can never explain a verdict divergence.

name source
abort-vs-block Cahill/Fekete, Serializable Snapshot Isolation; ept/hermitage
error-code-or-sqlstate vendor documentation
victim-identity ept/hermitage
repeatable-read-class Kleppmann, Hermitage: Testing the 'I' in ACID
skip-locked-degrades-to-for-update Postgres docs, SELECT FOR UPDATE SKIP LOCKED; RowLockMode contract
lock-block-vs-abort-conductor battery docstring; _drive_lock_race; Postgres FOR UPDATE EvalPlanQual; ept/hermitage
read-only-abort-vs-safe-snapshot Cahill/Fekete, Serializable Snapshot Isolation (read-only safe-retry optimization)
outbox-inbox-write-through forze_mock journal design (_journal.py, adapters/tx.py MockJournalTxManagerAdapter)

Corpus bug transfer

Mock↔real verdict pairs for every transferable misuse-corpus instance: the same hand-authored provocation (a forced port-level interleaving, a re-invocation, or a documented crash analog) runs on both backends, and the same final-state predicate — read back through the ports — decides detected/clean on each. = the verdicts agree; = mock artifact (mock detects, real clean — everything DST catches via that mutant is noise); = mock blind spot (real bleeds, mock clean — the dangerous direction: DST would green-light a real bug). There is no allowed-divergence catalog on this plane — any divergence is a finding.

Generated by just dst-transfer — do not edit by hand.

mock ↔ postgres

Instances: 19 mutants + 18 controls · mock artifacts (▲): 0 · mock blind spots (△): 0

mutant family tier mock real verdict
T1-blind-write-payment transactions conductor detected detected ✓ agree
T3-payment-outside-tx transactions conductor detected detected ✓ agree
T3-torn-activation transactions conductor detected detected ✓ agree
T3-double-torn transactions conductor detected detected ✓ agree
T4-weakened-oncall transactions conductor detected detected ✓ agree
T5-unchecked-reservation transactions conductor detected detected ✓ agree
I1-retry-without-key idempotency conductor detected detected ✓ agree
I2-naive-retry-loop idempotency conductor detected detected ✓ agree
M1-dual-write-shipment messaging fault-analog detected detected ✓ agree
I3-ack-before-processing idempotency fault-analog detected detected ✓ agree
M2-consumer-without-inbox messaging conductor detected detected ✓ agree
D1-skip-lock distributed conductor detected detected ✓ agree
D2-early-lease-release distributed conductor detected detected ✓ agree
D3-nonatomic-acquire distributed conductor detected detected ✓ agree
D4-unmerged-remote-hlc distributed conductor detected detected ✓ agree
D5-wall-clock-ordering distributed conductor detected detected ✓ agree
N1-drop-tenant-predicate data conductor detected detected ✓ agree
N3-unbound-cursor-walk data conductor detected detected ✓ agree
N2-stale-cache data conductor detected detected ✓ agree

Controls (expected clean on both backends)

control mock real verdict
ctrl-row-after-guard clean clean ✓ agree
ctrl-row-before-guard-in-tx clean clean ✓ agree
ctrl-atomic-provision clean clean ✓ agree
ctrl-unique-reservation clean clean ✓ agree
ctrl-retry-with-key clean clean ✓ agree
ctrl-atomic-pair clean clean ✓ agree
ctrl-idempotent-retry clean clean ✓ agree
ctrl-serializable-oncall clean clean ✓ agree
ctrl-merged-relay clean clean ✓ agree
ctrl-floored-append clean clean ✓ agree
ctrl-bound-cursor-walk clean clean ✓ agree
ctrl-release-after-write clean clean ✓ agree
ctrl-outbox-in-tx clean clean ✓ agree
ctrl-process-then-ack clean clean ✓ agree
ctrl-lock-protocol clean clean ✓ agree
ctrl-tenant-filtered-browse clean clean ✓ agree
ctrl-cache-invalidate-in-tx clean clean ✓ agree
ctrl-inbox-consumer clean clean ✓ agree

Not transferable — 1/20 mutants

Defects whose trigger or observable needs simulation-only machinery; their ground_truth stays undetermined by design, and the fraction is stated so a capped denominator never reads as full coverage.

mutant reason
T2-charge-before-guard The external charge is a trace-level marker by design (an effect that leaves the process, not a port write) — no real-backend final-state observable exists. The transferable sibling of this shape is T3.

Does anomaly divergence predict bug divergence?

The pre-registered predictor question: are matrix cells where the mock disagrees with the real engine on an isolation phenomenon also where corpus bugs fail to transfer? Protocol fixed before the data existed — each transferable mutant is mapped to the battery phenomenon its defect manifests through, its postgres cell is read at READ_COMMITTED (the level the corpus workloads run under), and the 2×2 is tested with the exact Fisher test. Both outcomes were committed to in advance: a predictive proxy (run the battery, trust the corpus) or a non-predictive one (the corpus-on-real run stays load-bearing).

Generated by just dst-transfer — do not edit by hand.

Mapped mutants

mutant phenomenon battery cell transfer mapping rationale
T1-blind-write-payment lost_update (G-single) ✓ agree ✓ agree the dropped rev guard lets the second writer blindly overwrite a concurrent update
T3-payment-outside-tx dirty_read (G1a) ✓ agree ✓ agree the outside-tx payment persists although its guard transaction aborts — the world observes an aborted transaction's effect (G1a shape)
T3-torn-activation intermediate_read (G1b) ✓ agree ✓ agree the torn state is a persisted intermediate of a logically-atomic activation (G1b shape)
T3-double-torn intermediate_read (G1b) ✓ agree ✓ agree two persisted intermediates of logically-atomic activations, observed together (G1b shape, doubled)
T5-unchecked-reservation predicate_write_skew (G2) ✓ agree ✓ agree both sessions evaluate the no-reservation predicate, then both insert (G2 shape)
T4-weakened-oncall write_skew (G2-item) ✓ agree ✓ agree the read-both/write-own rota constraint at SNAPSHOT is the write-skew shape verbatim (G2-item)
D2-early-lease-release lost_update (G-single) ✓ agree ✓ agree with the lease dropped mid-section, the waiter's read-modify-blind-write overlaps the holder's — a lost update on the document plane
D1-skip-lock lost_update (G-single) ✓ agree ✓ agree without the lock both workers read-modify-write the balance — a lost update on the document plane
D3-nonatomic-acquire write_skew (G2-item) ✓ agree ✓ agree check-then-act on the lock row — each session's check reads the row the other writes (G2-item shape)

The contingency table

transferred diverged
battery-clean cell 9 0
battery-divergent cell 0 0

Fisher exact (two-sided): p = 1.

Verdict

The data lands in the degenerate branch: the postgres matrix has zero divergent cells and the corpus run had zero transfer divergences, so both margins of the table are empty on one side and the test carries no evidence either way (p = 1 by construction). What the run does establish: every mutant in a battery-clean cell transferred — the hypothesis's clean-cell branch is consistent with all observed data — but the divergent-cell branch is unexercised, so the proxy's predictive power is untested, not confirmed. Per the pre-registered commitment, the conservative conclusion stands: the corpus-on-real run stays load-bearing; the battery is not certified as its substitute.

Outside the proxy's domain — 10/19 transferable mutants

These defects do not manifest through any isolation phenomenon, so anomaly conformance could never predict their transfer even in principle — for this part of the corpus the battery is not a proxy at all, only the transfer run speaks. This bound on the proxy's domain is itself a finding of the analysis.

mutant why no battery cell applies
I1-retry-without-key idempotency-plane defect — a duplicate re-invocation, no isolation phenomenon involved
I2-naive-retry-loop retry-plane defect — the duplicate comes from re-running a non-idempotent block; the conflict that triggers the retry is correct behavior, not an anomaly
M1-dual-write-shipment crash-atomicity across two planes (state + outbox); fault-triggered, not an interleaving
I3-ack-before-processing crash/redelivery defect on the messaging plane
M2-consumer-without-inbox duplicate-delivery semantics, not an isolation phenomenon
D4-unmerged-remote-hlc clock-discipline defect — the inversion comes from skewed stamping, not from any interleaving anomaly
D5-wall-clock-ordering clock-discipline defect — raw wall stamps under skew, no isolation phenomenon involved
N1-drop-tenant-predicate query-predicate/tenancy defect, no concurrency involved
N3-unbound-cursor-walk pagination-plane predicate defect (the resume drops the tenant filter), no concurrency involved
N2-stale-cache cache-plane invalidation ordering, outside the document isolation family

With a corpus this size the test is underpowered for subtle effects; the association worth acting on is the strong kind — a divergent cell with multiple diverging mutants — and none was observed.

Bugs the harness found in Forze itself

The strongest evidence is provenance. A git-history audit found three confirmed harness-found bugs — all surfaced by the conformance differential, which is exactly the component this page measures:

  • The mock's write-through dirty read. The default mock transaction manager let a concurrent transaction read another's uncommitted, later-rolled-back write — weaker than real read-committed. Found by the dirty_read battery case; fixed by buffering every write through the MVCC overlay. Pinned forever by the battery.
  • The revision-conflict kind divergence. On a stale-revision write the mock raised a different exception contract than every real adapter — an app's optimistic-concurrency handling would behave differently on the mock than in production. Found by the real-Postgres differential doing precisely its job; the mock (the outlier) was fixed to match.
  • The rev-guarded double charge. Making read-committed faithful exposed that two concurrent rev-guarded updates could both commit — a double charge. Fixed with first-committer-wins write-write rejection; the payments example's oracle keeps it caught.

The framing matters: these are differential catches, not seed-search catches — which is exactly what the tables above are for. Claiming more would be the overreach this page exists to prevent.

Which planes have a leg

A differential is only evidence for the plane it runs on, so the next question after "does the mock agree?" is "agree about what?". That answer is a manifest rather than a paragraph: [tool.conformance_manifest] in pyproject.toml names every plane, the scenario it runs, the contract ports it covers and the engines it must run against. just conformance-check (part of just quality) enforces it, and just conformance runs the legs themselves.

The manifest exists because the previous answer was prose, and prose does not fail a build. A plane could gain a backend whose only test ran against that backend alone, with nothing comparing it to anything, and CI stayed green. So the checker derives which packages actually register each plane's ports — from the integration packages, not from a list somebody maintains — and fails when one of them runs no leg. Adding a backend now means adding its leg or writing down, in the manifest, why there isn't one.

That check runs before the suite does, so it can only prove a leg exists. Existing is not running: a leg whose engine never starts, whose optional extra is missing, or whose suite is absent from CI's matrix skips quietly, and a skipped test looks exactly like a passing one in a green pipeline. So each CI shard also records what it actually ran, per leg, and a final job unions those records and fails on any manifested leg that passed nothing anywhere. That gate earned its place immediately: it found that two of the four inference legs, and the whole portability suite, had never run in CI at all. Individual skips inside a leg stay allowed — a check that cannot apply to an engine should skip with a reason naming it — but they are reported, so a leg quietly hollowing out one check at a time stays visible.

Uncovered planes are declared rather than omitted, which is the part worth reading:

Gap Engines with no differential Why it matters
queue RabbitMQ, SQS two brokers, no comparison of publish/consume/nack/redelivery
analytics BigQuery, ClickHouse, DuckDB, Postgres four engines answer the same ports
durable_function Postgres, Inngest replay determinism and step idempotency uncompared
kms Vault (plus the AWS/GCP/Yandex/local backends) wrap/unwrap/rotate under one AAD

Read that table as the honest complement to the green matrices above: those planes are tested, they are simply not compared.

Deriving the requirement from the code is what keeps that table honest, and one plane needed help to manage it. Field encryption's ports are resolved by the adapters that seal values rather than registered by a backend, so the census sees no providers for them — and a derivation that finds nothing requires nothing, which is a ratchet that cannot fail. The manifest lets such a plane name a proxy instead (derive_from), and here the proxy is exact rather than approximate: the battery is document-plane specific, so "which backends need a field-encryption leg" is "which backends provide a document port". A misspelled proxy key is a hard error for the same reason — it would derive from nothing and look like success.

Known differences that are real and expected live in forze_dst.conformance.catalog as data, not prose. Each row records what each engine did, what was done about it (unified, normalized, or declared), and a probe naming the test that asserts it — a link the checker resolves against real pytest collection, so a catalog entry cannot outlive the test behind it.

One row is worth reading for a different reason: it records a case where the oracle could not be wrong, because it could not model the outcome at all. The storage port lets a caller ask list(missing_ok=False) so a vanished bucket can be told from an emptied one — the distinction the re-encryption sweep is built on. The mock reached its bucket through setdefault, so the bucket existed the instant anything looked at it and the parameter was documented as a no-op. That is a stronger failure than "untested": no test written against that oracle could have failed, so every mock-backed test of the contract was green without exercising anything. Closing it meant giving the mock the concept first — reads never provision, the documented write paths do — and the sweep's own test then had to say which state it meant, having asserted "empty" while exercising "absent". The leg then went a step past the raise: missing_ok=True still reports container_missing on the page it returns, because tolerating an absent bucket should not mean being unable to see one. With per-tenant buckets that is the difference between a tenant nobody provisioned and a tenant that has uploaded nothing, and every backend in the leg — MinIO, floci, GCS, the mock — is held to it.

A third row records the one interaction none of this page's other machinery can reach. The offline mailbox bounds a reconnect replay by a retention cap, and clients ack cumulatively — "I have everything up to this id". Each is fine alone; together, a replay that delivered an incomplete window plus an ack on a live frame lets the cursor jump the gap, and the trim floor then deletes signals that were never sent. Nothing raises. Simulation cannot find it either, because the race lives in document-port code rather than stream code, so no schedule the explorer drives will interleave it. The leg drives that interleaving directly against the mock, Postgres and Mongo, and its controls reconstruct the fault by truncating the replay — so the check is known to fail when the guarantee does, rather than merely passing today.

One divergence there is worth reading as a pattern rather than an entry. The inference port is declarative: each adapter publishes an InferenceCapabilities and the shared validators gate requests against it, so "does this call get through?" is a property of the declaration, not of the model behind it. A mock told nothing advertises the full surface — unbounded batches, streaming, async jobs — which is true of the mock and truer than any backend it stands in for, so a capability gate that passes against the oracle can still refuse in production. The fix is a wiring obligation (MockInferenceRegistry.on(..., capabilities=…)) and it cannot be defaulted away, because the mock is also used where no backend is being mirrored at all. So the differential carries it instead: the battery compares a backend's gates against a mock built from that backend's own declaration, and asserts that an untold oracle disagrees — which is what makes forgetting the wiring fail at authoring time rather than in production.

What these numbers license — and what they don't

  • A green matrix licenses trusting the mock for the phenomena, levels, and backends tested — the isolation family on Postgres and Mongo. It says nothing about untested planes, and the gap table is where those are named.
  • The transfer table is the direct evidence, at found-bug granularity — and its N is what it is: every transferable corpus instance, currently against Postgres.
  • The transfer leg's zero is not a sampling result, and no interval will ever be attached to it. Elsewhere in DST a zero comes with a bound, because it is a zero out of repeated independent draws: detection statistics can say "0 violations in 1000 seeds licenses < 0.30%" precisely because there were 1000 chances. Here each transferable mutant runs once per backend under a deterministic verdict predicate. There is no repetition, no rate, and — because the corpus is hand-authored rather than sampled from the population of real defects — nothing a frequentist interval could be an interval over. "Does the mock's verdict hold on the real engine?" is an epistemic question, and a binomial bound on "0 divergences in K mutants" would be a category error dressed as rigour. The honest artifact is the list of what has been checked and the gap table naming what has not: untested, not confirmed.
  • The pre-registered predictor analysis is currently uninformative by construction (zero divergence on either plane), so the battery is not certified as a substitute for the transfer run — and for the corpus's non-isolation half it could never be one.
  • Logic below the port — triggers, generated columns, database views — is outside every oracle here. An invariant maintained by a trigger must be covered by an integration test, not by simulation — and that exclusion is now checkable, not just prose: declare it with a HorizonDeclaration naming the covering test, and per-invariant accounting keeps the clean verdict scoped to invariants the harness has been shown able to catch (see what a green run doesn't say).
  • A divergence is admissible only through the reviewed catalogs above; an unexplained one fails the build. There is deliberately no single "fidelity score" anywhere on this page — the two divergence directions have opposite costs, and averaging them would hide exactly the one that ships bugs.