# Cluster 05 — Dashboard
Audited docs: `docs/DashboardInterfaceDesign.md`, `docs/GatewayDashboardDesign.md`
Verified against: `src/ZB.MOM.WW.MxGateway.Server/Dashboard/**`, `src/ZB.MOM.WW.MxGateway.Server/wwwroot/**`
Audit date: 2026-06-03
---
DOC / DashboardInterfaceDesign.md / LINES / 39–57
CLAIM / "The shell does not use a sidebar. A horizontal navigation bar is enough…" with a `
` / `` HTML skeleton
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Layout/MainLayout.razor:7 — layout now delegates to `` with `NavRailSection`/`NavRailItem` kit components; there is no local navbar, no `dashboard-shell` class, no `dashboard-navbar` class, and no `container-fluid` content area anywhere in the codebase
CODE_AREA / dashboard.theme
SEVERITY / high
PROPOSED_FIX / Replace the HTML skeleton and prose description with the current ThemeShell side-rail pattern (`` → `` → `` / ``). Update the note about "horizontal navigation bar" — the nav is now a collapsible side rail managed by the ZB.MOM.WW.Theme kit.
---
DOC / DashboardInterfaceDesign.md / LINES / 115–123
CLAIM / Navigation uses `NavLink` and labels: `Overview`, `Sessions`, `Workers`, `Events`, `Settings`
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Layout/MainLayout.razor:9–23 — actual nav items are `Dashboard` (not "Overview"), `Sessions`, `Workers`, `Events`, `Alarms`, `Repository`, `Browse`, `API Keys`, `Settings`; the old flat list of five labels has been replaced by three grouped NavRailSections (`Runtime`, `Galaxy`, `Admin`) with eight leaf items
CODE_AREA / dashboard.theme
SEVERITY / high
PROPOSED_FIX / Update the nav-label list to match the current ThemeShell Nav: Dashboard / [Runtime: Sessions, Workers, Events, Alarms] / [Galaxy: Repository, Browse] / [Admin: API Keys, Settings].
---
DOC / DashboardInterfaceDesign.md / LINES / 63–79
CLAIM / Four local CSS tokens: `--mxgw-surface: #f7f8fa`, `--mxgw-border: #d8dee6`, `--mxgw-ink-muted: #667085`, `--mxgw-accent: #146c64`
CLAIM_TYPE / config-key
VERDICT / wrong
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/wwwroot/css/site.css:1–7 — no `--mxgw-*` tokens are defined anywhere in `site.css`; the file's own header states "Every colour … resolves to a theme.css token — no hard-coded hex." All colour expressions in site.css use theme kit tokens: `var(--card)`, `var(--rule)`, `var(--ink)`, `var(--ink-faint)`, `var(--accent)`, `var(--accent-deep)`, `var(--bad)`, `var(--bad-bg)`, etc.
CODE_AREA / dashboard.css
SEVERITY / high
PROPOSED_FIX / Remove the `--mxgw-*` token table entirely. Replace with a note that the dashboard's view-layer CSS (`site.css`) resolves all colour via the `ZB.MOM.WW.Theme` kit tokens (`--card`, `--rule`, `--ink`, `--ink-faint`, `--accent`, `--accent-deep`, etc.) and defines no local colour tokens.
---
DOC / DashboardInterfaceDesign.md / LINES / 87–97
CLAIM / Page headings use `1.35rem`, weight `650`. Metric labels use `uppercase text at .78rem` and weight `650`. Metric values use `1.7rem`, weight `700`, and the accent color.
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / site.css:30–31 (page h1: `font-size: 1.15rem; font-weight: 600`), site.css:64–65 (agg-label: `font-size: 0.68rem; font-weight: 600`), site.css:76–77 (agg-value: `font-size: 1.5rem; font-weight: 600; color: var(--ink)`) — page headings are `1.15rem/600` (not `1.35rem/650`); metric values are `1.5rem/600` in `var(--ink)` (not `1.7rem/700` in accent color)
CODE_AREA / dashboard.css
SEVERITY / medium
PROPOSED_FIX / Update typography table: h1 → 1.15rem/600, agg-label → 0.68rem/600/uppercase, agg-value → 1.5rem/600/var(--ink). Note metric values render in ink (not the accent colour) per the post-theme-migration design.
---
DOC / DashboardInterfaceDesign.md / LINES / 99–111
CLAIM / Page content has `1.25rem` padding on desktop and `.75rem` on small screens. Metric grids use `.75rem` gaps. Cards and empty states use Bootstrap's small radius `.375rem`. Content sections start with a top border and `1rem` top padding.
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / site.css:272–279 (`@media (max-width: 700px)` sets `.page { padding: 0.85rem }`; no 1.25rem desktop padding rule exists in site.css). site.css:59 (`border-radius: 8px` for `.agg-card`, not `.375rem`). site.css:59 (`box-shadow: none` but no top-border-only sections — `.dashboard-section` at line 91–100 is a raised card with `border: 1px solid var(--rule); border-radius: 8px`).
CODE_AREA / dashboard.css
SEVERITY / low
PROPOSED_FIX / Update spacing table: small-screen padding is 0.85rem; cards use 8px radius; sections are full-border raised cards (not top-border-only dividers).
---
DOC / DashboardInterfaceDesign.md / LINES / 153–168
CLAIM / `metric-grid` uses `repeat(auto-fit, minmax(12rem, 1fr))` and `compact` variant uses `minmax(10rem, 1fr)`
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / site.css:49 (`grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr))`) and site.css:54 (`repeat(auto-fill, minmax(10rem, 1fr))`) — base grid is `auto-fill, 11rem` (not `auto-fit, 12rem`); `auto-fill` not `auto-fit`
CODE_AREA / dashboard.css
SEVERITY / low
PROPOSED_FIX / Update code block: base grid is `repeat(auto-fill, minmax(11rem, 1fr))`; compact stays `minmax(10rem, 1fr)`.
---
DOC / DashboardInterfaceDesign.md / LINES / 191–200
CLAIM / Status uses Bootstrap badge classes (`text-bg-success`, `text-bg-info`, `text-bg-secondary`, `text-bg-danger`, `text-bg-light text-dark border`) with mapping: `Closed` → `text-bg-secondary`; `Creating`/`StartingWorker`/`WaitingForPipe`/`InitializingWorker`/`Closing` → `text-bg-info`
CLAIM_TYPE / behavior-rule
VERDICT / wrong
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Shared/StatusBadge.razor:1–16 — `StatusBadge` is now a thin adapter over the kit's `` component; no Bootstrap `text-bg-*` classes are used at all. State mapping uses `StatusState.Ok/Warn/Bad/Idle`. `Closed` falls through to `StatusState.Idle` (no `text-bg-secondary`). `Closing` is mapped to `StatusState.Warn` (not info). New states `Stale`, `Degraded`, `Active`, `Unavailable` are handled; `Unknown state` → `StatusState.Idle` (was `text-bg-light text-dark border`).
CODE_AREA / dashboard.theme
SEVERITY / high
PROPOSED_FIX / Replace the badge-class table with the current `StatusState` enum vocabulary: Ok (`Ready`, `Healthy`, `Active`); Warn (`Creating`, `StartingWorker`, `WaitingForPipe`, `InitializingWorker`, `Closing`, `Stale`, `Degraded`); Bad (`Faulted`, `Unavailable`); Idle (everything else including `Closed`). Note that visual rendering is owned by the ZB.MOM.WW.Theme `StatusPill` component.
---
DOC / DashboardInterfaceDesign.md / LINES / 229–245
CLAIM / Responsive breakpoint CSS: `.dashboard-content { padding: .75rem }` at `max-width: 700px`
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / site.css:272–279 — the responsive rule targets `.page { padding: 0.85rem }` (not `.dashboard-content`; not `.75rem`)
CODE_AREA / dashboard.css
SEVERITY / low
PROPOSED_FIX / Update code block to `@media (max-width: 700px) { .page { padding: 0.85rem; } … }`.
---
DOC / GatewayDashboardDesign.md / LINES / 78–110
CLAIM / Component tree lists `Layout/DashboardLayout.razor` and `Shared/StatusBadge.razor` as standalone status component
CLAIM_TYPE / path
VERDICT / stale
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Layout/ contains only `MainLayout.razor` and `LoginLayout.razor`; there is no `DashboardLayout.razor`. `StatusBadge.razor` still exists but is now a thin wrapper delegating to the kit's `StatusPill`; the doc's tree implies it is a standalone Bootstrap-badge component.
CODE_AREA / dashboard.theme
SEVERITY / medium
PROPOSED_FIX / In the component tree rename `DashboardLayout.razor` → `MainLayout.razor` and `LoginLayout.razor`. Add a note that `StatusBadge` delegates to `ZB.MOM.WW.Theme`'s `StatusPill`. Also add `BrowseTreeNodeView.razor` and `ConfirmDialog.razor` which are present in code but absent from the tree.
---
DOC / GatewayDashboardDesign.md / LINES / 507–510
CLAIM / "The dashboard serves Bootstrap 5.3.3 assets from `src/ZB.MOM.WW.MxGateway.Server/wwwroot/lib/bootstrap/` and local layout/status styling from `src/ZB.MOM.WW.MxGateway.Server/wwwroot/css/dashboard.css`."
CLAIM_TYPE / path
VERDICT / wrong
EVIDENCE / find shows `wwwroot/css/site.css` exists; there is no `dashboard.css` under wwwroot. Bootstrap 5.3.3 is confirmed (bootstrap.min.css header). App.razor:8–9 loads `/css/site.css`, not `/css/dashboard.css`. Additionally the denied-page renderer at DashboardEndpointRouteBuilderExtensions.cs:172–173 also loads theme kit CSS: `/_content/ZB.MOM.WW.Theme/css/theme.css` and `/_content/ZB.MOM.WW.Theme/css/layout.css`.
CODE_AREA / dashboard.css
SEVERITY / high
PROPOSED_FIX / Change `dashboard.css` → `site.css` throughout. Add that App.razor also loads ` ` (which injects the theme kit's CSS) and ` `. Note the denied-page also pulls `/_content/ZB.MOM.WW.Theme/css/theme.css` and `/_content/ZB.MOM.WW.Theme/css/layout.css` directly.
---
DOC / GatewayDashboardDesign.md / LINES / 406–428
CLAIM / "`DashboardAuthenticator` binds against `MxGateway:Ldap` … using `Novell.Directory.Ldap.NETStandard`"
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardAuthenticator.cs:1–6 — imports are `ZB.MOM.WW.Auth.Abstractions.Ldap`, `ZB.MOM.WW.Auth.Abstractions.Roles`, `ZB.MOM.WW.Auth.AspNetCore`; the csproj references `ZB.MOM.WW.Auth.Ldap 0.1.2`, not Novell. DashboardServiceCollectionExtensions.cs:35 calls `services.AddZbLdapAuth(configuration, "MxGateway:Ldap")`. `Novell.Directory.Ldap.NETStandard` is not referenced in the csproj.
CODE_AREA / dashboard.login
SEVERITY / medium
PROPOSED_FIX / Replace "using `Novell.Directory.Ldap.NETStandard`" with "using the shared `ZB.MOM.WW.Auth.Ldap` package (`ILdapAuthService`), registered via `AddZbLdapAuth`".
---
DOC / GatewayDashboardDesign.md / LINES / 420–422
CLAIM / Cookie name is `__Host-MxGatewayDashboard`
CLAIM_TYPE / config-key
VERDICT / wrong
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardAuthenticationDefaults.cs:38 — `public const string CookieName = "MxGatewayDashboard"` (no `__Host-` prefix). The code comment explains the `__Host-` prefix is not used; the cookie path is `/` set explicitly at DashboardServiceCollectionExtensions.cs:72.
CODE_AREA / dashboard.login
SEVERITY / high
PROPOSED_FIX / Change `__Host-MxGatewayDashboard` to `MxGatewayDashboard` everywhere in the auth section. Note that the cookie name is configurable via `MxGateway:Dashboard:CookieName`.
---
DOC / GatewayDashboardDesign.md / LINES / 289–306
CLAIM / Browse page is at `/dashboard/browse`; tree built by `DashboardBrowseTreeBuilder` from `IGalaxyHierarchyCache.Current`; subscription panel is the explicit opt-in for tag values
CLAIM_TYPE / path
VERDICT / stale
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Pages/BrowsePage.razor:1 — route is `@page "/browse"` (not `/dashboard/browse`). `DashboardBrowseTreeBuilder` is found at DashboardBrowseModel.cs:66 as a static class. Browse uses `IGalaxyHierarchyCache` (injected via `IDashboardBrowseService`) confirmed at BrowsePage.razor:3.
CODE_AREA / dashboard.hub
SEVERITY / medium
PROPOSED_FIX / Fix route to `/browse` (not `/dashboard/browse`). The tree builder name is accurate but clarify it is a static class inside `DashboardBrowseModel.cs`.
---
DOC / GatewayDashboardDesign.md / LINES / 307–318
CLAIM / Alarms page is at `/dashboard/alarms`; defaults to showing unacknowledged `Active` alarms; Alarms page reads via `IDashboardLiveDataService`
CLAIM_TYPE / path
VERDICT / stale
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Pages/AlarmsPage.razor:1 — route is `@page "/alarms"` (not `/dashboard/alarms`). The claim that alarm data comes from "gateway's always-on central monitor" via `IGatewayAlarmService.CurrentAlarms` is contradicted by the implementation: AlarmsPage.razor:3 injects `IDashboardLiveDataService` and calls `LiveData.QueryAlarmsAsync` in a poll loop — not `IGatewayAlarmService.CurrentAlarms` directly.
CODE_AREA / dashboard.hub
SEVERITY / medium
PROPOSED_FIX / Fix route to `/alarms`. Correct the live data source description: the Alarms page uses `IDashboardLiveDataService.QueryAlarmsAsync` (a polling loop every 3 s), not a direct read of `IGatewayAlarmService.CurrentAlarms`.
---
DOC / GatewayDashboardDesign.md / LINES / 337–345
CLAIM / API keys page is at `/dashboard/apikeys`
CLAIM_TYPE / path
VERDICT / stale
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/Components/Pages/ApiKeysPage.razor:1 — route is `@page "/apikeys"` (not `/dashboard/apikeys`)
CODE_AREA / dashboard.hub
SEVERITY / medium
PROPOSED_FIX / Fix route to `/apikeys`.
---
DOC / GatewayDashboardDesign.md / LINES / 387–391
CLAIM / "Every management action appends an `api_key_audit` entry (`dashboard-create-key`, `dashboard-rotate-key`, `dashboard-revoke-key`, `dashboard-delete-key`) with the key id and the caller's remote address."
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Dashboard/DashboardApiKeyManagementService.cs:59 — "both rows land in the canonical audit_event store"; DashboardApiKeyManagementService.cs:69,113,156,201 — action strings `dashboard-create-key`, `dashboard-rotate-key`, `dashboard-revoke-key`, `dashboard-delete-key` are confirmed. However the table used is `audit_event` (via `IAuditWriter`), not `api_key_audit`. Comments explicitly state "the library's `api_key_audit` table is left in place but UNUSED".
CODE_AREA / dashboard.login
SEVERITY / medium
PROPOSED_FIX / Change "appends an `api_key_audit` entry" to "appends an `audit_event` entry (via `IAuditWriter`)". The `api_key_audit` table is no longer used for dashboard actions.
---
DOC / GatewayDashboardDesign.md / LINES / 68–69
CLAIM / Galaxy page is at `/galaxy`; "summary is fed by `GalaxySummaryCache`, which is refreshed off the request path by `GalaxySummaryRefreshService` on the `MxGateway:Galaxy:DashboardRefreshIntervalSeconds` cadence"
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / `GalaxySummaryCache` and `GalaxySummaryRefreshService` do not exist in the codebase. The actual implementation uses `IGalaxyHierarchyCache` (GalaxyHierarchyCache.cs) refreshed by `GalaxyHierarchyRefreshService` (Galaxy/GalaxyHierarchyRefreshService.cs:19), driven by `GalaxyRepositoryOptions.DashboardRefreshIntervalSeconds` under config key `MxGateway:Galaxy:DashboardRefreshIntervalSeconds` (confirmed by appsettings.json:74). Galaxy page route `/galaxy` is confirmed.
CODE_AREA / dashboard.hub
SEVERITY / medium
PROPOSED_FIX / Replace `GalaxySummaryCache` / `GalaxySummaryRefreshService` with `GalaxyHierarchyCache` / `GalaxyHierarchyRefreshService`. Config key `MxGateway:Galaxy:DashboardRefreshIntervalSeconds` is correct.
---
DOC / GatewayDashboardDesign.md / LINES / 160–170
CLAIM / "Updates flow over three SignalR hubs … `DashboardSnapshotPublisher` (BackgroundService consuming `IDashboardSnapshotService.WatchSnapshotsAsync`)"; hub table row for EventsHub: "`DashboardEventBroadcaster` invoked by `EventStreamService` for each event it forwards to a gRPC client"
CLAIM_TYPE / behavior-rule
VERDICT / accurate
EVIDENCE / Dashboard/Hubs/DashboardSnapshotPublisher.cs confirms BackgroundService consuming `WatchSnapshotsAsync`. Dashboard/Hubs/EventsHub.cs:6–17 comment: "The publisher side is intentionally a follow-up. Today the dashboard's per-session event view is fed by the snapshot hub … Once a dedicated MxEvent broadcaster lands, this hub's group convention is what it will publish to." — so the doc's description of `DashboardEventBroadcaster` being active is aspirational; it currently exists as a stub.
CODE_AREA / dashboard.hub
SEVERITY / low
PROPOSED_FIX / Flag only — add a note that `EventsHub`'s broadcaster is a planned follow-up; today the per-session events view in `SessionDetailsPage` connects to `/hubs/events` directly and `DashboardEventBroadcaster` exists but the EventStreamService hook is not yet wired. The hub routing convention is stable.
---
DOC / GatewayDashboardDesign.md / LINES / 171–177
CLAIM / "`DashboardPageBase` … seeds `Snapshot` synchronously from `IDashboardSnapshotService.GetSnapshot()` … and calls `InvokeAsync(StateHasChanged)` on every `SnapshotUpdated` push. SignalR's `WithAutomaticReconnect` handles transient disconnects."
CLAIM_TYPE / behavior-rule
VERDICT / accurate
EVIDENCE / Dashboard/Components/DashboardPageBase.cs:37–78 — `GetSnapshot()` seed on line 37, hub `On` calls `InvokeAsync(StateHasChanged)` on line 65. DashboardHubConnectionFactory.cs:36 — `.WithAutomaticReconnect()` confirmed.
CODE_AREA / dashboard.hub
SEVERITY / low
PROPOSED_FIX / flag only
---
DOC / GatewayDashboardDesign.md / LINES / 559–577
CLAIM / "Initial Implementation Slice … 2. local Bootstrap static assets."
CLAIM_TYPE / behavior-rule
VERDICT / stale
EVIDENCE / App.razor:7–8 — ` ` is loaded before `/css/site.css`; ThemeScripts at line 15. The theme kit (`ZB.MOM.WW.Theme 0.2.0`) is now the primary asset provider via `/_content/ZB.MOM.WW.Theme/`. The "local Bootstrap static assets" description is no longer the full picture — Bootstrap is still vendored locally but the theme kit adds additional CSS/JS layers. DashboardEndpointRouteBuilderExtensions.cs:172–173 directly references `/_content/ZB.MOM.WW.Theme/css/theme.css` and `/_content/ZB.MOM.WW.Theme/css/layout.css`.
CODE_AREA / dashboard.css
SEVERITY / low
PROPOSED_FIX / Update item 2 to: "local Bootstrap static assets plus `ZB.MOM.WW.Theme` kit (PackageReference `0.2.0`) providing theme CSS, layout CSS, and JS via ` ` / ` `".
---
DOC / GatewayDashboardDesign.md / LINES / 463–465
CLAIM / "Two environmental bypasses … `MxGateway:Authentication:Mode = Disabled` authorizes every request"
CLAIM_TYPE / config-key
VERDICT / unverifiable
EVIDENCE / No code path for `MxGateway:Authentication:Mode` was found in Dashboard/ — search returned no matches. The `AllowAnonymousLocalhost` bypass is confirmed at DashboardAuthorizationHandler.cs (referenced from DashboardAuthorizationRequirement). The global Auth mode bypass may live in GatewayOptions outside the dashboard cluster.
CODE_AREA / dashboard.login
SEVERITY / low
PROPOSED_FIX / Cross-check against GatewayOptions and the auth middleware — if this config key was removed or renamed, update the doc. If it lives outside dashboard code, add a cross-reference.
---
## Gap findings (code behavior undocumented)
DOC / gap
LINES / n/a
CLAIM / `Login.razor` is a Blazor page (`@page "/login"`) using `LoginLayout` and the kit's `` component. GET /login is served by this Blazor page, not a static HTML form. POST /login is a minimal-API endpoint.
CLAIM_TYPE / behavior-rule
VERDICT / gap
EVIDENCE / Dashboard/Components/Pages/Login.razor:1–27; DashboardEndpointRouteBuilderExtensions.cs:27–36
CODE_AREA / dashboard.login
SEVERITY / medium
PROPOSED_FIX / Add to the auth section: "GET `/login` is served by the Blazor `Login.razor` page (using the shared kit's ``); the page is `[AllowAnonymous]` and uses `LoginLayout` (no side rail). POST `/login` remains a minimal-API endpoint."
---
DOC / gap
LINES / n/a
CLAIM / `StatusBadge.razor` now maps `Closed` → `StatusState.Idle` (not `text-bg-secondary`); adds `Stale`, `Degraded` → Warn; adds `Active` → Ok; adds `Unavailable` → Bad. None of these new states are documented.
CLAIM_TYPE / behavior-rule
VERDICT / gap
EVIDENCE / Dashboard/Components/Shared/StatusBadge.razor:10–14
CODE_AREA / dashboard.theme
SEVERITY / medium
PROPOSED_FIX / Document the full current state-to-StatusState mapping including `Active`, `Stale`, `Degraded`, `Unavailable`.
---
DOC / gap
LINES / n/a
CLAIM / `ZB.MOM.WW.Theme 0.2.0` is a PackageReference and provides `ThemeShell`, `ThemeHead`, `ThemeScripts`, `NavRailSection`, `NavRailItem`, `StatusPill`, `LoginCard` components. This dependency is not mentioned in either dashboard doc.
CLAIM_TYPE / behavior-rule
VERDICT / gap
EVIDENCE / ZB.MOM.WW.MxGateway.Server.csproj (PackageReference ZB.MOM.WW.Theme Version=0.2.0); MainLayout.razor; App.razor; Login.razor
CODE_AREA / dashboard.theme
SEVERITY / high
PROPOSED_FIX / Add a "Theme Kit" section to GatewayDashboardDesign.md (and update DashboardInterfaceDesign.md) documenting the ZB.MOM.WW.Theme dependency, which components it provides, and that the kit owns the shell frame, nav rail, login card, status pill rendering, and base CSS tokens.
---
DOC / gap
LINES / n/a
CLAIM / `DashboardOptions` has a `CookieName` override property (`MxGateway:Dashboard:CookieName`) and a `RequireHttpsCookie` flag. Neither is mentioned in the Configuration section of GatewayDashboardDesign.md.
CLAIM_TYPE / config-key
VERDICT / gap
EVIDENCE / src/ZB.MOM.WW.MxGateway.Server/Configuration/DashboardOptions.cs; DashboardServiceCollectionExtensions.cs:87–97
CODE_AREA / dashboard.login
SEVERITY / medium
PROPOSED_FIX / Add `CookieName` and `RequireHttpsCookie` to the effective-configuration JSON block and the configuration section prose.
---
DOC / gap
LINES / n/a
CLAIM / `SessionsPage` and `WorkersPage` both render admin `Close`/`Kill` action buttons (with `ConfirmDialog`), not only `SessionDetailsPage` as the doc implies. The `ConfirmDialog` shared component (`Shared/ConfirmDialog.razor`) is not listed in the component tree.
CLAIM_TYPE / behavior-rule
VERDICT / gap
EVIDENCE / Dashboard/Components/Pages/SessionsPage.razor:31–37 (ConfirmDialog usage); Dashboard/Components/Shared/ConfirmDialog.razor (file exists)
CODE_AREA / dashboard.theme
SEVERITY / low
PROPOSED_FIX / Add `ConfirmDialog.razor` to the Shared/ component tree. Note admin controls appear on Sessions list and Workers list pages, not only SessionDetailsPage.
---
## Summary
| Verdict | Count |
|---------|-------|
| accurate | 2 |
| stale | 11 |
| wrong | 4 |
| unverifiable | 1 |
| gap | 6 |
| Severity | Count |
|----------|-------|
| high | 7 |
| medium | 9 |
| low | 8 |
## High-severity findings
- **Layout: no horizontal navbar** — Both docs describe a horizontal top navbar with `dashboard-shell`/`dashboard-navbar`/`container-fluid` classes. The actual layout is a `ZB.MOM.WW.Theme` `ThemeShell` side-rail with `NavRailSection`/`NavRailItem` components. The HTML skeleton in DashboardInterfaceDesign.md is obsolete.
- **Nav labels wrong** — DashboardInterfaceDesign.md lists five flat labels (Overview/Sessions/Workers/Events/Settings). Actual nav has eight items in three groups (Runtime, Galaxy, Admin) and the home link is labelled "Dashboard" not "Overview".
- **CSS tokens do not exist** — DashboardInterfaceDesign.md documents four `--mxgw-*` custom CSS properties. None exist in `site.css`; all colour resolves through ZB.MOM.WW.Theme kit tokens.
- **StatusBadge uses Bootstrap `text-bg-*` classes** — DashboardInterfaceDesign.md documents a Bootstrap badge mapping. `StatusBadge` now delegates to the kit's `StatusPill` with `StatusState` enum; no `text-bg-*` classes are used.
- **`dashboard.css` does not exist** — GatewayDashboardDesign.md refers to `wwwroot/css/dashboard.css` as the local stylesheet. The file is `wwwroot/css/site.css`.
- **Cookie name wrong** — GatewayDashboardDesign.md states cookie name `__Host-MxGatewayDashboard`. Actual default is `MxGatewayDashboard` (no `__Host-` prefix).
- **ZB.MOM.WW.Theme dependency undocumented** — Neither doc mentions the theme kit package, its components (`ThemeShell`, `LoginCard`, `StatusPill`, etc.) or its CSS token system. This is the single most architecturally significant post-migration gap.