Deep-link audit: every item has Copy link, every link restores the exact view #167

Open
opened 2026-09-26 12:04:25 +00:00 by kayg · 10 comments
Owner

Owner rule (CLAUDE.md Deep links, DESIGN §33). Audit the whole UI: modes and sub-views, days and weeks, log entries (block anchors), notes, headings and blocks, files and folders, photos, albums, events, tasks, tags, saved searches, search queries, settings sections, admin pages, shares. For each: (1) a Copy link action exists in the context menu, the ⋯ menu, the touch swipe action and the header copy button where applicable; (2) the link uses the stable identity (calternal-id, item ID, block ID), never a path; (3) opening the link in a fresh session restores the exact view (scroll position, selection, open popover/inspector where the grammar says so); (4) a rename or move does not break it. Build an e2e deeplinks sweep that generates every link type from real data, renames/moves the target, opens the link and asserts the view. Fix every gap in the shared components (reuse gate). Commit per fix. Report a coverage table.

Owner rule (CLAUDE.md Deep links, DESIGN §33). Audit the whole UI: modes and sub-views, days and weeks, log entries (block anchors), notes, headings and blocks, files and folders, photos, albums, events, tasks, tags, saved searches, search queries, settings sections, admin pages, shares. For each: (1) a Copy link action exists in the context menu, the ⋯ menu, the touch swipe action and the header copy button where applicable; (2) the link uses the stable identity (calternal-id, item ID, block ID), never a path; (3) opening the link in a fresh session restores the exact view (scroll position, selection, open popover/inspector where the grammar says so); (4) a rename or move does not break it. Build an e2e deeplinks sweep that generates every link type from real data, renames/moves the target, opens the link and asserts the view. Fix every gap in the shared components (reuse gate). Commit per fix. Report a coverage table.
Author
Owner

Starting #167 on branch job/deeplink-audit, based on dev at 44b15bec4f. I am auditing the existing shared menu/action components and the real-data deep-link e2e sweep.

Starting #167 on branch job/deeplink-audit, based on dev at 44b15bec4f4e78e788c85b7ec60d54892a293b84. I am auditing the existing shared menu/action components and the real-data deep-link e2e sweep.
Author
Owner

Audit finding: docs/deep-links.md lists /f/<id>?open=share with no Copy link. In apps/web/src/lib/files/ShareDialog.svelte, the only CopyLink controls copy public /s/<slug> links; apps/web/e2e/deeplinks.mjs only checks that the share dialog opens. I am adding coverage and will wire a distinct Copy link for the share-dialog route if its caller exposes the stable file ID.

Audit finding: docs/deep-links.md lists `/f/<id>?open=share` with no Copy link. In apps/web/src/lib/files/ShareDialog.svelte, the only CopyLink controls copy public `/s/<slug>` links; apps/web/e2e/deeplinks.mjs only checks that the share dialog opens. I am adding coverage and will wire a distinct Copy link for the share-dialog route if its caller exposes the stable file ID.
Author
Owner

Second audit finding: apps/web/src/lib/files/SharedByYou.svelte rendered an item row with only a public /s/<slug> Copy link, so it had no stable internal /f/<item-id> action. The row now uses the existing CopyLink and fileHref helpers for the item link, while keeping the public-link control distinct. The e2e sweep creates a real public link and checks the item link from Shared by you.

Second audit finding: apps/web/src/lib/files/SharedByYou.svelte rendered an item row with only a public `/s/<slug>` Copy link, so it had no stable internal `/f/<item-id>` action. The row now uses the existing CopyLink and fileHref helpers for the item link, while keeping the public-link control distinct. The e2e sweep creates a real public link and checks the item link from Shared by you.
Author
Owner

Task audit detail: standalone Task files now have a persisted stable Task ID and legacy path aliases; the existing e2e already renames and moves a standalone Task file. Inline Tasks are still indexed as Notes/<path>.md#<block-id> (see crates/plugins/notes/src/lib.rs::reminders_uid_resolves_only_within_the_task_owner), so a Note rename or move changes their /t/ link. A durable inline Task identity needs a Notes API/data-model change; I recorded this as an open gap instead of changing that identity model in this UI audit.

