diff --git a/docs/navigation-audit.md b/docs/navigation-audit.md index 26fd67e1..fc657715 100644 --- a/docs/navigation-audit.md +++ b/docs/navigation-audit.md @@ -4,9 +4,10 @@ > Every finding H1–H5 and M1–M10 is done, void, or decided-and-recorded, and so is every Phase 4 line and > every cross-cutting line. **More sites were found by sweeping than by reading the table**, all after the > listed rows were closed: the email folder and the Soulseek room/peer rails (`grep useGlobal<` / -> `useState`), and six navigations on the Invoices dashboard (`grep "onClick={() => navigate("`). All done. -> The two greps are written into the cross-cutting section as the standing re-check. What remains, and -> only this: +> `useState`), six navigations on the Invoices dashboard (`grep "onClick={() => navigate("`), and one +> navigation to a URL that **had no route at all** (`/dashboards/new`, dead since `927267e` — the third +> grep). All done. The three greps are written into the cross-cutting section as the standing re-check. +> 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. @@ -18,7 +19,14 @@ > 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. +> +> **The runtime click-through has now happened** (2026-08-07, Playwright driving the system Brave against +> the live server on 9010): 23 of 25 checks pass, and the two that did not are missing *data*, not +> regressions — the email account list and the Soulseek room list are both empty on this machine, so there +> is nothing to click. Two further "failures" were the *test* being wrong, not the app: the Dock renders a +> user-pinned subset of 13 of 25 items, so `/plans` is absent by config; and `[data-sonner-toaster]` sits on +> an inner `
    ` that only exists while a toast is showing. **Suspect the instrument first.** Individual +> "Needs runtime test" notes below may still be true — the sweep covered the routing claims, not every row. **Date:** 2026-07-30 · **Origin:** written as exploration before any of the routing work was done. @@ -292,6 +300,23 @@ publishers means changing the chat panel, which is another agent's, so it is wri because they route through an `onOpen` prop. Every one was pure navigation to an already-addressable URL that the destination genuinely reads (`useInvoicesSection` parses both `status` and `selected`), so they were anchors written as buttons and nothing more. Fixed in `ea1dae5`; the grep is clean now. + + **A third sweep, because a navigation can be well-formed and still go nowhere.** Neither grep above + can tell you whether the URL a control navigates to *exists*. React Router does not error on an + unmatched path — it falls through to whatever `path="*"` or `` guard is nearest, + which is exactly what a correct app does for a bogus URL, so a dead destination is indistinguishable + from a working one until you click it. The file browser's **"Create Dashboard here"** navigated to + `/dashboards/new?name=…&cwd=…`; `new` matched `/dashboards/:id`, `DashboardScreen` found no dashboard + with that id, and its `` swallowed the URL *and both params*. + The menu item had been silently doing nothing since the workspaces→dashboards rename in `927267e`. + The sweep is to extract every literal target and check it against the route table: + `grep -rhoE "(navigate\(|to=)['\"]/[a-zA-Z0-9/_.-]*" src/apps/officer-web src/workspaces/officerdev/src | sed -E "s/.*['\"]//" | sort -u` + against `grep -rhoE 'path="[^"]*"' src/apps/officer-web/App.tsx`. Sixteen distinct literal targets + today; all sixteen resolve (`/auth/register` is the only miss and it is inside a commented-out block). + Fixed by `useNewDashboardDraft` — the intent is a hook call now, not a URL contract with one end + unimplemented. **The general lesson: cross-app intent that is not pure navigation should not be + encoded as a URL.** Creating a dashboard is five ordered state writes; expressing that as a link was + what made it silently breakable in the first place. See the status note §24 for the full write-up. - [x] Adopt `` (real react-router) for all nav chrome so active state stops being JS-derived. Done — `39125b5`. Note `end={item.to === '/'}`: without it NavLink treats `/` as an ancestor of every route, and with it on the rest a detail route would lose its tile.