mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-22 19:56:01 +00:00
657 lines
27 KiB
JSON
657 lines
27 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": "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": "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": "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": "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"
|
|
]
|
|
}
|
|
],
|
|
"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"
|
|
]
|
|
}
|
|
]
|
|
}
|