Skip to content

fix(studio-server): undo and redo put a file back though Windows holds it for a moment - #6506

Closed
miguel-heygen wants to merge 2 commits into
mainfrom
fix/history-undo-held-file
Closed

miguel-heygen wants to merge 2 commits into
mainfrom
fix/history-undo-held-file

Conversation

@miguel-heygen

@miguel-heygen miguel-heygen commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

What

Undo, redo and restore put a project file back by copying the stored bytes to a temp file and renaming it over the file. That rename now waits out a file Windows holds open for a moment, as every other history write already does.

Why

On Windows, a rename onto a file another process has open (an indexer, antivirus, a preview reading it) fails at once with EPERM, EBUSY or EACCES; the hold clears within milliseconds. The history's own writes (its log, project id, stat file) go through replaceFileAtomically, which retries those codes. The put-back in blobStore.ts called renameSync directly, so an Undo of a held file failed outright.

Related work

Refs the Windows held-file fixes in @hyperframes/engine (renameWithRetry). Core owns this retry: studio-server depends on core, not engine.

How

  • @hyperframes/core/atomic-file exports its existing renameWithRetry(from, to, operations?), the one replaceFileAtomically uses; from and to now come first, with the fs operations last and optional.
  • blobStore.ts cloneOrCopy publishes through it. The beforeReplace check still runs once, just before the first try.

Test plan

  • Unit tests added/updated: projectHistory.heldFile.test.ts refuses the first rename onto the project's file with EPERM, then checks that Undo and Redo each succeed and leave the right bytes. It fails with the bare renameSync.
  • The history suites (projectHistory.test.ts, projectHistory.swap.test.ts, the new one): 155 pass. Core's atomicFile tests: 34 pass. The new test passes 3 runs in a row.
  • Manual testing performed: not on Windows; the refusal is simulated, as the core retry's own tests do.
  • Comments follow CONTRIBUTING.md "Comments".

Size

A lone fix: no open PR of ours touches this code, so it ships on its own.

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 143 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 0 blocker · 1 important · 1 nit

  • important (follow-up): undo of a file add still deletes the project file with a bare rmSync (projectHistory.ts:1154, writeProjectFile, hash === null). It fails the same way: a holder that does not share delete gets EPERM/EBUSY at once, and rmSync's maxRetries is ignored unless recursive is set. So the body's "as every other history write already does" is not true for deletes yet.
Scope

Read all 3 files plus blobStore.ts and writeProjectFile. The only project-file put-back is writeTo → cloneOrCopy. The other renames in blobStore target history-internal blobs, and keep already falls back to a copy. renameWithRetry had one caller, and the argument reorder covers it. Locally: the 3 history suites pass (155) and core atomicFile passes (34). The new test fails with the base blobStore.ts (EPERM). Required CI is green. The optional Comments check is red, see inline.

Comment thread packages/core/src/atomicFile.ts Resolved

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE — 1 resolved, 1 open (rmSync follow-up), 0 new · 0406f9a → 1ec0847. The delta is the one comment line removed. CI, Windows and Comments are all green on this head.

@miguel-heygen

Copy link
Copy Markdown
Collaborator Author

Closing: main already covers this with renameWithRetry (#6559) and the blobStore write-in-place fallback (#6628).

auto-merge was automatically disabled October 31, 2026 21:00

Pull request was closed

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