fix(bars): the Settings bar no longer puts away an Attach menu opened on the note (#914, #943) #977

Closed
kayg wants to merge 0 commits from flaky/attach-stale-list into dev
Owner

Fixes the product bug behind "Attach menu closes itself 100 to 250 ms after a very early tap" (BM14e, #914 comment 79766) and the Divider timeout in #943. Found by the flaky lane (U4).

Cause. ui.attachOpen is one flag shared by every BottomBar. Each bar has an effect, "another note: the menu is not for it", that sets it false whenever its noteId changes, which includes the first run when the bar mounts. The Settings screen is built at idle (afterPaintIdle, up to a second after the first paint) and its own hidden bar one frame later. That bar has no note (noteId is null), mounts, runs the effect, and clears the flag: the menu a person opened on the note a moment earlier closes under their finger. On a quiet machine idle comes before anyone can tap; on a busy one it comes 100 to 250 ms after a very early tap.

How I found it. A diagnostic spec tapped Attach as soon as the bar was ready and logged the bar's mode, focus, address and pointer/resize/scroll events: under build load, 2 of 200 runs closed with nothing else happening (key=attach at 148 ms, key=tools at 306 ms) and one more went by before the poll saw it. Temporary logging in the effect (not committed) showed noteId effect null open=true. (My first theory, a note list lagging behind a fresh note, was wrong: the "isn't here any more" view never showed. I dropped it.)

Fix. The effect returns for a bar that shows no note (if (!inNote) return), one line. The note's own bar still puts the menu away on another note.

Test (note-bars.spec.ts, phone): holds the browser's idle callbacks until the menu is open, then runs them (Settings and its bar are built), and asserts the menu is still open. Test commit alone (43ad9d15), 20 repeats: chromium-390 20/20 failed, webkit-390 20/20 failed (attach expected, tools received). With the fix (2d0e82ff): all Attach tests in the file, 20 repeats: chromium-390 120/120 passed, webkit-390 100/100 passed (20 skipped: the Divider test skips WebKit by its own rule).

Other gates (dev-01, through Nix and ~/bin/slot): svelte-check 0 errors; web unit tests 109 passed; note-bars + related bar specs at chromium-1440 and chromium-390, 3 repeats: 69 passed, 0 failed (63 skipped by their own width rules). No hot path touched, no bytes added (one line in an effect that already existed).

🤖 Generated with Claude Code

Fixes the **product bug** behind "Attach menu closes itself 100 to 250 ms after a very early tap" (BM14e, [#914 comment 79766](https://git.kayg.org/kayg/calternal/issues/914#issuecomment-79766)) and the Divider timeout in #943. Found by the flaky lane (U4). **Cause.** `ui.attachOpen` is one flag shared by every `BottomBar`. Each bar has an effect, "another note: the menu is not for it", that sets it false whenever its `noteId` changes, which includes the first run when the bar mounts. The Settings screen is built at idle (`afterPaintIdle`, up to a second after the first paint) and its own hidden bar one frame later. That bar has no note (`noteId` is null), mounts, runs the effect, and clears the flag: the menu a person opened on the note a moment earlier closes under their finger. On a quiet machine idle comes before anyone can tap; on a busy one it comes 100 to 250 ms after a very early tap. **How I found it.** A diagnostic spec tapped Attach as soon as the bar was ready and logged the bar's mode, focus, address and pointer/resize/scroll events: under build load, 2 of 200 runs closed with nothing else happening (`key=attach` at 148 ms, `key=tools` at 306 ms) and one more went by before the poll saw it. Temporary logging in the effect (not committed) showed `noteId effect null open=true`. (My first theory, a note list lagging behind a fresh note, was wrong: the "isn't here any more" view never showed. I dropped it.) **Fix.** The effect returns for a bar that shows no note (`if (!inNote) return`), one line. The note's own bar still puts the menu away on another note. **Test** (`note-bars.spec.ts`, phone): holds the browser's idle callbacks until the menu is open, then runs them (Settings and its bar are built), and asserts the menu is still open. Test commit alone (`43ad9d15`), 20 repeats: **chromium-390 20/20 failed, webkit-390 20/20 failed** (`attach` expected, `tools` received). With the fix (`2d0e82ff`): all Attach tests in the file, 20 repeats: **chromium-390 120/120 passed, webkit-390 100/100 passed** (20 skipped: the Divider test skips WebKit by its own rule). **Other gates** (dev-01, through Nix and `~/bin/slot`): `svelte-check` 0 errors; web unit tests 109 passed; `note-bars` + related bar specs at chromium-1440 and chromium-390, 3 repeats: 69 passed, 0 failed (63 skipped by their own width rules). No hot path touched, no bytes added (one line in an effect that already existed). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The browser's idle callbacks are held until the menu is open, then run: Settings is built, then its bar. The menu must stay. Fails on dev: the Settings bar's 'another note' effect runs as it mounts and puts the shared menu away (the Attach menu closing 100 to 250 ms after a very early tap, #914).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
fix(bars): only the bar that shows a note puts the Attach menu away for another note
Some checks failed
CI / server (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
CI / web (pull_request) Has been cancelled
Markdown extraction contract / markdown-native-contract (pull_request) Has been cancelled
Markdown extraction contract / markdown-editor-contract (pull_request) Has been cancelled
2d0e82ffa9
The Settings bar is built at idle and shares ui.attachOpen. Its 'another note' effect ran as it mounted and closed a menu just opened on the note: the Attach menu closed itself 100 to 250 ms after a very early tap on a busy machine (BM14e, #914, #943). The effect now returns for a bar with no note.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Author
Owner

#977 gates: GREEN at 2d0e82ff (contains dev 02cdf878)

gate result
lint / svelte-check / vitest web / ui primitives / check-ui-primitives pass / 0 errors, 16 warnings (= dev) / 109 / 56 / clean
first-paint JS brotli (same machine, perf/web.sh --bundle-only --gate) 232.533 KB vs dev 232.617: −84 B; first CSS 17.952 = dev; idle-screens 51.275 (line 51.3); gate rc 0
Chromium (dev-01) 1440+390: note-bars (the new spec), note-bars-motion, bar-focus, bar-rest, sheet-geometry, settings-links, composer-open 56 passed, 0 failed
WebKit (dev-02) same 55 passed, 0 failed
Rust perf n/a
## #977 gates: GREEN at `2d0e82ff` (contains dev `02cdf878`) | gate | result | |---|---| | lint / svelte-check / vitest web / ui primitives / `check-ui-primitives` | pass / 0 errors, 16 warnings (= dev) / 109 / 56 / clean | | **first-paint JS brotli** (same machine, `perf/web.sh --bundle-only --gate`) | **232.533 KB vs dev 232.617: −84 B**; first CSS 17.952 = dev; `idle-screens` 51.275 (line 51.3); gate rc 0 | | Chromium (dev-01) 1440+390: note-bars (the new spec), note-bars-motion, bar-focus, bar-rest, sheet-geometry, settings-links, composer-open | 56 passed, 0 failed | | WebKit (dev-02) same | 55 passed, 0 failed | | Rust perf | n/a |
Author
Owner

Merged into dev by the orchestrator (U1 GREEN).

Merged into dev by the orchestrator (U1 GREEN).
kayg closed this pull request 2026-11-06 03:28:49 +00:00
Some checks failed
CI / server (pull_request) Has been cancelled
CI / rust (pull_request) Has been cancelled
CI / web (pull_request) Has been cancelled
Markdown extraction contract / markdown-native-contract (pull_request) Has been cancelled
Markdown extraction contract / markdown-editor-contract (pull_request) Has been cancelled

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!977
No description provided.