From 9b67320eb781a5c8b1bc9bc14f2b47ab47a1a732 Mon Sep 17 00:00:00 2001 From: silver Date: Tue, 27 Oct 2026 17:03:04 +0100 Subject: [PATCH 1/3] fix(test): retry renaming file while it is locked Preview generation after saving can briefly lock the file, so the WebDAV MOVE fails with a 500 LockedException. The response was not checked, so the test only failed later when opening the renamed file. Check for 201 and retry for up to 10 seconds. Signed-off-by: silver Assisted-by: ClaudeCode:claude-opus-5.5 --- playwright/support/fixtures/Node.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/playwright/support/fixtures/Node.ts b/playwright/support/fixtures/Node.ts index 82160da92ed..3ddd0731807 100644 --- a/playwright/support/fixtures/Node.ts +++ b/playwright/support/fixtures/Node.ts @@ -85,14 +85,18 @@ export class Node { } async move(newName: string) { - await this.page.request.fetch( - `/remote.php/webdav/${this.name}`, - { - headers: { - Destination: `/remote.php/webdav/${newName}`, - }, - method: 'MOVE', - }) + // retry while the file is locked, e.g. by preview generation after saving + await expect(async () => { + const response = await this.page.request.fetch( + `/remote.php/webdav/${this.name}`, + { + headers: { + Destination: `/remote.php/webdav/${newName}`, + }, + method: 'MOVE', + }) + expect(response.status()).toBe(201) + }).toPass({ timeout: 10_000 }) return new Node({ ...this, page: this.page, name: newName }) } From aed0a6fdd1583f2fa3798a8e2aaa90afa36446e4 Mon Sep 17 00:00:00 2001 From: silver Date: Tue, 27 Oct 2026 17:08:06 +0100 Subject: [PATCH 2/3] fix(a11y): hide collaborator carets from screen readers The caret label with the user name is rendered inline in the text, so screen readers read it as part of the content, e.g. a heading "Hello world" became "Hello wo alice rld". Signed-off-by: silver Assisted-by: ClaudeCode:claude-opus-5.5 --- src/extensions/CollaborationCaret.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/extensions/CollaborationCaret.ts b/src/extensions/CollaborationCaret.ts index 17755e9453e..527d1402bb8 100644 --- a/src/extensions/CollaborationCaret.ts +++ b/src/extensions/CollaborationCaret.ts @@ -48,6 +48,9 @@ function render(user: AwarenessUser, clientId?: number): HTMLElement { cursor.classList.add('collaboration-carets__caret') cursor.setAttribute('style', `border-color: ${user.color}`) + // The caret sits inside the document text. Hide it from screen readers + // so they don't read the user name in the middle of the text. + cursor.setAttribute('aria-hidden', 'true') const label = document.createElement('div') label.id = `collaboration-carets__label__${clientId}` From 7b558760ab2a2978fbc618a7a81b736e424ee88b Mon Sep 17 00:00:00 2001 From: silver Date: Tue, 27 Oct 2026 17:09:36 +0100 Subject: [PATCH 3/3] fix(autosave): keep retrying after a failed autosave When the pending autosave timer fired, pendingAutosave was not reset. If that save failed (e.g. while offline), no new retry was scheduled and autosave stopped until the user typed again. Also log the retry delay in seconds instead of milliseconds. Signed-off-by: silver Assisted-by: ClaudeCode:claude-opus-5.5 --- src/services/SaveService.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/services/SaveService.ts b/src/services/SaveService.ts index 8795da2197b..14c6430a73f 100644 --- a/src/services/SaveService.ts +++ b/src/services/SaveService.ts @@ -135,9 +135,13 @@ class SaveService { if (!this.pendingAutosave) { const wait = nextSaveAttempt - now logger.debug( - `Just saved, will try again in ${Math.ceil(wait)} seconds.`, + `Just saved, will try again in ${Math.ceil(wait / 1000)} seconds.`, ) - this.pendingAutosave = window.setTimeout(this.autosave, wait) + this.pendingAutosave = window.setTimeout(() => { + // Reset so a failing save can schedule the next attempt + this.pendingAutosave = 0 + this.autosave() + }, wait) } return }