SELECTION BAR: no 'Done'; the count is its own pill, disjoint from the actions pill #340

Closed
opened 2026-09-28 13:17:05 +00:00 by kayg · 16 comments
Owner

Owner (2026-09-28, screenshot of the Files selection capsule '1 selected · 👁 🔗 ⤴ ⓘ ✎ ⬇ 🗑 ⋯ Done'): 'there is absolutely no need for the "Done" to be there? it does not make sense - more actions and then done? The (1 Selected) should be its own pill? it should be disjoint from the rest of the actions. so pill within a pill for how many selected and then the actions pill.'

Build in the shared SelectionBar (packages/ui; used by Files, Photos and every selection context):

  • Two disjoint pills side by side (the tab-bar spring morph still animates the whole group): (1) a count pill 'N selected' (single-pill variant, pill-in-a-pill); (2) the actions pill (icons + ⋯ overflow), a PillGroup.
  • Remove 'Done'. Leaving selection: Esc, tapping/clicking empty space, navigating away, or tapping the count pill, which clears the selection. Give the count pill a small trailing × so it is discoverable on touch, with an accessible name 'Clear selection, N selected'. On a long-press or right-click the count pill offers 'Select all' / 'Select none' (reuse the shared menu).
  • The count uses the label roll animation (#236) when it changes; reduced motion = instant.
  • Phone: the same two pills; if the width is tight, the actions pill scrolls horizontally, never the count pill.
  • Keep role=toolbar on the actions pill; the count pill is a button; the aria-live announcement stays.
    Evidence: Files and Photos with 1 and 12 selected, at 390/820/1440, light and dark; zoom-check the vertical centring of the count text and the icons.
Owner (2026-09-28, screenshot of the Files selection capsule '1 selected · 👁 🔗 ⤴ ⓘ ✎ ⬇ 🗑 ⋯ Done'): 'there is absolutely no need for the "Done" to be there? it does not make sense - more actions and then done? The (1 Selected) should be its own pill? it should be disjoint from the rest of the actions. so pill within a pill for how many selected and then the actions pill.' Build in the shared `SelectionBar` (packages/ui; used by Files, Photos and every selection context): - **Two disjoint pills side by side** (the tab-bar spring morph still animates the whole group): (1) a **count pill** 'N selected' (single-pill variant, pill-in-a-pill); (2) the **actions pill** (icons + ⋯ overflow), a PillGroup. - **Remove 'Done'.** Leaving selection: Esc, tapping/clicking empty space, navigating away, or **tapping the count pill**, which clears the selection. Give the count pill a small trailing × so it is discoverable on touch, with an accessible name 'Clear selection, N selected'. On a long-press or right-click the count pill offers 'Select all' / 'Select none' (reuse the shared menu). - The count uses the label roll animation (#236) when it changes; reduced motion = instant. - Phone: the same two pills; if the width is tight, the actions pill scrolls horizontally, never the count pill. - Keep role=toolbar on the actions pill; the count pill is a button; the aria-live announcement stays. Evidence: Files and Photos with 1 and 12 selected, at 390/820/1440, light and dark; zoom-check the vertical centring of the count text and the icons.
Author
Owner

Starting work on job/selection-pills, based on 442b4f000b7e851023e6c0ae792e89c52e01969e (same as dev at start). I have read the binding docs and issue #340. I will update the shared SelectionBar and its selection consumers, preserve the tab-bar capsule morph and live announcement, and cover the count pill behavior in the existing web tests.

Starting work on `job/selection-pills`, based on `442b4f000b7e851023e6c0ae792e89c52e01969e` (same as `dev` at start). I have read the binding docs and issue #340. I will update the shared SelectionBar and its selection consumers, preserve the tab-bar capsule morph and live announcement, and cover the count pill behavior in the existing web tests.
Author
Owner

Finding: the existing production-build evidence flows in apps/web/e2e/files.mjs and apps/web/e2e/photos.mjs still locate a Done button and only capture a smaller selection. Those assertions no longer match #340. I am updating them to exercise the separate count pill and capture 1 and 12 selected on each required viewport and theme.

Finding: the existing production-build evidence flows in `apps/web/e2e/files.mjs` and `apps/web/e2e/photos.mjs` still locate a `Done` button and only capture a smaller selection. Those assertions no longer match #340. I am updating them to exercise the separate count pill and capture 1 and 12 selected on each required viewport and theme.
Author
Owner

Finding: The phone long-press menu closed on the touch release click. Evidence came from the production Files flow at 390 px: the Select all menu item became detached when Playwright attempted to click it, and the shared outside-click scrim intercepted the pointer. The touch release click was reaching the newly opened scrim before the menu could be used. SelectionBar now captures and swallows that one click, then opens its menu. A focused component regression test passes; I am rerunning production evidence now.

Finding: The phone long-press menu closed on the touch release click. Evidence came from the production Files flow at 390 px: the Select all menu item became detached when Playwright attempted to click it, and the shared outside-click scrim intercepted the pointer. The touch release click was reaching the newly opened scrim before the menu could be used. SelectionBar now captures and swallows that one click, then opens its menu. A focused component regression test passes; I am rerunning production evidence now.
Author
Owner

Finding from the one post-merge adversarial round: tests/adversarial/search_chaos.py reported HTTP 200 search responses that omitted the already-committed unicodenfcsentinel hit during an admin staged rebuild. It recorded eight misses from concurrent searches and three misses while sampling the old Index during the rebuild. The check treats a missing committed hit as an inconsistency, not a slow response. Search is outside the SelectionBar files owned by #340, so I am leaving its existing expectation intact and recording the evidence for the orchestrator.

Finding from the one post-merge adversarial round: `tests/adversarial/search_chaos.py` reported HTTP 200 search responses that omitted the already-committed `unicodenfcsentinel` hit during an admin staged rebuild. It recorded eight misses from concurrent searches and three misses while sampling the old Index during the rebuild. The check treats a missing committed hit as an inconsistency, not a slow response. Search is outside the SelectionBar files owned by #340, so I am leaving its existing expectation intact and recording the evidence for the orchestrator.
Author
Owner

Adversarial follow-up (partial, time-boxed at 32 minutes): the local run was interrupted while attack.py was still uploading its Photos fixtures, so the remaining attack and round-2 phases did not run. Additional non-SLOW findings already emitted before the cutoff:

  • Editor byte-stability probe: opening an untouched Note changed its Markdown bytes, including nested list indentation and attachment-link syntax.
  • Editor browser probe: an undo/redo round trip changed text spacing around a nested list.
  • Collaboration probe: deleting and editing one block timed out while waiting for both peers to receive the conflict.
  • Search probe: eight concurrent requests and three samples during the staged rebuild returned HTTP 200 without the committed unicodenfcsentinel hit (reported in the previous comment).

Load-sensitive output included one authz fixture upload with no response, file traversal and DAV request timeouts, 128 recent queries at roughly 18–24s, and a 10,000-block sync at 2969ms against a 2000ms budget. The run ended with KeyboardInterrupt (exit 130) at the timebox. These APIs and editor behaviors are outside the SelectionBar files owned by #340; I left their code and existing adversarial expectations unchanged.

Adversarial follow-up (partial, time-boxed at 32 minutes): the local run was interrupted while `attack.py` was still uploading its Photos fixtures, so the remaining attack and round-2 phases did not run. Additional non-SLOW findings already emitted before the cutoff: - Editor byte-stability probe: opening an untouched Note changed its Markdown bytes, including nested list indentation and attachment-link syntax. - Editor browser probe: an undo/redo round trip changed text spacing around a nested list. - Collaboration probe: deleting and editing one block timed out while waiting for both peers to receive the conflict. - Search probe: eight concurrent requests and three samples during the staged rebuild returned HTTP 200 without the committed `unicodenfcsentinel` hit (reported in the previous comment). Load-sensitive output included one authz fixture upload with no response, file traversal and DAV request timeouts, 128 recent queries at roughly 18–24s, and a 10,000-block sync at 2969ms against a 2000ms budget. The run ended with KeyboardInterrupt (exit 130) at the timebox. These APIs and editor behaviors are outside the SelectionBar files owned by #340; I left their code and existing adversarial expectations unchanged.
Author
Owner

Finished report

Branch: job/selection-pills
Base: dev, merged once at 13f97dd6
HEAD: ed3875c49f6b01d6995e6cc9fb1fe67c10d0ec4d
Push: Everything up-to-date

Built

  • Split the SelectionBar count and clear control from its actions pill. Tapping the count or × clears selection. Removed Done.
  • Added Select all/none to the shared context menu for right-click and touch long-press. Kept the #236 morph and accessible selection announcements.
  • Updated Files, Recent, Trash and Photos consumers. Photos loads current bucket data before Select all and cancels delayed selection work after an explicit user action.
  • Added SelectionBar and consumer tests, plus production E2E screenshot capture.

Files changed: packages/ui/src/components/SelectionBar.svelte; apps/web/src/lib/components/SelectionBar.svelte.test.ts; apps/web/src/lib/selectionContextBar.ts and its test; Files, Recent, Trash and Photos consumers; apps/web/e2e/files.mjs; apps/web/e2e/photos.mjs.

Evidence and gates

24 real production screenshots are attached to this issue: Files and Photos, at 390, 820 and 1440 px, in light and dark themes. Screenshot-only Files and Photos runs passed. Focused tests: 2 files, 5 tests passed.

cargo fmt --check: exit 0; stdout and stderr were empty.

cargo clippy --all-targets -- -D warnings: stopped with exit 130 while compiling vendored OpenSSL. The run had no Clippy diagnostics before stopping. cargo test was not run. I stopped the cold native build at the job timebox; these two workspace gates remain incomplete.

bun run check:

svelte-check found 0 errors and 0 warnings

bun run test:

Test Files  112 passed (112)
Tests  728 passed (728)
Start at  18:14:02
Duration  79.12s (transform 57%, environment 16%, import 15%, tests 9%, setup 3%)

cargo clean removed 17748 files, 5.8GiB total. Web build output was removed. Working tree is clean.

Known gaps

  • Full Files E2E stopped at the existing sidebar ordering assertion in apps/web/e2e/files.mjs:190, after screenshot capture. I did not change its expectation.
  • Full Photos E2E stopped while waiting for the existing May 2024 heading at apps/web/e2e/photos.mjs:622 under slow SQL acquisition. Screenshot-only Photos evidence passed. The selected-mode assertion now waits for the existing morph to finish; its expectation is unchanged.
  • The one adversarial round was interrupted after 32 minutes while creating Photos fixtures. It found search misses for a committed Unicode sentinel during rebuild, Notes reads that changed Markdown bytes, editor undo/redo spacing changes, and a delete/edit collaboration timeout. These are recorded in the earlier comments. The 10,000-block sync and request/DAV storm timings were load-only. No accepted traversal path or server crash was observed before interruption.

Decisions where DESIGN.md is silent

  • Photos Select all loads the current buckets sequentially before applying the selection, so the count describes loaded real items.
  • On touch, SelectionBar defers opening the menu until the compatibility click can be consumed. A 500 ms fallback handles browser stacks that omit that click.
## Finished report Branch: `job/selection-pills` Base: `dev`, merged once at `13f97dd6` HEAD: `ed3875c49f6b01d6995e6cc9fb1fe67c10d0ec4d` Push: `Everything up-to-date` ### Built - Split the SelectionBar count and clear control from its actions pill. Tapping the count or × clears selection. Removed Done. - Added Select all/none to the shared context menu for right-click and touch long-press. Kept the #236 morph and accessible selection announcements. - Updated Files, Recent, Trash and Photos consumers. Photos loads current bucket data before Select all and cancels delayed selection work after an explicit user action. - Added SelectionBar and consumer tests, plus production E2E screenshot capture. Files changed: `packages/ui/src/components/SelectionBar.svelte`; `apps/web/src/lib/components/SelectionBar.svelte.test.ts`; `apps/web/src/lib/selectionContextBar.ts` and its test; Files, Recent, Trash and Photos consumers; `apps/web/e2e/files.mjs`; `apps/web/e2e/photos.mjs`. ### Evidence and gates 24 real production screenshots are attached to this issue: Files and Photos, at 390, 820 and 1440 px, in light and dark themes. Screenshot-only Files and Photos runs passed. Focused tests: 2 files, 5 tests passed. `cargo fmt --check`: exit 0; stdout and stderr were empty. `cargo clippy --all-targets -- -D warnings`: stopped with exit 130 while compiling vendored OpenSSL. The run had no Clippy diagnostics before stopping. `cargo test` was not run. I stopped the cold native build at the job timebox; these two workspace gates remain incomplete. `bun run check`: ``` svelte-check found 0 errors and 0 warnings ``` `bun run test`: ``` Test Files 112 passed (112) Tests 728 passed (728) Start at 18:14:02 Duration 79.12s (transform 57%, environment 16%, import 15%, tests 9%, setup 3%) ``` `cargo clean` removed `17748 files, 5.8GiB total`. Web build output was removed. Working tree is clean. ### Known gaps - Full Files E2E stopped at the existing sidebar ordering assertion in `apps/web/e2e/files.mjs:190`, after screenshot capture. I did not change its expectation. - Full Photos E2E stopped while waiting for the existing `May 2024` heading at `apps/web/e2e/photos.mjs:622` under slow SQL acquisition. Screenshot-only Photos evidence passed. The selected-mode assertion now waits for the existing morph to finish; its expectation is unchanged. - The one adversarial round was interrupted after 32 minutes while creating Photos fixtures. It found search misses for a committed Unicode sentinel during rebuild, Notes reads that changed Markdown bytes, editor undo/redo spacing changes, and a delete/edit collaboration timeout. These are recorded in the earlier comments. The 10,000-block sync and request/DAV storm timings were load-only. No accepted traversal path or server crash was observed before interruption. ### Decisions where DESIGN.md is silent - Photos Select all loads the current buckets sequentially before applying the selection, so the count describes loaded real items. - On touch, SelectionBar defers opening the menu until the compatibility click can be consumed. A 500 ms fallback handles browser stacks that omit that click.
Author
Owner

Review of job/selection-pills ed3875c4 (Claude): two small fixes

The separation is right. Two defects are left:

  1. The count pill does not match the actions pill. It is outline-only (transparent with a border), while the actions pill has the glass fill. Both pills use the same glass pill surface (shared token; #319 pill-in-a-pill), so they read as siblings.
  2. The × touches the text on desktop ("12 selected×" at 1440 in Photos and Files). Use the shared icon+label gap token, and keep the icon optically centred on the cap height (#253 primitive).

Also run cargo clippy / cargo test or state that no Rust changed (none did: I checked). Re-shoot the 24 screenshots, plus zoom crops of the count pill at 1440 and 390.

## Review of job/selection-pills ed3875c4 (Claude): two small fixes The separation is right. Two defects are left: 1. **The count pill does not match the actions pill.** It is outline-only (transparent with a border), while the actions pill has the glass fill. Both pills use the same glass pill surface (shared token; #319 pill-in-a-pill), so they read as siblings. 2. **The × touches the text on desktop** ("12 selected×" at 1440 in Photos and Files). Use the shared icon+label gap token, and keep the icon optically centred on the cap height (#253 primitive). Also run `cargo clippy` / `cargo test` or state that no Rust changed (none did: I checked). Re-shoot the 24 screenshots, plus zoom crops of the count pill at 1440 and 390.
Author
Owner

Continuing the review fixes on job/selection-pills at ed3875c49f. The current dev SHA is cf919dd3bf. I am fixing the shared SelectionBar count pill material and spacing using existing UI tokens/components, then I will rebuild and capture the requested production screenshots and zoom crops.

Continuing the review fixes on job/selection-pills at ed3875c49f6b01d6995e6cc9fb1fe67c10d0ec4d. The current dev SHA is cf919dd3bfb13e8bb09a923b61f359c861b20bd9. I am fixing the shared SelectionBar count pill material and spacing using existing UI tokens/components, then I will rebuild and capture the requested production screenshots and zoom crops.
Author
Owner

Finding: the count's frosted Pill was still receiving from the generic actionable-Pill rule, while PillGroup kept ; that made the count read as an outline. The gap token was on Pill's inner wrapper, which has only one child, so it created no text-to-X spacing. Fixed both in 17aa8a7a, using the existing glass tokens, --icon-label-gap and optical-caps utility.

Finding: the count's frosted Pill was still receiving from the generic actionable-Pill rule, while PillGroup kept ; that made the count read as an outline. The gap token was on Pill's inner wrapper, which has only one child, so it created no text-to-X spacing. Fixed both in 17aa8a7a, using the existing glass tokens, --icon-label-gap and optical-caps utility.
Author
Owner

Correction to my previous finding: the count's frosted Pill was still receiving the shared --control-boundary token from the generic actionable-Pill rule, while PillGroup kept --glass-border. The gap token was on Pill's inner wrapper, which has only one child, so it created no text-to-X spacing. Fixed both in commit 17aa8a7a with the existing glass tokens, --icon-label-gap and optical-caps utility.

Correction to my previous finding: the count's frosted Pill was still receiving the shared --control-boundary token from the generic actionable-Pill rule, while PillGroup kept --glass-border. The gap token was on Pill's inner wrapper, which has only one child, so it created no text-to-X spacing. Fixed both in commit 17aa8a7a with the existing glass tokens, --icon-label-gap and optical-caps utility.
Author
Owner

Starting on job/selection-pills at base 3b300558692d17108cd8e9282a1f30601f96e70d (branch head 3f67fc877cc48cac91005e9a895cce1627c9855d). I am reading the latest review and implementing its two fixes together with #366's shared tri-state header selection control.

Starting on `job/selection-pills` at base `3b300558692d17108cd8e9282a1f30601f96e70d` (branch head `3f67fc877cc48cac91005e9a895cce1627c9855d`). I am reading the latest review and implementing its two fixes together with #366's shared tri-state header selection control.
Author
Owner

Resuming job/selection-pills at 3f67fc877cc48cac91005e9a895cce1627c9855d, based on 3b300558692d17108cd8e9282a1f30601f96e70d (dev at branch start). I read the latest Claude review on #340 and #366 in full. The #340 count-pill surface and spacing fixes are already committed in 17aa8a7a; I am continuing the existing uncommitted #366 shared header checkbox work, then will run the requested web gates and refresh production screenshot evidence.

Resuming `job/selection-pills` at `3f67fc877cc48cac91005e9a895cce1627c9855d`, based on `3b300558692d17108cd8e9282a1f30601f96e70d` (`dev` at branch start). I read the latest Claude review on #340 and #366 in full. The #340 count-pill surface and spacing fixes are already committed in `17aa8a7a`; I am continuing the existing uncommitted #366 shared header checkbox work, then will run the requested web gates and refresh production screenshot evidence.
Author
Owner

Selection pill evidence

Production browser captures from the local calternal server and production web build. The 24 Files and Photos screenshots cover 390, 820, and 1440 CSS px in light and dark themes, with 1 and 12 items selected. Count pill crops cover 390 and 1440 CSS px in both themes.

Files selection screenshots (12)

Photos selection screenshots (12)

Count pill crops (16)

# Selection pill evidence Production browser captures from the local calternal server and production web build. The 24 Files and Photos screenshots cover 390, 820, and 1440 CSS px in light and dark themes, with 1 and 12 items selected. Count pill crops cover 390 and 1440 CSS px in both themes. ## Files selection screenshots (12) - [files-selection-1-phone-light.png](https://git.kayg.org/attachments/5fddf886-01f7-4c8a-8c43-ad7bfc2ec8d6) - [files-selection-1-phone-dark.png](https://git.kayg.org/attachments/8e139436-bfb5-45a6-b3bf-df7f17287864) - [files-selection-1-tablet-light.png](https://git.kayg.org/attachments/00c41f3d-3523-464f-99ef-7bb03ee523c6) - [files-selection-1-tablet-dark.png](https://git.kayg.org/attachments/6df6845e-bbab-4387-bedf-34ed4f51efb6) - [files-selection-1-desktop-light.png](https://git.kayg.org/attachments/e492ebab-2b49-4e85-a73c-706947e39761) - [files-selection-1-desktop-dark.png](https://git.kayg.org/attachments/a860295a-b811-4355-a8f6-d6244874ee1c) - [files-selection-12-phone-light.png](https://git.kayg.org/attachments/19adb084-1e45-4fdd-8e63-b9c0afa99020) - [files-selection-12-phone-dark.png](https://git.kayg.org/attachments/1d186e3a-928e-4df6-b23c-06f9696734b5) - [files-selection-12-tablet-light.png](https://git.kayg.org/attachments/6dc66ec8-bdf2-4b5c-aeba-be71054e2399) - [files-selection-12-tablet-dark.png](https://git.kayg.org/attachments/183ee2b3-f221-48e7-8c64-f61d79b96fa1) - [files-selection-12-desktop-light.png](https://git.kayg.org/attachments/aae15566-5af9-415a-9294-73812577dd01) - [files-selection-12-desktop-dark.png](https://git.kayg.org/attachments/9d9538ea-0566-40d7-8578-87a6fa7f7a27) ## Photos selection screenshots (12) - [selection-1-390-paper-white.png](https://git.kayg.org/attachments/7e428272-0ade-4b0f-ae60-c185111218a1) - [selection-1-390-tokyo-night.png](https://git.kayg.org/attachments/68ed1423-52fe-4d6c-96f1-484573e5e7e0) - [selection-1-820-paper-white.png](https://git.kayg.org/attachments/435f62aa-d4d8-4340-a473-149d6a939ee2) - [selection-1-820-tokyo-night.png](https://git.kayg.org/attachments/b70a1159-f46c-432b-9f20-354b5143e06e) - [selection-1-1440-paper-white.png](https://git.kayg.org/attachments/26752f0d-3d38-480f-976f-65088ff79cf0) - [selection-1-1440-tokyo-night.png](https://git.kayg.org/attachments/f4c73cf4-e3db-4eec-8e36-75110a04e36e) - [selection-12-390-paper-white.png](https://git.kayg.org/attachments/51425d6e-8812-4d26-99e1-7b65b5a5f5dc) - [selection-12-390-tokyo-night.png](https://git.kayg.org/attachments/c4ed7f07-495f-4450-8a75-2bdd37801a95) - [selection-12-820-paper-white.png](https://git.kayg.org/attachments/1d02aa6f-c154-4867-b383-342b8b557d35) - [selection-12-820-tokyo-night.png](https://git.kayg.org/attachments/da5d3d4e-b741-4408-9c12-617ba5a286ca) - [selection-12-1440-paper-white.png](https://git.kayg.org/attachments/b5c29ddf-0048-40ec-88d0-7cbc5d91b3c2) - [selection-12-1440-tokyo-night.png](https://git.kayg.org/attachments/7522f77f-322c-420a-95db-e516c1a860fd) ## Count pill crops (16) - [files-selection-count-pill-1-phone-light.png](https://git.kayg.org/attachments/cc4d87ed-f777-462a-99c4-f9611e5d7ad1) - [files-selection-count-pill-1-phone-dark.png](https://git.kayg.org/attachments/25d16d7d-1c65-4e82-9b8b-73199c9b698a) - [files-selection-count-pill-1-desktop-light.png](https://git.kayg.org/attachments/fdbb5d1b-639a-4a6e-8a2f-803030ab7971) - [files-selection-count-pill-1-desktop-dark.png](https://git.kayg.org/attachments/6fea51dd-3bc9-4aa2-a811-efa7bb9db513) - [photos-selection-count-pill-1-390-paper-white.png](https://git.kayg.org/attachments/020b5fa6-fb98-4281-a3e3-33e822fc4d88) - [photos-selection-count-pill-1-390-tokyo-night.png](https://git.kayg.org/attachments/fb1ae991-4ec3-4839-918d-21411d9e45fb) - [photos-selection-count-pill-1-1440-paper-white.png](https://git.kayg.org/attachments/7034eef3-c917-4777-b997-66362c899a6a) - [photos-selection-count-pill-1-1440-tokyo-night.png](https://git.kayg.org/attachments/2571fa97-09f3-4bcd-93f7-3ab6e7c69b1e) - [files-selection-count-pill-12-phone-light.png](https://git.kayg.org/attachments/cc0e35b6-11c0-46e9-a5d0-fb421381ccc7) - [files-selection-count-pill-12-phone-dark.png](https://git.kayg.org/attachments/080019bb-9d58-4500-aa8f-188a8b3535a4) - [files-selection-count-pill-12-desktop-light.png](https://git.kayg.org/attachments/d9770d9a-77ce-4888-b7f3-8a8375c2c07a) - [files-selection-count-pill-12-desktop-dark.png](https://git.kayg.org/attachments/2941c618-2493-4b4b-a111-8c58df8e3ffb) - [photos-selection-count-pill-12-390-paper-white.png](https://git.kayg.org/attachments/ca80e8f8-a963-4c92-9399-8c61efa62553) - [photos-selection-count-pill-12-390-tokyo-night.png](https://git.kayg.org/attachments/ddb02b52-292f-4b38-80ca-48a972bdbe97) - [photos-selection-count-pill-12-1440-paper-white.png](https://git.kayg.org/attachments/36e5e9a2-885f-43a9-ae2c-5582bc50617c) - [photos-selection-count-pill-12-1440-tokyo-night.png](https://git.kayg.org/attachments/dd4ae675-c99e-4a75-bb2f-c06aa018d799)
Author
Owner

Finding from the current post-merge adversarial round on the real local server:

  • search_chaos.py reported 3 concurrent full-rebuild searches and 114 staged-rebuild samples that returned HTTP 200 without the committed hit. server.log also records a cancelled Tantivy merge caused by a missing rebuild .term file and a final index update failing with SQLite (code: 14) unable to open database file. This reproduces and expands the Search integrity finding recorded above.
  • The editor browser probe again found undo/redo changing whitespace around a nested list, and the delete/edit collaboration probe timed out waiting for both peers to receive the conflict.
  • Appearance probes found a fresh User returning auto_scheme: {mode: system, location: null} where the probe expects no saved scheme. A hostile font-family PUT returned 502 (local adversarial server is unavailable) where the probe expects a 4xx refusal.

These findings are outside the selection-pills files owned by this job, so I have not changed their behavior or test expectations. The 502, default mismatch, Search integrity loss, and editor mismatch are reported as findings; request and fixture timeouts are being assessed against the shared-host load. The single round is still running; I will append its final scope and exit status in the job report.

Finding from the current post-merge adversarial round on the real local server: - `search_chaos.py` reported 3 concurrent full-rebuild searches and 114 staged-rebuild samples that returned HTTP 200 without the committed hit. `server.log` also records a cancelled Tantivy merge caused by a missing rebuild `.term` file and a final index update failing with SQLite `(code: 14) unable to open database file`. This reproduces and expands the Search integrity finding recorded above. - The editor browser probe again found undo/redo changing whitespace around a nested list, and the delete/edit collaboration probe timed out waiting for both peers to receive the conflict. - Appearance probes found a fresh User returning `auto_scheme: {mode: system, location: null}` where the probe expects no saved scheme. A hostile font-family PUT returned 502 (`local adversarial server is unavailable`) where the probe expects a 4xx refusal. These findings are outside the selection-pills files owned by this job, so I have not changed their behavior or test expectations. The 502, default mismatch, Search integrity loss, and editor mismatch are reported as findings; request and fixture timeouts are being assessed against the shared-host load. The single round is still running; I will append its final scope and exit status in the job report.
Author
Owner

Final report — selection-pills and #366

Branch: job/selection-pills
HEAD: 3528e5417a25ea3c93258be56326283d1ad1a4ad
Push: git push origin job/selection-pills → Everything up-to-date
Working tree: clean

Built

  • Completed the two #340 review fixes in 17aa8a7a: the selection count pill uses the shared glass surface and the text/clear icon use the shared icon-label gap and cap-centering utility.
  • Added the shared tri-state Files list checkbox. It drives whole-list selection, including virtualized rows, and is wired into Files, Recent and Trash. The row checkbox is reused. The header has the folder-scoped accessible name, mixed state, Space, Cmd/Ctrl+A and touch target behavior from #366.
  • Updated production E2E screenshot capture and focused selection tests.

Files for this work:

  • packages/ui/src/components/files/FileCollection.svelte
  • packages/ui/src/components/files/FileSelectionCheckbox.svelte
  • apps/web/src/lib/files/selection.ts
  • apps/web/src/lib/files/selection.test.ts
  • apps/web/src/lib/files/FileCollection.svelte.test.ts
  • apps/web/src/lib/files/FilesBrowser.svelte
  • apps/web/src/lib/files/RecentView.svelte
  • apps/web/src/lib/files/TrashView.svelte
  • apps/web/e2e/files.mjs
  • apps/web/e2e/photos.mjs

Evidence

Production-build screenshot runners completed before the job cutoff:

FILES SCREENSHOTS PASSED
CSP REPORTS files: 0 across 3 pages
PHOTOS SCREENSHOTS PASSED
CSP REPORTS photos: 0 across 2 pages

The attached evidence was uploaded and verified: #340 has 24 selection screenshots and 16 count-pill crops; #366 has 54 Files/Recent/Trash state screenshots and 36 header-checkbox crops. The artifacts remain under artifacts/selection-pills/2026-09-28-resume.

Focused tests previously reported:

Test Files 2 passed (2)
Tests 8 passed (8)

The production web build completed. Its final output included:

✓ built in 1m 14s
> Using @sveltejs/adapter-static
  Wrote site to "build"
  ✔ done

Final gates and adversarial round

The final post-merge gates were not run. At the approximately four-hour job limit I stopped build work as required. These remain outstanding: cargo fmt --check, cargo clippy --all-targets -- -D warnings, cargo test, bun run check, and bun run test.

The single adversarial round ended at 31 minutes with exit 130 while attack.py was still creating its 120-photo upload fixtures. Its output ended with KeyboardInterrupt; the last five photo-byte uploads had no response. Many upload and Recent results were marked SLOW under shared-host load. The calendar_event_tags.mjs subprobe did not start because this run set ADVERSARIAL_SERVER_BIN, while that probe expects CALTERNAL_SERVER_BIN. The xuser/authz fixture setup also had HTTP -1/no-response results.

Non-SLOW findings and their evidence are recorded in the comments on this issue. They include Search losing a committed hit in 3 concurrent rebuild searches and 114 staged-rebuild samples (Search tracker #362), editor undo/redo spacing changes (tracker #314), a delete/edit conflict timeout (tracker #364), accepted DAV VALARM input (HTTP 201), and the fresh-User Appearance default mismatch. The hostile font-family request received the adversarial proxy's 502 response (local adversarial server is unavailable). These findings are outside the files owned by this job and were not changed here.

Decisions where DESIGN.md is silent

  • The Files header reports and selects the current collection as a whole, preserving its listing order and not depending on which rows are rendered.
  • Recent and Trash use their collection names in the header checkbox accessible label.

cargo clean removed 6884 files, 4.3GiB total. The web build and .svelte-kit/output directories were removed. The branch was pushed; no merge into dev was made.

## Final report — selection-pills and #366 Branch: `job/selection-pills` HEAD: `3528e5417a25ea3c93258be56326283d1ad1a4ad` Push: `git push origin job/selection-pills` → `Everything up-to-date` Working tree: clean ### Built - Completed the two #340 review fixes in `17aa8a7a`: the selection count pill uses the shared glass surface and the text/clear icon use the shared icon-label gap and cap-centering utility. - Added the shared tri-state Files list checkbox. It drives whole-list selection, including virtualized rows, and is wired into Files, Recent and Trash. The row checkbox is reused. The header has the folder-scoped accessible name, mixed state, Space, Cmd/Ctrl+A and touch target behavior from #366. - Updated production E2E screenshot capture and focused selection tests. Files for this work: - `packages/ui/src/components/files/FileCollection.svelte` - `packages/ui/src/components/files/FileSelectionCheckbox.svelte` - `apps/web/src/lib/files/selection.ts` - `apps/web/src/lib/files/selection.test.ts` - `apps/web/src/lib/files/FileCollection.svelte.test.ts` - `apps/web/src/lib/files/FilesBrowser.svelte` - `apps/web/src/lib/files/RecentView.svelte` - `apps/web/src/lib/files/TrashView.svelte` - `apps/web/e2e/files.mjs` - `apps/web/e2e/photos.mjs` ### Evidence Production-build screenshot runners completed before the job cutoff: ``` FILES SCREENSHOTS PASSED CSP REPORTS files: 0 across 3 pages PHOTOS SCREENSHOTS PASSED CSP REPORTS photos: 0 across 2 pages ``` The attached evidence was uploaded and verified: #340 has 24 selection screenshots and 16 count-pill crops; #366 has 54 Files/Recent/Trash state screenshots and 36 header-checkbox crops. The artifacts remain under `artifacts/selection-pills/2026-09-28-resume`. Focused tests previously reported: ``` Test Files 2 passed (2) Tests 8 passed (8) ``` The production web build completed. Its final output included: ``` ✓ built in 1m 14s > Using @sveltejs/adapter-static Wrote site to "build" ✔ done ``` ### Final gates and adversarial round The final post-merge gates were not run. At the approximately four-hour job limit I stopped build work as required. These remain outstanding: `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, `cargo test`, `bun run check`, and `bun run test`. The single adversarial round ended at 31 minutes with exit 130 while `attack.py` was still creating its 120-photo upload fixtures. Its output ended with `KeyboardInterrupt`; the last five photo-byte uploads had no response. Many upload and Recent results were marked SLOW under shared-host load. The `calendar_event_tags.mjs` subprobe did not start because this run set `ADVERSARIAL_SERVER_BIN`, while that probe expects `CALTERNAL_SERVER_BIN`. The xuser/authz fixture setup also had HTTP -1/no-response results. Non-SLOW findings and their evidence are recorded in the comments on this issue. They include Search losing a committed hit in 3 concurrent rebuild searches and 114 staged-rebuild samples (Search tracker #362), editor undo/redo spacing changes (tracker #314), a delete/edit conflict timeout (tracker #364), accepted DAV `VALARM` input (HTTP 201), and the fresh-User Appearance default mismatch. The hostile font-family request received the adversarial proxy's 502 response (`local adversarial server is unavailable`). These findings are outside the files owned by this job and were not changed here. ### Decisions where DESIGN.md is silent - The Files header reports and selects the current collection as a whole, preserving its listing order and not depending on which rows are rendered. - Recent and Trash use their collection names in the header checkbox accessible label. `cargo clean` removed `6884 files, 4.3GiB total`. The web `build` and `.svelte-kit/output` directories were removed. The branch was pushed; no merge into `dev` was made.
Author
Owner

Merged into dev by Claude after visual review (a9a16e90) and deployed to calternal.cloud. Closing.

Merged into dev by Claude after visual review (a9a16e90) and deployed to calternal.cloud. Closing.
kayg closed this issue 2026-09-28 22:31:12 +00:00
Sign in to join this conversation.
No labels
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#340
No description provided.