Publish note events after the note list commits #594

Closed
kayg wants to merge 1 commit from issue/587-event-after-write into dev
Owner

The server could publish a note change while notes.list still served its old row. Home::record queued the metadata refresh, and its worker waited 50 ms before updating meta.db; room edits could also announce a change before their deferred file save. Under load, the web app’s 250 ms reread still saw the old pin or a deleted note.

This change commits the list row before recording the event. Rooms describe their current text, including saved-base title precedence, while watcher and trash operations wait for their row refresh. Scans share the refresh lock, skip open rooms, and keep cold fills batched. Clean saved rows retain reusable file stamps after checking the saved path and file hash. Failed room publications are retained and retried separately from file dirtiness, without rewriting the note file. File persistence and SQLite synchronous=NORMAL remain as before; no forced fsync was added.

Server projection lag no longer requires the client’s 250 ms reread delay. The UI owner can shorten or remove it, or keep it to coalesce requests. Existing guards for reads that began before an event still apply. No client code changed.

Related to #587.

Before and after evidence:

  • Untouched base 9b4835e931f6015af966a617db06457778277b18 plus the regression tests: 26 failed, 0 passed.
  • Fixed server: 28 passed, including two warm-cache guards. Eighteen action and external-edit cases run 20 rounds with 16 competing writes each (360 target actions and 5,760 competing writes). Further cases cover startup events, stale scan writes, metadata errors, publication retries, title precedence, and 20 fresh-home watcher-outage repetitions.
  • Remote workspace Clippy and workspace tests passed under the perf VM lock. Detailed development evidence is on #587.

Head: 87959539a3b8f611fe7617a72c91d75419e0479f.

Final browser gate: 227 passed, 50 skipped, 3 WebKit interruptions (exit 1). Chromium completed all 10 repetitions without failures. WebKit reported one Page crashed and two Target page, context or browser has been closed errors during Undo. The count expectation was interrupted by the page crash. These are reported separately from completed ordering assertions.

Delete Undo repeat 4 trace
Delete Undo repeat 7 trace
Trash Undo repeat 8 trace

An earlier browser run had 229 passed, 50 skipped and one explicit Target crashed; its trace and the development diagnostics are on #587. The test recorder uses a weak engine reference and releases each fresh Home, so final workspace tests passed with the unchanged 1,024 descriptor limit.

All local heavy commands ran through the supplied build-slot.sh, with Cargo -j4 and Playwright --workers=1. Playwright used this branch’s freshly built server binary. Gate output follows verbatim.

Formatting

$ cargo fmt --check
exit=0

Clippy

$ cargo clippy -q -j4 --workspace --all-targets -- -D warnings
exit=0

Workspace tests

$ cargo test -q -j4 --workspace

running 12 tests
............
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.30s


running 2 tests
..
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.10s


running 2 tests
..
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.33s


running 3 tests
...
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.96s


running 1 test
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.12s


running 2 tests
..
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s


running 1 test
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s


running 1 test
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.02s


running 5 tests
.....
test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s


running 19 tests
...................
test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s


running 13 tests
.............
test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 9 tests
.........
test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s


running 6 tests
......
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s


running 3 tests
...
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s


running 11 tests
...........
test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s


running 7 tests
.......
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s


running 8 tests
........
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s


running 19 tests
....i..............
test result: ok. 18 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.04s


running 7 tests
.......
test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 21 tests
.....................
test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.41s


running 13 tests
.............
test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.50s


running 4 tests
....
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 12 tests
............
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s


running 2 tests
..
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 36 tests
....................................
test result: ok. 36 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s


running 255 tests
..................i.................................................................... 87/255
....................................................................................... 174/255
.................................................................................
test result: ok. 254 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 14.70s


running 6 tests
......
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 9 tests
.........
test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s


running 13 tests
.............
test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 12 tests
............
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.06s


running 2 tests
..
test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 1 test
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 6 tests
......
test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s


running 1 test
.
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s


running 3 tests
...
test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s


running 8 tests
........
test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.31s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

exit=0

Named ordering, recovery and cache tests

$ cargo test -j4 -p calternal-notes event_visibility -- --test-threads=2
   Compiling calternal-notes v0.1.0 (/home/kayg/Developer/calternal-wt-587/crates/notes)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 10.14s
     Running unittests src/lib.rs (/home/kayg/Developer/calternal-target-587/debug/deps/calternal_notes-0168fb844f060989)

