52 KiB
Performance And Scalability Contract
Contract Metadata
{
"subsystem_id": "performance-and-scalability",
"lane": "L10",
"contract_file": "docs/release-control/v6/internal/subsystems/performance-and-scalability.md",
"status_file": "docs/release-control/v6/internal/status.json",
"registry_file": "docs/release-control/v6/internal/subsystems/registry.json",
"dependency_subsystem_ids": ["api-contracts", "frontend-primitives"]
}
Purpose
Own measurable performance budgets, query-plan guarantees, and hot-path regression protection.
Canonical Files
pkg/metrics/store.gopkg/metrics/store_query_plan_test.gopkg/metrics/store_slo_test.gointernal/api/slo.gointernal/api/slo_bench_test.gofrontend-modern/src/components/Dashboard/Dashboard.tsxfrontend-modern/src/components/Dashboard/DashboardStateCards.tsxfrontend-modern/src/components/Dashboard/DashboardStatsStrip.tsxfrontend-modern/src/components/Dashboard/DashboardWorkloadTable.tsxfrontend-modern/src/components/Dashboard/WorkloadPanel.tsxfrontend-modern/src/components/Dashboard/WorkloadTableHeader.tsxfrontend-modern/src/components/Dashboard/useDashboardState.tsfrontend-modern/src/components/Dashboard/useDashboardControlsState.tsfrontend-modern/src/components/Dashboard/useDashboardWorkloadDerivedState.tsfrontend-modern/src/components/Dashboard/useDashboardGuestMetadataState.tsfrontend-modern/src/components/Dashboard/useDashboardSelectionState.tsfrontend-modern/src/components/Dashboard/useDashboardWorkloadRouteState.tsfrontend-modern/src/components/Dashboard/useDashboardWorkloadUrlSync.tsfrontend-modern/src/components/Dashboard/DashboardFilter.tsxfrontend-modern/src/components/Dashboard/dashboardFilterModel.tsfrontend-modern/src/components/Dashboard/useDashboardFilterState.tsfrontend-modern/src/components/Dashboard/ThresholdSlider.tsxfrontend-modern/src/components/Dashboard/thresholdSliderModel.tsfrontend-modern/src/components/Dashboard/useThresholdSliderState.tsfrontend-modern/src/components/Dashboard/StackedDiskBar.tsxfrontend-modern/src/components/Dashboard/stackedDiskBarModel.tsfrontend-modern/src/components/Dashboard/useStackedDiskBarState.tsfrontend-modern/src/components/Dashboard/StackedMemoryBar.tsxfrontend-modern/src/components/Dashboard/stackedMemoryBarModel.tsfrontend-modern/src/components/Dashboard/useStackedMemoryBarState.tsfrontend-modern/src/components/Dashboard/MetricBar.tsxfrontend-modern/src/components/Dashboard/metricBarModel.tsfrontend-modern/src/components/Dashboard/useMetricBarState.tsfrontend-modern/src/components/Dashboard/EnhancedCPUBar.tsxfrontend-modern/src/components/Dashboard/enhancedCpuBarModel.tsfrontend-modern/src/components/Dashboard/useEnhancedCPUBarState.tsfrontend-modern/src/components/Dashboard/DiskList.tsxfrontend-modern/src/components/Dashboard/diskListModel.tsfrontend-modern/src/components/Dashboard/useDiskListState.tsfrontend-modern/src/components/Dashboard/GuestRow.tsxfrontend-modern/src/components/Dashboard/GuestRowCells.tsxfrontend-modern/src/components/Dashboard/guestRowModel.tsxfrontend-modern/src/components/Dashboard/useGuestRowState.tsfrontend-modern/src/components/Dashboard/GuestDrawer.tsxfrontend-modern/src/components/Dashboard/GuestDrawerOverview.tsxfrontend-modern/src/components/Dashboard/guestDrawerModel.tsfrontend-modern/src/components/Dashboard/useGuestDrawerState.tsfrontend-modern/src/components/Dashboard/useGroupedTableWindowing.tsfrontend-modern/src/components/Dashboard/workloadSelectors.tsfrontend-modern/src/components/Dashboard/workloadTopology.tsfrontend-modern/src/components/Dashboard/dashboardSelectionModel.tsfrontend-modern/src/components/Dashboard/dashboardWorkloadRouteModel.tsfrontend-modern/src/components/Dashboard/dashboardWorkloadFilterConfigModel.tsfrontend-modern/src/components/Dashboard/dashboardWorkloadRouteStateModel.tsfrontend-modern/src/components/Dashboard/dashboardWorkloadUrlSyncModel.tsfrontend-modern/src/components/Dashboard/useDashboardWorkloadFilterOptions.tsfrontend-modern/src/components/Dashboard/__tests__/dashboardSelectionModel.test.tsfrontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadFilterConfigModel.test.tsfrontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteModel.test.tsfrontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadRouteStateModel.test.tsfrontend-modern/src/components/Dashboard/__tests__/dashboardWorkloadUrlSyncModel.test.tsfrontend-modern/src/components/Dashboard/__tests__/workloadTopology.test.tsfrontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsxfrontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.tsfrontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.tsfrontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.tsfrontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsxfrontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsxfrontend-modern/src/components/Workloads/WorkloadsSummary.tsxfrontend-modern/src/utils/throughputPresentation.tsfrontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsxfrontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsxfrontend-modern/src/components/Infrastructure/unifiedResourceTableModel.tsfrontend-modern/src/components/Infrastructure/infrastructureSelectors.tsfrontend-modern/src/components/Infrastructure/resourceDetailMappers.tsfrontend-modern/src/components/Dashboard/__tests__/Dashboard.performance.contract.test.tsxfrontend-modern/src/components/Dashboard/__tests__/DashboardFilter.test.tsxfrontend-modern/src/components/Dashboard/__tests__/useDashboardFilterState.test.tsfrontend-modern/src/components/Dashboard/__tests__/useDashboardSelectionState.test.tsfrontend-modern/src/components/Dashboard/MetricBar.test.tsxfrontend-modern/src/components/Dashboard/__tests__/useMetricBarState.test.tsxfrontend-modern/src/components/Dashboard/__tests__/EnhancedCPUBar.test.tsxfrontend-modern/src/components/Dashboard/__tests__/useEnhancedCPUBarState.test.tsxfrontend-modern/src/components/Dashboard/ThresholdSlider.test.tsxfrontend-modern/src/components/Dashboard/__tests__/useThresholdSliderState.test.tsfrontend-modern/src/components/Dashboard/__tests__/StackedDiskBar.test.tsxfrontend-modern/src/components/Dashboard/__tests__/useStackedDiskBarState.test.tsxfrontend-modern/src/components/Dashboard/StackedMemoryBar.test.tsxfrontend-modern/src/components/Dashboard/__tests__/useStackedMemoryBarState.test.tsxfrontend-modern/src/components/Dashboard/__tests__/DiskList.test.tsxfrontend-modern/src/components/Dashboard/__tests__/GuestRow.test.tsxfrontend-modern/src/components/Dashboard/GuestDrawer.test.tsxfrontend-modern/src/components/Dashboard/__tests__/useGroupedTableWindowing.test.tsfrontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsxfrontend-modern/src/components/Dashboard/useDashboardWorkloadViewportSync.tsfrontend-modern/src/components/Dashboard/__tests__/useDashboardWorkloadViewportSync.test.tsxfrontend-modern/src/components/Infrastructure/InfrastructureSummary.tsxfrontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.tsfrontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts
Shared Boundaries
frontend-modern/src/components/Infrastructure/infrastructureSelectors.tsshared withunified-resources: the infrastructure selector pipeline is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsxshared withunified-resources: the infrastructure summary surface is both a canonical unified-resource consumer and a fleet-scale summary chart hot-path boundary.frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.tsshared withunified-resources: infrastructure summary chart matching, focused-summary view derivation, and metric-series shaping are both a canonical unified-resource consumer surface and a fleet-scale summary chart hot-path boundary.frontend-modern/src/components/Infrastructure/resourceDetailMappers.tsshared withunified-resources: resource detail mappers are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsxshared withunified-resources: the unified resource host table card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsxshared withunified-resources: the unified resource PBS section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsxshared withunified-resources: the unified resource PMG section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsxshared withunified-resources: the unified resource service infrastructure card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsxshared withunified-resources: the unified resource table is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.tsshared withunified-resources: unified resource service row shaping and I/O emphasis are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.tsshared withunified-resources: unified resource table state derivation, sort-cycle policy, service sorting, and responsive column layout are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.tsshared withunified-resources: infrastructure summary chart polling, cache hydration, and summary-state orchestration are both a canonical unified-resource consumer surface and a fleet-scale summary chart hot-path boundary.frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.tsshared withunified-resources: unified resource table state, grouping, and windowing are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.tsshared withunified-resources: unified resource table viewport sync and selected-row reveal are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.internal/api/slo.goshared withapi-contracts: the SLO endpoint is both an API contract surface and a protected performance hot-path boundary.
Extension Points
- Add performance budgets through SLO or contract tests
- Add query-plan guardrails for DB-backed hot paths
- Optimize hot paths only when backed by benchmarks or proven query issues
- Extend dashboard hot-path filter, sort, grouping, and stats math through
frontend-modern/src/components/Dashboard/workloadSelectors.ts, and extend workload identity, discovery routing, and node-topology helpers throughfrontend-modern/src/components/Dashboard/workloadTopology.ts, rather than duplicating selector or topology logic infrontend-modern/src/components/Dashboard/Dashboard.tsx - Normalize dashboard workload view-mode aliases through
frontend-modern/src/utils/workloads.tsinstead of keeping local URL/storage parsing infrontend-modern/src/components/Dashboard/Dashboard.tsx - Deduplicate dashboard workload rows by canonical workload ID from
frontend-modern/src/utils/workloads.tsrather than via local pass-through wrappers infrontend-modern/src/components/Dashboard/Dashboard.tsx - Render dashboard row identity directly from the shared canonical workload helper so row selection, hover, and fallback metadata lookup stay aligned with the same workload contract
- Format infrastructure sensor labels through the shared
frontend-modern/src/utils/textPresentation.tspresentation helper instead of maintaining a local title-casing implementation infrontend-modern/src/components/Infrastructure/resourceDetailMappers.ts - Extend dashboard row contract and per-row hot-path derivations through
frontend-modern/src/components/Dashboard/guestRowModel.tsxandfrontend-modern/src/components/Dashboard/useGuestRowState.ts, and extend tooltip-backed row cell presentation throughfrontend-modern/src/components/Dashboard/GuestRowCells.tsx, rather than rebuilding column metadata, row identity, cell tooltips, or anomaly correlation insidefrontend-modern/src/components/Dashboard/GuestRow.tsx - Extend dashboard drawer derivations and runtime wiring through
frontend-modern/src/components/Dashboard/guestDrawerModel.tsandfrontend-modern/src/components/Dashboard/useGuestDrawerState.ts, and extend drawer overview rendering throughfrontend-modern/src/components/Dashboard/GuestDrawerOverview.tsx, rather than rebuilding canonical guest identity, discovery routing, or drawer-local normalization insidefrontend-modern/src/components/Dashboard/GuestDrawer.tsx - Extend dashboard disk-list derivations and fallback runtime wiring through
frontend-modern/src/components/Dashboard/diskListModel.tsandfrontend-modern/src/components/Dashboard/useDiskListState.tsrather than rebuilding usage math, progress-state mapping, or tooltip fallback logic insidefrontend-modern/src/components/Dashboard/DiskList.tsx - Extend dashboard guest metadata cache persistence, metadata refresh, org-scope switching, and optimistic custom-URL updates through
frontend-modern/src/components/Dashboard/useDashboardGuestMetadataState.tsrather than rebuilding dashboard-local storage caches, event listeners, or guest metadata API wiring insidefrontend-modern/src/components/Dashboard/useDashboardState.ts - Extend dashboard deep-link selection and hovered-row continuity semantics through
frontend-modern/src/components/Dashboard/dashboardSelectionModel.ts, and extend table scroll preservation plus reactive selection state throughfrontend-modern/src/components/Dashboard/useDashboardSelectionState.ts, rather than rebuilding resource-query parsing, selected-row scroll pinning, or hovered-row invalidation insidefrontend-modern/src/components/Dashboard/useDashboardState.ts; canonical typed workload IDs such asapp-container:<host>:<provider-id>must remain exact route/selection keys and must not be reinterpreted into synthetic node scopes - Extend dashboard workload route ownership, route-driven option catalogs, and toolbar filter config through
frontend-modern/src/components/Dashboard/useDashboardWorkloadRouteState.ts,frontend-modern/src/components/Dashboard/useDashboardWorkloadFilterOptions.ts,frontend-modern/src/components/Dashboard/dashboardWorkloadRouteModel.ts,frontend-modern/src/components/Dashboard/dashboardWorkloadFilterConfigModel.ts, andfrontend-modern/src/components/Dashboard/dashboardWorkloadRouteStateModel.ts, and extend query-param synchronization plus managed workload URL semantics throughfrontend-modern/src/components/Dashboard/useDashboardWorkloadUrlSync.tsandfrontend-modern/src/components/Dashboard/dashboardWorkloadUrlSyncModel.ts, rather than rebuilding route sync, alias parsing, option derivation, toolbar callback/config wiring, reset policy, node-selection compatibility rules, param precedence, or managed workload URLs insidefrontend-modern/src/components/Dashboard/useDashboardState.ts - Extend grouped dashboard workload derivation, summary fallbacks, and grouped/windowed table presentation through
frontend-modern/src/components/Dashboard/useDashboardWorkloadDerivedState.ts, extend viewport-driven grouped table synchronization throughfrontend-modern/src/components/Dashboard/useDashboardWorkloadViewportSync.ts, and extend node parent mapping throughfrontend-modern/src/components/Dashboard/workloadTopology.ts, rather than rebuilding grouped selectors, summary snapshot math, scroll listeners, or topology lookups insidefrontend-modern/src/components/Dashboard/useDashboardState.ts - Extend dashboard control defaults, persistent view preferences, keyboard reset behavior, column-visibility ownership, and tag-search flow through
frontend-modern/src/components/Dashboard/useDashboardControlsState.tsandfrontend-modern/src/components/Dashboard/dashboardFilterModel.tsrather than rebuilding sort/search/grouping state, reset drift, or column-toggle plumbing insidefrontend-modern/src/components/Dashboard/useDashboardState.ts - Extend dashboard filter active-count, reset semantics, and mobile toolbar state through
frontend-modern/src/components/Dashboard/dashboardFilterModel.tsandfrontend-modern/src/components/Dashboard/useDashboardFilterState.ts, rather than rebuilding filter-local state insidefrontend-modern/src/components/Dashboard/DashboardFilter.tsx - Extend threshold-slider value-position math, title/label derivation, and drag scroll-lock runtime through
frontend-modern/src/components/Dashboard/thresholdSliderModel.tsandfrontend-modern/src/components/Dashboard/useThresholdSliderState.tsrather than rebuilding slider-local state and pointer lifecycle insidefrontend-modern/src/components/Dashboard/ThresholdSlider.tsx - Extend stacked disk-bar capacity math, segment/tooltip derivation, and resize-observer runtime through
frontend-modern/src/components/Dashboard/stackedDiskBarModel.tsandfrontend-modern/src/components/Dashboard/useStackedDiskBarState.tsrather than rebuilding disk-bar-local state, mode branching, and tooltip shaping insidefrontend-modern/src/components/Dashboard/StackedDiskBar.tsx - Extend stacked memory-bar capacity math, balloon/swap derivation, and resize-observer runtime through
frontend-modern/src/components/Dashboard/stackedMemoryBarModel.tsandfrontend-modern/src/components/Dashboard/useStackedMemoryBarState.tsrather than rebuilding memory-bar-local state, tooltip shaping, and label-fit logic insidefrontend-modern/src/components/Dashboard/StackedMemoryBar.tsx - Extend metric-bar width, label-fit logic, and resize-observer runtime through
frontend-modern/src/components/Dashboard/metricBarModel.tsandfrontend-modern/src/components/Dashboard/useMetricBarState.tsrather than rebuilding metric-local state and threshold mapping insidefrontend-modern/src/components/Dashboard/MetricBar.tsx - Extend enhanced CPU bar usage/anomaly presentation and tooltip runtime through
frontend-modern/src/components/Dashboard/enhancedCpuBarModel.tsandfrontend-modern/src/components/Dashboard/useEnhancedCPUBarState.tsrather than rebuilding tooltip-local state and CPU-threshold formatting insidefrontend-modern/src/components/Dashboard/EnhancedCPUBar.tsx - Extend grouped dashboard row windowing, reveal-index clamping, overscan math, and per-group visible-slice derivation through
frontend-modern/src/components/Dashboard/useGroupedTableWindowing.ts, and extend viewport event wiring throughfrontend-modern/src/components/Dashboard/useDashboardWorkloadViewportSync.tsrather than rebuilding scroll handlers, mounted-row budgets, viewport listeners, or group-slice math insidefrontend-modern/src/components/Dashboard/useDashboardWorkloadDerivedState.ts - Extend dashboard shell rendering through
frontend-modern/src/components/Dashboard/DashboardStateCards.tsx,frontend-modern/src/components/Dashboard/DashboardWorkloadTable.tsx, andfrontend-modern/src/components/Dashboard/DashboardStatsStrip.tsxrather than accreting loading cards, workload table markup, or stats-strip presentation back intofrontend-modern/src/components/Dashboard/Dashboard.tsx - Extend dashboard workload table shell ownership through
frontend-modern/src/components/Dashboard/WorkloadTableHeader.tsxandfrontend-modern/src/components/Dashboard/WorkloadPanel.tsxrather than rebuilding sortable header markup, grouped node rows, row expansion, or guest-drawer rendering insidefrontend-modern/src/components/Dashboard/DashboardWorkloadTable.tsx - Keep long-range workload chart capping time-proportional across
frontend-modern/src/components/Workloads/WorkloadsSummary.tsx,frontend-modern/src/api/charts.ts, andinternal/api/router.go: when the workload hot path caps mixed-cadence history for top cards, it must bucket by time window rather than raw point index so 7-day and 30-day workload cards stay visually even without relaxing the protected payload budget. - Keep summary hover/focus and sticky-card behavior on shared hot paths: infrastructure, workloads, and storage summary shells must reuse one focused-series model plus
frontend-modern/src/components/shared/StickySummarySection.tsxinside the app scroll shell instead of per-page scroll listeners or per-card hover derivations, so row scrubbing highlights all cards without multiplying render or scroll work. - Keep summary-card hover emphasis on one bounded rendering budget: when a summary row is active, shared sparkline and density-map primitives must promote the selected series and demote background series through the same active-series ID rather than layering a second page-local highlight pass, so zoom-range and hover scrubbing stay visually coherent without reintroducing multi-series overdraw on the hot summary cards. Density maps on that hot path must stay overview-first under focus: preserve the multi-entity heatmap rows, layer focused-entity detail inside the card, and avoid swapping transient hover into a separate single-series chart path.
Forbidden Paths
- Speculative micro-optimizations without evidence
- New N+1 data loading paths on dashboard/resource views
- Hot-path query changes without updating plan or SLO guardrails
Completion Obligations
- Update benchmarks, SLOs, or query-plan tests when hot-path behavior changes
- Update this contract when a new protected hot path is adopted
- Route runtime changes through the explicit performance proof policies in
registry.json; default fallback proof routing is not allowed - Record the evidence source for any claimed performance improvement
Current State
This lane already has strong evidence and guardrails, but it still trails on score because critical hot paths need more complete protection and verification.
All governed performance-owned runtime files now require explicit registry path-policy coverage, so new protected hot paths must be mapped to a concrete proof route instead of falling back to subsystem-default verification.
The dashboard workload selector path and the dashboard runtime that consumes it
are now part of the protected performance surface rather than proof-only
context. Future hot-path filter/group/sort/windowing changes must route through
the explicit dashboard performance proof policy in the subsystem registry.
That same hot-path ownership now covers top-of-page summary emphasis: infrastructure
and workloads summary cards must treat row hover, chart hover, and route focus
as one shared active-series contract so time-range switches, row scrubbing, and
chart cross-highlighting reuse one existing chart path instead of repainting
page-local “selected row” overlays on top of already downsampled summary
history. Hovering a sparkline or density map for one entity must promote that
entity into the shared active series so sibling cards highlight the same object
at once rather than maintaining chart-local hover state, and the synchronized
hover timestamp must remain visible across those sibling cards even when the
active entity has no samples for one metric in the current range.
For shared line charts on that hot path, the shared sparkline primitive may
isolate the selected series inside the existing render budget, but that
isolation must still reuse the same summary series set and timeline data rather
than triggering a second page-local chart recomputation.
That same hot-path rule now covers contextual row focus on those pages.
frontend-modern/src/components/Dashboard/useDashboardSelectionState.ts must
write workload selection back into the workloads route through the shared
same-path route-state scheduler so opening a focused workload preserves scroll
and does not look like a full page reload, and the governed infrastructure and
workloads summary surfaces must keep the summary page-scoped while that focus
reuses the shared highlight contract; density maps may retain page-level
context, but they must now also surface focused-entity detail inside the same
card instead of dimming the rest of the map into unusable background noise or
swapping the hot path into a transient single-series chart. Line-card
isolation must still flow through the shared sparkline runtime instead of a
page-local focus overlay.
That same hot-path rule now has one shared runtime boundary. Interactive-series
filtering, active-series derivation, focused-label lookup, and local
scroll-preserving row focus must extend
frontend-modern/src/components/shared/contextualFocus.ts instead of
rebuilding page-local Set scans or scroll repair logic in dashboard,
infrastructure, or workloads hot paths.
That same hot-path rule now applies to infrastructure summary resource
filtering: frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts
must include API-backed systems such as top-level TrueNAS appliances through
the shared isAgentFacetInfrastructureResource(...) helper instead of a local
resource.type branch, so the summary poll/cache path stays on one canonical
infrastructure selector contract.
That same dashboard shell boundary also owns empty-state action routing in
frontend-modern/src/components/Dashboard/DashboardStateCards.tsx. When the
dashboard has no connected infrastructure, the CTA must hand operators
directly to the canonical infrastructure install route via
buildInfrastructureWorkspacePath('install') instead of bouncing through a
generic settings landing page.
That workload route now also treats readiness as a route-owned contract instead
of a raw websocket proxy signal: frontend-modern/src/components/Dashboard/Dashboard.tsx
and frontend-modern/src/components/Dashboard/useDashboardState.ts must keep
filters, stats, and table visibility driven by the workload route's own
REST-backed health so websocket churn does not hide already-fetched workloads
or swap the protected hot path into a false disconnected shell.
The same performance ownership now applies to the downsampled
pkg/metrics/store.go batched query path. QueryAllBatch may drop the global
SQLite ORDER BY resource_id, metric_type, bucket_ts sort from the grouped
query only if the runtime preserves ascending timestamps plus correct
avg/min/max bucket aggregates within every returned resource/metric series, and
the hot-path proof keeps latency, ordering, and aggregate correctness guarded
together in the explicit metrics SLO surface. That protected surface should
That same workload-summary hot path now also owns chart-cache invalidation
whenever the shaped timeline contract changes. frontend-modern/src/components/Workloads/WorkloadsSummary.tsx
must version-bust cached summary payloads in the same slice that changes
workload chart bucket semantics or timestamp precision, so operators are not
served stale mixed-cadence chart shapes after the backend timeline model has
already been corrected.
stay on one ordered index scan plus Go-side bucket aggregation rather than
forcing SQLite to GROUP BY computed buckets through a temp B-tree on the
fleet-scale dashboard path.
That runtime is now intentionally split by concern:
frontend-modern/src/components/Dashboard/useDashboardState.ts owns
top-level dashboard orchestration, workload loading, and composition across
the canonical dashboard owners, while
frontend-modern/src/components/Dashboard/useDashboardControlsState.ts
owns persistent control defaults, keyboard-reset semantics, sort/search/tag
behavior, column visibility, and summary display preferences, while
frontend-modern/src/components/Dashboard/useDashboardWorkloadDerivedState.ts
owns grouped workload derivation, summary fallbacks, parent-node mapping,
and grouped/windowed table math, while
frontend-modern/src/components/Dashboard/useDashboardWorkloadViewportSync.ts
owns grouped workload viewport synchronization and the scroll/resize listener
lifecycle, while
frontend-modern/src/components/Dashboard/useDashboardGuestMetadataState.ts
owns guest metadata cache persistence, optimistic custom-URL updates,
org-scope switching, and metadata refresh, and
frontend-modern/src/components/Dashboard/useDashboardWorkloadRouteState.ts
owns workload-route synchronization, deep-link normalization, and route-scoped
filter contracts. Future dashboard hot-path changes must extend through those
owners instead of accreting back into frontend-modern/src/components/Dashboard/Dashboard.tsx.
That same route-owned filter contract now also includes canonical workload
platform scoping for API-backed runtimes. Dashboard URL-sync, filter-option
assembly, and workload drill-down routes must preserve
platform=<owned-source-key> for surfaces such as TrueNAS app-containers,
while treating host or cluster identity as secondary scope instead of
collapsing those routes back to generic agent-only semantics. The derived
workload hot path must also tolerate transient async route/data gaps by
treating missing filtered-workload collections as empty until the route and
resource snapshots converge, rather than crashing the dashboard between sync
phases.
That same workload hot path also owns the split between canonical
app-container routing and Docker-only actions. frontend-modern/src/hooks/useWorkloads.ts,
frontend-modern/src/components/Dashboard/workloadTopology.ts, and
frontend-modern/src/components/Dashboard/useGuestRowState.ts must preserve a
canonical app-container navigation path while keeping Docker runtime action
identifiers explicit. Discovery affordances on the dashboard drawer must follow
the canonical discoveryTarget contract, not generic app-container host
fallbacks. TrueNAS app-containers may reuse runtime metadata such as image and
runtime strings, but they must not inherit Docker-only update affordances or
agent-only Discovery tabs on the dashboard row path unless the unified
resource contract explicitly supplies discovery ownership.
That same row-and-selection boundary also requires canonical app-container
identity to stay intact on the workload surface. /workloads rows, deep links,
drawer selection, anomaly correlation, and route-owned filters must key on the
unified resource ID such as app-container:truenas-main:nextcloud, while
Docker-native runtime IDs stay in a separate action-only field for Docker
controls like image updates. Performance work must not collapse API-backed
platforms back onto runtime-native container IDs or derive fake node scopes
from typed canonical resource IDs.
That same summary hot path must also keep workload hover identity canonical
across provider-backed history. Row hover and focus plus top-card isolation on
/workloads must resolve against the same canonical workload ID even when the
backing history is stored under a provider metrics target, so provider-backed
VM rows do not silently drop out of summary emphasis.
The shared infrastructure table hot path now also treats operator-facing
resource identity as a protected boundary: sorting, searching, summary-series
matching, and row titles on the infrastructure page must use the canonical
local instance identity rather than governed AI-summary text, so performance
work cannot “optimize” the table into ambiguous labels that collapse multiple
resources into the same visible name.
That derived workload owner now also routes grouped row windowing through
frontend-modern/src/components/Dashboard/useGroupedTableWindowing.ts, which
owns row-window thresholds, overscan behavior, reveal-index clamping, and
per-group visible-slice derivation. Future dashboard table windowing changes
must extend through that hook instead of rebuilding scroll math or mounted-row
budgets inline inside frontend-modern/src/components/Dashboard/useDashboardWorkloadDerivedState.ts.
Viewport-driven grouped table synchronization now also routes through
frontend-modern/src/components/Dashboard/useDashboardWorkloadViewportSync.ts,
which owns the dashboard table body measurement and the scroll/resize listener
lifecycle. Future viewport sync changes must extend through that hook rather
than rebuilding browser-event wiring or table-body geometry reads inside
frontend-modern/src/components/Dashboard/useDashboardWorkloadDerivedState.ts.
The dashboard guest-row path now follows the same pattern: the render shell
stays in frontend-modern/src/components/Dashboard/GuestRow.tsx, tooltip-backed
cell presentation lives in frontend-modern/src/components/Dashboard/GuestRowCells.tsx,
and the canonical row contract and per-row hot-path derivations live in
frontend-modern/src/components/Dashboard/guestRowModel.tsx and
frontend-modern/src/components/Dashboard/useGuestRowState.ts. Future row
identity, column, cell-tooltip, anomaly-correlation, and link-state changes
must extend through those owners instead of rebuilding row-local state inside
the shell.
That per-row link state now also consumes the shared
frontend-modern/src/routing/resourceLinks.ts workload-to-infrastructure
helper instead of a dashboard-local routing shim. Future infrastructure-link
changes for dashboard rows must extend through the shared routing owner rather
than recreating feature-local path builders.
That shell now also routes tag-dot rendering through the shared
frontend-modern/src/components/shared/TagBadges.tsx primitive instead of
keeping a dashboard-local badge helper. Future guest-row tag presentation
changes must extend through that shared owner rather than reintroducing a
dashboard-only tag-badge variant.
The dashboard guest drawer now follows that same ownership rule: the shell
stays in frontend-modern/src/components/Dashboard/GuestDrawer.tsx, the
overview card surface lives in
frontend-modern/src/components/Dashboard/GuestDrawerOverview.tsx, and
drawer-local normalization, backup/tag formatting, discovery identity wiring,
and workload-derived navigation state live in
frontend-modern/src/components/Dashboard/guestDrawerModel.ts and
frontend-modern/src/components/Dashboard/useGuestDrawerState.ts. Future
drawer runtime and overview-surface changes must extend through those owners
instead of adding more mixed state and helper drift back into the shell.
That drawer state now also consumes the same shared
frontend-modern/src/routing/resourceLinks.ts workload-to-infrastructure
helper, so row and drawer navigation stay aligned without a second
dashboard-local link-mapping file.
The shared infrastructure mapper hot path now stays intentionally narrow:
frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts
continues to own sensor-label presentation and hot-path host/agent projection,
while canonical drawer discovery-target derivation now lives in
frontend-modern/src/components/Infrastructure/resourceDetailDiscoveryModel.ts
under unified-resources. Future discovery-config or target-resolution
changes must extend through that unified-resource owner instead of
re-accumulating discovery heuristics back into the performance hot-path mapper.
The dashboard disk list now follows the same pattern: the shell stays in
frontend-modern/src/components/Dashboard/DiskList.tsx, while disk-row
presentation derivations and fallback tooltip/runtime wiring live in
frontend-modern/src/components/Dashboard/diskListModel.ts and
frontend-modern/src/components/Dashboard/useDiskListState.ts. Future disk
usage math, threshold-color routing, and fallback handling must extend
through those owners instead of accreting back into the shell.
The dashboard filter now follows that same ownership rule: the shell
stays in frontend-modern/src/components/Dashboard/DashboardFilter.tsx, while
toolbar defaults, active-filter counting, and reset semantics live in
frontend-modern/src/components/Dashboard/dashboardFilterModel.ts and
frontend-modern/src/components/Dashboard/useDashboardFilterState.ts.
The dashboard-owned filter-config assembly now lives in
frontend-modern/src/components/Dashboard/useDashboardState.ts, so future
filter runtime changes must extend through those owners instead of
reintroducing dashboard-local state, reset drift, or inline config assembly
into the shell.
The dashboard threshold slider now follows that same pattern: the shell stays
in frontend-modern/src/components/Dashboard/ThresholdSlider.tsx, while
metric-type text and fill presentation live in
frontend-modern/src/utils/thresholdSliderPresentation.ts, while
slider bounds math, thumb-position transforms, and title/label derivations
live in frontend-modern/src/components/Dashboard/thresholdSliderModel.ts
and drag scroll-lock lifecycle lives in
frontend-modern/src/components/Dashboard/useThresholdSliderState.ts.
Future slider runtime changes must extend through those owners instead of
reintroducing mixed drag state, type-color formatting, and presentation logic
into the shell.
The dashboard stacked disk bar now follows that same pattern: the shell stays
in frontend-modern/src/components/Dashboard/StackedDiskBar.tsx, while
disk-capacity math, segment and tooltip derivation, max-disk labeling, and
mode-specific presentation live in
frontend-modern/src/components/Dashboard/stackedDiskBarModel.ts and
resize-observer plus tooltip lifecycle live in
frontend-modern/src/components/Dashboard/useStackedDiskBarState.ts.
Future disk-bar runtime changes must extend through those owners instead of
reintroducing mixed resize state and presentation branching into the shell.
The dashboard stacked memory bar now follows that same pattern: the shell
stays in frontend-modern/src/components/Dashboard/StackedMemoryBar.tsx,
while memory-capacity math, balloon/swap tooltip derivation, anomaly label
presentation, and sublabel-fit logic live in
frontend-modern/src/components/Dashboard/stackedMemoryBarModel.ts and
resize-observer plus tooltip lifecycle live in
frontend-modern/src/components/Dashboard/useStackedMemoryBarState.ts.
Future memory-bar runtime changes must extend through those owners instead of
reintroducing mixed resize state, balloon branching, and tooltip shaping into
the shell.
The dashboard metric bar now follows that same pattern: the shell stays in
frontend-modern/src/components/Dashboard/MetricBar.tsx, while width,
show-label, sublabel-fit, and threshold-color derivation live in
frontend-modern/src/components/Dashboard/metricBarModel.ts and
resize-observer lifecycle lives in
frontend-modern/src/components/Dashboard/useMetricBarState.ts. Future
metric-bar runtime changes must extend through those owners instead of
reintroducing mixed resize state and label-fit logic into the shell.
The dashboard enhanced CPU bar now follows that same pattern: the shell stays
in frontend-modern/src/components/Dashboard/EnhancedCPUBar.tsx, while usage
formatting, anomaly presentation, tooltip load-average formatting, and
threshold-driven label state live in
frontend-modern/src/components/Dashboard/enhancedCpuBarModel.ts and
tooltip lifecycle lives in
frontend-modern/src/components/Dashboard/useEnhancedCPUBarState.ts. Future
CPU-bar runtime changes must extend through those owners instead of
reintroducing mixed tooltip state and formatting logic into the shell.
The unified resource table hot path is now also governed as explicit
performance-owned runtime, with shared ownership against the unified-resource
consumer boundary. The remaining performance work is no longer top-level
ownership ambiguity on the main dashboard or infrastructure tables.
The table's reactive runtime, grouping, and row-windowing owner now lives in
frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts,
while pure table-state derivation, service sorting, sort-cycle policy, and
responsive column layout now live in
frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts,
and viewport-sync plus selected-row reveal behavior now live in
frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts,
so future hot-path table-state changes must not fold selector derivation,
layout policy, and scroll coordination back into one mixed owner or the render
shell.
That hot-path contract now includes policy badge rendering on resource rows.
The infrastructure summary hot path is now explicit shared ownership too:
InfrastructureSummary.tsx stays a render shell,
useInfrastructureSummaryState.ts owns chart polling and cache lifecycle, and
infrastructureSummaryModel.ts owns chart matching, focused-summary display
selection, empty-state wording, and summary-series/metric derivation. Future
summary-chart work must not put polling, cache hydration, and series math
back into the shell.
The summary API feeding that hot path must also normalize mixed-resolution
history into equal-time summary buckets before it reaches the shell/runtime
owners, so long-range cards do not bunch recent higher-resolution samples at
the right edge.
It now also includes the compact resource-facet summary chips rendered next
to policy metadata, and those chips must stay within the same bounded
windowing and mounted-row budget proved by
UnifiedResourceTable.performance.contract.test.tsx.
The same facet summary contract applies to the service-resource rows inside
the unified table as well, so PBS and PMG entries must keep the same bounded
presentation and verification surface as the primary fleet rows. The shared
ResourceFacetSummary component now owns that chip rendering path, so any
future summary changes must preserve the same bounded row budget instead of
forking separate table-only presentation logic. That component now also
consumes the shared frontend-modern/src/utils/resourceChangePresentation.ts
label helper for canonical change kinds, source types, and adapter provenance
so the chip wording stays consistent without adding extra hot-path branching.
The default table hot path now scopes those summary chips to timeline and
change-provenance badges only. Generic capability and relationship badges are
removed from the default row surface entirely until the underlying data is
proven populated, which preserves the fleet-table scan path and avoids
spending hot-path visual budget on model nouns that do not yet clear the
product bar.
Row summaries now also prefer canonical facetCounts on each resource when
they are available, so the hot path can stay within the same budget while
still reading totals from the shared resource contract. The drawer history
surface reuses the same governed resource route helpers for relationship and
related-resource links, so cross-resource navigation stays within the existing
infrastructure surface rather than branching into custom detail-only routing.
The detail drawer now follows the same default posture by collapsing its
history overview down to timeline counts and timeline-summary chips, so the
performance-sensitive shared presentation path stays aligned with the
investigation-first product contract instead of rendering low-signal generic
facet sections by default.
Governance metadata such as sensitivity and routing scope may be visible in
the table, but it must remain on the same bounded row-windowing and mounted-row
budget proved by UnifiedResourceTable.performance.contract.test.tsx rather
than creating a separate unbounded rendering path for policy-rich fleets.
The shared table and detail drawer now also render governed resource labels
through the shared identity/display contract, which routes policy-aware
resources through the canonical policy-aware helper and suppresses the raw
alternate name when policy requires governed handling. That keeps the
policy-aware label path inside the same hot-row rendering budget instead of
adding a second display branch for redacted fleets, and the proof for that
behavior lives in UnifiedResourceTable.performance.contract.test.tsx.
The shared table now also passes the same canonical resource-label resolver
into the detail drawer so related-resource chips in the timeline/history path
can resolve through the canonical catalog without adding a separate
detail-only lookup branch to the hot-row path.
The same detail drawer also uses that resolver for correlation dependency and
dependent chips, so the investigation path does not fall back to raw IDs in
the drawer while the AI page keeps its broader no-catalog fallback.
The shared infrastructure selector search path now also routes through that
same preferred resource display contract, so governed resources do not
reappear via raw-name search candidates while the selector stays on the same
hot-path budget.
The shared workloads-link helper used by the resource drawer and table now
also routes its Kubernetes-cluster fallback through the same preferred
resource display contract, so navigation context does not leak raw
displayName values for governed clusters.
That same workloads-link path and the dashboard workload projection now also
share the canonical cluster-name helpers in the shared agent-resource layer,
so route labels, pod grouping, and cluster-name fetch keys keep using the
same source of truth instead of rebuilding the clusterName/context/
clusterId prefix locally.
The infrastructure host-table hot path now also suppresses the default
Internal + Cloud Summary policy pair in row chrome. That baseline posture
still belongs to the canonical policy contract, but repeating it on every host
burns row-density budget without adding operator-grade signal.
The shared node adapter also uses that same cluster-name helper for the
infrastructure summary surface, so Proxmox node projections stay aligned with
the same canonical cluster label instead of carrying a raw adapter-local
cluster string.
The drawer's Kubernetes namespace/deployment tabs use the canonical
cluster-name helper for fetch keys, so the visible navigation label stays
separate from the backend cluster lookup contract.
The workloads projection in useWorkloads also uses that same helper for pod
context labels, keeping the dashboard's Kubernetes grouping aligned with the
same canonical cluster-name boundary.
The drawer's discovery mapper also reuses that helper for pod fallback agent
IDs, so the resource-detail hot path and the dashboard selector path stay
aligned on the same cluster-name source of truth.
The unified-resource projection also uses that same helper for Kubernetes
clusterId, so the shared store, dashboard grouping, and detail-navigation
surfaces all see the same cluster-context prefix before any surface-specific
fallback applies.
The aggregate /api/charts/workloads-summary endpoint now also has its own
explicit API p95 budget constant, aligned with the per-workload charts budget,
and internal/api/slo_bench_test.go must fail if that aggregate budget or its
store-backed mixed-workload benchmark coverage drifts.
The infrastructure and workload summary cards now share a canonical
throughput-rate formatter in frontend-modern/src/utils/throughputPresentation.ts,
so bytes-per-second labels stay consistent between the two summary surfaces
instead of each component carrying its own rate string builder.
That shared throughput boundary is now also explicitly governed here.
frontend-modern/src/components/Workloads/WorkloadsSummary.tsx is the
canonical workload-summary hot-path surface, and
frontend-modern/src/utils/throughputPresentation.ts is the canonical
bytes-per-second formatter shared by workload and infrastructure summary
cards. Future throughput wording or workload-summary hot-path changes must
extend these performance-owned surfaces instead of leaving the formatter or
summary shell unowned in registry coverage.
Infrastructure selector status ordering must now tolerate arbitrary filter-set strings without widening the canonical hot-path order tuple. Unknown statuses must sort after the governed status order instead of forcing the selector path to abandon the typed canonical order used by the infrastructure table and its performance proof surface.
The Infrastructure page now also normalizes source filter keys through the
shared frontend-modern/src/utils/sourcePlatforms.ts helper directly, so the
selector boundary keeps using the canonical source-platform contract instead of
maintaining a local source-normalization alias.
Resource detail mappers now also use the shared
frontend-modern/src/utils/textPresentation.ts title-case helper for sensor
labels, so the canonical presentation layer owns that wording instead of the
mapper carrying its own title-casing branch.
Dashboard, workload-summary, infrastructure-summary, and org-scoped cache-key
paths now normalize org scope through the shared
frontend-modern/src/utils/orgScope.ts helper instead of each file carrying
its own getOrgID() || 'default' fallback. That keeps cache isolation and
multi-tenant row-scoping aligned across the dashboard and resource-summary hot
paths.
GitHub-hosted runner proof for the API performance surface now intentionally uses a looser budget envelope than local/staging benchmark runs for the mixed-endpoint load test and the infrastructure/workload chart p95 checks. Those CI targets remain regression guardrails, but they are calibrated to the observed contention and CPU variability of the public release workflow rather than to workstation-class latency.
The metrics store write boundary now fails closed on malformed samples. Empty
resource identifiers, empty metric names, unsupported tiers, and legacy
resource-type writes must be dropped before they reach SQLite so the governed
hot-path query surface cannot silently accumulate unqueryable garbage rows that
inflate store size and distort downstream performance evidence.
Canonical metrics resource types now also normalize case at the store boundary.
agent, vm, and other governed resource-type keys must not drift into
uppercase or mixed-case variants that write successfully but fragment the
metrics hot path into effectively separate query spaces.
The query boundary must use the same canonicalization rules. Resource
identifiers and metric names passed back into Query, QueryAll, and
QueryAllBatch must be normalized the same way writes are, so whitespace- or
case-polluted callers cannot manufacture false "missing metrics" results,
split one governed metric stream into mixed-case query buckets, or trigger
redundant batch work against otherwise valid stored samples.
That same metrics-store boundary also owns the persistent DB file path. The
runtime must normalize the owned metrics directory and resolve the selected DB
filename through the shared storage-path helper before it creates directories
or opens SQLite, instead of trusting raw caller-built paths.
That same metrics hot path must also keep startup maintenance off the
constructor critical path. NewStore may initialize schema and return a usable
store, but restart-time retention cleanup and one-time auto-vacuum migration
must run through the background worker so large historical databases do not
block application startup before the metrics store is even available.