- fault-injection cargo feature (compiled OUT of prod): slow-fsync + disk-full WAL hooks in tidal/src/fault.rs, inert until armed, tier-3 builds with feature - first-class invariant checkers (tests/support/invariants.rs): AckLedger no-acked-loss (now consumed by m11p3 gate), feed parity, single-leader-per-term, monotonic frontiers - cluster_faults.rs tier-3 suite 4/4: disk-full degrade+recover, slow-fsync lag+converge, both-slow quorum 503, asymmetric partition no-split-brain - tidal-stress soak gates: --json-summary + --max-p99-ms/--max-error-pct/ --fail-on-knee → non-zero exit on regression - Woodpecker cron nightly flow (chaos + gated soak), event-routed, not GH Actions - guarantee-traceability.md: roadmap §2 guarantees → named tests (closes G-C apparatus; 30-day-green is a calendar criterion)
7.1 KiB
Enterprise-Guarantee → Automated-Test Traceability (m11p9)
This is the m11p9 exit-gate artifact: every guarantee in roadmap-to-cluster.md §2 maps to a named automated test (the second half of the GA bar is the calendar one — the nightly suite green for 30 consecutive days; see phase-9.md).
Each guarantee lists the named test(s) that prove it, the fault class each one
injects (where applicable), and the first-class invariant checker
(tidal-server/tests/support/invariants.rs)
it asserts through. All mp_* tests are tier-3 over REAL OS processes
(MultiProcCluster); partitions sever real loopback TCP; the disk-full /
slow-fsync faults return a real ENOSPC / sleep the real fsync behind the
fault-injection feature (tidal/src/fault.rs).
Run any suite locally:
cargo test -p tidal-server --features "cluster-e2e fault-injection" --test <suite> -- --test-threads 1 --nocapture.
Every named test that EXISTS below runs nightly via the cron pipeline in
.woodpecker.yaml: the chaos/correctness suites and
the gated soak in nightly-chaos/nightly-soak, and the G-Sec/G-Op owner-tests
(mTLS, cluster_security, tidalctl backup/restore, WAL-archival) in
nightly-security-ops. The one exception is the G-S throughput gate, which
is not yet written (m11p6 L4) — its row is marked accordingly.
| Guarantee | Named automated test(s) | Suite | Fault / scenario | Invariant checker |
|---|---|---|---|---|
G-D Durability — ack=quorum 2xx ⇒ majority-durable; SIGKILL any node ⇒ zero acked loss |
mp_quorum_ledger_zero_acked_loss_across_killpoints |
cluster_quorum |
SIGKILL leader across N random kill-points under quorum load | AckLedger (frontier + content) |
mp_auto_failover_writes_resume_zero_acked_loss |
cluster_election |
SIGKILL leader, auto-elect, across kill-points | AckLedger |
|
mp_disk_full_follower_degrades_no_acked_loss |
cluster_faults |
disk-full (ENOSPC) on a follower | AckLedger + MonotonicCounters |
|
mp_slow_fsync_follower_lags_but_quorum_holds, mp_slow_fsync_both_followers_force_honest_quorum_timeout |
cluster_faults |
slow-fsync on one / both followers | AckLedger |
|
mp_follower_reseeds_via_snapshot_after_compaction, mp_quarantined_node_reseeds_without_wipe |
cluster_reseed |
WAL compaction past cursor / divergent-suffix quarantine | content probes | |
| G-A Availability — single-node loss ⇒ reads continue, writes resume <10 s, no dual-leader | mp_auto_failover_writes_resume_zero_acked_loss |
cluster_election |
leader SIGKILL → election (<10 s) | AckLedger |
mp_fenced_ex_leader_restart_cannot_write |
cluster_election |
partition leader away, restart while fenced | fencing assertions | |
mp_flapping_links_bounded_churn |
cluster_election |
repeated link flaps | single-leader-per-term | |
mp_asymmetric_partition_no_split_brain_no_loss |
cluster_faults |
asymmetric partition (inbound severed, outbound up) | assert_single_leader_per_term + AckLedger |
|
mp_self_heal_converges_without_operator_verb |
cluster_chaos |
gRPC link sever, no operator verb | feed parity | |
| G-S Scalability — write throughput scales with shard count at RF=3 (≥2.5× 1→3) | (NOT YET WRITTEN — m11p6 L4) the 3 shards × RF=3 ≥5,000 quorum signals/s gate + tidal-stress --write-path path-collapse comparison |
pending m11p6 L4 | sharded × replicated scaling | throughput gate |
| G-E Elasticity — online add/remove/replace; snapshot+stream catch-up; p99 <2× for <60 s | mp_scale_3_5_3_under_load_zero_loss, mp_seed_join_snapshot_catchup, mp_dns_hostname_topology_replicates |
cluster_membership |
scale 3→5→3 under load; seed-join after compaction | AckLedger (lost=0), p99 bound |
| G-Sec Security — all inter-node links mTLS; authenticated RPC; rotation no downtime; admin audit | http_tls_serves_ca_trusting_client_and_rejects_foreign, http_tls_cert_rotation_under_load_drops_zero |
cluster_security |
foreign-CA client rejected; cert hot-rotation under load | zero-drop assertion |
mtls (foreign-pod ship rejected), cluster::security unit tests (token mint/verify, marker-not-bypass) |
tidal-net/tests/mtls.rs, engine unit |
foreign pod cannot ship or call internal routes | negative tests | |
| G-O Observability — per-node Prometheus metrics; dashboard answers golden signals; alerts on lag / commit stall / election churn | per-node /metrics listener + tidaldb_cluster_* set (m11p8); grafana-dashboard.json "Cluster Replication" row (12 panels); prometheus-alerts.yaml tidaldb-cluster group (8 rules) |
cluster_runbook (runbook_s5_health_and_openapi) + artifacts |
metric/alert presence | artifact + status tests |
| G-Op Operability — rolling upgrade N/N+1 under load (CI gate); backup/restore + PITR drilled; runbooks executable | mp_rolling_upgrade_no_loss_no_stall (the Woodpecker release gate) |
cluster_lifecycle |
graceful SIGTERM → version-tagged restart → heal → fixpoint under load | AckLedger |
backup_then_restore_roundtrips, restore_rejects_corrupted_backup, online_compaction_archives_before_deleting |
tidalctl / engine |
offline backup/restore integrity; gap-free WAL archival (PITR) | BLAKE3 manifest | |
runbook_s5..s11 (full operator playbook) |
cluster_runbook |
failover / partition / shutdown+recovery drills | per-drill | |
| G-C Continuous correctness — nightly chaos + soak green 30 consecutive days | the entire cluster_faults suite + the nightly-chaos/nightly-soak cron pipeline + tidal-stress soak regression gates + THIS matrix |
cluster_faults / .woodpecker.yaml / tidal-stress |
all fault classes nightly; soak p99/error regression gates | all four checkers |
Honest status of the bar
- G-D, G-A, G-E, G-Sec, G-Op — each maps to a green named test that runs in the nightly pipeline. ✅
- G-S (Scalability) — the sharding × replication data plane is in place
(m11p6 L0–L2); the ≥5,000/s 3-shard×RF=3 throughput gate and the
tidal-stresspath-collapse comparison land with m11p6 L4. The named owner-test is recorded here so the guarantee is not orphaned. ⏳ (tracked in m11p6.) - G-O (Observability) — proven by artifact + presence tests (the metric set, the dashboard, the alert group) rather than one behavioral test; the golden-signal coverage is the m11p8 exit-gate evidence.
- G-C (Continuous correctness) — the apparatus is complete and green (the fault suite passes; the cron pipeline runs every named suite + the gated soak). The remaining half of the bar is calendar: 30 consecutive nightly-green days before GA. That cannot be completed in one session — the pipeline is what produces it. ⏳ (accrues nightly.)
- Ref-A line items — the throughput / 100k-item / 1-hour-soak figures that
must run on the live 3-region k3s cluster remain blocked on k3s access (the
standing M11 caveat from m11p1–p3); the in-runner soak gates regressions
locally and the same
tidal-stressinvocation targets Ref-A when reachable.