Skip to content

fix(state): fsync state.json before atomic rename and clean up temp file - #250

Merged
tupe12334 merged 1 commit into
mainfrom
fix/state-durable-write
Nov 8, 2026
Merged

tupe12334 merged 1 commit into
mainfrom
fix/state-durable-write

Conversation

@tupe12334

Copy link
Copy Markdown
Member

Opened by the moadim routine Polyhook/steplock production-readiness audit → PR + Slack.

Problem

save_state (core/src/state.rs) wrote state.json.tmp.<pid> and renamed it over state.json, but never synced the temp file. On filesystems with delayed allocation (ext4, APFS), a crash or power loss can persist the rename before the data. The result is an empty or truncated state.json, and the session fails to load. A failed write or rename also left the temp file behind.

Change

  • Write via File + sync_all() before fs::rename.
  • Remove the temp file if the write or rename fails (best effort; the original error is returned).
  • Fix the doc comment (it said "POSIX mv"; it is fs::rename).
  • Tests: overwrite wins and leaves no temp file; failed rename cleans up the temp file.
  • Ratchet clippy::mem_forget to deny (pre-push checklist convention).
  • CHANGELOG Unreleased > Fixed entry.

Verification

cargo fmt --check, cargo clippy --all-targets --locked -- -D warnings, and cargo test --locked pass locally (193 tests).

🤖 Generated with Claude Code

save_state wrote a temp file and renamed it over state.json, but never
synced the temp file first. On ext4 (delalloc) or APFS a crash or power
loss after the rename can persist the rename before the data, leaving an
empty or truncated state.json and a session that fails to load. A failed
write or rename also left state.json.tmp.<pid> behind.

Write through File + sync_all before the rename, and remove the temp file
on failure. Adds tests for overwrite + no leftover temp, and for cleanup
when the rename fails. Ratchets clippy::mem_forget to deny per the
pre-push checklist.

Opened by the moadim routine "Polyhook/steplock production-readiness audit → PR + Slack".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@tupe12334
tupe12334 merged commit d1d361f into main Nov 8, 2026
13 checks passed
@tupe12334
tupe12334 deleted the fix/state-durable-write branch November 8, 2026 19:24
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