running 28 tests
test tests::event_visibility::a_scan_cannot_replace_an_announced_live_pin_with_the_old_file ... ok
test tests::event_visibility::a_failed_list_commit_cannot_announce_a_pin ... ok
test tests::event_visibility::create ... ok
test tests::event_visibility::create_text ... ok
test tests::event_visibility::delete ... ok
test tests::event_visibility::edit ... ok
test tests::event_visibility::edit_title ... ok
test tests::event_visibility::edit_title_property ... ok
test tests::event_visibility::outside_create ... ok
test tests::event_visibility::move_note ... ok
test tests::event_visibility::outside_delete ... ok
test tests::event_visibility::outside_edit ... ok
test tests::event_visibility::outside_edit_closed ... ok
test tests::event_visibility::outside_rename ... ok
test tests::event_visibility::outside_rename_closed ... ok
test tests::event_visibility::pin ... ok
test tests::event_visibility::rename_public_retry ... ok
test tests::event_visibility::rename_retry ... ok
test tests::event_visibility::rename ... ok
test tests::event_visibility::restore ... ok
test tests::event_visibility::save ... ok
test tests::event_visibility::save_outside_retry ... ok
test tests::event_visibility::save_retry ... ok
test tests::event_visibility::saved_rows_keep_file_stamps_for_warm_scans ... ok
test tests::event_visibility::startup_scan_events_are_listed_before_the_scan_finishes ... ok
test tests::event_visibility::save_background_retry ... ok
test tests::event_visibility::unread_external_bytes_do_not_get_a_clean_stamp ... ok
test tests::event_visibility::unpin ... ok

test result: ok. 28 passed; 0 failed; 0 ignored; 0 measured; 227 filtered out; finished in 5.19s

exit=0

Server binary

$ cargo build -q -j4 -p calternal
exit=0

Browser repetitions

$ bunx playwright test swipe-rows.spec.ts --project=chromium-390 --project=webkit-390 --repeat-each=10 --workers=1 --reporter=dot --output=/tmp/issue-587/pw-final
copied 7 font files to public/fonts
(!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite:
  - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension
  - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension
Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning.
11:35:11 PM [vite-plugin-svelte] src/App.svelte:157:4 Unused CSS selector ".toast"
https://svelte.dev/e/css_unused_selector
155:   }
156:   @media (prefers-reduced-motion: no-preference) {
157:     .toast {
               ^
158:       animation: toast-in 240ms var(--ease-out) backwards;
159:     }
11:35:11 PM [vite-plugin-svelte] /home/kayg/Developer/calternal-wt-587/packages/ui/src/primitives/toast/ToastCapsule.svelte:19:53 This reference only captures the initial value of `id`. Did you mean to reference it inside a derived instead?
https://svelte.dev/e/state_referenced_locally
17: 
18:   // Keep the last thing it said while it leaves (the view is gone by then).
19:   let last = $state<ToastView | undefined>(views.get(id));
                                                           ^
20:   $effect(() => {
21:     const v = views.get(id);
11:35:11 PM [vite-plugin-svelte] src/components/Shell.svelte:396:44 Unused CSS selector ".pblur"
https://svelte.dev/e/css_unused_selector
394:   /* Narrow and Wide: the paper itself floats on the backdrop (lib/paper.ts), so there is no glass
395:      frame, and what you see of the page reaches the pane's edges. */
396:   .floating :is(.frame-fill, .frame-shadow, .pblur) {
                                                       ^
397:     display: none;
398:   }
11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:474:2 Unused CSS selector ".seg.wide button"
https://svelte.dev/e/css_unused_selector
472:     text-underline-offset: 2px;
473:   }
474:   .seg.wide button {
                       ^
475:     flex: 1;
476:   }
11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:477:2 Unused CSS selector ".phone .seg.wide button"
https://svelte.dev/e/css_unused_selector
475:     flex: 1;
476:   }
477:   .phone .seg.wide button {
                              ^
478:     padding: 0 6px;
479:     font-size: calc(12.5 * var(--type-px));
11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:627:2 Unused CSS selector ".toggle input"
https://svelte.dev/e/css_unused_selector
625:     font-weight: 400;
626:   }
627:   .toggle input {
                    ^
628:     appearance: none;
629:     flex: none;
11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:637:2 Unused CSS selector ".toggle input::after"
https://svelte.dev/e/css_unused_selector
635:     transition: background-color 150ms var(--ease-out);
636:   }
637:   .toggle input::after {
                           ^
638:     content: "";
639:     position: absolute;
11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:649:2 Unused CSS selector ".toggle input:checked"
https://svelte.dev/e/css_unused_selector
647:     transition: translate 200ms var(--ease-out);
648:   }
649:   .toggle input:checked {
                            ^
650:     background: var(--accent);
651:   }
11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:652:2 Unused CSS selector ".toggle input:checked::after"
https://svelte.dev/e/css_unused_selector
650:     background: var(--accent);
651:   }
652:   .toggle input:checked::after {
                                   ^
653:     translate: 16px 0;
654:   }
11:35:12 PM [vite-plugin-svelte] src/components/Inspector.svelte:19:7 This reference only captures the initial value of `noteId`. Did you mean to reference it inside a closure instead?
https://svelte.dev/e/state_referenced_locally
17:   const isTitle = $derived(current === "h1");
18:   const why = (_t: BlockType) => undefined as string | undefined;
19:   void noteId;
                 ^
