Cutover: the old install is a reference, kept until someone says otherwise

John, 2026-09-19, on both counts. The old install is kept, shut down, not
removed: its unit installed and disabled, its store read-only, started
again if a rollback is ever wanted. When it stops being worth the disk the
tool asks — keep or delete — rather than deciding, because it does not
remove the thing its own rollback depends on.

And the new stack depends on nothing in it. That is the shape's purpose:
/opt/stalwart is a reference, everything needed is copied to new paths, and
when it goes nothing notices. Nothing in the fork works against that —
inbuxa.service substitutes its own prefix, no path names the old tree, and
certificates and ACME keys are in the registry inside the store — so a
dependency, if one appears, was made by hand during the move.

Which is worth proving rather than asserting, and reversibly: nothing open
under the old tree, then rename it and leave it a day under real traffic.
Deleting proves the same thing and cannot be undone.

Two corrections this forces. The rollback has to make the original store
writable again first: the guard of step 3 blocks the Enterprise build
exactly as it blocks the fork, and finding that out during a rollback is
the worst time. And the copy has to be chowned — rsync -a preserves
ownership, so it arrives owned by the old service user while the unit runs
as User=inbuxa.

Also drops the stale "untested" wording about carrying the data back. It
was tested; it is impossible.
This commit is contained in:
2026-09-19 22:45:09 -07:00
parent 7c27bae4f3
commit 3e69b6139f
2 changed files with 77 additions and 37 deletions
+10 -2
View File
@@ -111,10 +111,18 @@ A first-class path, not an appendix.
has flowed leaves that mail in the fork's store. The tool says how many
messages that is rather than letting the operator find out.
- **What it never does**: point the old server at the store the fork has
been writing. That has never been tested and is not a recovery path
been writing. That is not a recovery path and cannot be made into one —
the old build refuses to open a store the fork has touched at all
(`cutover.md`).
- **What it undoes first**: the read-only flag on the original store. The
guard that stops the fork opening it by mistake also stops the old build
starting on it.
- The old install is kept until the operator retires it deliberately. The
tool does not delete the thing its rollback depends on.
tool does not delete the thing its rollback depends on, and when the
operator is done with it the tool **asks** — keep, or delete — rather
than deciding. Nothing the fork runs on may be inside it by then, which
`verify` checks: no open file under the old tree, and no path in the
fork's config or unit naming it.
## Rehearsal