Perch Hub: reachable from the dashboard, and back from the board - #351
Merged
Merged
Conversation
Three navigation gaps reported after Perch Hub shipped:
- Perch had no nav entry or launcher icon. Converted it from a bare route
mounted onto /dashboard (routes/perch-hub.js) into a registered panel
(panels/perch-hub.js, category "ai") so nav-registry auto-assigns it into
the Agents group on every install, no migration needed. The panel handler
still renders perchHubDocument directly and never calls layout() — the
standalone document is what keeps the chat surface usable on a phone.
routes/perch-hub.js is deleted; the /perch short link stays, now pointing
at the one remaining handler.
- The bot board had no link back to Perch (Perch already links to the
board). Added one next to the bot switcher, i18n'd in en/es.
- The board's session actions (card-face bird glyph, #bird=<sid> deep link,
Open/Answer/Sessions/Talk, and a successful roost dispatch) all opened the
in-page bird drawer instead of the chat surface. They now navigate to
/dashboard/perch#<sid> (bare /dashboard/perch for action=sessions, which
has no specific session) via one goToPerch() helper. drawer.js and its
markup are untouched — removed in a later, separately-gated change.
Retranslated botboard.roostDispatchSent ("Sent — reloading…" is stale;
there's no more reload).
Tests: rewrote the two perch-hub-page.test.js assertions that pinned the old
router mount to pin the new panel registration instead (mutation-tested:
each wiring line independently turns the guard red). Added a manifest-shape
test and a request-level handler test. Added tests/bot-board-perch-link.test.js
for the new board link. Rewrote roost-strip-ui.test.js's dispatch-success
test for the new navigate-not-reload behavior and added three tests covering
the other four converted call sites — every new assertion mutation-tested
red/green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Perch Hub shipped in #350 as a page you could only reach by typing a URL. Operator feedback, verbatim:
All three fixed here.
The phasing mistake this corrects
The original plan bundled the nav entry with the drawer deletion in "PR 2". Those are different risk classes: adding ways to reach the hub is additive and reversible; deleting the working drawer is neither. Shipping an unreachable page and then asking for it to be evaluated was not a usable increment.
So navigation lands now. The drawer is untouched — it simply stops being the destination — and its deletion stays gated on real use.
A registered panel, not a hard-coded link
The plan had ruled against a panel registration, on the grounds that
nav-registryonly routes to registered panels and that existing installs never receive new defaults. Both halves were wrong on closer reading:dashboard/index.js's panel loader comments// Handler may have already sent responseand only sendsresultwhen!res.headersSent. A panel handler can render its own document — so Perch keeps its standalone full-page layout (neverlayout()), which is the whole reason it works on a phone.nav-registryauto-assigns panels missing from stored assignments viaCATEGORY_TO_GROUP, andcategory: "ai"→ the agents group. The migration objection applies to changing defaults, not to adding a new panel.So
routes/perch-hub.jsis gone andpanels/perch-hub.jsreplaces it (id: "perch",category: "ai",navOrder: 15.5). The/perchshort link still redirects.Verified against real code rather than assumed: built the actual
dashboardRouterand ran realresolveNavGroups()against a realinit-db.jsdatabase — Agents group resolves to[bot-builder, bot-board, perch, model-catalog, skills]. CDP-live confirms/dashboard/perchrenders with no.sidebar(still a standalone document) while the board's sidebar shows the Perch entry.Board → Perch, both directions
botboard.perchLink, en/es).openBirdDrawer(...)call sites now navigate through onegoToPerch(sid)helper: the bird-glyph click, the#bird=<sid>deep link,open,answer,sessions, andtalk's spawn-success branch. Dispatch navigates to the new session instead of reloading, andbotboard.roostDispatchSentis retranslated since there is no longer a reload.drawer.jsis deliberately not deleted or modified.Tests
98/98 across
perch-hub-page,perch-hub-client,perch-hub-render,roost-strip-ui,roost-strip-data,board-i18n-literals,i18n-global-parity,a11y-baseline. A collateral sweep of 46 files touching bot-board / dashboard index / nav-registry / panel-registry / i18n: 642/642.16 mutations, each independently verified to turn its guarding assertion red and then restored — the wiring lines, every manifest field, the board link, i18n parity, and all six navigation call sites. Following this branch's standing rule: an assertion that cannot fail is not a test.
Known, non-blocking
icon: "messages"reuses the Messages glyph.NAV_ICONShas no dedicated chat icon, and several existing panels already reference keys absent from it and silently fall back (bot-board's"project", fediverse's"globe", memory's"memory"). Pre-existing; worth its own sweep.