| name | maintain-navigation |
| description | Maintain Chat/Live/Settings/Debug navigation, tab state, panel visibility, teardown ordering, epoch races, and focus handoff. Use when changing destination switching, titlebar chrome, or navigation accessibility. |
Maintain navigation
Role and boundary
Keep wirePrimaryNavigation as the single synchronous owner of tab chrome and the asynchronous owner of settled panel/focus state. Navigation coordinates teardown; it must not duplicate Live, speech, session, or diagnostics state.
Source map
src/navigation.ts: AppView, wirePrimaryNavigation, syncViewChrome, showView, navigationEpoch, two-frame focus handoff, and Debug refresh hook.
src/main.ts: four tab buttons, four content sections, sidebar/composer references, wireStatusChrome callback, and beforeunload cleanup.
src/style.css: .app-tabs, .app-tab, .content, .sidebar[hidden], focus-visible rules, and responsive/reduced-motion navigation styling.
tests/navigation.test.ts: tab/panel/aria-current agreement, Live/speech teardown ordering, stale-click epoch protection, and two-frame Debug focus.
Cover
- Update active tab,
aria-current="page", titlebar destination text, and panel hidden state from one path; keep optimistic chrome synchronous while teardown awaits.
- When leaving Live, await
live.stop(); when entering Live, await Chat speech stop. Let a newer click win through the navigation epoch and ignore stale continuations.
- Keep the sidebar visible only for Chat/Live, refresh diagnostics on Debug entry, and focus the composer, Live control, Settings heading, or Debug heading only after required render frames.
- Preserve Live's pinned conversation when the sidebar changes; navigation must never retarget a running Live session.
- Inspect the current DOM and tests before changing transitions or focus. Do not add route surfaces, browser history, or framework routing.
Validate and accept
- Run
bun test tests/navigation.test.ts and verify every destination's tab, panel, sidebar, focus, and race behavior.
- Run
git diff --check against the actual files changed; run just check when the change crosses TypeScript/Rust/build boundaries. Inspect keyboard navigation and reduced-motion behavior in a packaged WebKit window with $test-voice-layer-app.
- Treat native Live stop settlement and packaged accessibility-tree inspection as separate gates; unit tests cannot prove WebKit timing on a device.
Relationships
Coordinate with $maintain-app-shell, $maintain-live, $maintain-voice-output, $maintain-session-sidebar, and $maintain-debug; avoid copying their state machines.