restic: finish the failure-alert rollout on kai-server, and test the restore path #917
Labels
No labels
burndown-2026-06
burndown-2026-08
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/advocate
role/director
role/exec
role/frontend
role/gamedev
role/human
role/platform
role/qa
role/science
role/sysadmin
state
ambient
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/infrastructure#917
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Not the question that was asked
The question was whether the 208.5 GB restic repo on ser8 holds too many backups and should be pruned for space. It does not, and the space case is weak. The check for a retention policy turned up a coverage problem instead, which matters more.
Coverage has holes
Repo
/var/lib/rest-server/repos/kai-server, created2026-08-01 18:19. Snapshots by date:15 snapshots across 24 days. Missing dates:
Recent cadence is clean: every day from the 16th through today. So whatever caused the six-day gap appears to have stopped, but nothing recorded that it happened and nothing would have surfaced it. A six-day hole in the only working backup of kai-server is a real RPO gap, and it was invisible until someone counted files by hand.
No retention policy is running
Every snapshot since repo creation is still present.
restic forgetdeletes snapshot files, and none are missing other than the never-taken dates above. So noforget --prunehas ever run against this repo.That means the repo grows unbounded. 208.5 GB in 24 days is not alarming on its own, since restic deduplicates and most of that is the initial snapshot, but the trajectory is unmanaged rather than chosen.
Why not prune now
Recommending against acting on this for space reasons:
restic forget --pruneis irreversible and destroys recovery points. Running it against a repo whose policy nobody has chosen, to reclaim space nobody needs, is the wrong trade.Space is the weakest reason to touch this repo. Coverage is the good one.
Worth doing instead, unsequenced
--keep-daily/--keep-weekly/--keep-monthly), then let prune follow from it. The policy decision comes first; the reclaim is a side effect, not the goal.Evidence
Read-only inspection over SSH: directory listing of
snapshots/sorted by mtime, andstatonconfigfor repo creation time. No restic command was run against the repo and no credentials were used, so snapshot contents and sizes are not verified here, only their existence and timing.Correction on the central finding. There is no six-day backup gap. Aug 10 through Aug 15 is the retention policy working as designed, and
restic forget --prunehas run against this repo.The inference in the body was that missing snapshot dates meant missing backups. It is the opposite: those dates are missing because prune deleted them.
restic-prune is deployed, enabled, and running
It runs on ser8, not kai-server, which is why it is easy to miss.
systemd/restic-prune.timerand.servicein this repo, installed at/usr/local/sbin/restic-prune:is-enabledreturnsenabled. Last runResult=success,ExecMainStatus=0.The journal for that run is unambiguous:
scripts/restic-prune.shdefaultsRESTIC_REPOSITORYto/var/lib/rest-server/repos/kai-server, so it is this repo, not another one. The policy is already chosen in code:--keep-daily 7 --keep-weekly 4 --keep-monthly 3.The retention math accounts for every missing date
Current snapshot files by date on ser8:
Prune ran 2026-08-23.
--keep-daily 7from that date retains Aug 16 onward, which is exactly the unbroken run the body noticed. Everything earlier is thinned to weekly and monthly.The survivors before Aug 16 are
08-04 x2, 08-05, 08-06, 08-07, 08-09. That is 7 snapshots, and--keep-weekly 4plus--keep-monthly 3is 7. Exact match, not a coincidence.Aug 02, 03, 08, and 10 through 15 were deleted by policy. So were the six the journal reports removing.
What this changes
What survives, and it is the real finding
Item 2 stands, and it is now the whole issue. Neither
restic-backup.servicenorrestic-prune.servicecarries anOnFailure=. Verified by grep against both units. A failing backup would be silent exactly as the body argued, and the only reason that has not bitten is that it has not failed.Current backup health, for the record:
restic-backup.timeron kai-server is enabled, last run Mon 2026-08-24 04:30:36 PDT withResult=successandExecMainStatus=0, next fires Tue 2026-08-25 04:59:19 PDT.Item 4 also stands. The restore path is still untested and an untested backup is still a hypothesis.
Suggest retitling to the failure-surfacing gap, since the gap and the retention policy in the current title are both resolved.
How this was checked
Read-only throughout.
systemctl list-timers,is-enabled, andshowon both hosts,journalctl -u restic-prune.service, a directory listing ofsnapshots/, andgrepagainst the unit files in this repo. No restic command was run against the repo and no password file was read.Failure surfacing landed in #921, plus a follow-up in #922. This is the item that survived the correction above, and it is now half rolled out.
What shipped
Both units carry
OnFailure=restic-failure-alert@%N.service. The handler posts the unit, itsResultandExecMainStatus, and the tail of its journal to the Telegram red channel, reading the token from thefleet-o11ycache theo11y-telegramrole already stages.Two things worth recording:
-Kconfig, which curl parses line by line, so every send would have died atoption -K: error encountered when reading a filebefore any request left the host. An alerter that silently does not alert is precisely what this issue asked to prevent. Only the token and chat id go through the config now; the journal text is on argv where curl URL-encodes it. Verified against a local sink with a hostilejournalctlemittingurl = "http://evil.example/pwn": it arrives as encoded body text and nothing reaches that host.%nversus%N.%nkeeps the type suffix, so the handler instantiated asrestic-failure-alert@restic-prune.service.service. It worked, but the name reads like a bug in exactly the place someone meets it during an incident. Fixed in #922.Rollout status
ser8: done and verified.
systemd 259 instantiates and runs it to
status=0/SUCCESS.kai-server: not applied. It fails unattended with
Missing sudo password, which is environmental rather than anything about this change. Sorestic-pruneis covered andrestic-backupis not, andrestic-backupis the one that matters more.The same wall is blocking the k3s pod-resolver fix in #864. If it keeps recurring it deserves its own issue.
Still open on this issue
Item 4 from the body: the restore path is untested. Nothing here changes that, and an untested backup is still a hypothesis. Related: #262.
Suggest this issue stays open for item 4 and the kai-server rollout, and that the title moves off the gap and retention framing, both of which were resolved or never real.
restic backups of kai-server have a 6-day gap and no retention policyto restic: finish the failure-alert rollout on kai-server, and test the restore path