Skip to content

fix(studio-server): undo and redo on Windows wait out a briefly held file - #6559

Merged
miguel-heygen merged 2 commits into
mainfrom
fix/history-rename-retry
Oct 27, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
fix/history-rename-retry

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

Undo and redo on Windows no longer fail when another process (an editor, the preview, an antivirus scan) holds a project file open for a moment. History's blob store now retries its renames the way the engine already does, through one rename helper that now lives in core.

Why

Windows refuses a rename over a file that another process has open, with EPERM, EBUSY or EACCES, usually for a few milliseconds. The history blob store renamed with plain rename / renameSync, so one held file failed the whole undo or redo. The engine already had a retrying helper, and core's atomic write kept a second, shorter copy of the same idea.

Related work

None.

How

  • renameWithRetry / renameWithRetryAsync and removeScratch move from packages/engine/src/utils to packages/core/src, exported as @hyperframes/core/rename-retry and @hyperframes/core/remove-scratch. The engine imports them from core, and its public re-exports in index.ts stay the same.
  • blobStore.ts routes its four renames (restore copy, put, keep's move-aside and temp rename) through the helper.
  • Core's atomicFile.ts drops its private retry loop and uses the shared helper. One behavior change: that write now retries only on Windows, with the engine's longer backoff (about 1.3 s in total, instead of 100 ms). On macOS and Linux a busy-rename error is real, so it is thrown at once.

Not changed: the other raw renames in history (pruneHistories.ts moving a history to trash, videoState.ts writing its state file). They are not on the undo/redo path.

Test plan

  • Unit tests added/updated
    • New blobStore.test.ts, run as win32: a mocked rename throws EPERM twice, then succeeds. Both the restore write and put succeed on the third attempt. Against the old blobStore.ts both tests fail with EPERM.
    • Core's atomicFile.test.ts busy-target case runs as win32 and expects the helper's 8 attempts.
    • Core: 251 test files pass. studio-server history: 248 tests pass. The engine unit suite passes except ffprobe.test.ts, which needs an installed ffprobe and the HDR PNG fixture; this change does not touch it.
    • Typecheck is clean for core, engine, studio-server and producer.
    • check:package-subpaths, check:workspace-contracts, check:package-cycles, oxlint and oxfmt pass.
  • Manual testing performed (not run on a Windows machine)
  • Documentation updated (if applicable)
  • Comments follow CONTRIBUTING.md "Comments"

@miguel-heygen
miguel-heygen force-pushed the fix/history-rename-retry branch from 261aa8c to f8e6191 Compare October 27, 2026 13:50
@github-actions

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 152 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 · 0 important · 0 nits · head f8e61918

The rebase only adds new context from main. The PR patch is otherwise the same as 9400172c plus the oxfmt fix. No relative utils/renameWithRetry or utils/removeScratch imports are left after #6550. All Actions runs at this head are green, including Build's size budget and the Windows lanes.

Scope

Read the full diff. Checked every blobStore rename path and its projectHistory callers (keep, then rmSync; writeTo with assertWritable). Checked the move to the core subpath (exports, package-subpaths, cli bundling through noExternal). The atomicFile behavior change (Windows only, about 1.3 s backoff) is described in the body.

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit d6e16aa Oct 27, 2026
82 checks passed
@miguel-heygen
miguel-heygen deleted the fix/history-rename-retry branch October 27, 2026 14:50
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