Skip to content

feat(s19): snapshot producer, restore-check, live doctor probes, bundle folding - #64

Merged
im-tyler merged 3 commits into
mainfrom
w5/s19-snapshot-restore
Oct 4, 2026
Merged

im-tyler merged 3 commits into
mainfrom
w5/s19-snapshot-restore

Conversation

@im-tyler

@im-tyler im-tyler commented Oct 4, 2026

Copy link
Copy Markdown
Contributor

What

The S19 tail from the programme (row #49): the snapshot producer, the restore-check command, doctor's store/clock probes, and folding doctor + the latest backup receipt into the support bundle.

  • teploy-ship snapshot — produces the same archive shape as scripts/ship-backup.sh backup (<label>-<date>/nucleus-data-full.tgz + .sha256 sidecar + manifest.txt under SHIP_BACKUP_DIR, default /_backups). Refuses while any ship-* container it can see is running, printing the exact coordinated docker stop it expects, unless the operator attests with --i-stopped-writers. Never overwrites; never deletes anything except its own partial output after a failed production (so a failed tar cannot occupy the label+date slot forever — retention stays the operator's). Docker absent/unreachable is advisory, not a refusal: a box without docker can still take a snapshot.
  • teploy-ship restore-check <archive> — verifies WITHOUT unpacking: sha256 sidecar in sha256sum -c form (the sidecar must travel with its archive), full-stream gzip integrity (node zlib, the honest gzip -t), and the tar content listing, failing on absolute or .. paths that would escape an unpack target. Exit 0 only for verified. The verdict is integrity-only and names the rehearsal (scripts/ship-backup.sh rehearse) as the restore proof — the unpack and rehearse steps stay in the script by design.
  • doctor — store-connectivity and clock stop reporting blind unknowns when NUCLEUS_URL is set: read-only liveness (SELECT 1) and skew against the store's own clock (SELECT now()), each degrading to unknown rather than guessing. Store CONSISTENCY is deliberately not probed (cannot be established read-only while writers run); with no configured store both stay unknown and say why.
  • Support bundle (scriptVersion 2) — now carries doctor.json and backup-receipt.txt (the latest backup manifest — the receipt, never the archive), both through the redaction gate and both degrading to note files.

Verification

  • pnpm run lint clean; pnpm run build clean.
  • Full pnpm test: 2180/2180 root, 222/223 scripts (1 skip = ship-backup.test.mjs rehearse-without-docker on a docker-present machine; the grader-sensitivity port-8901 test passed on the recorded run — it is the documented CI-run item on contention).
  • New tests, fake fixtures only, no live systems:
    • src/snapshot.test.ts (11): archive shape parity with the script, running-writer refusal with the exact stop line, --i-stopped-writers attestation recorded in the manifest, docker-unavailable advisory, overwrite refusal with bytes unchanged, dry-run writes nothing, failed-production cleanup + retryable slot, tampered sidecar / wrong-name sidecar / missing sidecar, truncated archive with a re-computed sidecar caught by gzip (the checksum alone cannot), path-escape listing, receipt selection (newest, skips rehearsals, bounded).
    • src/install-doctor.test.ts (+4): SELECT 1 liveness true/false, store clock parsed from Date/number/ISO, garbage/throwing time query degrades the clock to unknown (runDoctor reports incomplete, not ready), probes wired through runDoctor (answering store = ready; silent store = not-ready with clock unknown).
    • src/support.test.ts (+2): bundle carries redacted doctor.json + receipt; both degrade to notes.
  • CLI smoke-tested end to end against a fake ship root: dry-run, produce, overwrite refusal, restore-check, the script's own verify accepting the CLI-produced archive, and a file-store support bundle containing both new files.

Deliberately deferred

  • The unpack (restore --into) and rehearsal remain script-only — they touch a live recovery.
  • restore-readiness.ts still has no command of its own.
  • Nothing in this tail has run against a live store or live docker; the probes are proven against fakes per repo discipline.

Programme row #49 and AUDIT_OPEN.md updated to match. No upstream defects found. DO NOT MERGE (slice discipline).

…le folding

Productizes the practiced procedure in scripts/ship-backup.sh where that is
safe, keeping its invariants load-bearing in the CLI too:

- teploy-ship snapshot: same archive shape as the script (tar of the nucleus
  data dir + sha256 sidecar + manifest); refuses while ship-* containers run
  unless the operator attests the coordinated stop (--i-stopped-writers);
  never overwrites; never deletes anything except its own partial output
  after a failed production so a failed tar cannot wedge the label+date slot.
- teploy-ship restore-check: verifies an archive WITHOUT unpacking (sidecar
  in sha256sum -c form, full-stream gzip integrity, content listing failing
  on absolute/.. paths); verdict is integrity-only and names the rehearsal
  as the restore proof. The unpack and rehearse stay in the script.
- doctor: store liveness (SELECT 1) and clock skew against the store's own
  clock (SELECT now()) probed read-only when NUCLEUS_URL is set; unknown
  otherwise or when the engine answers no time query; store consistency
  deliberately not probed (read-only while writers may run).
- support bundle (scriptVersion 2): doctor.json + the latest backup manifest
  (the receipt, never the archive), both degrading to note files.

Tests: 11 snapshot/restore-check tests incl. negative controls (running-writer
refusal with the exact stop line, overwrite refusal, tampered sidecar,
truncated archive with re-computed checksum caught by gzip, path-escape
listing, failed-production cleanup), 4 live-probe doctor tests against a fake
store client, 2 bundle folding tests. Fake fixtures only; no live systems.

No upstream defects found; nothing to report upstream.
@im-tyler im-tyler closed this Oct 4, 2026
@im-tyler im-tyler reopened this Oct 4, 2026
@im-tyler
im-tyler merged commit 4540ad2 into main Oct 4, 2026
4 checks passed
@im-tyler
im-tyler deleted the w5/s19-snapshot-restore branch October 4, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant