Notes: deleted link block comes back after Delete block #1384

Open
opened 2026-10-07 17:16:21 +00:00 by kayg · 18 comments
Owner

Owner report (2026-10-07)

"I delete a link block via 3 dot menu → delete block, i get a toast saying deleted and the link comes back again....."

Expected

Delete block removes the link block for good. The "1 block deleted" toast with Undo appears. Without Undo, the block never comes back: not after the toast ends, not after save, not after reload, not after a tab switch.

Code pointers

  • apps/web/src/lib/notes/NoteView.svelte deleteBlocksWithUndo (#1125): deletes through the Yjs doc with a scoped Y.UndoManager origin.
  • apps/web/src/lib/editor/blockMenu.ts / blockToolbarActions.ts: the "Delete block" action.
  • Possible re-creators to check: packages/editor/src/wikilinks.ts (converts [[Title]] on load and flush), any link card / bare-URL conversion, the collaboration server replaying a Markdown baseline, the Markdown save round-trip.
  • Possibly related: the owner also sees "multiple link icons" appearing in the editor.

Acceptance

  • A real-browser e2e test does what the User does: a Note with a link block (Markdown link, bare URL, and a [[wikilink]] line), ⋯ → Delete block, wait past the toast and the save debounce, reload. The block stays deleted. Undo still restores it.
  • The root cause is named in the fix commit and in a comment at the fix.
## Owner report (2026-10-07) "I delete a link block via 3 dot menu → delete block, i get a toast saying deleted and the link comes back again....." ## Expected Delete block removes the link block for good. The "1 block deleted" toast with Undo appears. Without Undo, the block never comes back: not after the toast ends, not after save, not after reload, not after a tab switch. ## Code pointers - `apps/web/src/lib/notes/NoteView.svelte` `deleteBlocksWithUndo` (#1125): deletes through the Yjs doc with a scoped `Y.UndoManager` origin. - `apps/web/src/lib/editor/blockMenu.ts` / `blockToolbarActions.ts`: the "Delete block" action. - Possible re-creators to check: `packages/editor/src/wikilinks.ts` (converts `[[Title]]` on load and flush), any link card / bare-URL conversion, the collaboration server replaying a Markdown baseline, the Markdown save round-trip. - Possibly related: the owner also sees "multiple link icons" appearing in the editor. ## Acceptance - A real-browser e2e test does what the User does: a Note with a link block (Markdown link, bare URL, and a `[[wikilink]]` line), ⋯ → Delete block, wait past the toast and the save debounce, reload. The block stays deleted. Undo still restores it. - The root cause is named in the fix commit and in a comment at the fix.
Author
Owner

Sharper repro from the owner (2026-10-07)

"deleting things immediately followed by another keyboard action makes the deleted blocks return? happens with any block? if i wait and then press another action then it's fine?"

So: this is not specific to links. Delete any block (⋯ → Delete block), then press another key or shortcut right away (typing, Enter, arrow, Cmd+Z, another block action), and the deleted block comes back. Waiting a moment before the next action does not trigger it. Treat this as the primary repro: find the time window and which key presses trigger it, then explain why. Suspects for a timing race: the scoped Y.UndoManager with captureTimeout: 0 versus the editor's own y-prosemirror undo plugin (whose capture window can merge the next keystroke with the delete and undo it together); a ProseMirror transaction built from a stale state before the Yjs update is applied back; a pending save or flush that replays pre-delete content. The e2e must cover "delete, then type immediately" and "delete, then Enter immediately" for a paragraph, a heading, a list item and a link block, plus the waited case.

## Sharper repro from the owner (2026-10-07) "deleting things immediately followed by another keyboard action makes the deleted blocks return? happens with any block? if i wait and then press another action then it's fine?" So: this is not specific to links. Delete any block (⋯ → Delete block), then press another key or shortcut right away (typing, Enter, arrow, Cmd+Z, another block action), and the deleted block comes back. Waiting a moment before the next action does not trigger it. Treat this as the primary repro: find the time window and which key presses trigger it, then explain why. Suspects for a timing race: the scoped `Y.UndoManager` with `captureTimeout: 0` versus the editor's own y-prosemirror undo plugin (whose capture window can merge the next keystroke with the delete and undo it together); a ProseMirror transaction built from a stale `state` before the Yjs update is applied back; a pending save or flush that replays pre-delete content. The e2e must cover "delete, then type immediately" and "delete, then Enter immediately" for a paragraph, a heading, a list item and a link block, plus the waited case.
Author
Owner

Starting work on job/linkdel-1384 from base SHA 0419170fe4. I will reproduce the immediate-action race in a real browser before changing code, then add regression coverage and fix the state/undo root cause.

Starting work on job/linkdel-1384 from base SHA 0419170fe456b58614befcb12d9c9d255118f1c0. I will reproduce the immediate-action race in a real browser before changing code, then add regression coverage and fix the state/undo root cause.
Author
Owner

Real-browser finding (worktree 0419170fe, production web build plus this worktree's local server): the sharper immediate sequence did not reproduce yet. Through the real block capsule and ⋯ menu, I deleted a paragraph, heading, list item, and Markdown link, then sent type or Enter before waiting for the toast; each deleted block stayed absent in the live editor, saved Markdown, and reload. With no follow-up key, Markdown links, bare URLs, wikilinks, and links in list items also stayed absent immediately, after the toast interval, in saved Markdown, and after reload. I am continuing to isolate the reported timing path before choosing a code change.

Real-browser finding (worktree `0419170fe`, production web build plus this worktree's local server): the sharper immediate sequence did not reproduce yet. Through the real block capsule and ⋯ menu, I deleted a paragraph, heading, list item, and Markdown link, then sent type or Enter before waiting for the toast; each deleted block stayed absent in the live editor, saved Markdown, and reload. With no follow-up key, Markdown links, bare URLs, wikilinks, and links in list items also stayed absent immediately, after the toast interval, in saved Markdown, and after reload. I am continuing to isolate the reported timing path before choosing a code change.
Author
Owner

Expanded real-browser findings (worktree 0419170fe, Chromium, production web build and local server): the completed immediate type/Enter cases for headings, list items, bare URLs, wikilinks and linked list items stayed deleted in the live editor, saved Markdown and reload. The Markdown-link no-follow-up case and the bare-URL, wikilink and linked-list-item no-follow-up cases also stayed deleted immediately, after the toast, in saved Markdown and after reload. A mounted-editor unit probe likewise keeps the delete absent after a synchronous text edit and editor Undo; a focused calternal-collab conflict-shadow probe keeps it absent after a marked delete followed by a normal edit.

The expanded E2E reached intermittent editor-ready/toast/save timeouts late in the run after many fixture Notes; those are harness/server availability failures, not observed resurrection. I narrowed its immediate matrix to the four block shapes required by the issue. I still do not have a reproducible resurrection or a root cause, so I have not changed production behavior. Screenshots are in artifacts/notes-delete-race-1384-before-final/ (before/after, 390/820/1440 px, light/dark).

Expanded real-browser findings (worktree `0419170fe`, Chromium, production web build and local server): the completed immediate type/Enter cases for headings, list items, bare URLs, wikilinks and linked list items stayed deleted in the live editor, saved Markdown and reload. The Markdown-link no-follow-up case and the bare-URL, wikilink and linked-list-item no-follow-up cases also stayed deleted immediately, after the toast, in saved Markdown and after reload. A mounted-editor unit probe likewise keeps the delete absent after a synchronous text edit and editor Undo; a focused `calternal-collab` conflict-shadow probe keeps it absent after a marked delete followed by a normal edit. The expanded E2E reached intermittent editor-ready/toast/save timeouts late in the run after many fixture Notes; those are harness/server availability failures, not observed resurrection. I narrowed its immediate matrix to the four block shapes required by the issue. I still do not have a reproducible resurrection or a root cause, so I have not changed production behavior. Screenshots are in `artifacts/notes-delete-race-1384-before-final/` (before/after, 390/820/1440 px, light/dark).
Author
Owner

#1384 investigation report

Result

The reported resurrection did not reproduce in the required real-browser flow, so I did not change production behavior or claim a root cause. The new coverage is a characterization suite for the reported timing and link cases. The issue remains open pending a reproduction that fails against this branch.

The production web build from this worktree ran in Playwright against a real local server using the shared server binary at ef0aa12b1 (the change does not alter server behavior). All four immediate block shapes (paragraph, heading, list item and Markdown link) stayed deleted after immediate typing and Enter, after the toast, in saved Markdown and after reload. Bare URL, wikilink and linked list item also stayed deleted immediately, after the toast, in saved Markdown and after reload. The waited save/reload flow passed, and Undo restored the deleted paragraph. The mounted Note editor probe and the collaboration conflict-shadow probe also kept the block deleted after a following edit.

The scoped Y.UndoManager, editor Undo, conflict-shadow merge and Markdown save/reload suspects therefore did not reproduce the report in these probes. This is evidence about the tested path, not proof that each suspect is impossible.

No duplicate link rendering was observed in the tested link deletion flows. inlineLinks.ts renders each standalone URL or resolved wikilink through one widget; Markdown links use mark decorations. Existing inline link tests cover a standalone URL and exact wikilink anchor counts. The deletion browser test does not assert an icon-node count.

Changes

  • Added apps/web/e2e/notes-delete-race-1384.mjs for the real menu flow, immediate type/Enter matrix, four link forms, Undo, waited save/reload, and before/after macOS screenshots at phone (390), tablet (820) and desktop (1440) widths in light and dark themes.
  • Added a mounted editor test for a scoped delete followed by an immediate text edit and editor Undo.
  • Added a calternal-collab conflict-shadow test for a marked delete followed by a normal edit.
  • No production behavior changed.

Screenshots are in artifacts/notes-delete-race-1384-final/ and are not committed.

Gates (verbatim output excerpts)

cargo fmt --check exited 0 and printed no output.

bun run check:

perf-lint: PASS; 0 violations; 22543 scoped exceptions
svelte-check found 0 errors and 4 warnings in 2 files

bun run test --maxWorkers=2:

 Test Files  293 passed (293)
      Tests  2104 passed (2104)
   Start at  00:32:23
   Duration  444.44s (transform 30%, environment 26%, import 22%, tests 17%, setup 5%)

notes-delete-race-1384.mjs:

regression matrix results: []
notes delete race #1384 passed: 7 Markdown block forms, immediate type/Enter, Undo, and waited save/reload; screenshots in /home/kayg/Developer/calternal-wt/linkdel-1384/artifacts/notes-delete-race-1384-final

cargo clippy -p calternal-collab --all-targets -- -D warnings:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 45s

cargo test -p calternal-collab -- --test-threads=4 result lines:

test result: ok. 135 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 148.42s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.20s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.87s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.77s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 78.49s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.20s
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.45s
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.48s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.19s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.91s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.12s
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.03s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 25.01s
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14s
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.46s
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 26.31s
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

Gaps and decision

  • Known gap: the original resurrection remains unconfirmed. No production fix can be validated until one of the immediate cases reproduces.
  • UX gaps closed: the requested User flows now have real-browser coverage.
  • UX gaps left: the reported resurrection still needs a failing reproduction. Duplicate icon-node count is not asserted directly in this E2E.
  • Decision not covered by DESIGN: I kept this change test-only rather than make a speculative production change without a failing reproduction.

Head: db3dd373fe8e01d5a8bdd2eb8cf50e0713fb74b0 (test(notes): record #1384 root-cause reproduction gap). No push, deploy, merge or issue close performed.

## #1384 investigation report ### Result The reported resurrection did not reproduce in the required real-browser flow, so I did not change production behavior or claim a root cause. The new coverage is a characterization suite for the reported timing and link cases. The issue remains open pending a reproduction that fails against this branch. The production web build from this worktree ran in Playwright against a real local server using the shared server binary at `ef0aa12b1` (the change does not alter server behavior). All four immediate block shapes (paragraph, heading, list item and Markdown link) stayed deleted after immediate typing and Enter, after the toast, in saved Markdown and after reload. Bare URL, wikilink and linked list item also stayed deleted immediately, after the toast, in saved Markdown and after reload. The waited save/reload flow passed, and Undo restored the deleted paragraph. The mounted Note editor probe and the collaboration conflict-shadow probe also kept the block deleted after a following edit. The scoped `Y.UndoManager`, editor Undo, conflict-shadow merge and Markdown save/reload suspects therefore did not reproduce the report in these probes. This is evidence about the tested path, not proof that each suspect is impossible. ### Link rendering No duplicate link rendering was observed in the tested link deletion flows. `inlineLinks.ts` renders each standalone URL or resolved wikilink through one widget; Markdown links use mark decorations. Existing inline link tests cover a standalone URL and exact wikilink anchor counts. The deletion browser test does not assert an icon-node count. ### Changes - Added `apps/web/e2e/notes-delete-race-1384.mjs` for the real menu flow, immediate type/Enter matrix, four link forms, Undo, waited save/reload, and before/after macOS screenshots at phone (390), tablet (820) and desktop (1440) widths in light and dark themes. - Added a mounted editor test for a scoped delete followed by an immediate text edit and editor Undo. - Added a `calternal-collab` conflict-shadow test for a marked delete followed by a normal edit. - No production behavior changed. Screenshots are in `artifacts/notes-delete-race-1384-final/` and are not committed. ### Gates (verbatim output excerpts) `cargo fmt --check` exited 0 and printed no output. `bun run check`: ``` perf-lint: PASS; 0 violations; 22543 scoped exceptions svelte-check found 0 errors and 4 warnings in 2 files ``` `bun run test --maxWorkers=2`: ``` Test Files 293 passed (293) Tests 2104 passed (2104) Start at 00:32:23 Duration 444.44s (transform 30%, environment 26%, import 22%, tests 17%, setup 5%) ``` `notes-delete-race-1384.mjs`: ``` regression matrix results: [] notes delete race #1384 passed: 7 Markdown block forms, immediate type/Enter, Undo, and waited save/reload; screenshots in /home/kayg/Developer/calternal-wt/linkdel-1384/artifacts/notes-delete-race-1384-final ``` `cargo clippy -p calternal-collab --all-targets -- -D warnings`: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 3m 45s ``` `cargo test -p calternal-collab -- --test-threads=4` result lines: ``` test result: ok. 135 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 148.42s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.20s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 5.87s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.77s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 78.49s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.20s test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.45s test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 7.48s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.19s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.91s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 11.12s test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 2.03s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 25.01s test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.14s test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.46s test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 26.31s test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` ### Gaps and decision - Known gap: the original resurrection remains unconfirmed. No production fix can be validated until one of the immediate cases reproduces. - UX gaps closed: the requested User flows now have real-browser coverage. - UX gaps left: the reported resurrection still needs a failing reproduction. Duplicate icon-node count is not asserted directly in this E2E. - Decision not covered by DESIGN: I kept this change test-only rather than make a speculative production change without a failing reproduction. Head: `db3dd373fe8e01d5a8bdd2eb8cf50e0713fb74b0` (`test(notes): record #1384 root-cause reproduction gap`). No push, deploy, merge or issue close performed.
Author
Owner

Verification correction for #1384

The full passing Playwright matrix was rerun with both artifacts built from this worktree at db3dd373fe8e01d5a8bdd2eb8cf50e0713fb74b0: the production web build and /home/kayg/build/targets/linkdel-1384/debug/calternal-server (cargo build -p calternal-server --bin calternal-server, completed in 10m45s). This corrects the server provenance in my prior report, which described the earlier shared-binary run.

One first attempt with the worktree binary timed out while the test waited for the text formatting bubble to hide before the paragraph-Enter case. No deleted content returned in the completed cases. A full retry completed successfully:

regression matrix results: []
notes delete race #1384 passed: 7 Markdown block forms, immediate type/Enter, Undo, and waited save/reload; screenshots in /home/kayg/Developer/calternal-wt/linkdel-1384/artifacts/notes-delete-race-1384-final

The run covered immediate type and Enter on paragraph, heading, list item and Markdown link; immediate deletion persistence for Markdown link, bare URL, wikilink and linked list item; Undo restore; and a waited save/reload case. All deleted blocks remained absent. The screenshot set in artifacts/notes-delete-race-1384-final/ was refreshed by this run at 390, 820 and 1440 CSS pixels, light and dark, with macOS platform emulation.

The root cause remains unconfirmed because the reported resurrection still does not reproduce. The complete web and Rust gate excerpts are in my previous report comment. Head remains db3dd373fe8e01d5a8bdd2eb8cf50e0713fb74b0; no source changed after that commit.

## Verification correction for #1384 The full passing Playwright matrix was rerun with both artifacts built from this worktree at `db3dd373fe8e01d5a8bdd2eb8cf50e0713fb74b0`: the production web build and `/home/kayg/build/targets/linkdel-1384/debug/calternal-server` (`cargo build -p calternal-server --bin calternal-server`, completed in 10m45s). This corrects the server provenance in my prior report, which described the earlier shared-binary run. One first attempt with the worktree binary timed out while the test waited for the text formatting bubble to hide before the paragraph-Enter case. No deleted content returned in the completed cases. A full retry completed successfully: ``` regression matrix results: [] notes delete race #1384 passed: 7 Markdown block forms, immediate type/Enter, Undo, and waited save/reload; screenshots in /home/kayg/Developer/calternal-wt/linkdel-1384/artifacts/notes-delete-race-1384-final ``` The run covered immediate type and Enter on paragraph, heading, list item and Markdown link; immediate deletion persistence for Markdown link, bare URL, wikilink and linked list item; Undo restore; and a waited save/reload case. All deleted blocks remained absent. The screenshot set in `artifacts/notes-delete-race-1384-final/` was refreshed by this run at 390, 820 and 1440 CSS pixels, light and dark, with macOS platform emulation. The root cause remains unconfirmed because the reported resurrection still does not reproduce. The complete web and Rust gate excerpts are in my previous report comment. Head remains `db3dd373fe8e01d5a8bdd2eb8cf50e0713fb74b0`; no source changed after that commit.
Author
Owner

Continuing #1384 on job/linkdel-1384, base/head db3dd373fe8e01d5a8bdd2eb8cf50e0713fb74b0. Reproduce with real Safari mouse menu and immediate keys, then latency, long Notes/Daily notes, two clients and pending saves. No speculative fix. Prior harness explicitly refocuses the editor before typing; this may bypass the focus path in the owner report.

Continuing #1384 on `job/linkdel-1384`, base/head `db3dd373fe8e01d5a8bdd2eb8cf50e0713fb74b0`. Reproduce with real Safari mouse menu and immediate keys, then latency, long Notes/Daily notes, two clients and pending saves. No speculative fix. Prior harness explicitly refocuses the editor before typing; this may bypass the focus path in the owner report.
Author
Owner

Real Safari prerequisite failed while holding the Mac lock. macOS 27.0 (26A428), Safari 27.0 (22625.1.29.11.27), cua-driver 0.30.2.

Native desktop capture: No main display detected.
Native screencapture: could not create image from display
AppleScript JavaScript: Safari got an error: AppleEvent timed out. (-1712)
Safari WebDriver session creation: Could not create a session: The session timed out while connecting to a Safari instance. The following asynchronous operation timed out: Request creation of a new automation session
Cua invoke_menu File/New Window: menu_path_unavailable, target window 9648 did not become stably key and frontmost.
Cua bring_to_front: bring_to_front_exact_window_unverified, focused=true, frontmost_ordinary=false. Accessibility and Screen Recording permissions report true.

No real Safari case or screenshot can be counted as completed. Continuing local browser probes; owner GUI restoration is required for the first requested environment.

Real Safari prerequisite failed while holding the Mac lock. macOS 27.0 (26A428), Safari 27.0 (22625.1.29.11.27), cua-driver 0.30.2. Native desktop capture: `No main display detected.` Native screencapture: `could not create image from display` AppleScript JavaScript: `Safari got an error: AppleEvent timed out. (-1712)` Safari WebDriver session creation: `Could not create a session: The session timed out while connecting to a Safari instance. The following asynchronous operation timed out: Request creation of a new automation session` Cua invoke_menu File/New Window: `menu_path_unavailable`, `target window 9648 did not become stably key and frontmost`. Cua bring_to_front: `bring_to_front_exact_window_unverified`, focused=true, frontmost_ordinary=false. Accessibility and Screen Recording permissions report true. No real Safari case or screenshot can be counted as completed. Continuing local browser probes; owner GUI restoration is required for the first requested environment.
Author
Owner

Native-focus investigation finding (#1384): a normal Playwright locator click put the nominal immediate key 665–2206 ms after the Delete click on the busy build host. The revised probe queues native mouse-up and the key without waiting for click rendering checks. Its first completed Chromium case delivered x 51.1 ms after the delete event; document.activeElement was the still-closing Delete block menu item. The block stayed absent in live content, saved Markdown and reload. Earlier post-click keys landed on BODY. Neither completed focus path hit the toast Undo button.

The collaboration trace decoder must skip custom frame type 101 and its empty payload before the marked deletion update; it prefixes the update in the same WebSocket frame. This is a diagnostic correction, not a change to production behavior. The extended probe also delays both TCP directions (including WebSocket), tests 320 added blocks, two clients, pending edits, and real Daily notes/Journal Log content through the Files block editor. Investigation continues.

Native-focus investigation finding (#1384): a normal Playwright locator click put the nominal immediate key 665–2206 ms after the Delete click on the busy build host. The revised probe queues native mouse-up and the key without waiting for click rendering checks. Its first completed Chromium case delivered `x` 51.1 ms after the delete event; `document.activeElement` was the still-closing Delete block menu item. The block stayed absent in live content, saved Markdown and reload. Earlier post-click keys landed on BODY. Neither completed focus path hit the toast Undo button. The collaboration trace decoder must skip custom frame type 101 and its empty payload before the marked deletion update; it prefixes the update in the same WebSocket frame. This is a diagnostic correction, not a change to production behavior. The extended probe also delays both TCP directions (including WebSocket), tests 320 added blocks, two clients, pending edits, and real Daily notes/Journal Log content through the Files block editor. Investigation continues.
Author
Owner

Save-path finding at db3dd373f: the live Note surface emits Yjs updates through apps/web/src/lib/notes/collab.ts; its onUpdate hook in NoteEditorSurface.svelte calls the host outline/title handler, not a browser Markdown save. A production-source search for convertWikilinks / hasWikilinkSyntax finds definitions, the package export and type declarations, with no app caller. Thus the load/flush description in the packages/editor/src/wikilinks.ts header does not describe this live Note path. Server Markdown materialization remains a possible race source and is being exercised with real persistence/reload and delayed peer updates. No resurrection or production root cause is confirmed.

Save-path finding at `db3dd373f`: the live Note surface emits Yjs updates through `apps/web/src/lib/notes/collab.ts`; its `onUpdate` hook in `NoteEditorSurface.svelte` calls the host outline/title handler, not a browser Markdown save. A production-source search for `convertWikilinks` / `hasWikilinkSyntax` finds definitions, the package export and type declarations, with no app caller. Thus the load/flush description in the `packages/editor/src/wikilinks.ts` header does not describe this live Note path. Server Markdown materialization remains a possible race source and is being exercised with real persistence/reload and delayed peer updates. No resurrection or production root cause is confirmed.
Author
Owner

Security incident during the Mac prerequisite check: an early broad cua-driver accessibility snapshot of the existing Safari lab setup window (window 9648) included a setup token in the URL field. Subsequent snapshots use bounded fields. A read-only redaction audit confirmed token presence without printing the token again. The token is not repeated in this issue or committed files. The owner must invalidate that lab setup token. No credential store was accessed.

Security incident during the Mac prerequisite check: an early broad cua-driver accessibility snapshot of the existing Safari lab setup window (window 9648) included a setup token in the URL field. Subsequent snapshots use bounded fields. A read-only redaction audit confirmed token presence without printing the token again. The token is not repeated in this issue or committed files. The owner must invalidate that lab setup token. No credential store was accessed.
Author
Owner

Continued from db3dd373f. Commits 589a39de4 and c68015112 extend the existing real-server browser probe. Production behavior is unchanged.

A long Note (320 added paragraphs), two collab clients, pending peer edit, and 120 ms TCP delay in both directions passed the Markdown-link → Delete block → Enter case. The actual native key gap was 244.3 ms. Enter targeted the closing Delete block menu item. The deleted marker stayed absent in the primary editor, peer editor, saved Markdown and reload. Pending and concurrent peer text both reached Markdown. Evidence: artifacts/linkdel2/chromium-link-delayed.log and chromium-link-delayed/*.json.

A previous per-character peer fixture exceeded the save polling deadline under host load. Its trace shows the final character reaching the primary client at 50.7 seconds. Deleted text stayed absent. The fixture now uses one native text insertion for each peer edit; the primary follow-up key remains a native keypress. No timeout expectation was relaxed.

Fetched and merged origin/dev once: fdd3983f3c. The merged changes do not alter the Note/editor/collab production files used by this probe. Web gates have started. Real Safari is still blocked by the VM display/session failure previously reported; Linux WebKit is an explicitly labelled fallback, not Safari evidence.

Continued from db3dd373f. Commits 589a39de4 and c68015112 extend the existing real-server browser probe. Production behavior is unchanged. A long Note (320 added paragraphs), two collab clients, pending peer edit, and 120 ms TCP delay in both directions passed the Markdown-link → Delete block → Enter case. The actual native key gap was 244.3 ms. Enter targeted the closing Delete block menu item. The deleted marker stayed absent in the primary editor, peer editor, saved Markdown and reload. Pending and concurrent peer text both reached Markdown. Evidence: artifacts/linkdel2/chromium-link-delayed.log and chromium-link-delayed/*.json. A previous per-character peer fixture exceeded the save polling deadline under host load. Its trace shows the final character reaching the primary client at 50.7 seconds. Deleted text stayed absent. The fixture now uses one native text insertion for each peer edit; the primary follow-up key remains a native keypress. No timeout expectation was relaxed. Fetched and merged origin/dev once: fdd3983f3c1442795f4a7e505cd28e042fc0f4d7. The merged changes do not alter the Note/editor/collab production files used by this probe. Web gates have started. Real Safari is still blocked by the VM display/session failure previously reported; Linux WebKit is an explicitly labelled fallback, not Safari evidence.
Author
Owner

Post-merge gates at fdd3983f3c:

cargo fmt --check: exit 0, no output.

cargo clippy -p calternal-collab --all-targets -- -D warnings: exit 0. Verbatim final line:

    Finished `dev` profile [unoptimized + debuginfo] target(s) in 15m 41s

bun run check: exit 0. Verbatim summaries:

perf-lint: PASS; 0 violations; 22544 scoped exceptions
svelte-check found 0 errors and 4 warnings in 2 files

cargo test -p calternal-collab -- --test-threads=4 has started. bun run test --maxWorkers=2 is still running; it has reported failures in ThemePicker, InfoPanel and CalendarFeedsGroup. None of those files are changed by this job. Full diagnostics and final counts are pending; these are not passing gates.

Daily-note create, body write and Files stat returned 200 in Chromium and Linux WebKit. Chromium stopped at editor-ready timeout; WebKit reached the editor but stopped because native insertText did not enter its background peer editor. Neither attempt exercised deletion. Their logs remain in artifacts/linkdel2/. The Mac display recheck still says No main display detected. Real Safari is blocked, not passed.

Post-merge gates at fdd3983f3c1442795f4a7e505cd28e042fc0f4d7: `cargo fmt --check`: exit 0, no output. `cargo clippy -p calternal-collab --all-targets -- -D warnings`: exit 0. Verbatim final line: ``` Finished `dev` profile [unoptimized + debuginfo] target(s) in 15m 41s ``` `bun run check`: exit 0. Verbatim summaries: ``` perf-lint: PASS; 0 violations; 22544 scoped exceptions svelte-check found 0 errors and 4 warnings in 2 files ``` `cargo test -p calternal-collab -- --test-threads=4` has started. `bun run test --maxWorkers=2` is still running; it has reported failures in ThemePicker, InfoPanel and CalendarFeedsGroup. None of those files are changed by this job. Full diagnostics and final counts are pending; these are not passing gates. Daily-note create, body write and Files stat returned 200 in Chromium and Linux WebKit. Chromium stopped at editor-ready timeout; WebKit reached the editor but stopped because native insertText did not enter its background peer editor. Neither attempt exercised deletion. Their logs remain in artifacts/linkdel2/. The Mac display recheck still says `No main display detected.` Real Safari is blocked, not passed.
Author
Owner

Head 35b6804969 adds explicit owner timing qualification, bounded Daily-note setup diagnostics, native caret probes, and a replacement-browser origin fix. The original default regression assertions are unchanged. No production fix exists yet.

17 cases completed; 12 delivered a key within 0–300 ms of the first Delete block click. All 17 kept the block absent in the editor, saved Markdown and reload. Full rows, actual gaps and activeElement facts: artifacts/linkdel2/completed-matrix.json. Logs and collaboration vectors are retained beside each run.

Completed combinations:

  • Chromium, short paragraph, x/Enter/Backspace/ArrowRight, nominal gaps 0/100/300 ms (12 cases). Actual gaps range 51.1–381.3 ms; eight qualify for the owner window.
  • Chromium, short heading, x at 100.1 ms and Enter at 88.7 ms.
  • Chromium, 320 added paragraphs, two clients, pending edit, 120 ms TCP delay in each direction: paragraph/x at 263.1 ms and Markdown link/Enter at 244.3 ms. Both peer edits persisted in the Markdown-link case.
  • Linux WebKit, short Markdown link/Enter: passed persistence checks, but actual gap 718 ms. This is outside the owner timing window and is not Safari evidence.

Within the recorded Yjs vectors, every case contains the initial block and its removal; none contains a later restoration. Native immediate keys targeted the closing Delete block menu item or BODY, never the toast Undo button. Enter sometimes generates a second native click on the closing menu item. This is observed input behavior, not a confirmed resurrection cause.

Incomplete attempts remain explicit: real Safari has no usable VM display; Daily-note Chromium timed out before editor readiness; Daily-note WebKit reached the editor but the background peer insertText was not accepted. Target-caret attempts stopped before deletion at smart hover hiding and then a live DOM replacement; the current attempt approaches through right whitespace and uses native hover's retry. These are not counted as successful deletion cases. No large-Home fixture or production internet run completed. Requested real-Safari light/dark screenshots are unavailable.

Head 35b68049697d2e26ee72f568f3eaac3e223a585f adds explicit owner timing qualification, bounded Daily-note setup diagnostics, native caret probes, and a replacement-browser origin fix. The original default regression assertions are unchanged. No production fix exists yet. 17 cases completed; 12 delivered a key within 0–300 ms of the first Delete block click. All 17 kept the block absent in the editor, saved Markdown and reload. Full rows, actual gaps and activeElement facts: artifacts/linkdel2/completed-matrix.json. Logs and collaboration vectors are retained beside each run. Completed combinations: - Chromium, short paragraph, x/Enter/Backspace/ArrowRight, nominal gaps 0/100/300 ms (12 cases). Actual gaps range 51.1–381.3 ms; eight qualify for the owner window. - Chromium, short heading, x at 100.1 ms and Enter at 88.7 ms. - Chromium, 320 added paragraphs, two clients, pending edit, 120 ms TCP delay in each direction: paragraph/x at 263.1 ms and Markdown link/Enter at 244.3 ms. Both peer edits persisted in the Markdown-link case. - Linux WebKit, short Markdown link/Enter: passed persistence checks, but actual gap 718 ms. This is outside the owner timing window and is not Safari evidence. Within the recorded Yjs vectors, every case contains the initial block and its removal; none contains a later restoration. Native immediate keys targeted the closing Delete block menu item or BODY, never the toast Undo button. Enter sometimes generates a second native click on the closing menu item. This is observed input behavior, not a confirmed resurrection cause. Incomplete attempts remain explicit: real Safari has no usable VM display; Daily-note Chromium timed out before editor readiness; Daily-note WebKit reached the editor but the background peer insertText was not accepted. Target-caret attempts stopped before deletion at smart hover hiding and then a live DOM replacement; the current attempt approaches through right whitespace and uses native hover's retry. These are not counted as successful deletion cases. No large-Home fixture or production internet run completed. Requested real-Safari light/dark screenshots are unavailable.
Author
Owner

Starting #1384 on job/linkdel-1384 at base 35b6804969. I am tracing the immediate post-action menu focus window in Chromium and WebKit with reduced motion off; the regression test and fix will follow the confirmed path.

Starting #1384 on job/linkdel-1384 at base 35b68049697d2e26ee72f568f3eaac3e223a585f. I am tracing the immediate post-action menu focus window in Chromium and WebKit with reduced motion off; the regression test and fix will follow the confirmed path.
Author
Owner

Chromium finding on head 35b680496, production web build, macOS platform emulation, and reduced motion set to no-preference: native keys landed within 0–150 ms after Delete (x 93.8 ms, Enter 90.6 ms, Space 118.4 ms, ArrowDown 42.4 ms, Backspace 73.5 ms, Cmd+Z 91.1 ms). document.activeElement was still a menu item for every key. Enter and Space each caused a second native click on Delete. Each case produced one local Yjs transaction with origin Y.UndoManager and one marked outgoing update; no later Yjs update restored the block. The block stayed absent in the editor, saved Markdown and reload. Linux Playwright WebKit delivered Enter 502 ms later with focus on BODY, so it did not qualify for the 150 ms window. The source fix now releases focus and input ownership when the shared FloatingSurface starts closing.

Chromium finding on head 35b680496, production web build, macOS platform emulation, and reduced motion set to no-preference: native keys landed within 0–150 ms after Delete (x 93.8 ms, Enter 90.6 ms, Space 118.4 ms, ArrowDown 42.4 ms, Backspace 73.5 ms, Cmd+Z 91.1 ms). document.activeElement was still a menu item for every key. Enter and Space each caused a second native click on Delete. Each case produced one local Yjs transaction with origin Y.UndoManager and one marked outgoing update; no later Yjs update restored the block. The block stayed absent in the editor, saved Markdown and reload. Linux Playwright WebKit delivered Enter 502 ms later with focus on BODY, so it did not qualify for the 150 ms window. The source fix now releases focus and input ownership when the shared FloatingSurface starts closing.
Author
Owner

#1384 final report

Branch: job/linkdel-1384, based on origin/dev at 35b680496; the required fetch/merge completed with Already up to date.
Head: 4452ae706114f773d6f5427e0997ab32d47e10c5 (fix(ui): release closing-menu focus to block stale activation).

Built

  • Shared Menu now makes its closing layer inert and hidden from assistive technology immediately. It restores focus before the outro and ignores a queued activation after open becomes false.
  • Note block menus restore focus to the live Note editor. The programmatic handoff suppresses an action-induced focus ring. The close path costs O(1) DOM operations and performs no I/O.
  • FloatingSurface releases its focus trap when closing starts; Menu disables its delayed unmount-time restore.
  • The focused E2E trace records active element, activation count, and Yjs wire update origin/state without printing Note text or request data.

Trace findings

At 35b680496, the requested race was present: Chromium kept focus on the Delete menu item during its close motion; Enter/Space could issue a second native activation. The regression asserts one Delete activation and that the next key targets the editor, so it fails on that baseline.

After the fix, Chromium targeted the editor for x (91.5 ms on the repeat), Enter (80.8 ms), Space (60.6 ms), ArrowDown (113.4 ms), and Backspace (132.8 ms). There was one Delete activation in each case. The delete update had the scoped UndoManager origin; the next editor update did not restore the removed block. The block stayed absent in the live Note, saved Markdown, and reload.

Linux WebKit returned focus to the editor, but Playwright delivered Enter at 532 ms, outside the 0–150 ms window. This is not real macOS Safari evidence. In the tested fixtures, the block itself never reappeared, so no re-insertion path was found. The observed second runMenu call on baseline had context === null and emitted no further Yjs update in that fixture. This remains a gap against the requested re-insertion investigation.

UX gaps

  • Closed: the outroing menu no longer holds focus or accepts another key/action; block menus return to the editor without an action-induced ring; existing Undo still restores the block when selected.
  • Left: the originating re-insertion path remains unconfirmed because the block did not reappear in the requested key matrix.

Screenshots

Twelve actual-size screenshots were captured from the production web build with macOS platform emulation, before and after, at 390×844, 820×900, and 1440×900 in light and dark:
apps/web/artifacts/linkdel-1384/review/

These PNGs are gitignored and were not committed. fj issue comment accepts comment text only, so this comment records their worktree path for the visual reviewer.

Gates (verbatim output)

apps/web: bun run check exited 0.

PASS production dependency licences: 759 locked package releases across apps/web, apps/docs and packages
perf-lint: PASS; 0 violations; 22544 scoped exceptions
User browser caches use userStorage; only documented device/public-link exceptions remain.
Glass alpha, blur and backdrop-filter roles use packages/ui/src/tokens.css.
Text sizes and UI shape values use shared role tokens.
Keyboard focus rings use the shared focus tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
svelte-check found 0 errors and 4 warnings in 2 files

apps/web: bun run test exited 0.

 Test Files  297 passed (297)
      Tests  2118 passed (2118)
   Start at  04:00:35
   Duration  339.89s (environment 28%, transform 27%, import 25%, tests 15%, setup 5%)

Production E2E output:

notes delete race #1384 passed: 7 Markdown block forms, immediate type/Enter, Undo, and waited save/reload; screenshots in /home/kayg/Developer/calternal-wt/linkdel-1384/apps/web/artifacts/linkdel-1384/review

packages/ui has no check or test script; packages/editor was not changed. apps/web check/test, the production E2E, and git diff --check passed. cargo clean removed 1 file (356 B); web build output was deleted.

Decisions not specified in DESIGN

A block context menu returns focus to the Note editor surface, rather than the hover capsule button, because pointer-opened menus do not move focus to that button and it may disappear after deletion. All such programmatic closes use focusVisible: false; keyboard navigation inside the menu does not make its closing animation retain focus.

## #1384 final report Branch: `job/linkdel-1384`, based on `origin/dev` at `35b680496`; the required fetch/merge completed with `Already up to date.` Head: `4452ae706114f773d6f5427e0997ab32d47e10c5` (`fix(ui): release closing-menu focus to block stale activation`). ### Built - Shared `Menu` now makes its closing layer inert and hidden from assistive technology immediately. It restores focus before the outro and ignores a queued activation after `open` becomes false. - Note block menus restore focus to the live Note editor. The programmatic handoff suppresses an action-induced focus ring. The close path costs O(1) DOM operations and performs no I/O. - `FloatingSurface` releases its focus trap when closing starts; Menu disables its delayed unmount-time restore. - The focused E2E trace records active element, activation count, and Yjs wire update origin/state without printing Note text or request data. ### Trace findings At `35b680496`, the requested race was present: Chromium kept focus on the Delete menu item during its close motion; Enter/Space could issue a second native activation. The regression asserts one Delete activation and that the next key targets the editor, so it fails on that baseline. After the fix, Chromium targeted the editor for `x` (91.5 ms on the repeat), Enter (80.8 ms), Space (60.6 ms), ArrowDown (113.4 ms), and Backspace (132.8 ms). There was one Delete activation in each case. The delete update had the scoped `UndoManager` origin; the next editor update did not restore the removed block. The block stayed absent in the live Note, saved Markdown, and reload. Linux WebKit returned focus to the editor, but Playwright delivered Enter at 532 ms, outside the 0–150 ms window. This is not real macOS Safari evidence. In the tested fixtures, the block itself never reappeared, so no re-insertion path was found. The observed second `runMenu` call on baseline had `context === null` and emitted no further Yjs update in that fixture. This remains a gap against the requested re-insertion investigation. ### UX gaps - Closed: the outroing menu no longer holds focus or accepts another key/action; block menus return to the editor without an action-induced ring; existing Undo still restores the block when selected. - Left: the originating re-insertion path remains unconfirmed because the block did not reappear in the requested key matrix. ### Screenshots Twelve actual-size screenshots were captured from the production web build with macOS platform emulation, before and after, at 390×844, 820×900, and 1440×900 in light and dark: `apps/web/artifacts/linkdel-1384/review/` These PNGs are gitignored and were not committed. `fj issue comment` accepts comment text only, so this comment records their worktree path for the visual reviewer. ### Gates (verbatim output) `apps/web`: `bun run check` exited 0. ```text PASS production dependency licences: 759 locked package releases across apps/web, apps/docs and packages perf-lint: PASS; 0 violations; 22544 scoped exceptions User browser caches use userStorage; only documented device/public-link exceptions remain. Glass alpha, blur and backdrop-filter roles use packages/ui/src/tokens.css. Text sizes and UI shape values use shared role tokens. Keyboard focus rings use the shared focus tokens. UI transitions and animation options use shared motion tokens or documented exceptions. svelte-check found 0 errors and 4 warnings in 2 files ``` `apps/web`: `bun run test` exited 0. ```text Test Files 297 passed (297) Tests 2118 passed (2118) Start at 04:00:35 Duration 339.89s (environment 28%, transform 27%, import 25%, tests 15%, setup 5%) ``` Production E2E output: ```text notes delete race #1384 passed: 7 Markdown block forms, immediate type/Enter, Undo, and waited save/reload; screenshots in /home/kayg/Developer/calternal-wt/linkdel-1384/apps/web/artifacts/linkdel-1384/review ``` `packages/ui` has no `check` or `test` script; `packages/editor` was not changed. `apps/web` check/test, the production E2E, and `git diff --check` passed. `cargo clean` removed 1 file (356 B); web build output was deleted. ### Decisions not specified in DESIGN A block context menu returns focus to the Note editor surface, rather than the hover capsule button, because pointer-opened menus do not move focus to that button and it may disappear after deletion. All such programmatic closes use `focusVisible: false`; keyboard navigation inside the menu does not make its closing animation retain focus.
kayg referenced this issue from a commit 2026-10-08 10:41:40 +00:00
Author
Owner

Deployed in merge round 35a (cc1af3c12). Left open for the owner's retest.

Deployed in merge round 35a (cc1af3c12). Left open for the owner's retest.
Commenting is not possible because the repository is archived.
No labels
No milestone
No project
No assignees
1 participant
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal-v0#1384
No description provided.