Skip to main content
Every data store — databases, config, object storage, ZFS pools — is assigned one of four protection classes. There is no fifth class and no per-store exception outside the exemption tier below.

Why three numbers, not one

RPO alone does not describe protection. A real-time replica can have an RPO of seconds and still faithfully replicate a mistaken DROP TABLE five minutes after it happens — the replica is fresh and the data is still gone. Recovery window is a peer of RPO, not a footnote: it is how far back you can reach, not just how current the copy is.
  • RPO — how much recent data can be lost.
  • RTO — how long until the data is available to restore into a rebuilt guest.
  • Recovery window — how far back an error can still be corrected, not just how fast a crash can be recovered from.

Assignment rule

Every store gets its class by answering three questions, in order. Stop at the first one that applies.
  1. Is it reproducible byte-for-byte from infrastructure-as-code, or re-downloadable from a public source?P3. The source of truth lives elsewhere; regenerating it is the recovery path.
  2. Does anything outside the codebase — a human, an external API, a sensor — write to it such that the last hour cannot be recreated?P0. This is state nothing else remembers.
  3. OtherwiseP1.
P2 is unreachable by this tree. The only way into it is a written exemption with a named owner and a stated reason. That asymmetry is deliberate — it is how “a slow cold-standby recovery is not an acceptable default” gets encoded honestly. The default for anything new is P0 or P1; anything slower is a decision someone signed, not a default anyone drifted into.
RTO is honest, not aspirational. Nothing here implies automated failover. An RTO of ”≤ 30 min” means the data is available to restore into a rebuilt guest within 30 minutes — not that the service self-heals. A protection class is only real once a drill has demonstrated its RTO once; an undemonstrated RTO is a guess.

Derived vs source of truth

The question underneath every class assignment: is this store a source of truth — something writes to it that cannot be recreated — or is it derived — an index, cache, or rebuild target some other source of truth already covers? That single distinction is what collapses dozens of individually-named stores down to three classes plus one exemption tier. Search indexes, vector embeddings, session stores, and scrape caches are routinely P3 for this reason: the data they hold is regenerated from something else, not lost.

The telemetry contract

Every protection mechanism reports one line per run, with a fixed set of fields (timestamp, host, mechanism, job, class, outcome, age). Three rules keep the signal honest:
  • A job that has never run reports it explicitly — never a value that could be misread as “just ran.”
  • A host with nothing to protect says so explicitly, so silence from a healthy host stays distinguishable from silence from a dead one.
  • A skipped run is not a success. It is its own outcome, and it must carry a reason.
Mechanisms emit facts; the alerting layer decides what’s wrong. Absence of a report is caught the same way — by comparing what ran against what was expected to run, not by watching each mechanism individually.

Data platform resilience

A worked P0 example — replication and layered backups for a shared application database.

ZFS backup and replication

A worked example at the host layer — the 3-2-1 rule built as four escalating ZFS layers.