Skip to content

Stale delayed edits in notebook and rich Markdown views no longer overwrite newer text - #31760

Merged
nwparker merged 4 commits into
mainfrom
nwparker/editor-stale-view-edit-fence
Oct 22, 2026
Merged

nwparker merged 4 commits into
mainfrom
nwparker/editor-stale-view-edit-fence

Conversation

@nwparker

@nwparker nwparker commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 8 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​511 $\color{#cf222e}{\Huge{\mathbf{−}}}$​5 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​506
Prod 19 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​367 $\color{#cf222e}{\Huge{\mathbf{−}}}$​88 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​279

ELI5

Rich Markdown and notebook views wait a moment before writing your typing into the file. If the file changed somewhere else in that moment (another view of the same file, another workspace, the phone), the delayed write could overwrite the newer text — or, in Markdown, your typing silently vanished. Now a stale delayed write is refused and a short toast says so, and edits to notebook cells nobody else touched are kept.

What Changed

  • Notebooks: each pending cell edit remembers the cell text it was typed against. When it's written, edits to cells that haven't changed are merged onto the latest notebook; only edits to cells that changed underneath are dropped (and cells keyed by position are also dropped if the cell list changed). Fixes a real overwrite between split panes of the same notebook today. Notebooks now also write pending edits when focus leaves them.
  • Rich Markdown: when newer text arrives while an edit is pending, the pending edit is cancelled with a toast instead of disappearing silently. Pending edits are written when focus leaves the editor. Cmd/Ctrl+S doesn't save an edit that was just rejected.
  • Toast: "Recent typing in this view was discarded because the file changed in another view." Not shown after a Discard.
  • After a dropped edit, the tab's unsaved state is recomputed, so it isn't left marked dirty with text identical to disk.

Why

The rejection is checked against the text each edit was based on, so a stale edit can never overwrite newer text. Merging per cell keeps the common case (two people/views editing different cells) working as before.

Linked Issue

N/A (maintainer).

Visual Proof

A notebook open in two split panes; the left pane's delayed edit arrived after the file had changed elsewhere:

toast

Testing

  • Regression tests: split-pane notebook overwrite (fails on main), different cells edited in two panes both kept, same-cell conflict rejected with toast, no toast after acknowledgement or Discard, rich pending edit cancelled with toast, focus-leave flush, Cmd/Ctrl+S skipping a rejected edit, notebook not republishing older text.

  • Editor tests (2,911), pnpm tc, check:code-quality:changed, oxfmt, oxlint, localization checks pass.

  • Screenshot captured from a background, isolated Orca build; the other view's change was driven through the app because clicking into the other pane writes the first pane's typing immediately.

  • I manually tested these changes locally

  • Automated tests added/updated, or explained why not below

AI Disclosure

Review

Agent skill upstream boundary

  • Not applicable, or this change copies or mechanically translates no upstream skill-installer source, tests, fixtures, registry entries, path tables, comments, or documentation.

Notes

Ensure no issues in: Security, Cross-platoform support (Linux, Windows, Mac), Remote SSH, Mobile, general backwards compatibility, performance

CSV views are unchanged (they already refuse stale cell edits inline). No wire or persisted-state change.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

nwparker and others added 3 commits October 21, 2026 14:33
… overwriting

A rich Markdown or notebook view commits its typing into the tab's shared text
after a short delay. If another pane of the same tab (or a disk reload) replaced
that text in the meantime, the delayed commit either overwrote the newer text
(notebook) or was silently dropped (rich Markdown). Each pending commit now
carries the text it was based on; a commit onto newer text is refused, the view
re-syncs, and a toast says the last edit in that view couldn't be applied.
Notebooks also commit pending drafts when focus leaves them, so ordinary
alternation between panes never goes stale. CSV already refuses stale cell edits.

Co-Authored-By: Claude <noreply@anthropic.com>
… rejecting stale view edits

- Notebook drafts record each cell's source when typing began; a flush merges
  drafts whose cell is unchanged onto the latest notebook and drops only drafts
  whose cell changed or no longer resolves (position keys also require the same
  cell layout). The toast fires only when typing was actually lost.
- An acknowledgement that empties the draft map clears the flush timer and bases.
- Rich markdown flushes its pending edit when focus leaves the view; the
  debounce/flush logic moves into useRichMarkdownPendingSerialization.
- Dropped or cancelled edits republish the shared text so the tab's dirty flag
  is recomputed.
- Discard bumps its epoch before flushing, so pending edits it cancels never toast.
- Clearer toast copy in every locale.

Co-Authored-By: Claude <noreply@anthropic.com>
…aving rejected edits

- A notebook flush republishes only after its own typing, a dropped draft, or
  a real change, so stale text never lands over another view's newer text.
- The rich flush reports whether it rejected the pending edit; Cmd/Ctrl+S skips
  the save when it did.
- The rich discard epoch is captured where the serialize timer starts, replacing
  the dirty-hint wrapper; the redundant shared-text comparison is removed.

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 4 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5f67a840-8731-4295-86a3-457af1eadaaf
📥 Commits

Reviewing files that changed from the base of the PR and between 9249708 and 3d44144.

📒 Files selected for processing: 27
  • src/renderer/src/components/editor/IpynbCellEditor.external-sync.test.tsx
  • src/renderer/src/components/editor/IpynbViewer.tsx
  • src/renderer/src/components/editor/RichMarkdownEditor.focus-leave.test.tsx
  • src/renderer/src/components/editor/RichMarkdownEditor.tsx
  • src/renderer/src/components/editor/RichMarkdownEditorSurface.tsx
  • src/renderer/src/components/editor/discard-editor-file-changes.ts
  • src/renderer/src/components/editor/editor-stale-view-edit.ts
  • src/renderer/src/components/editor/ipynb-source-drafts.ts
  • src/renderer/src/components/editor/rich-markdown-editor-config.test.ts
  • src/renderer/src/components/editor/rich-markdown-editor-config.ts
  • src/renderer/src/components/editor/rich-markdown-key-handler.ts
  • src/renderer/src/components/editor/rich-markdown-save-shortcut.ts
  • src/renderer/src/components/editor/rich-markdown-serialization-commit.test.ts
  • src/renderer/src/components/editor/use-editor-content-change-handler.undo-clean.test.tsx
  • src/renderer/src/components/editor/useIpynbDocumentEditing.test.tsx
  • src/renderer/src/components/editor/useIpynbDocumentEditing.ts
  • src/renderer/src/components/editor/useRichMarkdownEditorInstance.test.tsx
  • src/renderer/src/components/editor/useRichMarkdownPendingSerialization.ts
  • src/renderer/src/components/editor/useRichMarkdownProgrammaticSync.test.ts
  • src/renderer/src/components/editor/useRichMarkdownProgrammaticSync.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/pt.json
  • src/renderer/src/i18n/locales/zh.json
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nwparker
nwparker merged commit 84cafff into main Oct 22, 2026
39 checks passed
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