Task audit detail: standalone Task files now have a persisted stable Task ID and legacy path aliases; the existing e2e already renames and moves a standalone Task file. Inline Tasks are still indexed as `Notes/<path>.md#<block-id>` (see `crates/plugins/notes/src/lib.rs::reminders_uid_resolves_only_within_the_task_owner`), so a Note rename or move changes their `/t/` link. A durable inline Task identity needs a Notes API/data-model change; I recorded this as an open gap instead of changing that identity model in this UI audit.
Author
Owner

The first real-server run stopped at the calendar header assertion: the sweep looked for Copy link to this view as a standalone button, but ModeHeader renders it as a menuitem under More actions. I changed the sweep to use that shared overflow action for Calendar, Files, Shared, Recent and Trash. No UI defect was found at that point; the test role was wrong.

The first real-server run stopped at the calendar header assertion: the sweep looked for `Copy link to this view` as a standalone button, but ModeHeader renders it as a `menuitem` under `More actions`. I changed the sweep to use that shared overflow action for Calendar, Files, Shared, Recent and Trash. No UI defect was found at that point; the test role was wrong.
Author
Owner

The immediate retry hit net::ERR_CONNECTION_REFUSED on /robots.txt: the harness treated the setup token as server readiness, but the token is printed before the listener binds. startServer() now polls the real /robots.txt response before it returns. This removes the startup race from the sweep.

The immediate retry hit `net::ERR_CONNECTION_REFUSED` on `/robots.txt`: the harness treated the setup token as server readiness, but the token is printed before the listener binds. `startServer()` now polls the real `/robots.txt` response before it returns. This removes the startup race from the sweep.
Author
Owner

The next e2e run reached the undated Task preview. Its follow-up step still expected a standalone “Show day info” button, while the current Calendar header puts “Day info” in the shared More actions menu. I updated the sweep to open that menu and select its menu item.

The next e2e run reached the undated Task preview. Its follow-up step still expected a standalone “Show day info” button, while the current Calendar header puts “Day info” in the shared `More actions` menu. I updated the sweep to open that menu and select its menu item.
Author
Owner

The sweep next reached the Note. Its note-level Copy link is also a shared ModeHeader overflow menuitem (“Copy link”), not a standalone button named “Copy link to this note”. I changed that assertion to exercise the actual shared menu action; the Note heading block menu remains checked separately.

The sweep next reached the Note. Its note-level Copy link is also a shared ModeHeader overflow `menuitem` (“Copy link”), not a standalone button named “Copy link to this note”. I changed that assertion to exercise the actual shared menu action; the Note heading block menu remains checked separately.
Author
Owner

The sweep reached the Note overflow menu, where both “Copy link” and “Copy link to this block” matched the non-exact locator. I made the shared overflow helper require an exact menu-item name so it selects the intended action.

The sweep reached the Note overflow menu, where both “Copy link” and “Copy link to this block” matched the non-exact locator. I made the shared overflow helper require an exact menu-item name so it selects the intended action.
Author
Owner

Read-only source evidence from the #861 audit is recorded in its committed audit-findings.md. Focused follow-up issues: #878 (current-view header Copy link), #879 (Calendar attachment card target), #880 (internal Share grant links), #881 (heading links after rename), #882 (Inspector state), and #884 (plugin and admin list-item links). Existing tracked gaps received evidence on #55 (Task ID), #627 (folder ID), #773 (Search state), and #592 (Albums).

Read-only source evidence from the #861 audit is recorded in its committed audit-findings.md. Focused follow-up issues: #878 (current-view header Copy link), #879 (Calendar attachment card target), #880 (internal Share grant links), #881 (heading links after rename), #882 (Inspector state), and #884 (plugin and admin list-item links). Existing tracked gaps received evidence on #55 (Task ID), #627 (folder ID), #773 (Search state), and #592 (Albums).
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#167
No description provided.