diff --git a/docs/release-control/v6/internal/subsystems/ai-runtime.md b/docs/release-control/v6/internal/subsystems/ai-runtime.md index f179d5285..0239ba99f 100644 --- a/docs/release-control/v6/internal/subsystems/ai-runtime.md +++ b/docs/release-control/v6/internal/subsystems/ai-runtime.md @@ -66,6 +66,11 @@ runtime cost control, and shared AI transport surfaces. cache for assistant context and suggestions, but it must not reopen `useResources()` or trigger a second unfiltered `all-resources` REST fetch just because the drawer component is present in the app shell. + The same app-shell boundary keeps Patrol/Assistant utility navigation + accessible-name safe: labelled icon SVGs may remain meaningful when rendered + standalone, but `frontend-modern/src/AppLayout.tsx` must treat them as + decorative inside tabs so the announced tab name comes from product chrome + and meaningful badge text. ## Forbidden Paths diff --git a/docs/release-control/v6/internal/subsystems/cloud-paid.md b/docs/release-control/v6/internal/subsystems/cloud-paid.md index 181f0f52d..eb9b4e75f 100644 --- a/docs/release-control/v6/internal/subsystems/cloud-paid.md +++ b/docs/release-control/v6/internal/subsystems/cloud-paid.md @@ -278,6 +278,10 @@ Community limit enforcement. invitation flow must therefore refresh org bootstrap through the shared `organizations_changed` app-shell path instead of forking a second hosted org bootstrap or pricing-aware shell reload. + App-shell navigation rendered by `frontend-modern/src/AppLayout.tsx` must + also keep decorative icon titles out of tab accessible names, so hosted and + self-hosted chrome announce the canonical tab label plus meaningful badge + counts rather than duplicating branded SVG titles. 22. Keep the hosted account portal shell task-first and compact. Section headers, billing action rows, and the maintained portal bundle under `internal/cloudcp/portal/` may surface the facts an operator needs, but the diff --git a/frontend-modern/src/AppLayout.tsx b/frontend-modern/src/AppLayout.tsx index ea4c2bb55..474fb8264 100644 --- a/frontend-modern/src/AppLayout.tsx +++ b/frontend-modern/src/AppLayout.tsx @@ -48,6 +48,16 @@ const NAV_TAB_ICON_CLASS = 'w-4 h-4 shrink-0'; const AI_CHAT_LAUNCHER_BUTTON_CLASS = 'fixed right-4 bottom-[calc(5rem+env(safe-area-inset-bottom,0px))] z-40 flex h-11 w-11 items-center justify-center rounded-full border border-border bg-surface text-blue-600 shadow-lg transition-colors duration-200 hover:bg-surface-hover hover:text-blue-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 dark:text-blue-400 dark:hover:text-blue-300 lg:right-0 lg:top-1/2 lg:bottom-auto lg:h-auto lg:w-auto lg:min-h-9 lg:min-w-10 lg:-translate-y-1/2 lg:rounded-l-lg lg:rounded-r-none lg:border-r-0 lg:px-2.5 lg:py-2.5 lg:shadow-none'; +function getDesktopUtilityTabAriaLabel(tab: UtilityTab): string { + if (tab.id === 'alerts') { + const count = tab.count ?? 0; + if (count > 0) { + return `${count} ${tab.label}`; + } + } + return tab.label; +} + export interface AppLayoutProps { connectionStatus: () => AppConnectionStatus; lastUpdateText: () => string; @@ -604,12 +614,15 @@ export function AppLayout(props: AppLayoutProps) {