From bccbe478ec8f6a78ea3f877b0941751525067b47 Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sun, 19 Jul 2026 21:32:10 -0700 Subject: [PATCH] docs(editor): document the failed-move suppression window as a bounded trade-off A self-move stamp is placed before the rename and retracted if it fails, so an event consumed during the pre-failure window is swallowed. Note that this only matters for the rare unrelated-dirty-tab-at-destination case and the recoverable missed-source-tombstone case, and that a move has no bytes to echo-verify the way self-writes do. Co-authored-by: Orca --- src/renderer/src/hooks/useEditorExternalWatch.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/renderer/src/hooks/useEditorExternalWatch.ts b/src/renderer/src/hooks/useEditorExternalWatch.ts index be19310cd8d..aa936f09bdc 100644 --- a/src/renderer/src/hooks/useEditorExternalWatch.ts +++ b/src/renderer/src/hooks/useEditorExternalWatch.ts @@ -494,6 +494,9 @@ export function createExternalWatchEventHandler( // Why: if this delete is the source side of an Orca-initiated move, the // tab has already been (or is about to be) re-homed to the new path — do // not tombstone it 'deleted'/'renamed' from the move's own watcher echo. + // (Bounded by the TTL: if the rename then fails and something else really + // deleted the source in that window, the tombstone is missed until a later + // event — a save simply recreates the file, so no data is lost.) const file = openFilesAtStart.find((f) => f.id === fileId) return !file || !isRecentSelfMoveSource(file.filePath, target.runtimeEnvironmentId) }) @@ -664,7 +667,13 @@ export function createExternalWatchEventHandler( // by the self-move TTL instead — a genuine external write landing on this // exact path within that short window is the accepted trade-off (the // in-memory draft is preserved either way; only an unheralded save could - // overwrite it, the same limit as any missed write on a dirty tab). + // overwrite it, the same limit as any missed write on a dirty tab). A move + // whose rename ultimately fails retracts its stamp, but an event consumed + // during that pre-failure window is already swallowed; it only matters for + // the rare case of an unrelated dirty tab already open at the move's + // destination (the common non-overlapping move has no dirty tab there yet). + // A move changes no bytes, so there is nothing to echo-verify the way + // self-writes do. const isSelfMoveTargetPath = isRecentSelfMoveTarget(absolutePath, target.runtimeEnvironmentId) if (dirtyMatches.length > 0 && !isSelfMoveTargetPath) { // Why: an external write landing on a dirty tab must not vanish