Skip to content

fix(server): make SQLite checkpoints durable on macOS - #14457

Open
SoroushRF wants to merge 1 commit into
pingdotgg:mainfrom
SoroushRF:fix/sqlite-checkpoint-fullfsync
Open

SoroushRF wants to merge 1 commit into
pingdotgg:mainfrom
SoroushRF:fix/sqlite-checkpoint-fullfsync

Conversation

@SoroushRF

Copy link
Copy Markdown

What Changed

PRAGMA checkpoint_fullfsync = ON is now set, before any migrations or writes, in two places:

  • The shared SQLite setup (apps/server/src/persistence/Layers/Sqlite.ts), right after WAL mode.
  • The direct state.sqlite connection in apps/server/scripts/t3-sqlite-state.ts, which bypasses that setup.

The pragma is per connection, so each path needs its own. PRAGMA fullfsync stays off.

Why

On macOS, fsync() does not flush the drive's write cache, and WAL checkpoints currently sync with plain fsync(). The maintainer triage on #13544 identified this missing checkpoint barrier as a corruption risk on power loss or hard reset.

With the pragma on, SQLite uses F_FULLFSYNC for checkpoint syncs where the platform supports it. This is the fix requested there:

  • No per-commit fullfsync. It isn't needed for the checkpoint barrier, and it made commits about 28× slower in the reporter's disk-backed benchmark.
  • The cost lands on checkpoints only. That benchmark measured 8,063 commits/s before and 4,485 after, against a real peak of about 3 events/s.
  • No platform guard. The pragma has no effect where F_FULLFSYNC doesn't exist.
    • Where a filesystem rejects F_FULLFSYNC, SQLite falls back to a plain fsync() (os_unix.c).

migrate-dev-db.ts is unchanged, because it only rebuilds a throwaway worktree dev database.

Fixes #13544.

Tests

Run on Windows 11 with Node 24.13.1:

  • Targeted tests: vp test run src/persistence/Layers/Sqlite.test.ts scripts/t3-sqlite-state.test.ts in apps/server, 8 passed.
    • The two new tests read PRAGMA checkpoint_fullfsync back as 1 through the real initialized connections.
    • With only the two pragma lines removed, exactly those two tests fail, reading back 0.
  • Static checks: vp lint and vp fmt --check on the changed files, plus pnpm --filter t3 typecheck, pass.

These tests only confirm the setting is applied. They don't exercise macOS F_FULLFSYNC or reproduce power-loss corruption, and this change doesn't repair an already-corrupt database.

Checklist

  • This PR is small and focused
  • I explained what changed and why

Written by Claude (Opus 5.5) in Claude Code and reviewed with Codex, directed by @SoroushRF.

🤖 Generated with Claude Code

macOS fsync() does not flush the drive cache, so a power loss during a
WAL checkpoint can persist b-tree pages that point at pages that never
reached disk. Enable checkpoint_fullfsync in the shared persistence
setup and on the direct state.sqlite connection in t3-sqlite-state, so
checkpoint syncs use F_FULLFSYNC. Per-commit fullfsync stays off.

Fixes pingdotgg#13544

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XS 0-9 changed lines (additions + deletions). labels Sep 30, 2026
@macroscopeapp

macroscopeapp Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR changes SQLite checkpoint synchronization defaults for shared server persistence and the direct state CLI, improving macOS durability while potentially affecting checkpoint performance. The implementation is small and test-covered, but the product-default behavior change warrants human review.

Notes:

  • Diff unchanged. Approvability was decided on eligibility alone.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Sep 30, 2026

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: pingdotgg/t3code/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: d3417730-16b5-4021-84c3-6abf8a8ab6d2

📥 Commits

Reviewing files that changed from the base of the PR and between c2fa9fc and 8d455d8.

📒 Files selected for processing (4)
  • apps/server/scripts/t3-sqlite-state.test.ts
  • apps/server/scripts/t3-sqlite-state.ts
  • apps/server/src/persistence/Layers/Sqlite.test.ts
  • apps/server/src/persistence/Layers/Sqlite.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

SQLite setup now enables checkpoint_fullfsync in the persistence layer and the state script. Tests verify the setting through both connection paths.

Changes

SQLite checkpoint synchronization

Layer / File(s) Summary
Enable and verify checkpoint full-sync
apps/server/src/persistence/Layers/Sqlite.ts, apps/server/scripts/t3-sqlite-state.ts, apps/server/src/persistence/Layers/Sqlite.test.ts, apps/server/scripts/t3-sqlite-state.test.ts
Both SQLite connection paths enable checkpoint_fullfsync. Tests query the setting and expect a value of 1.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~8 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: juliusmarminge

Merge Risk: ⚪ Minimal · up to 8d455

The durable-state connection paths enable full-sync checkpoints, and the other identified writers use disposable databases; no material user-data durability gap remains.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 8d455

The change requests stronger checkpoint durability without expanding database access or changing transaction boundaries. Risk is low, although actual power-loss protection depends on platform and filesystem behavior that was not validated here.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed behavior affects checkpoints performed by connections initialized through the two covered paths, including server persistence and the selected local state database. The patch does not expand the set of selectable databases or grant additional privileges.

Trust Boundaries and Controls

  • observed — Operator-supplied SQL still reaches the existing SQL execution sink. Query connections remain read-only; exec retains canonical-path rejection of the shared home, backup creation, and restrictive backup permissions. These controls and exposure predate this PR and are not weakened by the added pragma.

Resilience and Maintainability Implications

  • observed — The existing client owns scoped connection closure and semaphore-based transaction acquisition. The patch leaves these boundaries and backup-before-transaction ordering intact. Dependency-level rollback on interruption was not directly verified, so this establishes preservation of the existing structure rather than a new recovery guarantee.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: improving SQLite checkpoint durability on macOS.
Description check ✅ Passed The description explains what changed, why the change is needed, the affected connection paths, performance tradeoffs, test results, and known test limitations. It also confirms the PR is small and fo…
Linked Issues check ✅ Passed The PR implements the coding requirements in issue [#13544]. apps/server/src/persistence/Layers/Sqlite.ts enables PRAGMA checkpoint_fullfsync = ON in the shared SQLite setup. `apps/server/scripts/…
Out of Scope Changes check ✅ Passed The changed source lines directly implement issue [#13544]. The two added tests verify the pragma on the shared persistence connection and the direct state.sqlite connection. Comments document the F…
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 4…
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Comment @coderabbitai help to get the list of available commands.

@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 1, 2026 — with ChatGPT Codex Connector

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:XS 0-9 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Hard shutdown on macOS corrupts state.sqlite: SQLite never uses F_FULLFSYNC

2 participants