to-be 43: backups against mistakes, declared by modules, kept on the machine
Graduates research 030 into a design for ADR 0214, which merged without one and left the cycle check failing on main.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
---
|
||||
status: active
|
||||
status: graduated
|
||||
became: [03-DESIGN/01-to-be/43-backups-against-mistakes.md, 02-DECISIONS/0214-backups-guard-against-mistakes-and-stay-on-the-machine.md]
|
||||
initiated: 2026-10-05
|
||||
touches: [04-ISSUES/242-the-mesh-has-no-backups, 02-DECISIONS/0030-data-outlives-the-mesh-that-declared-it.md, 02-DECISIONS/0053-a-step-that-runs-on-a-schedule.md, 03-DESIGN/01-to-be/31-a-module-declares-its-fail2ban-jail.md]
|
||||
---
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
layer: to-be
|
||||
status: designed
|
||||
code: []
|
||||
updated: 2026-10-05
|
||||
decisions:
|
||||
- 02-DECISIONS/0214-backups-guard-against-mistakes-and-stay-on-the-machine.md
|
||||
- 02-DECISIONS/0053-a-step-that-runs-on-a-schedule.md
|
||||
- 02-DECISIONS/0085-a-secret-is-a-provision.md
|
||||
- 02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md
|
||||
---
|
||||
|
||||
# 43 — Backups against mistakes: a module declares its data, the node keeps restore points
|
||||
|
||||
**Every machine with data keeps a restore point of it for every night of the last two weeks, every
|
||||
week of the last two months and every month of the last half year, on the machine itself.** It is
|
||||
there for the day a person, an agent or the mesh does something wrong — drops a database, empties a
|
||||
bucket, runs a bad migration — and not for the day a disk dies (ADR 0214).
|
||||
|
||||
## The shape
|
||||
|
||||
- **A node seat, `node-backup`,** held on each machine by one module, named for the tool it wraps.
|
||||
It keeps one encrypted, deduplicating repository on the machine and runs a nightly scheduled step
|
||||
(ADR 0053). The repository's key is a secret provisioned to the holder (ADR 0085), held in the
|
||||
vault, so a person can open the repository without the holder running.
|
||||
- **A module declares its data in its manifest,** naming no node and no absolute path (ADR 0112),
|
||||
in one of two forms:
|
||||
- **a dump** — for a store provider: the command that writes a consistent, logical copy of each
|
||||
database it serves, run by the provider in its own container, its output handed to the holder.
|
||||
The provider covers every consumer it provisions, so a module that only *uses* a database
|
||||
declares nothing.
|
||||
- **paths** — for files a module keeps itself (mailboxes, the forge's attachments, a service's
|
||||
state directory), named through the module's own directory references.
|
||||
- **The mesh composes the declarations per node,** as it composes jails (to-be 31) and filters: the
|
||||
holder receives, as contributions, exactly the data of the modules assigned to its machine. A
|
||||
module assigned is covered the next night; a module unassigned stops being backed up, and its
|
||||
restore points age out by the rotation, never at once.
|
||||
|
||||
## A night
|
||||
|
||||
Each declared dump runs and writes a full logical copy; each declared path is read as it stands. All
|
||||
of it goes into the repository as one snapshot, tagged by module. The repository keeps only chunks it
|
||||
has not seen, so the object store's first night costs its full size and later nights cost what
|
||||
changed. Then the rotation prunes to 14 daily, 8 weekly and 6 monthly snapshots. A dump that fails
|
||||
fails the night for that module only; the others are still taken.
|
||||
|
||||
## The verbs
|
||||
|
||||
On the seat, for a person or an agent:
|
||||
|
||||
- **what is backed up here** — each module, what it declared, its last good night and its size;
|
||||
- **take one now** — for one module or all, before a risky act; a migration or a database's retirement
|
||||
calls it first;
|
||||
- **restore** — one module's database or path, from a named night, **beside** the live one: a database
|
||||
as `<name>_restore` owned by the consumer's role, a path as `<path>.restored-<date>`. Swapping it
|
||||
in stays a person's act. Nothing restores over live data.
|
||||
|
||||
## Where the repository lives
|
||||
|
||||
On the machine, outside every directory the mesh manages, on a filesystem other than the live data's
|
||||
where the machine has one. The holder's module names the place as a machine setting, never a path in
|
||||
a manifest. Not off-site: a lost machine loses its backups with its data, by the operator's choice.
|
||||
|
||||
## Proving it
|
||||
|
||||
- A night that fails, or does not run, reaches the operator's output channel, naming the module.
|
||||
- Weekly, the holder checks the repository's integrity and restores the newest dump of one database,
|
||||
in rotation, into a throwaway instance with no network, comparing table row counts with the live
|
||||
database.
|
||||
- The mesh's status lists every machine whose last good night is older than 48 hours.
|
||||
|
||||
## Not in this design
|
||||
|
||||
- Copies off the machine, and encryption to anyone but the mesh's own vault.
|
||||
- The media library and anything else a module declares no data for.
|
||||
- Recreatable things: container images, the artifact registry, caches.
|
||||
|
||||
## How it is checked
|
||||
|
||||
The catalogue check refuses a module that provides a store seat and declares no dump. The weekly
|
||||
restore test above, and the 48-hour status line, are the running checks.
|
||||
@@ -3,7 +3,7 @@ status: open
|
||||
opened: 2026-10-05
|
||||
located-in: []
|
||||
fixed-by:
|
||||
amended-design:
|
||||
amended-design: 03-DESIGN/01-to-be/43-backups-against-mistakes.md
|
||||
---
|
||||
|
||||
# 242 — The mesh has no backups
|
||||
|
||||
Reference in New Issue
Block a user