Repository navigation
Description
Problem
openclaw-backup.sh treats the one file the backup exists for — the agent state DB, state/openclaw.sqlite — as optional. If that file is absent at run time (state dir moved, DB renamed by an OpenClaw update, partial restore), the run still exits 0, prints the full success line, uploads the archive to both remotes, and advances the journal cursor. Every later restore from that date silently lacks the agent state, and nothing ever signals the loss: the manifest is generated from whatever staging produced, so archive verification is self-referential for this member.
This is the exact failure class the sibling script fixed with its expected set: pm-dashboard-backup.sh declares required members once (EXPECTED_SET, pm-dashboard-backup.sh:149-176, from #1025) and its verify step fails the run when a required member is missing. openclaw-backup.sh re-implemented the same pattern (DATE validation, lock, prune, journal cursor) but never got the expected-set half.
Evidence (verified this run, main 7b87168c)
nixos/home/openclaw-backup.sh:136-140— the sqlite snapshot is guarded byif [ -f "$OC/state/openclaw.sqlite" ]; the absent case falls through with no log line at all. A present-but-failing.backupdoes fail the run — only absence is silent.nixos/home/openclaw-backup.sh:160-176— the manifest is built by walking the staged tree;:259printsOK openclaw $DATE backed up to local + R2 + Driveunconditionally once the legs succeed. No required-member check exists anywhere in the script (grep: noexpectedin openclaw-backup.sh, vs the EXPECTED_SET block in pm-dashboard-backup.sh).nixos/home/openclaw-backup.test.sh— the suite'ssetup_homealways createsstate/openclaw.sqlite(line ~188); no scenario covers its absence.- Probe (laptop,
~/git/fleet/probe-2026-10-28-laneB-ocsqlite/; drove the real script, sha256ade2b21e…identical to main, with the test suite's stub pattern for bws/journalctl/sqlite3/rclone):- Control (sqlite present): exit 0, archive contains
./state/openclaw.sqlite, full OK line, marker advanced. - Missing DB (
.openclawotherwise intact:session.log,state/,tmp/): exit 0,local OK … (484 bytes …)and the fullOK openclaw 2026-10-28 backed up to local + R2 + Driveline, both offsite copies uploaded, journal marker advanced — and the archive listing contains./state/but nostate/openclaw.sqlite.
- Control (sqlite present): exit 0, archive contains
Why it matters
The backup's value is concentrated in that one file: it is the transaction-consistent snapshot the header (lines 14-18) calls out as the reason for the sqlite .backup step. A layout change upstream would degrade every daily backup to a state-less shell — logs and config survive, agent state does not — while the job reports success on all three legs indefinitely. The dashboard sibling already established the house rule: a required member missing at staging or verify fails the run, naming the member.
Acceptance criteria
- A run whose
$HOME/.openclaw/state/openclaw.sqliteis absent fails non-zero, naming the missing member, before any upload (no local archive promoted, no offsite copy, journal marker un-advanced) — or, if triage decides absence must be tolerated (e.g. a pre-first-run host), the run prints an explicit WARN naming the file and the manifest records the member as missing; silence is the one outcome not allowed. - The manifest/verify path records the state DB as a required member in the feat(home): install OpenClaw gateway via nix-openclaw #1025 sense: recorded present in the archive is checked at verify, not just at staging.
-
openclaw-backup.test.shgains a missing-sqlite scenario in the existing stub harness pinning the chosen behaviour; all existing scenarios still pass. - Behaviour with the DB present is unchanged: same archive layout, same OK line, marker advances only after all three legs succeed.
Triage note: fail-the-run mirrors pm-dashboard-backup's required-member rule and is the likely pin; the tolerated-with-WARN alternative is listed only because a brand-new host might legitimately have no state DB yet — triage decides which hosts that covers.
Activity
developing-today commentedon Oct 28, 2026
CODE-705
dezren39 commentedon Oct 28, 2026
🤖 Agent note · filed
7b87168cthatopenclaw-backup.sh:136-140guards the state-DB snapshot withif [ -f ... ]so a missingstate/openclaw.sqlitefalls through silently, and the script has no required-member/expected-set check (unlike pm-dashboard-backup.sh's EXPECTED_SET from feat(home): install OpenClaw gateway via nix-openclaw #1025). Laptop probe (real script, sha256 ade2b21e… = main, suite stub pattern): control with DB present passes with the file archived; with the DB absent the run exits 0, prints the full OK line, uploads both offsite copies, advances the journal marker, and the archive contains./state/but nostate/openclaw.sqlite.queue-packets/packet-1748.json(repo-health-code-pilot, triage); probe~/git/fleet/probe-2026-10-28-laneB-ocsqlite/(laptop)dezren39 commentedon Nov 1, 2026
🤖 Agent note · picked up
23 remaining items
dezren39 commentedon Nov 1, 2026
🤖 Agent note · parked
dezren39 commentedon Nov 1, 2026
🤖 Agent note · picked up / triage verdict
state/openclaw.sqlitefails the run before upload, archive/manifest verification independently requires the member, and tests cover missing-source and missing-snapshot with marker unchanged.dezren39 commentedon Nov 1, 2026
🤖 Agent note · done