Skip to content

Derive the remaining eight hand-maintained page tab lists from the nav manifest #6383

Description

@atomantic

Follow-up to #6365, which shipped the tabGroup/getPageNavTabs(group) mechanism in server/lib/navManifest.js and converted six of the fourteen pages named in the original audit: Calendar, Goals, Insights, Privacy, Messages, Wiki. This issue covers the remaining eight.

Problem

server/lib/navManifest.js still has no tabGroup for the tab sets declared by:

  • client/src/components/brain/constants.js (TABS)
  • client/src/components/cos/constants.js (TABS)
  • client/src/components/digital-twin/constants.js (TABS)
  • client/src/components/meatspace/constants.js (TABS)
  • client/src/pages/MediaGen.jsx (TABS, allowBasePrefix: true)
  • client/src/pages/Music.jsx (TABS, allowBasePrefix: true)
  • client/src/pages/Sharing.jsx (SECTIONS, kind: 'links' — a different source shape than the rest)
  • client/src/pages/SystemHealthPage.jsx (RESOURCE_TABS, allowBasePrefix: true)

navManifest.test.js's TABBED_PAGES still scrapes each of these via extractConstArrayBlock/extractConstIds/extractTabPaths (kind: 'ids' for the first six, kind: 'links' for Sharing) instead of the manifest being the one registry.

Brain has a real pre-existing gap, not just a naming mismatch: constants.js declares spotify and youtube tabs (TABS array, ids spotify/youtube) with no corresponding NAV_COMMANDS entry at all — they are unreachable from ⌘K and voice ui_navigate today, contrary to the rule in root AGENTS.md ("Adding a <Route> without a NAV_COMMANDS entry leaves the page unreachable"). Converting Brain to derive TABS from getPageNavTabs('brain') requires adding nav.brain.spotify and nav.brain.youtube manifest entries first (pick paths /brain/spotify and /brain/youtube to match the existing /brain/<id> pattern), or the conversion will silently drop those two tabs from the page.

Fix

Same mechanism as #6365, applied per page:

  1. Add tabGroup: '<page>' ('brain', 'cos', 'digital-twin', 'meatspace', 'media', 'music', 'system-resources') plus tabId to each relevant NAV_COMMANDS entry. Add tabLabel for any page-local label that differs from the manifest label (the original audit's 17-differing-labels count includes at least /system-resources/queues "Queues" vs "Active Queues", /music/generate "Generate" vs "Music Designer", and /digital-twin/legacy "Legacy" vs "Legacy Bundle" — none of these are in the six already shipped).
  2. Reorder the manifest entries within each new group so file order matches the page's deliberate tab order — getPageNavTabs(group) returns entries in declaration order, not alphabetical (see [code-quality-page-tabs-from-manifest] Derive the fourteen hand-maintained page tab lists from the nav manifest #6365's Messages/Wiki/Calendar reorders for the pattern).
  3. Add the two missing Brain entries (nav.brain.spotify, nav.brain.youtube) before converting Brain.
  4. Each page keeps its local presentation map (icon, fullBleed, any other page-only flag) keyed by tab id, and builds TABS via getPageNavTabs(group).map(...), throwing at module load if a manifest tab has no presentation entry — same shape as client/src/pages/Wiki.jsx after [code-quality-page-tabs-from-manifest] Derive the fourteen hand-maintained page tab lists from the nav manifest #6365.
  5. allowBasePrefix: true pages (MediaGen, Music, SystemHealthPage) — confirm whether that flag is still needed once the manifest owns the id list; it exists in the current scraper to also allow the bare /media//music//system-resources path with no tab id. If the bare-path manifest entry already exists as a separate NAV_COMMANDS row without a tabId/tabGroup (default-tab redirect), the flag has no equivalent to carry over into getPageNavTabs and can likely be dropped — verify against the live route.
  6. Sharing is the odd one out — SECTIONS is a list of { to/path, label, ...nested links }, not a flat { id, label } tab array like the other kind-'ids' pages, and mixes in-page tabs with cross-links (the old kind: 'links' filtering logic in navManifest.test.js already separates them). Decide the tabGroup shape needed to cover it, or carve it into its own follow-up if it doesn't fit the same getPageNavTabs contract cleanly.
  7. Remove each migrated page's row from TABBED_PAGES in server/lib/navManifest.test.js as it converts. Once ALL eight are done, delete the now-dead extractConstArrayBlock/extractSwitchCases/extractConstIds/extractTabPaths kind: 'ids'/kind: 'links' machinery and nestedIdSources, per the original [code-quality-page-tabs-from-manifest] Derive the fourteen hand-maintained page tab lists from the nav manifest #6365 acceptance criteria — TABBED_PAGES should end up listing only the POST switch page.
  8. Add a per-page test (colocated, following client/src/pages/Wiki.test.jsx's post-[code-quality-page-tabs-from-manifest] Derive the fourteen hand-maintained page tab lists from the nav manifest #6365 shape) asserting TABS matches getPageNavTabs(group) in id/label/order.

Out of scope

Same as #6365: the POST switch (tab) dispatch (kind: 'switch') and Settings.jsx's switch (activeTab) parity stay as-is; getSectionNavTabs and the App.jsx route scan are untouched.

Acceptance criteria

  • Brain, CoS, Digital Twin, MeatSpace, Media Gen, Music, Sharing and System Resources each derive TABS/RESOURCE_TABS/SECTIONS from getPageNavTabs(<group>) plus a local presentation map.
  • nav.brain.spotify and nav.brain.youtube manifest entries exist and Brain's Spotify/YouTube tabs are reachable via ⌘K/voice.
  • navManifest.test.js's TABBED_PAGES contains only the POST switch row; the ids/links parsers and nestedIdSources are deleted.
  • cd client && npm test and cd server && npx vitest run lib/navManifest.test.js pass.

Scope: large

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    code-qualityProposed from a code-quality auditeffort:highDispatch reasoning effort: highmodel:mediumModel size: mediumplanTracked by /do:replanplanner:opus-5Plan authored by the opus-5 model

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions