KynetraDB verification

Reliability

This is not a claim that the database is finished. It is a description of how we know what we know — which tests exist, which run by default, what adversarial review caught that the happy-path suite missed, and where the evidence stops.

2,000 Raft simulation seeds (opt-in sweep)
21 Workspace crates
0 openraft dependencies
4 Serious bugs review caught

Deterministic simulation

Raft is hand-written, and simulated

Consensus is implemented from scratch rather than delegated to a library — openraft appears zero times in the lockfile. That is a deliberate choice with a cost attached: it means the correctness burden is ours, so it is discharged by FoundationDB / TigerBeetle-style deterministic simulation rather than by trust.

Test Seeds Runs by default? Asserts
raft_survives_1000_seeds 0..1000 no — #[ignore] Never two leaders in one term, under injected faults.
shard_groups_survive_1000_seeds 0..1000 no — #[ignore] Shard-group membership survives the same fault schedule.
raft_survives_100_seeds 0..100 yes Converges to exactly one leader.
shard_groups_survive_100_seeds 0..100 yes Per-seed shard-group run.
running the exhaustive sweep bash
# The 100-seed gates run in the normal suite.
cargo test -p kynetra-raft

# The 2,000-seed sweep (2 tests x 1,000 seeds) is opt-in, because each
# injected restart does a real WAL replay:
cargo test -p kynetra-raft -- --ignored

Adversarial review

What review caught that the tests did not

Every build slice passes through the same gate: an independent verify pass re-runs the coding agent's own tests rather than trusting its report, then an adversarial review hunts specifically for crash, restart and concurrency bugs that pass happy-path tests. Nothing lands until a re-verify comes back clean.

Silent data loss

A stale checkpoint could resurrect restored-away entities and drop new writes

restore_to_seq / delete_all left stale on-disk checkpoint artifacts, so a later delta linked onto a stale base. Two failures at once: restored-away entities came back, and new post-restore writes that reused sequence numbers were silently dropped after the next boot.

Fixed structurally as the Tideline guarantee: delete checkpoint artifacts before truncating the WAL, fence detached writer threads with a monotonic checkpoint epoch, and delete any checkpoint the reject-guard discards on open. Two adversarial rounds; round 1 alone found six follow-on findings including a detached-writer TOCTOU.

Silent data loss

WAL-tail loss: entities written between checkpoint and restart vanished

Engine::open seeded last_checkpoint_seq but never seeded dirty_ids from the replayed WAL tail, so the first post-reboot delta claimed a coverage range that omitted those records. Reproduced exactly: 5 puts, restart, 2 puts, restart, 5 puts, restart — the count was 10 when it should have been 12.

Fixed by seeding dirty tracking from the tail replay, with red-to-green regression tests covering both the row and columnar checkpoint formats.

Cross-tenant takeover

A project-plane credential could assert platform authority

One root cause, three routes. A tenant holding its own project's jwt_secret (previously leaked in project-JSON responses) could mint a JWT whose sub was a victim org's owner uid and pass the owner check — rotating the victim's keys or deleting the victim org. Separately, cluster and settings routes did bare role=="admin" checks that a per-project service key satisfied. And namespace selection came from an unverified pid JWT claim.

Took three review rounds — each of the first two found a HIGH cross-tenant hole, including one that the previous round's own fix introduced. That is precisely why the final fix is structural (Bulkhead) rather than point-patched. Round 3 shipped with a full enumeration of every remaining role check, proving no admin route was missed.

Account takeover

The export path handed out brute-forceable OTP hashes

The t_{pid}___ prefix scan is exactly right for isolation and wrong for sensitivity: a tenant's own namespace includes its auth kinds. auth_otp stores an unsalted SHA-256 of a 6-digit code — all 106 hashes take milliseconds on a laptop. Anyone holding an export taken during a live 15-minute OTP window could recover the code and replay it to take over an end-user account. The same file carried session token hashes and password hashes for offline cracking.

Fixed by redacting at the export boundary (Ferry), keyed on the auth crate's own kind constants rather than string guesses. The lesson generalises: an export boundary needs a sensitivity filter distinct from its isolation filter.

Silent failure

A restore reported success while writing zero rows

HttpSink counted a non-2xx response as a successful write, so a restore that wrote zero rows reported full success. Separately, ScopedSink re-scoped only kind and not id, so restores minted fresh ids instead of preserving them.

Both fixed; the NDJSON restore path is now byte-faithful including embeddings, and the attrs-only HTTP path is documented as such rather than advertised as a full restore.

Verification method

A test that cannot fail is not evidence

The discipline that matters most is proving a guard test has teeth: revert the guard, watch the test fail with the exact expected message, restore it, watch it pass. A green test beside an untested guard is theatre.

Redaction proven by reversion

Reverting the export exclusion guard makes the test fail with OTP code_hash leaked, and it passes once restored. The guard is therefore load-bearing, not decorative.

Cross-tenant leak proven by reversion

No-op'ing the per-kind index retraction makes the leak test fail with the exact cross-tenant message. Pinned per storage profile.

Mutations must reconstruct the defect

Disabling code near a bug proves nothing if that code is not load-bearing for the input. A mutation has to reconstruct the real defect to count.

Test the branch production takes

SPANN's large-filter branch is the only one production reaches, and it was the one without coverage — the committed matrix test sat entirely under the dispatch threshold. See Lodestar.

A single green run is not evidence

For a contention-dependent failure, one passing run says nothing. Timeouts inside a parallel suite are liveness bounds — hang detectors — not performance assertions.

Flaky gates get stable fixtures, not lower bars

A nondeterministic corpus makes a knife-edge quality gate flake. Fixtures get stable ids; the gate itself is left alone and any resulting headroom is documented rather than quietly enjoyed.

Recorded suite results

The numbers we can actually cite

These are per-slice results as recorded in the dated benchmark ledger at the time each change landed. They are the figures with provenance.

Slice Suite result Failed Commit
Bulkhead — tenant isolation kynetra-server 215 tests (197 lib + 16 + 2) 0 fc469ee
Ferry — export + redaction server 204 + 16 + 2; migrators 38 + 1 0 f9fe907
Meridian — per-kind index 129 lib + all integration suites 0 3755145
Tideline — durability kynetra-core green (exit 0); restore_checkpoint_consistency 6/6; checkpoint 13/13 0 a9e39ad + 16a8c5e