Skip to content

fix(snapshot): bound APFS checkpoint cutover - #76

Merged
fuller-stack-dev merged 1 commit into
mainfrom
fix/bound-apfs-snapshot-cutover
Aug 14, 2026
Merged

fix(snapshot): bound APFS checkpoint cutover#76
fuller-stack-dev merged 1 commit into
mainfrom
fix/bound-apfs-snapshot-cutover

Conversation

@fuller-stack-dev

Copy link
Copy Markdown
Member

Summary

  • move whole-root SQLite discovery and race fingerprints before service quiescence
  • use macOS directory clonefile for an all-or-nothing APFS checkpoint with no byte-copy fallback
  • after quiescence, rewalk metadata and verify only new, changed, removed, or unstable files and related SQLite state
  • retain the complete-root full-copy fallback, legacy snapshot readability, and existing service-policy restoration
  • preserve symlinks and special mode bits in the macOS fallback instead of following or weakening them

Verdict and overlap

The outage is still present on canonical main after #72 and #75. PR #60's
whole-root checkpoint work was already extracted into #72; its remaining broad
lifecycle and local-source changes do not remove the post-quiesce whole-root
hashing and SQLite discovery cost. This PR is a focused checkpoint/cutover fix
and does not absorb target-readiness preflight, runtime packaging, restart
protocol, or startup migration work.

Canonical invariant:

A published APFS checkpoint is an all-or-nothing complete-root clone with no
byte-copy fallback. Any file that changed or was unstable during live
preflight must match the quiesced clone, and changed SQLite state must pass
PRAGMA quick_check. Otherwise OCM removes the partial and publishes only
after complete full-copy verification.

Performance

Same deterministic fixture on base and head:

  • 393,738 regular files
  • 2,718,195,923 logical bytes
  • 2,718,232,576 allocated bytes
  • generated node_modules and build trees plus secret, browser, plugin,
    SQLite, sidecar, symlink, and unknown future-owner state
Revision Command Available preflight Stopped-to-ready Storage
5d8ef1184f34e8ae8f2fccec87f14f9b31e9184c 254.182930s 0.241922s 253.941008s apfs-clone-v1
7eb8e05414033e2bdc7537f83983c7f8b0fb517a 61.418625s 48.473917s 12.857870s apfs-clone-v1

The final head reduces the unavailable interval by 94.9%. An independent
recursive copyfile control still takes 54.083927s with zero copied bytes,
confirming the improvement comes from atomic hierarchy cloning and removing
whole-root content verification from the stopped window.

Validation

  • cargo check --all-targets --locked
  • cargo test --locked (complete macOS suite)
  • cargo test --locked store::checkpoints::tests
  • cargo test --locked --test env_snapshot_tests
  • cargo test --locked --test upgrade_command_tests
  • Linux Docker: checkpoint owner tests and all 36 environment snapshot tests
  • mounted HFS+ fallback: full-copy-v1, secret mode 0600, symlink target,
    browser/plugin/generated content, and SQLite quick-check
  • source-blind CLI validation: exact large fixture, generated-tree controls,
    post-capture mutation isolation, and corrupt SQLite failure before any
    quiesce command while the service remained running
  • structured autoreview: clean, no actionable P0/P1 findings

Focused regressions cover:

  • complete durable-root restore, including secrets, browser/plugin state,
    generated trees, unknown future state, symlinks, modes, SQLite WAL/SHM
  • same-size SQLite mutation after preflight
  • busy live SQLite deferred until quiescence
  • corrupt SQLite cleanup and service restoration
  • already-stopped and disabled service policy
  • macOS symlink and special-mode preservation
  • legacy tar metadata and current full-copy/APFS restore paths

Remaining risk

APFS cutover no longer scales with generated byte volume or whole-tree hashing,
but atomic directory cloning and the metadata rewalk still depend on namespace
count and filesystem pressure. Linux, non-APFS, cross-filesystem, and clone
failure paths intentionally retain the honest size-dependent full-copy outage.

No agent transcript is included.

@fuller-stack-dev
fuller-stack-dev merged commit 19a708a into main Aug 14, 2026
5 checks passed
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