Files
pulse/frontend-modern/scripts/shared-template-registry.json
T
2026-06-12 15:07:50 +01:00

840 lines
36 KiB
JSON

{
"version": 1,
"rules": [
{
"id": "runtime-web-interface-name-link",
"category": "resource-launch",
"summary": "Runtime resource rows must launch saved or inferred web-interface URLs through the shared name-link template, not a page-local link or separate web column.",
"canonical": {
"path": "src/components/shared/WebInterfaceNameLink.tsx",
"export": "WebInterfaceNameLink"
},
"requiredConsumers": [
{
"path": "src/components/shared/NodeGroupHeader.tsx"
},
{
"path": "src/components/Workloads/GuestRow.tsx"
},
{
"path": "src/features/standalone/AgentsMachinesTable.tsx"
},
{
"path": "src/features/proxmox/ProxmoxNodesTable.tsx"
}
],
"forbiddenPatterns": [
{
"path": "src/components/Workloads/GuestRow.tsx",
"patterns": ["target=\"_blank\"", "rel=\"noopener noreferrer\""]
},
{
"path": "src/components/shared/NodeGroupHeader.tsx",
"patterns": ["target=\"_blank\"", "rel=\"noopener noreferrer\""]
},
{
"path": "src/features/standalone/AgentsMachinesTable.tsx",
"patterns": [
"target=\"_blank\"",
"rel=\"noopener noreferrer\"",
"AgentMachineWebLinkCell",
"data-agent-machine-web-link"
]
},
{
"path": "src/features/standalone/agentMachineTableModel.ts",
"patterns": ["id: 'web'", "label: 'Web'"]
},
{
"path": "src/features/proxmox/ProxmoxNodesTable.tsx",
"patterns": [
"target=\"_blank\"",
"rel=\"noopener noreferrer\"",
"data-proxmox-host-web-link"
]
},
{
"path": "src/features/proxmox/proxmoxHostTableModel.ts",
"patterns": ["id: 'web'", "label: 'Web'"]
}
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/__tests__/NodeGroupHeader.test.tsx",
"src/features/standalone/__tests__/AgentsMachinesTable.test.tsx",
"src/components/Workloads/__tests__/GuestRow.test.tsx",
"src/features/proxmox/__tests__/ProxmoxNodesTable.test.tsx",
"src/features/proxmox/__tests__/proxmoxHostTableModel.test.ts"
]
},
{
"id": "inline-detail-table-row-shell",
"category": "row-detail",
"summary": "Platform, workload, and infrastructure inline detail rows must compose the shared row/cell/content shell instead of recreating page-local surface-alt drawer rows.",
"canonical": {
"path": "src/components/shared/InlineDetailTableRow.tsx",
"export": "InlineDetailTableRow"
},
"requiredConsumers": [
{ "path": "src/components/Infrastructure/UnifiedResourceHostTableCard.tsx" },
{ "path": "src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx" },
{ "path": "src/components/Infrastructure/UnifiedResourcePMGTableSection.tsx" },
{ "path": "src/components/Workloads/WorkloadPanel.tsx" },
{ "path": "src/features/docker/DockerAlertsTable.tsx" },
{ "path": "src/features/docker/DockerHostsTable.tsx" },
{ "path": "src/features/docker/DockerNetworksTable.tsx" },
{ "path": "src/features/kubernetes/KubernetesAlertsTable.tsx" },
{ "path": "src/features/platformPage/PlatformResourceDetailTableRow.tsx" },
{ "path": "src/features/proxmox/ProxmoxCephTable.tsx" },
{ "path": "src/features/proxmox/ProxmoxCoverageTable.tsx" },
{ "path": "src/features/proxmox/ProxmoxMailGatewayTable.tsx" },
{ "path": "src/features/proxmox/ProxmoxNodesTable.tsx" },
{ "path": "src/features/truenas/TrueNASAlertsTable.tsx" },
{ "path": "src/features/truenas/TrueNASProtectionTable.tsx" },
{ "path": "src/features/truenas/TrueNASServicesTable.tsx" },
{ "path": "src/features/vmware/VsphereActivityTable.tsx" },
{ "path": "src/features/vmware/VsphereAlertsTable.tsx" }
],
"forbiddenPatterns": [
{
"path": "src/components/Workloads/WorkloadPanel.tsx",
"patterns": [
"p-0 border-b border-border bg-surface-alt",
"border-b border-border bg-surface-alt p-0"
]
},
{
"path": "src/features/platformPage/PlatformResourceDetailTableRow.tsx",
"patterns": ["border-b border-border bg-surface-alt p-0"]
}
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/__tests__/InlineDetailTableRow.test.tsx",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "table-card-frame-shell",
"category": "table-card",
"summary": "Product table surfaces must compose TableCard for the shared card frame instead of recreating local overflow-hidden bordered table wrappers.",
"canonical": {
"path": "src/components/shared/TableCard.tsx",
"export": "TableCard"
},
"requiredConsumers": [
{ "path": "src/components/Infrastructure/UnifiedResourceHostTableCard.tsx" },
{ "path": "src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx" },
{ "path": "src/components/Storage/StorageContentCard.tsx" },
{ "path": "src/components/Workloads/WorkloadsSurface.tsx" },
{ "path": "src/components/Workloads/WorkloadsTable.tsx" },
{ "path": "src/features/alerts/AlertHistoryTableSection.tsx" },
{ "path": "src/features/platformPage/sharedPlatformPage.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "table-card-header-shell",
"category": "table-card",
"summary": "Table-card headers must compose TableCardHeader for title/action/clear chrome instead of recreating local summary-table header aliases.",
"canonical": {
"path": "src/components/shared/TableCardHeader.tsx",
"export": "TableCardHeader"
},
"requiredConsumers": [
{ "path": "src/components/Infrastructure/UnifiedResourceHostTableCard.tsx" },
{ "path": "src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx" },
{ "path": "src/components/Storage/StorageContentCard.tsx" },
{ "path": "src/features/platformPage/sharedPlatformPage.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "platform-table-loading-state",
"category": "platform-table-loading-state",
"summary": "Platform page and table loading states must compose PlatformTableLoadingState instead of recreating local TableCard status rows.",
"canonical": {
"path": "src/features/platformPage/sharedPlatformPage.tsx",
"export": "PlatformTableLoadingState"
},
"requiredConsumers": [
{ "path": "src/features/docker/DockerPageSurface.tsx" },
{ "path": "src/features/kubernetes/KubernetesPageSurface.tsx" },
{ "path": "src/features/proxmox/ProxmoxBackupsTable.tsx" },
{ "path": "src/features/proxmox/ProxmoxPageSurface.tsx" },
{ "path": "src/features/proxmox/ProxmoxReplicationTable.tsx" },
{ "path": "src/features/standalone/StandalonePageSurface.tsx" },
{ "path": "src/features/truenas/TrueNASPageSurface.tsx" },
{ "path": "src/features/truenas/TrueNASProtectionTable.tsx" },
{ "path": "src/features/vmware/VmwarePageSurface.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "platform-error-state",
"category": "platform-error-state",
"summary": "Platform page and table load failures must compose PlatformErrorState instead of recreating a local EmptyState plus Refresh action.",
"canonical": {
"path": "src/features/platformPage/sharedPlatformPage.tsx",
"export": "PlatformErrorState"
},
"requiredConsumers": [
{ "path": "src/features/docker/DockerPageSurface.tsx" },
{ "path": "src/features/kubernetes/KubernetesPageSurface.tsx" },
{ "path": "src/features/proxmox/ProxmoxBackupsTable.tsx" },
{ "path": "src/features/proxmox/ProxmoxPageSurface.tsx" },
{ "path": "src/features/proxmox/ProxmoxReplicationTable.tsx" },
{ "path": "src/features/standalone/StandalonePageSurface.tsx" },
{ "path": "src/features/truenas/TrueNASPageSurface.tsx" },
{ "path": "src/features/truenas/TrueNASProtectionTable.tsx" },
{ "path": "src/features/vmware/VmwarePageSurface.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "platform-section-tabs",
"category": "platform-section-tabs",
"summary": "Platform page workflow tabs must compose PlatformSectionTabs instead of recreating page-local nav tab bars.",
"canonical": {
"path": "src/features/platformPage/sharedPlatformPage.tsx",
"export": "PlatformSectionTabs"
},
"requiredConsumers": [
{ "path": "src/features/docker/DockerPageSurface.tsx" },
{ "path": "src/features/kubernetes/KubernetesPageSurface.tsx" },
{ "path": "src/features/proxmox/ProxmoxPageSurface.tsx" },
{ "path": "src/features/standalone/StandalonePageSurface.tsx" },
{ "path": "src/features/truenas/TrueNASPageSurface.tsx" },
{ "path": "src/features/vmware/VmwarePageSurface.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "filter-bar-catalog-shell",
"category": "filter-bar",
"summary": "Resource-list filter surfaces must compose the shared FilterBar catalog shell instead of recreating page-local filter rows or legacy PageControls decks.",
"canonical": {
"path": "src/components/shared/FilterBar/FilterBar.tsx",
"export": "FilterBar"
},
"requiredConsumers": [
{ "path": "src/components/Alerts/ThresholdsTable.tsx" },
{ "path": "src/components/Settings/AuditLogPanel.tsx" },
{ "path": "src/components/Storage/StoragePageControls.tsx" },
{ "path": "src/components/Workloads/WorkloadsFilter.tsx" },
{ "path": "src/features/alerts/AlertHistoryFiltersCard.tsx" },
{ "path": "src/features/platformPage/sharedPlatformPage.tsx" },
{ "path": "src/features/proxmox/ProxmoxBackupsTable.tsx" }
],
"forbiddenPatterns": [
{
"path": "src/components/Storage/StoragePageControls.tsx",
"patterns": [
"from '@/components/shared/PageControls'",
"<PageControls",
"<StorageControls",
"<StorageFilter",
"LabeledFilterSelect",
"FilterSegmentedControl"
]
},
{
"path": "src/components/Workloads/WorkloadsFilter.tsx",
"patterns": [
"from '@/components/shared/PageControls'",
"<PageControls",
"LabeledFilterSelect",
"LabeledFilterToggleGroup"
]
},
{
"path": "src/features/proxmox/ProxmoxBackupsTable.tsx",
"patterns": [
"from '@/components/shared/PageControls'",
"<PageControls",
"LabeledFilterSelect",
"LabeledFilterToggleGroup"
]
}
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/FilterBar/FilterBar.test.tsx",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "search-field-shell",
"category": "search-control",
"summary": "Product surfaces with simple search fields must compose SearchField for the shared icon, clear button, keyboard, focus, aria, and input chrome instead of rendering native search inputs.",
"canonical": {
"path": "src/components/shared/SearchField.tsx",
"export": "SearchField"
},
"requiredConsumers": [
{ "path": "src/components/AI/Chat/AssistantCommandHelpDialog.tsx" },
{ "path": "src/components/AI/Chat/index.tsx" },
{ "path": "src/components/Settings/InfrastructureSourcePicker.tsx" },
{ "path": "src/components/Settings/ResourcePicker.tsx" },
{ "path": "src/components/Settings/UserAssignmentsPanel.tsx" },
{ "path": "src/components/shared/AIModelPicker.tsx" },
{ "path": "src/components/shared/CommandPaletteModal.tsx" },
{ "path": "src/components/shared/SearchInput.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/__tests__/SearchField.test.tsx",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "search-input-shell",
"category": "search-control",
"summary": "Resource-list and drawer search boxes that need history, tips, or type-to-search behavior must compose SearchInput instead of rebuilding search-enhancement controls locally.",
"canonical": {
"path": "src/components/shared/SearchInput.tsx",
"export": "SearchInput"
},
"requiredConsumers": [
{ "path": "src/components/Docker/SwarmServicesDrawer.tsx" },
{ "path": "src/components/Kubernetes/K8sDeploymentsDrawer.tsx" },
{ "path": "src/components/Kubernetes/K8sNamespacesDrawer.tsx" },
{ "path": "src/components/Settings/SettingsPageShell.tsx" },
{ "path": "src/components/shared/FilterBar/FilterBar.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/__tests__/SearchInput.test.tsx",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "filter-button-group-shell",
"category": "segmented-selector",
"summary": "Settings and compact feature segmented selectors must compose FilterButtonGroup instead of recreating active-button group styling locally.",
"canonical": {
"path": "src/components/shared/FilterButtonGroup.tsx",
"export": "FilterButtonGroup"
},
"requiredConsumers": [
{ "path": "src/components/Settings/GeneralSettingsPanel.tsx" },
{ "path": "src/components/Settings/ReportingPanel.tsx" },
{ "path": "src/features/patrol/PatrolIntelligenceHeader.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/FilterButtonGroup.test.tsx",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "chart-visibility-toggle-button",
"category": "display-toggle",
"summary": "Summary-bearing filter surfaces must compose ChartVisibilityToggleButton for chart show/hide display actions instead of recreating one-off chart toggle buttons.",
"canonical": {
"path": "src/components/shared/FilterToolbar.tsx",
"export": "ChartVisibilityToggleButton"
},
"requiredConsumers": [{ "path": "src/components/Workloads/WorkloadsFilter.tsx" }],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/FilterToolbar.test.tsx",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "column-picker-shell",
"category": "column-picker",
"summary": "Table column visibility controls must compose ColumnPicker instead of recreating column chooser trigger, panel, reset, or hidden-count chrome locally.",
"canonical": {
"path": "src/components/shared/ColumnPicker.tsx",
"export": "ColumnPicker"
},
"requiredConsumers": [
{ "path": "src/components/Workloads/WorkloadsFilter.tsx" },
{ "path": "src/features/standalone/AgentsMachinesTable.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/ColumnPicker.test.tsx",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "selection-card-group-shell",
"category": "selection-card-group",
"summary": "Selectable settings card groups must compose SelectionCardGroup instead of recreating compact/detail active-card styling and disabled selection behavior locally.",
"canonical": {
"path": "src/components/shared/SelectionCardGroup.tsx",
"export": "SelectionCardGroup"
},
"requiredConsumers": [
{ "path": "src/components/Settings/AISettingsDialogs.tsx" },
{ "path": "src/components/Settings/UpdatesSettingsPanel.tsx" }
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"src/components/shared/SelectionCardGroup.test.tsx",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "grouped-table-mode-segmented-control",
"category": "table-mode-control",
"summary": "Grouped/list table-mode controls must compose GroupedTableModeSegmentedControl instead of recreating grouped/list labels, titles, or icons locally.",
"canonical": {
"path": "src/components/shared/GroupedTableModeSegmentedControl.tsx",
"export": "GroupedTableModeSegmentedControl"
},
"requiredConsumers": [{ "path": "src/components/Workloads/WorkloadsFilter.tsx" }],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
}
],
"patternGuards": [
{
"id": "platform-table-shell-local-frame",
"category": "platform-table-shell",
"summary": "Platform tables must compose the shared PlatformTableShell frame instead of recreating the TableCard/TableHeader/TableBody shell locally.",
"canonical": {
"path": "src/features/platformPage/sharedPlatformPage.tsx",
"export": "PlatformTableShell"
},
"scopes": ["src/features", "src/components"],
"extensions": [".tsx"],
"allPatterns": [
"TableCard class={PLATFORM_TABLE_CARD_CLASS}",
"TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}",
"TableBody class={PLATFORM_TABLE_BODY_CLASS}"
],
"legacyReason": "Retired migration debt. Platform table frames must use PlatformTableShell; no local-frame exceptions are currently allowed.",
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "platform-table-empty-state-local-empty-state",
"category": "platform-table-empty-state",
"summary": "Platform feature tables must compose PlatformTableEmptyState for their table/card empty-state shell instead of importing EmptyState directly.",
"canonical": {
"path": "src/features/platformPage/sharedPlatformPage.tsx",
"export": "PlatformTableEmptyState"
},
"scopes": [
"src/features/docker",
"src/features/kubernetes",
"src/features/proxmox",
"src/features/standalone",
"src/features/truenas",
"src/features/vmware"
],
"extensions": [".tsx"],
"allPatterns": ["@/components/shared/EmptyState"],
"legacyReason": "Retired migration debt. Platform table empty states must use PlatformTableEmptyState; no platform feature exceptions are currently allowed.",
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "table-card-frame-local-wrapper",
"category": "table-card",
"summary": "Product table surfaces must not copy the retired local bordered overflow-hidden table wrapper owned by TableCard.",
"canonical": {
"path": "src/components/shared/TableCard.tsx",
"export": "TableCard"
},
"scopes": ["src/components", "src/features", "src/pages"],
"extensions": [".tsx"],
"allPatterns": ["overflow-hidden border-border-subtle bg-surface"],
"legacyReason": "Retired migration debt. Product table frames must use TableCard; local bordered overflow-hidden table wrappers are not allowed.",
"allowedPaths": [],
"ignoredPaths": ["src/components/shared/SharedPrimitives.guardrails.test.ts"],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "table-card-header-local-summary-header",
"category": "table-card",
"summary": "Product table surfaces must not reintroduce the retired SummaryTableCardHeader local alias.",
"canonical": {
"path": "src/components/shared/TableCardHeader.tsx",
"export": "TableCardHeader"
},
"scopes": ["src/components", "src/features", "src/pages"],
"extensions": [".tsx"],
"allPatterns": ["SummaryTableCardHeader"],
"legacyReason": "Retired migration debt. Table-card title/action/clear chrome must use TableCardHeader; no local header aliases are allowed.",
"allowedPaths": [],
"ignoredPaths": ["src/components/shared/SharedPrimitives.guardrails.test.ts"],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "platform-table-loading-state-local-status-row",
"category": "platform-table-loading-state",
"summary": "Platform feature loading states must compose PlatformTableLoadingState instead of recreating the compact TableCard status row locally.",
"canonical": {
"path": "src/features/platformPage/sharedPlatformPage.tsx",
"export": "PlatformTableLoadingState"
},
"scopes": [
"src/features/docker",
"src/features/kubernetes",
"src/features/proxmox",
"src/features/standalone",
"src/features/truenas",
"src/features/vmware"
],
"extensions": [".tsx"],
"allPatterns": ["role=\"status\"", "px-3 py-2 text-xs text-muted"],
"legacyReason": "Retired migration debt. Platform table loading states must use PlatformTableLoadingState; no compact local status-row exceptions are currently allowed.",
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "platform-section-tabs-local-nav",
"category": "platform-section-tabs",
"summary": "Platform page surfaces must not recreate the active-link tab navigation owned by PlatformSectionTabs.",
"canonical": {
"path": "src/features/platformPage/sharedPlatformPage.tsx",
"export": "PlatformSectionTabs"
},
"scopes": [
"src/features/docker",
"src/features/kubernetes",
"src/features/proxmox",
"src/features/standalone",
"src/features/truenas",
"src/features/vmware"
],
"extensions": [".tsx"],
"allPatterns": ["aria-current={", "border-b-2", "border-b border-border"],
"legacyReason": "Retired migration debt. Platform page section tabs must use PlatformSectionTabs; no page-local tab-bar exceptions are currently allowed.",
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "chart-visibility-local-toggle-labels",
"category": "display-toggle",
"summary": "Summary-bearing surfaces must not copy the Show charts / Hide charts display-toggle labels owned by ChartVisibilityToggleButton.",
"canonical": {
"path": "src/components/shared/FilterToolbar.tsx",
"export": "ChartVisibilityToggleButton"
},
"scopes": ["src/components/Workloads", "src/features", "src/pages"],
"extensions": [".tsx"],
"allPatterns": ["Show charts", "Hide charts"],
"legacyReason": "Retired migration debt. Chart visibility display actions must use ChartVisibilityToggleButton; local show/hide chart toggle copies are not allowed.",
"allowedPaths": [],
"ignoredPaths": ["src/components/Workloads/__tests__/WorkloadsFilter.test.tsx"],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "column-picker-local-column-chooser",
"category": "column-picker",
"summary": "Table surfaces must not copy the column chooser title and panel copy owned by ColumnPicker.",
"canonical": {
"path": "src/components/shared/ColumnPicker.tsx",
"export": "ColumnPicker"
},
"scopes": ["src/components", "src/features", "src/pages"],
"extensions": [".tsx"],
"allPatterns": ["Choose which columns to display", "Show Columns"],
"legacyReason": "Retired migration debt. Table column visibility controls must use ColumnPicker; local column chooser copies are not allowed.",
"allowedPaths": [],
"ignoredPaths": ["src/components/shared/ColumnPicker.test.tsx"],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "selection-card-group-local-active-card-styles",
"category": "selection-card-group",
"summary": "Settings and feature surfaces must not copy the compact/detail active-card styling owned by SelectionCardGroup.",
"canonical": {
"path": "src/components/shared/selectionCardGroupModel.ts",
"export": "getSelectionCardButtonClass"
},
"scopes": ["src/components/Settings", "src/features", "src/pages"],
"extensions": [".tsx"],
"allPatterns": [
"p-4 rounded-md border-2 transition-all text-left",
"p-3 rounded-md border-2 transition-all text-center"
],
"legacyReason": "Retired migration debt. Selectable settings card groups must use SelectionCardGroup; local compact/detail active-card styling forks are not allowed.",
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "grouped-table-mode-local-segmented-control",
"category": "table-mode-control",
"summary": "Resource surfaces must not copy the grouped/list table-mode segmented-control labels owned by GroupedTableModeSegmentedControl.",
"canonical": {
"path": "src/components/shared/GroupedTableModeSegmentedControl.tsx",
"export": "GroupedTableModeSegmentedControl"
},
"scopes": ["src/components", "src/features"],
"extensions": [".tsx"],
"allPatterns": ["Grouped table view", "Flat list view"],
"legacyReason": "Retired migration debt. Grouped/list table-mode controls must use GroupedTableModeSegmentedControl; no local label/title copies are currently allowed.",
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "filter-bar-consumer-legacy-page-controls",
"category": "filter-bar",
"summary": "Page and feature filter surfaces must not import the legacy PageControls deck when they should be expressed as a FilterBar catalog.",
"canonical": {
"path": "src/components/shared/FilterBar/FilterBar.tsx",
"export": "FilterBar"
},
"scopes": ["src/components", "src/features"],
"extensions": [".tsx"],
"allPatterns": ["@/components/shared/PageControls"],
"legacyReason": "Retired migration debt. Resource-list filter surfaces must compose FilterBar; no page-level filter exceptions are currently allowed.",
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "search-control-native-search-input",
"category": "search-control",
"summary": "Product surfaces must not render native type=search inputs; they must compose SearchField or SearchInput so search chrome, clear behavior, keyboard handling, and aria labels stay canonical.",
"canonical": {
"path": "src/components/shared/SearchField.tsx",
"export": "SearchField"
},
"scopes": ["src/components", "src/features", "src/pages"],
"extensions": [".tsx"],
"allPatterns": ["type=\"search\""],
"legacyReason": "Retired migration debt. Search controls must use SearchField or SearchInput; native search inputs are not allowed in product surfaces.",
"allowedPaths": [],
"ignoredPaths": ["src/components/shared/SharedPrimitives.guardrails.test.ts"],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "filter-chip-status-dot-local-factory",
"category": "filter-bar",
"summary": "Filter option status-dot leading icons must use the FilterBar presentation helper instead of page-local span factories.",
"canonical": {
"path": "src/components/shared/FilterBar/filterOptionPresentation.tsx",
"export": "filterChipStatusDot"
},
"scopes": ["src/components", "src/features"],
"extensions": [".tsx"],
"allPatterns": ["h-2 w-2 rounded-full ${className}"],
"legacyReason": "Retired migration debt. Filter chip leading-dot presentation is owned by the FilterBar primitive family.",
"allowedPaths": [],
"ignoredPaths": ["src/components/shared/SharedPrimitives.guardrails.test.ts"],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "filter-button-group-local-segmented-control-styles",
"category": "segmented-selector",
"summary": "Settings and feature surfaces must not copy the compact active-button segmented-control styling owned by FilterButtonGroup.",
"canonical": {
"path": "src/components/shared/filterButtonGroupModel.ts",
"export": "getFilterButtonGroupButtonClass"
},
"scopes": ["src/components/Settings", "src/features", "src/pages"],
"extensions": [".tsx"],
"allPatterns": [
"flex items-center bg-base rounded-md p-1 border shadow-inner",
"flex-1 py-1.5 px-2 text-xs font-semibold rounded-md transition-all duration-200"
],
"legacyReason": "Retired migration debt. Settings and compact feature segmented selectors must use FilterButtonGroup; local active-button selector styling forks are not allowed.",
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
}
],
"requiredPatternGuards": [
{
"id": "platform-row-detail-toggle-shared-state",
"category": "row-disclosure",
"summary": "Platform rows using shared resource-detail expansion state must render the canonical disclosure toggle instead of relying on row-only click behavior or local chevrons.",
"canonical": {
"path": "src/features/platformPage/PlatformResourceDetailTableRow.tsx",
"export": "PlatformResourceDetailToggleButton"
},
"scopes": [
"src/features/docker",
"src/features/kubernetes",
"src/features/proxmox",
"src/features/standalone",
"src/features/truenas",
"src/features/vmware"
],
"extensions": [".tsx"],
"triggerPatterns": ["createPlatformResourceDetailState"],
"requiredPatterns": ["PlatformResourceDetailToggleButton"],
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "platform-row-detail-toggle-inline-detail",
"category": "row-disclosure",
"summary": "Platform tables that render page-local inline detail rows must compose the canonical disclosure toggle in the owning row.",
"canonical": {
"path": "src/features/platformPage/PlatformResourceDetailTableRow.tsx",
"export": "PlatformResourceDetailToggleButton"
},
"scopes": [
"src/features/docker",
"src/features/kubernetes",
"src/features/proxmox",
"src/features/standalone",
"src/features/truenas",
"src/features/vmware"
],
"extensions": [".tsx"],
"triggerPatterns": ["data-inline", "aria-expanded"],
"requiredPatterns": ["PlatformResourceDetailToggleButton"],
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "inline-detail-table-row-shared-shell",
"category": "row-detail",
"summary": "Files that render inline/detail table rows in platform, workload, or infrastructure surfaces must use InlineDetailTableRow for the shared row/cell/content shell.",
"canonical": {
"path": "src/components/shared/InlineDetailTableRow.tsx",
"export": "InlineDetailTableRow"
},
"scopes": [
"src/components/Infrastructure",
"src/components/Workloads",
"src/features/docker",
"src/features/kubernetes",
"src/features/platformPage",
"src/features/proxmox",
"src/features/truenas",
"src/features/vmware"
],
"extensions": [".tsx"],
"triggerPatterns": ["data-inline", "TableRow"],
"requiredPatterns": ["InlineDetailTableRow"],
"allowedPaths": [],
"ignoredPaths": [
"src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx"
],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "platform-error-state-required",
"category": "platform-error-state",
"summary": "Platform feature files that surface load-failure copy must compose PlatformErrorState for the canonical retry shell.",
"canonical": {
"path": "src/features/platformPage/sharedPlatformPage.tsx",
"export": "PlatformErrorState"
},
"scopes": [
"src/features/docker",
"src/features/kubernetes",
"src/features/proxmox",
"src/features/standalone",
"src/features/truenas",
"src/features/vmware"
],
"extensions": [".tsx"],
"triggerPatterns": ["title=\"Could not load"],
"requiredPatterns": ["PlatformErrorState"],
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
},
{
"id": "named-detail-table-row-shared-shell",
"category": "row-detail",
"summary": "Named platform detail rows such as Docker network detail rows must use InlineDetailTableRow even when their row attribute is not data-inline-*.",
"canonical": {
"path": "src/components/shared/InlineDetailTableRow.tsx",
"export": "InlineDetailTableRow"
},
"scopes": [
"src/components/Infrastructure",
"src/components/Workloads",
"src/features/docker",
"src/features/kubernetes",
"src/features/platformPage",
"src/features/proxmox",
"src/features/truenas",
"src/features/vmware"
],
"extensions": [".tsx"],
"triggerPatterns": ["detail-row", "TableRow"],
"requiredPatterns": ["InlineDetailTableRow"],
"allowedPaths": [],
"proof": [
"src/components/shared/SharedPrimitives.guardrails.test.ts",
"scripts/shared-template-audit.mjs"
]
}
]
}