Skip to content

fix(coding-agent): build forks atomically and keep a header write's prefix - #4305

Open
code-yeongyu wants to merge 3 commits into
mainfrom
fix/4295-atomic-fork-header-prefix
Open

code-yeongyu wants to merge 3 commits into
mainfrom
fix/4295-atomic-fork-header-prefix

Conversation

@code-yeongyu

@code-yeongyu code-yeongyu commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Fixes #4295

Summary

  • forkFrom is atomic. The fork is built through replaceFileAtomically (temp file in the same directory, fsync, rename) instead of an exclusive header write followed by one appendFileSync per entry. A full disk part-way through now leaves no half-copied fork in the session list. The fork's name carries a fresh timestamp and session id, as before; no extra existence probe is added, because the RPC session path's no-sync audit admits no new blocking call. The two retired forkFrom ledger entries (writeFileSync, appendFileSync) are removed.
  • A failed header catch-up keeps its prefix. _writeHeaderAsync writes the header and the first entries through an exclusive handle, then appends entries persisted while that handle closed. When that catch-up append failed, the cleanup deleted the whole new file, including the header and the entries already on disk. Now the file is kept and cut back to the bytes known whole, the transcript counts as flushed, and the entries the failed append carried are written, one line each, before the next append. A failure while the exclusive handle is still open removes the part-written file as before (fix(coding-agent): a refused delivery, header or release write never leaves a session stuck #2370).
  • createBranchedSession already writes through the atomic _rewriteFile (fix(coding-agent): rewrite session files atomically so a failed migration keeps the original #2367). Its full-disk case is added as a guard test.

Evidence

  • RED on main 96f8ac1: fork-full-disk.test.ts (three half-copied forks left behind) and the new session-manager-header-write.test.ts case (expected [] to deeply equal [ 'session', 'before' ]).
  • GREEN at this head: test/session-manager (all files), session-manager-header-write and session-append-refused-mid-turn, 234/234. tsc --noEmit, oxlint, oxfmt --check, lint ratchet and the changelog gate pass.
  • Simulated ENOSPC only (fs / fs/promises mocks with a byte budget); no real disk was filled.

Merge order (with bugwatch)

#4297 (A1) -> #4303 (B) -> #4300 (A2) -> #4305 (C) last. #4305 touches the same flushed-append block in SessionManager._persist as #4300, so it rebases after #4300 merges. #4305 carries Fixes #4295; the others are Part of #4295.

…refix (#4295)

forkFrom writes through replaceFileAtomically so a full disk leaves no partial fork; a failed catch-up append in _writeHeaderAsync keeps the header and whole entries, cuts the rest, and writes the remaining entries before the next append.
Co-authored-by: sisyphus-dev-ai <sisyphus-dev-ai@users.noreply.github.com>

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

None yet

Projects

None yet

1 participant