Skip to content

fix(snapshot): reject dest journals; copy WAL-only families - #1019

Merged
ScriptedAlchemy merged 2 commits into
codex/tracedecay-total-redesign-plan-reopenedfrom
cursor/snapshot-family-publish-fdd6
Sep 7, 2026
Merged

fix(snapshot): reject dest journals; copy WAL-only families#1019
ScriptedAlchemy merged 2 commits into
codex/tracedecay-total-redesign-plan-reopenedfrom
cursor/snapshot-family-publish-fdd6

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

Follow-up to merged #951. Codex review on that PR found three publication holes that #933's merge did not close.

  • Unix rename of an existing destination now refuses a dest that still has -wal/-shm/-journal sidecars. A leftover journal stays bound to the old main and would be replayed against the new standalone backup.
  • A WAL family whose transient -shm is absent is treated as an unlocked offline family: main+WAL are copied into owned staging and folded there. Opening that source as a reader reconstructs SHM in the source directory.
  • Copy-mode scratch admission charges main + WAL only. SHM is never written by the online backup; copied_bytes() after Copy-mode is the published file size.

Do not undraft or merge #707. This does not claim power-loss durability.

Motivation

#951 is merged and #933 is closed. The review findings are still real on the redesign branch:

  1. Public Unix replace of dest-with-sidecars publishes a new main beside the old journal.
  2. SnapshotMode::Copy of WAL-without-SHM mutated the source (new -shm) after the byte-copy path was removed.
  3. Admission still charged main + WAL + SHM after Copy-mode stopped copying SHM.

Changes

  • crates/tracedecay-runtime-core/src/sqlite_read_snapshot.rs
  • crates/tracedecay-runtime-core/src/sqlite_read_snapshot_backup_tests.rs

Admission is still a pre-flight upper bound (main + WAL). It does not open the source for page_count; a large repetitive WAL can still over-admit. Under-admitting from main alone would be worse.

Test plan

  • cargo test -p tracedecay-runtime-core --lib sqlite_read_snapshot:: — 38 passed
  • cargo clippy -p tracedecay-runtime-core --all-targets -- -D warnings
  • cargo test -p tracedecay-graph-db --features test-helpers --test durability_crash_contract — 7 passed
  • Native Windows shards on this head

Checklist

  • CHANGELOG.md updated (under [Unreleased] if no version bump)
  • No secrets, credentials, or .env files included
  • Breaking changes documented (if any)
Open in Web Open in Cursor 

Unix replace now refuses a destination that still has WAL, SHM, or
rollback-journal sidecars, so a leftover journal cannot replay into the
new standalone backup. WAL families whose transient SHM is absent are
copied as unlocked offline files and folded in staging, which keeps the
source directory untouched. Copy-mode admission charges main+WAL only.

Co-authored-by: Zack Jackson <ScriptedAlchemy@users.noreply.github.com>
@changeset-bot

changeset-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: ebd863f

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@ScriptedAlchemy
ScriptedAlchemy marked this pull request as ready for review September 7, 2026 13:55
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 7, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-07T13:57:40.923513Z ebd863f Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ScriptedAlchemy
ScriptedAlchemy merged commit 047fec7 into codex/tracedecay-total-redesign-plan-reopened Sep 7, 2026
1 of 4 checks passed
ScriptedAlchemy added a commit that referenced this pull request Sep 7, 2026
Closes the #1019 replacement race (#1046). backup_live_sqlite_database no
longer replaces an existing destination on any platform and never removes
anything at the destination after publication. The whole destination
family (main, -wal, -shm, -journal) is refused with AlreadyExists before
the source is opened or staging is reserved, and publication is a
kernel-atomic no-replace rename, so a main created concurrently keeps its
own WAL/SHM and fails the attempt instead of being displaced.

Both production callers already publish into a directory they exclusively
created (LCM gc backup staging dir; the private snapshot scratch dir) and
swap at a higher level, so the removed replacement path had no caller.

Tests use before/after-publish seams to inject a real WAL-mode SQLite
opener between the family check and the rename, and immediately after
publication, proving neither the concurrent main nor a legitimate new
family's sidecars are replaced or removed.
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.

2 participants