fix(editor): scope external disk syncs and encoding reloads to one model - #3194
Merged
Merged
Conversation
The external-sync suppression was a process-wide depth counter, so a bracketed disk write on one model also muted dirty tracking for every other model that a content listener edited synchronously. Track the bracket per model instead, and keep emitting the content-changed notification for disk writes even while dirty tracking is suppressed. The encoding reload had no request ownership either: a slow read could overwrite a newer view, a newer encoding selection, or edits made while it was in flight. Guard it with a request id, a live view check, and a buffer version comparison, and commit the decoded buffer with its saved baseline before awaiting file metadata. Cover both paths with the new component test and the extended model manager tests, and record the focused verification command in the editor guide. Co-authored-by: OpenBitFun <318544290+bitfun-ai@users.noreply.github.com>
wgqqqqq
force-pushed
the
wgq/editor-sync-followup
branch
from
September 22, 2026 09:11
b197fc1 to
211d4dd
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #3185. Two dirty-state correctness gaps around programmatic disk writes in the code editor.
Root cause: external-sync suppression was process-wide.
MonacoModelManagertracked it with a global depth counter, so a bracketed disk write on one model also muted dirty tracking for every other model that a content listener edited synchronously during that write. The bracket is now tracked per model (WeakMap), and a disk write still emitsmonaco-model-content-changedwhile dirty tracking is suppressed.Root cause: the encoding reload had no request ownership.
handleEncodingConfirmawaitedreadFileContentand then wrote the result unconditionally, so a slow read could overwrite a newer view, a newer encoding selection, or edits made while the read was in flight. It now guards on a request id, a live model/view check, and the model's alternative version id, and commits the decoded buffer together with its saved baseline (applyDiskSnapshotToEditor) before awaiting file metadata.Follow-up to #3185, related to #3165.
Type and Areas
Type: regression fix
Areas: web UI (
src/web-ui/src/tools/editor)Motivation / Impact
The global counter made the #3165 fix too broad: any model edited by a content listener while another model was being synced from disk silently skipped its dirty recompute and its dirty-state broadcast, so a tab could keep showing a stale modified/unmodified state. Scoping the bracket to the synchronized model keeps the original guarantee - no transient "modified" flash for a disk sync - without suppressing unrelated edits.
The encoding reload guard closes a race where a slow read resolved after the user had switched view, picked another encoding, or typed; the resolved content then replaced newer state. No user-facing strings change.
Verification
pnpm --dir src/web-ui run test:run src/tools/editor/components/CodeEditor.test.tsx src/tools/editor/services/MonacoModelManager.test.ts src/tools/editor/services/EditorDocument.test.ts src/tools/editor/utils/diskFileVersion.test.ts-> 4 files, 39 tests passedpnpm run type-check:web-> passednode scripts/check-git-object-sizes.mjs --base upstream/main --head HEAD-> no unapproved objectsNot covered by these checks: live SSH and peer-device transport for the editor, and manual interaction in a running editor.
Reviewer Notes
CodeEditor.test.tsxrenders the realCodeEditoragainst the realMonacoModelManagerandEditorDocument, with fake Monaco rendering and host IO. It covers delayed reads, stale requests, surface changes, and view remounts.0be594d8b(currentupstream/main), so the PR diff is only that commit.Checklist
Generated with OpenBitFun