close out the navigation audit's remaining decide-or-skip items

Jobs step deep-link: skipped, and measured first — selectedKey is plain
useState, not a channel, so it breaks none of this document's rules. The only
thing anchor semantics would buy is a deep link nobody asked for.

Preview slug: void, there is no Preview app.

FileBrowser widget: stays local, and M4 turned that shrug into a rule — only a
workspace guaranteed to host one browser may own the address bar.

Phases 1-4 are now closed except H4 and the New Chat button, both of which
live in the chat nucleus.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 12:52:31 +00:00
co-authored by Claude Opus 5
parent bbcb041ef3
commit 98636224eb
+26 -10
View File
@@ -1,11 +1,19 @@
# Frontend Navigation Audit — the "opaque click" anti-pattern
> **Status, 2026-07-31.** H1 (jobs), H2 (dashboards) and H4's groundwork are **done** — rows are real
> `<Link>`s and selection lives in `?selected=` / `useParams`. **H3 is void: the Projects feature was
> deleted**, so every reference to `Projects/`, `SELECTED_PROJECT` and `/projects/:id` below is historical
> and should be read as an example of the pattern, not as work to do. **H4 (chat detail reading
> `sessionId` from `useParams` rather than the `chat:selected-session` channel) is the one item still
> open.** The rules in this file are current and authoritative; the findings table is a snapshot.
> **Status, 2026-08-07. Phases 14 are closed except the two chat items.** Every finding H1H5 and M1M10
> is done, void, or decided-and-recorded, and so is every Phase 4 line. What remains, and only this:
> **H4** (chat detail reading `sessionId` from `useParams` instead of the `chat:selected-session` channel)
> and the **"New Chat"** button that depends on it. Both are inside the chat nucleus, which has its own
> owner — they are not stalled here, they are somebody else's to land.
>
> Three findings turned out to be wrong on inspection and are marked as such rather than quietly dropped:
> **H3** is void (Projects was deleted, so every `Projects/`, `SELECTED_PROJECT` and `/projects/:id`
> reference below is historical), **M7**'s "every caller inherits the opaque click" was false (it had no
> callers, and the component is deleted), and the **Preview slug** item names an app that does not exist.
> Two components — `Combobox` and `BackButton` — were deleted rather than fixed, having never been used.
>
> The rules in this file are current and authoritative; the findings table is a snapshot.
> **Nothing below has had a runtime click-through.** Every "Needs runtime test" note is still true.
**Date:** 2026-07-30 · **Origin:** written as exploration before any of the routing work was done.
@@ -125,9 +133,17 @@ is **one design decision** that cascades across many files:
costs no extra request. En route: the row's Focus and Close buttons were nested *inside* the row
`<button>`, which is invalid HTML and only worked because of two `stopPropagation` calls; they are
siblings of the anchor now. And its "Set up in Integrations" was a raw `<a href>` that reloaded the SPA.
- **Jobs step/iteration** (`Jobs/JobDetail.tsx:234,255`) — intra-detail sub-selection; only if we want `/jobs/:id/:stepKey` deep links.
- **Preview slug** (`Preview/PreviewApp.tsx:23`) — Preview usually derives its target from the surrounding dashboard/project `cwd`; the manual picker is a fallback. Probably leave URL-less.
- **FileBrowser widget** (`FileBrowserWidget/.../BrowseTab.tsx:36`) — compact sidebar widget; keeping its browse cursor local is defensible.
- **Jobs step/iteration** (`Jobs/JobDetail.tsx`) — **decided: skipped, and it is not an anti-pattern.**
Measured rather than assumed: `selectedKey` is plain `useState` behind a context, not a channel and not a
global, so it breaks none of the rules this document sets. What it lacks is anchor semantics, and the only
thing that buys is a `/jobs/:id/:stepKey` deep link — a feature nobody has asked for, on keys that are
array indexes and iteration labels. Building it is a product call, not a fix. **Owner's if he wants it.**
- ~~**Preview slug**~~ (`Preview/PreviewApp.tsx:23`) — **void.** There is no Preview app. Nothing in the tree
matches `PreviewApp`, and it is in no registry. It went with the Projects removal on 2026-07-30, or earlier.
- **FileBrowser widget** (`FileBrowserWidget/.../BrowseTab.tsx`) — **decided: stays local**, and M4 turned
the shrug into a rule. A widget sits on dashboards next to other browsers, and one shared `?path=` would
drive all of them; only a workspace guaranteed to host exactly one browser may own the address bar, which
is why the widget passes no `searchForPath` and its breadcrumb stays buttons. Same test, same answer.
- **Music favorites view** — the channel is `music:favorites`, not `music:fav`. **Decided: it stays a channel.**
It is a view of the detail panel rather than a location, it survives no reload worth surviving, and the one
case where its being off-URL shows is handled explicitly: going Home or opening a favorite closes it by hand,
@@ -246,7 +262,7 @@ publishers means changing the chat panel, which is another agent's, so it is wri
shape that fits none of the icon-only back controls in the app. Adopting it would have been a visual
redesign of the Jobs header dressed up as a navigation fix, so it is deleted instead. The two sibling
panes (`ScriptJobDetail`, `DownloadJobDetail`) were already `<Link to="/jobs">`; this was the odd one out.
- [ ] Decide/skip: Jobs step deep-link, Preview slug, FileBrowser widget. (Browser tabs: **done** — see the LOW section. Monitor scope: **done** as M10, it was not a view toggle. Music favorites: **decided** — stays a channel, reasoning in the LOW section.)
- [x] Decided/skipped: Jobs step deep-link (a feature, not a fix — owner's call), Preview slug (**void**: no such app), FileBrowser widget (stays local, on M4's rule). Reasoning for each in the LOW section. (Browser tabs: **done** — see the LOW section. Monitor scope: **done** as M10, it was not a view toggle. Music favorites: **decided** — stays a channel, reasoning in the LOW section.)
### Cross-cutting for the refactor itself
- [ ] Standardise a URL-as-source-of-truth pattern for panel selection (replace the `usePanelChannel`/`useGlobal`