20: 
21:   function apply(type: BlockType) {
11:35:12 PM [vite-plugin-svelte] src/components/InsertSheet.svelte:42:7 This reference only captures the initial value of `noteId`. Did you mean to reference it inside a closure instead?
https://svelte.dev/e/state_referenced_locally
40:     openSheet(null);
41:   }
42:   void noteId;
                 ^
43: 
44:   function key(e: KeyboardEvent) {
11:35:12 PM [vite-plugin-svelte] src/components/InfoSheet.svelte:383:2 Unused CSS selector ".avatar.agent"
https://svelte.dev/e/css_unused_selector
381:     color: var(--accent);
382:   }
383:   .avatar.agent {
                    ^
384:     background: var(--hover);
385:     color: var(--ink-2);
11:35:12 PM [vite-plugin-svelte] src/components/NoteList.svelte:114:14 This reference only captures the initial value of `phone`. Did you mean to reference it inside a closure instead?
https://svelte.dev/e/state_referenced_locally
112:   // A phone in a browser tab scrolls the document, not this box (PhoneStack, #445): where the rows are
113:   // is then the window's scroll less where this box starts, and the view is the window.
114:   const doc = phone && phoneDocScroll();
                        ^
115:   $effect(() => {
116:     const el = scroll;
[WebServer] (node:495030) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (node:495060) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite:
[WebServer]   - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension
[WebServer]   - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension
[WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning.
[WebServer] (node:495213) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite:
[WebServer]   - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension
[WebServer]   - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension
[WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning.
[WebServer] (node:495316) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite:
[WebServer]   - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension
[WebServer]   - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension
[WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning.
[WebServer] (node:495391) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite:
[WebServer]   - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension
[WebServer]   - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension
[WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning.
[WebServer] (node:495470) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
[WebServer] (Use `node --trace-warnings ...` to show where the warning was created)
[WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite:
[WebServer]   - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension
[WebServer]   - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension
[WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning.

Running 280 tests using 1 worker
(node:495517) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°··(node:496141) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°··(node:496720) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°··(node:497354) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°··(node:497974) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°··(node:499618) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········
°°··(node:500254) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°··(node:500845) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°··(node:501453) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°··(node:502059) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°··(node:502673) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°·°(node:504201) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
······
····°°·°(node:505703) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°·°(node:507187) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°·°(node:508699) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
······F(node:509571) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
···°°·°(node:510267) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°·°(node:512694) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°·°(node:514411) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··
····F(node:515338) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
···°°·°(node:516076) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
·······F(node:517226) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··°°·°(node:517766) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set.
(Use `node --trace-warnings ...` to show where the warning was created)
Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set.
··········°°·°

  1) [webkit-390] › e2e/swipe-rows.spec.ts:177:1 › Delete moves the note to the Trash with Undo; a long swipe does the same 

    Error: locator.click: Target page, context or browser has been closed
    Call log:
      - waiting for locator('[data-sonner-toast]').or(getByRole('status', { name: 'Notification' })).first().getByRole('button', { name: 'Undo' })
        - locator resolved to <button type="button" class="act svelte-1125l4b">Undo</button>
      - attempting click action
        2 × waiting for element to be visible, enabled and stable
          - element is not stable
        - retrying click action
        - waiting 20ms
        - waiting for element to be visible, enabled and stable


      186 |   await expect(toast(page)).toContainText('to the Trash')
      187 |   await expect(rows).toHaveCount(1)
    > 188 |   await toast(page).getByRole('button', { name: 'Undo' }).click()
          |                                                           ^
      189 |   await expect(rows).toHaveCount(2, { timeout: 10_000 })
      190 |   // The long swipe.
      191 |   const two_ = page.locator('section .ra', { hasText: b })
        at /home/kayg/Developer/calternal-wt-587/apps/web/e2e/swipe-rows.spec.ts:188:59

    Error Context: ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat4/error-context.md

    attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
    ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat4/trace.zip
    Usage:

        npx playwright show-trace ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat4/trace.zip

    ────────────────────────────────────────────────────────────────────────────────────────────────

  2) [webkit-390] › e2e/swipe-rows.spec.ts:177:1 › Delete moves the note to the Trash with Undo; a long swipe does the same 

    Error: expect(locator).toHaveCount(expected) failed

    Locator:  locator('section .ra').filter({ hasText: 'swd-tldd1r' })
    Expected: 2
    Received: 1

    Call log:
      - Expect "toHaveCount" locator('section .ra').filter({ hasText: 'swd-tldd1r' }) with timeout 10000ms
      - waiting for locator('section .ra').filter({ hasText: 'swd-tldd1r' })
        4 × locator resolved to 1 element
          - unexpected value "1"
      - Page crashed


      187 |   await expect(rows).toHaveCount(1)
      188 |   await toast(page).getByRole('button', { name: 'Undo' }).click()
    > 189 |   await expect(rows).toHaveCount(2, { timeout: 10_000 })
          |                      ^
      190 |   // The long swipe.
      191 |   const two_ = page.locator('section .ra', { hasText: b })
      192 |   await swipe(page, two_, -330, w)
        at /home/kayg/Developer/calternal-wt-587/apps/web/e2e/swipe-rows.spec.ts:189:22

    Error Context: ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat7/error-context.md

    attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
    ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat7/trace.zip
    Usage:

        npx playwright show-trace ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat7/trace.zip

    ────────────────────────────────────────────────────────────────────────────────────────────────

  3) [webkit-390] › e2e/swipe-rows.spec.ts:197:1 › the Trash: Restore (a long swipe too, with Undo); Delete forever asks Confirm in place 

    Error: locator.click: Target page, context or browser has been closed
    Call log:
      - waiting for locator('[data-sonner-toast]').or(getByRole('status', { name: 'Notification' })).first().getByRole('button', { name: 'Undo' })


      215 |   await expect(rows).toHaveCount(1, { timeout: 10_000 })
      216 |   await expect(toast(page)).toContainText('Restored')
    > 217 |   await toast(page).getByRole('button', { name: 'Undo' }).click()
          |                                                           ^
      218 |   await expect(rows).toHaveCount(2, { timeout: 10_000 })
      219 |   // Left: Delete forever never runs from a long swipe, and asks again on the button.
      220 |   const row = rows.first()
        at /home/kayg/Developer/calternal-wt-587/apps/web/e2e/swipe-rows.spec.ts:217:59

    Error Context: ../../../../../../tmp/issue-587/pw-final/swipe-rows-the-Trash-Resto-d6cfa-rever-asks-Confirm-in-place-webkit-390-repeat8/error-context.md

    attachment #2: trace (application/zip) ─────────────────────────────────────────────────────────
    ../../../../../../tmp/issue-587/pw-final/swipe-rows-the-Trash-Resto-d6cfa-rever-asks-Confirm-in-place-webkit-390-repeat8/trace.zip
    Usage:

        npx playwright show-trace ../../../../../../tmp/issue-587/pw-final/swipe-rows-the-Trash-Resto-d6cfa-rever-asks-Confirm-in-place-webkit-390-repeat8/trace.zip

    ────────────────────────────────────────────────────────────────────────────────────────────────

  3 failed
    [webkit-390] › e2e/swipe-rows.spec.ts:177:1 › Delete moves the note to the Trash with Undo; a long swipe does the same 
    [webkit-390] › e2e/swipe-rows.spec.ts:177:1 › Delete moves the note to the Trash with Undo; a long swipe does the same 
    [webkit-390] › e2e/swipe-rows.spec.ts:197:1 › the Trash: Restore (a long swipe too, with Undo); Delete forever asks Confirm in place 
  50 skipped
  227 passed (8.5m)
exit=1

The server could publish a note change while `notes.list` still served its old row. `Home::record` queued the metadata refresh, and its worker waited 50 ms before updating `meta.db`; room edits could also announce a change before their deferred file save. Under load, the web app’s 250 ms reread still saw the old pin or a deleted note. This change commits the list row before recording the event. Rooms describe their current text, including saved-base title precedence, while watcher and trash operations wait for their row refresh. Scans share the refresh lock, skip open rooms, and keep cold fills batched. Clean saved rows retain reusable file stamps after checking the saved path and file hash. Failed room publications are retained and retried separately from file dirtiness, without rewriting the note file. File persistence and SQLite `synchronous=NORMAL` remain as before; no forced fsync was added. Server projection lag no longer requires the client’s 250 ms reread delay. The UI owner can shorten or remove it, or keep it to coalesce requests. Existing guards for reads that began before an event still apply. No client code changed. Related to #587. Before and after evidence: - Untouched base `9b4835e931f6015af966a617db06457778277b18` plus the regression tests: 26 failed, 0 passed. - Fixed server: 28 passed, including two warm-cache guards. Eighteen action and external-edit cases run 20 rounds with 16 competing writes each (360 target actions and 5,760 competing writes). Further cases cover startup events, stale scan writes, metadata errors, publication retries, title precedence, and 20 fresh-home watcher-outage repetitions. - Remote workspace Clippy and workspace tests passed under the perf VM lock. Detailed development evidence is on #587. Head: `87959539a3b8f611fe7617a72c91d75419e0479f`. Final browser gate: 227 passed, 50 skipped, 3 WebKit interruptions (exit 1). Chromium completed all 10 repetitions without failures. WebKit reported one `Page crashed` and two `Target page, context or browser has been closed` errors during Undo. The count expectation was interrupted by the page crash. These are reported separately from completed ordering assertions. [Delete Undo repeat 4 trace](https://git.kayg.org/attachments/cb960a0c-4d3d-4e78-953d-9ba4b69e8ff2) [Delete Undo repeat 7 trace](https://git.kayg.org/attachments/0669b2dd-72bd-4972-8655-29ef1d262a66) [Trash Undo repeat 8 trace](https://git.kayg.org/attachments/78444cb5-9047-4fad-80ab-77ac1cb1f491) An earlier browser run had 229 passed, 50 skipped and one explicit `Target crashed`; its [trace](https://git.kayg.org/attachments/bea64478-c0e1-4521-998e-524ab6022a45) and the development diagnostics are on #587. The test recorder uses a weak engine reference and releases each fresh Home, so final workspace tests passed with the unchanged 1,024 descriptor limit. All local heavy commands ran through the supplied `build-slot.sh`, with Cargo `-j4` and Playwright `--workers=1`. Playwright used this branch’s freshly built server binary. Gate output follows verbatim. Formatting ```text $ cargo fmt --check exit=0 ``` Clippy ```text $ cargo clippy -q -j4 --workspace --all-targets -- -D warnings exit=0 ``` Workspace tests ```text $ cargo test -q -j4 --workspace running 12 tests ............ test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.30s running 2 tests .. test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.10s running 2 tests .. test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.33s running 3 tests ... test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 4.96s running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 3.12s running 2 tests .. test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.02s running 5 tests ..... test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s running 19 tests ................... test result: ok. 19 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s running 13 tests ............. test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 9 tests ......... test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.04s running 6 tests ...... test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s running 3 tests ... test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s running 11 tests ........... test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s running 7 tests ....... test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s running 8 tests ........ test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.07s running 19 tests ....i.............. test result: ok. 18 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.04s running 7 tests ....... test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 21 tests ..................... test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.41s running 13 tests ............. test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.50s running 4 tests .... test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.21s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 12 tests ............ test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.06s running 2 tests .. test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 36 tests .................................... test result: ok. 36 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s running 255 tests ..................i.................................................................... 87/255 ....................................................................................... 174/255 ................................................................................. test result: ok. 254 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 14.70s running 6 tests ...... test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 9 tests ......... test result: ok. 9 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s running 13 tests ............. test result: ok. 13 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 12 tests ............ test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.06s running 2 tests .. test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 6 tests ...... test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.05s running 3 tests ... test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s running 8 tests ........ test result: ok. 8 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.31s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s exit=0 ``` Named ordering, recovery and cache tests ```text $ cargo test -j4 -p calternal-notes event_visibility -- --test-threads=2 Compiling calternal-notes v0.1.0 (/home/kayg/Developer/calternal-wt-587/crates/notes) Finished `test` profile [unoptimized + debuginfo] target(s) in 10.14s Running unittests src/lib.rs (/home/kayg/Developer/calternal-target-587/debug/deps/calternal_notes-0168fb844f060989) running 28 tests test tests::event_visibility::a_scan_cannot_replace_an_announced_live_pin_with_the_old_file ... ok test tests::event_visibility::a_failed_list_commit_cannot_announce_a_pin ... ok test tests::event_visibility::create ... ok test tests::event_visibility::create_text ... ok test tests::event_visibility::delete ... ok test tests::event_visibility::edit ... ok test tests::event_visibility::edit_title ... ok test tests::event_visibility::edit_title_property ... ok test tests::event_visibility::outside_create ... ok test tests::event_visibility::move_note ... ok test tests::event_visibility::outside_delete ... ok test tests::event_visibility::outside_edit ... ok test tests::event_visibility::outside_edit_closed ... ok test tests::event_visibility::outside_rename ... ok test tests::event_visibility::outside_rename_closed ... ok test tests::event_visibility::pin ... ok test tests::event_visibility::rename_public_retry ... ok test tests::event_visibility::rename_retry ... ok test tests::event_visibility::rename ... ok test tests::event_visibility::restore ... ok test tests::event_visibility::save ... ok test tests::event_visibility::save_outside_retry ... ok test tests::event_visibility::save_retry ... ok test tests::event_visibility::saved_rows_keep_file_stamps_for_warm_scans ... ok test tests::event_visibility::startup_scan_events_are_listed_before_the_scan_finishes ... ok test tests::event_visibility::save_background_retry ... ok test tests::event_visibility::unread_external_bytes_do_not_get_a_clean_stamp ... ok test tests::event_visibility::unpin ... ok test result: ok. 28 passed; 0 failed; 0 ignored; 0 measured; 227 filtered out; finished in 5.19s exit=0 ``` Server binary ```text $ cargo build -q -j4 -p calternal exit=0 ``` Browser repetitions ```text $ bunx playwright test swipe-rows.spec.ts --project=chromium-390 --project=webkit-390 --repeat-each=10 --workers=1 --reporter=dot --output=/tmp/issue-587/pw-final copied 7 font files to public/fonts (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite: - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning. 11:35:11 PM [vite-plugin-svelte] src/App.svelte:157:4 Unused CSS selector ".toast" https://svelte.dev/e/css_unused_selector 155: } 156: @media (prefers-reduced-motion: no-preference) { 157: .toast { ^ 158: animation: toast-in 240ms var(--ease-out) backwards; 159: } 11:35:11 PM [vite-plugin-svelte] /home/kayg/Developer/calternal-wt-587/packages/ui/src/primitives/toast/ToastCapsule.svelte:19:53 This reference only captures the initial value of `id`. Did you mean to reference it inside a derived instead? https://svelte.dev/e/state_referenced_locally 17: 18: // Keep the last thing it said while it leaves (the view is gone by then). 19: let last = $state<ToastView | undefined>(views.get(id)); ^ 20: $effect(() => { 21: const v = views.get(id); 11:35:11 PM [vite-plugin-svelte] src/components/Shell.svelte:396:44 Unused CSS selector ".pblur" https://svelte.dev/e/css_unused_selector 394: /* Narrow and Wide: the paper itself floats on the backdrop (lib/paper.ts), so there is no glass 395: frame, and what you see of the page reaches the pane's edges. */ 396: .floating :is(.frame-fill, .frame-shadow, .pblur) { ^ 397: display: none; 398: } 11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:474:2 Unused CSS selector ".seg.wide button" https://svelte.dev/e/css_unused_selector 472: text-underline-offset: 2px; 473: } 474: .seg.wide button { ^ 475: flex: 1; 476: } 11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:477:2 Unused CSS selector ".phone .seg.wide button" https://svelte.dev/e/css_unused_selector 475: flex: 1; 476: } 477: .phone .seg.wide button { ^ 478: padding: 0 6px; 479: font-size: calc(12.5 * var(--type-px)); 11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:627:2 Unused CSS selector ".toggle input" https://svelte.dev/e/css_unused_selector 625: font-weight: 400; 626: } 627: .toggle input { ^ 628: appearance: none; 629: flex: none; 11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:637:2 Unused CSS selector ".toggle input::after" https://svelte.dev/e/css_unused_selector 635: transition: background-color 150ms var(--ease-out); 636: } 637: .toggle input::after { ^ 638: content: ""; 639: position: absolute; 11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:649:2 Unused CSS selector ".toggle input:checked" https://svelte.dev/e/css_unused_selector 647: transition: translate 200ms var(--ease-out); 648: } 649: .toggle input:checked { ^ 650: background: var(--accent); 651: } 11:35:12 PM [vite-plugin-svelte] src/components/Settings.svelte:652:2 Unused CSS selector ".toggle input:checked::after" https://svelte.dev/e/css_unused_selector 650: background: var(--accent); 651: } 652: .toggle input:checked::after { ^ 653: translate: 16px 0; 654: } 11:35:12 PM [vite-plugin-svelte] src/components/Inspector.svelte:19:7 This reference only captures the initial value of `noteId`. Did you mean to reference it inside a closure instead? https://svelte.dev/e/state_referenced_locally 17: const isTitle = $derived(current === "h1"); 18: const why = (_t: BlockType) => undefined as string | undefined; 19: void noteId; ^ 20: 21: function apply(type: BlockType) { 11:35:12 PM [vite-plugin-svelte] src/components/InsertSheet.svelte:42:7 This reference only captures the initial value of `noteId`. Did you mean to reference it inside a closure instead? https://svelte.dev/e/state_referenced_locally 40: openSheet(null); 41: } 42: void noteId; ^ 43: 44: function key(e: KeyboardEvent) { 11:35:12 PM [vite-plugin-svelte] src/components/InfoSheet.svelte:383:2 Unused CSS selector ".avatar.agent" https://svelte.dev/e/css_unused_selector 381: color: var(--accent); 382: } 383: .avatar.agent { ^ 384: background: var(--hover); 385: color: var(--ink-2); 11:35:12 PM [vite-plugin-svelte] src/components/NoteList.svelte:114:14 This reference only captures the initial value of `phone`. Did you mean to reference it inside a closure instead? https://svelte.dev/e/state_referenced_locally 112: // A phone in a browser tab scrolls the document, not this box (PhoneStack, #445): where the rows are 113: // is then the window's scroll less where this box starts, and the view is the window. 114: const doc = phone && phoneDocScroll(); ^ 115: $effect(() => { 116: const el = scroll; [WebServer] (node:495030) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. [WebServer] (Use `node --trace-warnings ...` to show where the warning was created) [WebServer] (node:495060) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. [WebServer] (Use `node --trace-warnings ...` to show where the warning was created) [WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite: [WebServer] - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension [WebServer] - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension [WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning. [WebServer] (node:495213) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. [WebServer] (Use `node --trace-warnings ...` to show where the warning was created) [WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite: [WebServer] - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension [WebServer] - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension [WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning. [WebServer] (node:495316) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. [WebServer] (Use `node --trace-warnings ...` to show where the warning was created) [WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite: [WebServer] - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension [WebServer] - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension [WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning. [WebServer] (node:495391) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. [WebServer] (Use `node --trace-warnings ...` to show where the warning was created) [WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite: [WebServer] - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension [WebServer] - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension [WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning. [WebServer] (node:495470) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. [WebServer] (Use `node --trace-warnings ...` to show where the warning was created) [WebServer] (!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite: [WebServer] - import "./scripts/precompress-plugin" without a file extension (vite.config.ts:3:29). Add the file extension [WebServer] - import "./scripts/sw-plugin" without a file extension (vite.config.ts:4:31). Add the file extension [WebServer] Set `VITE_CONFIG_NATIVE_IGNORE_WARNING=true` to suppress this warning. Running 280 tests using 1 worker (node:495517) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°··(node:496141) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°··(node:496720) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°··(node:497354) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°··(node:497974) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°··(node:499618) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ·········· °°··(node:500254) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°··(node:500845) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°··(node:501453) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°··(node:502059) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°··(node:502673) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°·°(node:504201) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ······ ····°°·°(node:505703) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°·°(node:507187) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°·°(node:508699) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ······F(node:509571) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ···°°·°(node:510267) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°·°(node:512694) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°·°(node:514411) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ·· ····F(node:515338) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ···°°·°(node:516076) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ·······F(node:517226) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··°°·°(node:517766) Warning: The 'NO_COLOR' env is ignored due to the 'FORCE_COLOR' env being set. (Use `node --trace-warnings ...` to show where the warning was created) Skipping host requirements validation logic because `PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS` env variable is set. ··········°°·° 1) [webkit-390] › e2e/swipe-rows.spec.ts:177:1 › Delete moves the note to the Trash with Undo; a long swipe does the same Error: locator.click: Target page, context or browser has been closed Call log: - waiting for locator('[data-sonner-toast]').or(getByRole('status', { name: 'Notification' })).first().getByRole('button', { name: 'Undo' }) - locator resolved to <button type="button" class="act svelte-1125l4b">Undo</button> - attempting click action 2 × waiting for element to be visible, enabled and stable - element is not stable - retrying click action - waiting 20ms - waiting for element to be visible, enabled and stable 186 | await expect(toast(page)).toContainText('to the Trash') 187 | await expect(rows).toHaveCount(1) > 188 | await toast(page).getByRole('button', { name: 'Undo' }).click() | ^ 189 | await expect(rows).toHaveCount(2, { timeout: 10_000 }) 190 | // The long swipe. 191 | const two_ = page.locator('section .ra', { hasText: b }) at /home/kayg/Developer/calternal-wt-587/apps/web/e2e/swipe-rows.spec.ts:188:59 Error Context: ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat4/error-context.md attachment #2: trace (application/zip) ───────────────────────────────────────────────────────── ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat4/trace.zip Usage: npx playwright show-trace ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat4/trace.zip ──────────────────────────────────────────────────────────────────────────────────────────────── 2) [webkit-390] › e2e/swipe-rows.spec.ts:177:1 › Delete moves the note to the Trash with Undo; a long swipe does the same Error: expect(locator).toHaveCount(expected) failed Locator: locator('section .ra').filter({ hasText: 'swd-tldd1r' }) Expected: 2 Received: 1 Call log: - Expect "toHaveCount" locator('section .ra').filter({ hasText: 'swd-tldd1r' }) with timeout 10000ms - waiting for locator('section .ra').filter({ hasText: 'swd-tldd1r' }) 4 × locator resolved to 1 element - unexpected value "1" - Page crashed 187 | await expect(rows).toHaveCount(1) 188 | await toast(page).getByRole('button', { name: 'Undo' }).click() > 189 | await expect(rows).toHaveCount(2, { timeout: 10_000 }) | ^ 190 | // The long swipe. 191 | const two_ = page.locator('section .ra', { hasText: b }) 192 | await swipe(page, two_, -330, w) at /home/kayg/Developer/calternal-wt-587/apps/web/e2e/swipe-rows.spec.ts:189:22 Error Context: ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat7/error-context.md attachment #2: trace (application/zip) ───────────────────────────────────────────────────────── ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat7/trace.zip Usage: npx playwright show-trace ../../../../../../tmp/issue-587/pw-final/swipe-rows-Delete-moves-th-17344--a-long-swipe-does-the-same-webkit-390-repeat7/trace.zip ──────────────────────────────────────────────────────────────────────────────────────────────── 3) [webkit-390] › e2e/swipe-rows.spec.ts:197:1 › the Trash: Restore (a long swipe too, with Undo); Delete forever asks Confirm in place Error: locator.click: Target page, context or browser has been closed Call log: - waiting for locator('[data-sonner-toast]').or(getByRole('status', { name: 'Notification' })).first().getByRole('button', { name: 'Undo' }) 215 | await expect(rows).toHaveCount(1, { timeout: 10_000 }) 216 | await expect(toast(page)).toContainText('Restored') > 217 | await toast(page).getByRole('button', { name: 'Undo' }).click() | ^ 218 | await expect(rows).toHaveCount(2, { timeout: 10_000 }) 219 | // Left: Delete forever never runs from a long swipe, and asks again on the button. 220 | const row = rows.first() at /home/kayg/Developer/calternal-wt-587/apps/web/e2e/swipe-rows.spec.ts:217:59 Error Context: ../../../../../../tmp/issue-587/pw-final/swipe-rows-the-Trash-Resto-d6cfa-rever-asks-Confirm-in-place-webkit-390-repeat8/error-context.md attachment #2: trace (application/zip) ───────────────────────────────────────────────────────── ../../../../../../tmp/issue-587/pw-final/swipe-rows-the-Trash-Resto-d6cfa-rever-asks-Confirm-in-place-webkit-390-repeat8/trace.zip Usage: npx playwright show-trace ../../../../../../tmp/issue-587/pw-final/swipe-rows-the-Trash-Resto-d6cfa-rever-asks-Confirm-in-place-webkit-390-repeat8/trace.zip ──────────────────────────────────────────────────────────────────────────────────────────────── 3 failed [webkit-390] › e2e/swipe-rows.spec.ts:177:1 › Delete moves the note to the Trash with Undo; a long swipe does the same [webkit-390] › e2e/swipe-rows.spec.ts:177:1 › Delete moves the note to the Trash with Undo; a long swipe does the same [webkit-390] › e2e/swipe-rows.spec.ts:197:1 › the Trash: Restore (a long swipe too, with Undo); Delete forever asks Confirm in place 50 skipped 227 passed (8.5m) exit=1 ```
Publish note events after list rows commit
Some checks failed
CI / server (pull_request) Successful in 22s
CI / web (pull_request) Failing after 34s
CI / rust (pull_request) Failing after 1m11s
87959539a3
Commit live room metadata before journaling note events and serialize
scan refreshes. Preserve reusable saved-file stamps and retry failed
publication without rewriting note files.

Add immediate-read regressions under concurrent writes, plus cache and
recovery guards. Related to #587.
Author
Owner

Closing: superseded by #597 (named in the PR body or comments). Branch kept.

Closing: superseded by #597 (named in the PR body or comments). Branch kept.
kayg closed this pull request 2026-11-04 13:04:27 +00:00
Some checks failed
CI / server (pull_request) Successful in 22s
CI / web (pull_request) Failing after 34s
CI / rust (pull_request) Failing after 1m11s

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
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!594
No description provided.