mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-09 16:00:59 +00:00
Land SMART/SSH temperature feature, rc.6 finalization, and post-IA-revert governance reconciliation
This commit is contained in:
parent
affc1c76ed
commit
8769f07eea
25 changed files with 922 additions and 3033 deletions
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
6.0.0-rc.5
|
||||
6.0.0-rc.6
|
||||
|
|
|
|||
|
|
@ -8,22 +8,25 @@
|
|||
|
||||
1. The latest shipped Pulse v6 prerelease tag is `v6.0.0-rc.5`.
|
||||
2. That shipped prerelease tag resolves to commit `e32db04543c7fb20f2cac782dafbf3422a13dfe3`.
|
||||
3. The governed release profile in `docs/release-control/control_plane.json`
|
||||
3. The selected remote ref `origin/pulse/v6-release` is still behind the current
|
||||
local governed branch state, so `Release Dry Run` would exercise stale remote
|
||||
control-plane metadata instead of the intended candidate.
|
||||
4. The governed release profile in `docs/release-control/control_plane.json`
|
||||
currently declares both `prerelease_branch` and `stable_branch` as
|
||||
`pulse/v6-release`.
|
||||
4. The active control-plane target is still `v6-product-lane-expansion`, not
|
||||
5. The active control-plane target is still `v6-product-lane-expansion`, not
|
||||
`v6-ga-promotion`.
|
||||
5. The active local `pulse/v6-release` branch currently reports `VERSION=6.0.0-rc.5`, so the
|
||||
6. The active local `pulse/v6-release` branch currently reports `VERSION=6.0.0-rc.6`, so the
|
||||
working line is still prerelease and there is not yet a governed local stable
|
||||
`6.0.0` candidate.
|
||||
6. There is still no governed `Prerelease-to-GA Rehearsal Record` proving a successful
|
||||
7. There is still no governed `Prerelease-to-GA Rehearsal Record` proving a successful
|
||||
non-publish `Release Dry Run` for the eventual stable `6.0.0` candidate.
|
||||
7. `docs/releases/RELEASE_NOTES_v6.md` and
|
||||
8. `docs/releases/RELEASE_NOTES_v6.md` and
|
||||
`docs/release-control/v6/internal/V5_MAINTENANCE_SUPPORT_POLICY.md` now carry the
|
||||
currently proposed exact dates for the eventual GA notice:
|
||||
- `v6` GA date: `2026-04-20`
|
||||
- `v5` end-of-support date: `2026-07-19`
|
||||
8. There is still no governed `Release Dry Run` artifact or rehearsal record
|
||||
9. There is still no governed `Release Dry Run` artifact or rehearsal record
|
||||
exercising stable inputs for:
|
||||
- `version=6.0.0`
|
||||
- `promoted_from_tag=v6.0.0-rc.5`
|
||||
|
|
@ -40,7 +43,7 @@
|
|||
|
||||
The blocker is no longer missing governance text. The remaining problem is that
|
||||
the control plane still holds v6 on the pre-GA prerelease line, the working
|
||||
version is still prerelease (`6.0.0-rc.5`), and there is still no exercised
|
||||
version is still prerelease (`6.0.0-rc.6`), and there is still no exercised
|
||||
`Release Dry Run` record proving the eventual stable `6.0.0`
|
||||
candidate is ready for GA-style promotion. Until that rehearsal exists, stable
|
||||
users would still be the first real cohort for the final promotion path.
|
||||
|
|
|
|||
|
|
@ -562,11 +562,6 @@
|
|||
}
|
||||
],
|
||||
"evidence": [
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Settings/__tests__/MonitoredSystemLedgerPanel.test.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Settings/__tests__/OrganizationBillingPanel.test.tsx",
|
||||
|
|
@ -1020,11 +1015,6 @@
|
|||
"path": "frontend-modern/src/components/Settings/__tests__/OrganizationBillingPanel.test.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/pages/__tests__/HostedSignup.test.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "internal/api/hosted_lifecycle_integration_test.go",
|
||||
|
|
@ -1312,11 +1302,6 @@
|
|||
"path": "frontend-modern/src/components/Settings/__tests__/OrganizationBillingPanel.test.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/pages/__tests__/CloudPricing.test.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "internal/cloudcp/account/handlers_test.go",
|
||||
|
|
@ -1889,11 +1874,6 @@
|
|||
"path": "docs/release-control/v6/internal/subsystems/unified-resources.md",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Storage/__tests__/DiskList.test.tsx",
|
||||
|
|
@ -4175,11 +4155,6 @@
|
|||
"path": "frontend-modern/src/components/Workloads/workloadSelectors.ts",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Workloads/WorkloadsStateCards.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Workloads/WorkloadsSurface.tsx",
|
||||
|
|
@ -4579,16 +4554,6 @@
|
|||
"path": "docs/STORAGE_ARCHITECTURE.md",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Recovery/Recovery.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Storage/__tests__/storagePageState.test.ts",
|
||||
|
|
@ -4697,11 +4662,6 @@
|
|||
"path": "frontend-modern/src/api/nodes.ts",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Infrastructure/deploy/ResultsStep.tsx",
|
||||
"kind": "file"
|
||||
},
|
||||
{
|
||||
"repo": "pulse",
|
||||
"path": "frontend-modern/src/components/Settings/__tests__/connectionsTableModel.test.ts",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ management, and fleet control surfaces.
|
|||
|
||||
1. `internal/api/agent_install_command_shared.go`
|
||||
2. `internal/api/config_setup_handlers.go`
|
||||
2a. `internal/api/setup_script_render.go`
|
||||
3. `internal/api/unified_agent.go`
|
||||
4. `internal/agentupdate/update.go`
|
||||
5. `internal/hostagent/agent.go`
|
||||
|
|
@ -51,49 +52,38 @@ management, and fleet control surfaces.
|
|||
28. `frontend-modern/src/components/Settings/discoverySettingsModel.ts`
|
||||
29. `frontend-modern/src/components/Settings/infrastructureWorkspaceModel.ts`
|
||||
30. `frontend-modern/src/components/Settings/proxmoxSettingsModel.ts`
|
||||
31. `frontend-modern/src/components/Settings/ConfiguredNodeTables.tsx`
|
||||
32. `frontend-modern/src/components/Settings/SettingsSectionNav.tsx`
|
||||
33. `frontend-modern/src/components/Settings/useInfrastructureOperationsState.tsx`
|
||||
34. `frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts`
|
||||
35. `frontend-modern/src/components/Settings/NodeModalAuthenticationSection.tsx`
|
||||
36. `frontend-modern/src/components/Settings/NodeModalBasicInfoSection.tsx`
|
||||
37. `frontend-modern/src/components/Settings/nodeModalModel.ts`
|
||||
38. `frontend-modern/src/components/Settings/NodeModalMonitoringSection.tsx`
|
||||
39. `frontend-modern/src/components/Settings/NodeModalSetupGuideSection.tsx`
|
||||
40. `frontend-modern/src/components/Settings/NodeModalStatusFooter.tsx`
|
||||
41. `frontend-modern/src/components/Settings/useNodeModalState.ts`
|
||||
42. `frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx`
|
||||
43. `frontend-modern/src/components/Infrastructure/deploy/CandidatesStep.tsx`
|
||||
44. `frontend-modern/src/components/Infrastructure/deploy/ConfirmStep.tsx`
|
||||
45. `frontend-modern/src/components/Infrastructure/deploy/DeployingStep.tsx`
|
||||
46. `frontend-modern/src/components/Infrastructure/deploy/PreflightStep.tsx`
|
||||
47. `frontend-modern/src/components/Infrastructure/deploy/ResultsStep.tsx`
|
||||
48. `frontend-modern/src/utils/agentProfilesPresentation.ts`
|
||||
49. `frontend-modern/src/utils/agentInstallCommand.ts`
|
||||
50. `frontend-modern/src/utils/infrastructureOnboardingPresentation.ts`
|
||||
51. `frontend-modern/src/api/nodes.ts`
|
||||
52. `frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx`
|
||||
53. `frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx`
|
||||
54. `frontend-modern/src/components/Settings/infrastructureSettingsModel.ts`
|
||||
55. `frontend-modern/src/components/Settings/useInfrastructureConfiguredNodesState.ts`
|
||||
56. `frontend-modern/src/components/Settings/useInfrastructureDiscoveryRuntimeState.ts`
|
||||
57. `frontend-modern/src/utils/infrastructureSettingsPresentation.ts`
|
||||
54. `frontend-modern/src/utils/agentCapabilityPresentation.ts`
|
||||
55. `frontend-modern/src/utils/agentProfileSuggestionPresentation.ts`
|
||||
56. `frontend-modern/src/utils/configuredNodeCapabilityPresentation.ts`
|
||||
57. `frontend-modern/src/utils/configuredNodeStatusPresentation.ts`
|
||||
58. `frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts`
|
||||
59. `frontend-modern/src/utils/unifiedAgentStatusPresentation.ts`
|
||||
60. `frontend-modern/src/utils/clusterEndpointPresentation.ts`
|
||||
61. `frontend-modern/src/utils/nodeModalPresentation.ts`
|
||||
62. `frontend-modern/src/utils/proxmoxSettingsPresentation.ts`
|
||||
63. `frontend-modern/src/components/Settings/useTrueNASSettingsPanelState.ts`
|
||||
64. `frontend-modern/src/components/Settings/useVMwareSettingsPanelState.ts`
|
||||
65. `frontend-modern/src/components/Settings/MonitoredSystemImpactPreview.tsx`
|
||||
66. `internal/hostagent/proxmox_setup.go`
|
||||
67. `internal/remoteconfig/client.go`
|
||||
68. `internal/agenttls/config.go`
|
||||
69. `internal/api/agent_exec_token_binding.go`
|
||||
31. `frontend-modern/src/components/Settings/useInfrastructureOperationsState.tsx`
|
||||
32. `frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts`
|
||||
33. `frontend-modern/src/components/Settings/NodeModalAuthenticationSection.tsx`
|
||||
34. `frontend-modern/src/components/Settings/NodeModalBasicInfoSection.tsx`
|
||||
35. `frontend-modern/src/components/Settings/nodeModalModel.ts`
|
||||
36. `frontend-modern/src/components/Settings/NodeModalMonitoringSection.tsx`
|
||||
37. `frontend-modern/src/components/Settings/NodeModalSetupGuideSection.tsx`
|
||||
38. `frontend-modern/src/components/Settings/NodeModalStatusFooter.tsx`
|
||||
39. `frontend-modern/src/components/Settings/useNodeModalState.ts`
|
||||
40. `frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx`
|
||||
41. `frontend-modern/src/utils/agentProfilesPresentation.ts`
|
||||
42. `frontend-modern/src/utils/agentInstallCommand.ts`
|
||||
43. `frontend-modern/src/utils/infrastructureOnboardingPresentation.ts`
|
||||
44. `frontend-modern/src/api/nodes.ts`
|
||||
45. `frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx`
|
||||
46. `frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx`
|
||||
47. `frontend-modern/src/components/Settings/infrastructureSettingsModel.ts`
|
||||
48. `frontend-modern/src/components/Settings/useInfrastructureConfiguredNodesState.ts`
|
||||
49. `frontend-modern/src/components/Settings/useInfrastructureDiscoveryRuntimeState.ts`
|
||||
50. `frontend-modern/src/utils/infrastructureSettingsPresentation.ts`
|
||||
51. `frontend-modern/src/utils/agentCapabilityPresentation.ts`
|
||||
52. `frontend-modern/src/utils/agentProfileSuggestionPresentation.ts`
|
||||
53. `frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts`
|
||||
54. `frontend-modern/src/utils/unifiedAgentStatusPresentation.ts`
|
||||
55. `frontend-modern/src/utils/nodeModalPresentation.ts`
|
||||
56. `frontend-modern/src/components/Settings/useTrueNASSettingsPanelState.ts`
|
||||
57. `frontend-modern/src/components/Settings/useVMwareSettingsPanelState.ts`
|
||||
58. `frontend-modern/src/components/Settings/MonitoredSystemImpactPreview.tsx`
|
||||
59. `internal/hostagent/proxmox_setup.go`
|
||||
60. `internal/remoteconfig/client.go`
|
||||
61. `internal/agenttls/config.go`
|
||||
62. `internal/api/agent_exec_token_binding.go`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
|
|
@ -136,8 +126,9 @@ reverse.
|
|||
18. `frontend-modern/src/utils/infrastructureSettingsPresentation.ts` shared with `api-contracts`: the infrastructure settings presentation helper is both an agent lifecycle control surface and an API-backed direct-node/discovery settings boundary.
|
||||
19. `internal/api/agent_install_command_shared.go` shared with `api-contracts`: agent install command assembly is both an agent lifecycle control surface and a canonical API payload contract boundary.
|
||||
20. `internal/api/config_setup_handlers.go` shared with `api-contracts`: auto-register and setup handlers are both an agent lifecycle control surface and a canonical API payload contract boundary.
|
||||
21. `internal/api/unified_agent.go` shared with `api-contracts`: unified agent download and installer handlers are both an agent lifecycle control surface and a canonical API payload contract boundary.
|
||||
22. `scripts/install.ps1` shared with `deployment-installability`: the Windows installer is both a deployment installability entry point and a canonical agent lifecycle runtime continuity boundary.
|
||||
21. `internal/api/setup_script_render.go` shared with `api-contracts`, `storage-recovery`: the generated Proxmox setup-script is a shared boundary across agent lifecycle (forced-command keys, install/uninstall edits), API contracts (rendered token shape and encoded rerun URL), and storage/recovery (backup visibility grants, Pulse-managed temperature SSH keys, and SMART disk-temperature collection).
|
||||
22. `internal/api/unified_agent.go` shared with `api-contracts`: unified agent download and installer handlers are both an agent lifecycle control surface and a canonical API payload contract boundary.
|
||||
23. `scripts/install.ps1` shared with `deployment-installability`: the Windows installer is both a deployment installability entry point and a canonical agent lifecycle runtime continuity boundary.
|
||||
The Windows installer must support a non-mutating download preflight that
|
||||
can run before Administrator-only install work, must accept token-file
|
||||
enrollment input, and must persist plain-HTTP/insecure runtime continuity
|
||||
|
|
@ -146,7 +137,7 @@ reverse.
|
|||
`pulse-agent` runs so installer "healthy" verification and post-install
|
||||
smoke checks prove a live agent runtime, not merely a running service
|
||||
wrapper.
|
||||
23. `scripts/install.sh` shared with `deployment-installability`: the shell installer is both a deployment installability entry point and a canonical agent lifecycle runtime continuity boundary.
|
||||
24. `scripts/install.sh` shared with `deployment-installability`: the shell installer is both a deployment installability entry point and a canonical agent lifecycle runtime continuity boundary.
|
||||
|
||||
Agent lifecycle and fleet-operation surfaces may consume
|
||||
`POST /api/actions/plan` for resource capability planning, but the action plan
|
||||
|
|
@ -668,61 +659,6 @@ profile and assignment columns, but embedded table framing must route through
|
|||
Approval-gated command execution must expose stable rejection reasons for
|
||||
invalid approval grants so fleet operators can distinguish missing, expired,
|
||||
mismatched, and signature-invalid grants through agent metrics.
|
||||
9. Add or change profile management, the extracted agent profiles runtime owner, the agent profile settings catalog, the infrastructure source-manager landing, the pure unified-agent inventory/install model, the connections-ledger workspace shell, the unified ConnectionEditor and its per-type credential slots, route model, shared install section owner, the shared direct-node/discovery infrastructure settings owners plus their model, shared frontend install-command assembly, Proxmox setup/install API transport, TrueNAS platform-connection management, VMware platform-connection management, the shared monitored-system impact preview shell for those platform connections, setup-completion install handoff transport, deploy-fallback manual install transport, and fleet-control presentation through `frontend-modern/src/api/agentProfiles.ts`, `frontend-modern/src/api/nodes.ts`, `frontend-modern/src/components/Settings/AgentProfilesPanel.tsx`, `frontend-modern/src/components/Settings/agentProfileSettings.ts`, `frontend-modern/src/components/Settings/useAgentProfilesPanelState.ts`, `frontend-modern/src/components/Settings/connectionsTableModel.ts`, `frontend-modern/src/components/Settings/useConnectionsLedger.ts`, `frontend-modern/src/components/Settings/useConnectionRowActions.ts`, `frontend-modern/src/components/Settings/ConnectionEditor/ConnectionEditor.tsx`, `frontend-modern/src/components/Settings/ConnectionEditor/AddressProbeStep.tsx`, `frontend-modern/src/components/Settings/ConnectionEditor/useConnectionEditor.ts`, `frontend-modern/src/components/Settings/ConnectionEditor/CredentialSlots/NodeCredentialSlot.tsx`, `frontend-modern/src/components/Settings/ConnectionEditor/CredentialSlots/TrueNASCredentialSlot.tsx`, `frontend-modern/src/components/Settings/ConnectionEditor/CredentialSlots/VMwareCredentialSlot.tsx`, `frontend-modern/src/components/Settings/infrastructureOperationsModel.tsx`, `frontend-modern/src/components/Settings/InfrastructureInstallerSection.tsx`, `frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx`, `frontend-modern/src/components/Settings/InfrastructureSourceManager.tsx`, `frontend-modern/src/components/Settings/infrastructureWorkspaceModel.ts`, `frontend-modern/src/components/Settings/MonitoredSystemImpactPreview.tsx`, `frontend-modern/src/components/Settings/useTrueNASSettingsPanelState.ts`, `frontend-modern/src/components/Settings/useVMwareSettingsPanelState.ts`, `frontend-modern/src/components/Settings/proxmoxSettingsModel.ts`, `frontend-modern/src/components/Settings/ConfiguredNodeTables.tsx`, `frontend-modern/src/components/Settings/SettingsSectionNav.tsx`, `frontend-modern/src/components/Settings/infrastructureSettingsModel.ts`, `frontend-modern/src/components/Settings/useInfrastructureConfiguredNodesState.ts`, `frontend-modern/src/components/Settings/useInfrastructureDiscoveryRuntimeState.ts`, `frontend-modern/src/components/Settings/useInfrastructureInstallState.tsx`, `frontend-modern/src/components/Settings/useInfrastructureOperationsState.tsx`, `frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts`, `frontend-modern/src/components/Settings/nodeModalModel.ts`, `frontend-modern/src/components/Settings/useNodeModalState.ts`, `frontend-modern/src/components/SetupWizard/SetupCompletionPanel.tsx`, and `frontend-modern/src/utils/agentInstallCommand.ts`. Phase 9 retired the legacy reporting/inventory surface (InfrastructureOperationsController, InfrastructureInventorySection, InfrastructureActiveRowDetails, InfrastructureIgnoredRowDetails, InfrastructureStopMonitoringDialog, useInfrastructureReportingState) and the per-type shells (PlatformConnectionsWorkspace, ProxmoxSettingsPanel, ProxmoxDirectWorkspace, ProxmoxConfiguredNodesTable, ProxmoxDirectConnectionsCard, ProxmoxDiscoveryResultsCard, ProxmoxDeleteNodeDialog, ProxmoxNodeModalStack, NodeModal shell, TrueNASSettingsPanel, VMwareSettingsPanel, useProxmoxDirectWorkspaceState); lifecycle extensions must route through the unified aggregator ledger, source-manager cards, and ConnectionEditor credential slots rather than reintroducing those retired surfaces.
|
||||
Those lifecycle-owned settings hooks may consume websocket state only through `frontend-modern/src/contexts/appRuntime.ts`; they must not import `frontend-modern/src/App.tsx` or recreate root-shell providers.
|
||||
Discovery configuration is part of that same lifecycle-owned workspace boundary. `InfrastructureSourceManager.tsx` must open one canonical discovery editor through `InfrastructureDiscoverySettingsDialog.tsx`, `DiscoverySettingsForm.tsx`, and `discoverySettingsModel.ts`, while the System/Network shell stays limited to network-boundary controls instead of reintroducing a second editable discovery surface. That same workspace boundary now owns the infrastructure source-management toolbar too: the landing page exposes `Add infrastructure`, `Run discovery`, and `Discovery settings` as first-viewport toolbar actions inside the source manager, while governed source rows expose per-source add actions such as `Install Pulse Agent` from the shared catalog. `Run discovery` must remain a visible text command for manual scans rather than an icon-only affordance. `Detect address` remains inside the single add-flow source picker/probe path rather than a duplicate toolbar action. The same landing boundary may surface setup confidence from the unified rows and discovered candidates, including connected-system count, API coverage, agent coverage, sources that still need an agent, and discovery review state, without creating a second inventory model or provider-specific summary fetch. Source groups must stay in the governed source catalog order instead of re-sorting by current row count, row-level lifecycle entry points must use `Manage` language, and locked agent-install states must show a compact command inventory without raw token placeholders or disabled copy commands until a token exists. Network discovery settings remain safety-critical: automatic scanning must surface the shared-network/subnet warning before operators save scan mode changes. The AI settings manual workload refresh at `/api/discovery/run` is a discovery/API refresh sweep, not an enrollment or source-admission path; lifecycle surfaces may observe the refreshed candidates but must not reinterpret it as agent install authority. Agent command-execution handoff copy belongs to that same install surface: `InfrastructureInstallerSection.tsx` may expose the Pulse command-execution toggle for Patrol, but the label must describe Patrol remediation rather than reviving `Patrol auto-fix` or implying a paid monitoring-volume gate.
|
||||
Setup-completion handoff belongs to that same single add-flow boundary. The first-run completion screen must keep credentials as the first surfaced object, then present one compact next-step surface that sends operators to Add infrastructure or directly to the Agent handoff; source-choice explanation may live inside that surface, but lifecycle work must not reintroduce a separate setup-wizard tour, duplicate CTA section, or inline install-command owner before the canonical infrastructure workspace.
|
||||
The same lifecycle-owned workspace boundary now also owns attached-agent composition. When a unified Pulse Agent augments a first-class platform source such as Proxmox VE, the source manager and edit dialog must present one primary platform row with explicit `API` plus `Pulse Agent` composition rather than duplicating that same machine as a second peer row under a generic Pulse Agent platform bucket. Standalone hosts with no owning platform source remain grouped under a standalone-host owner bucket, with `Pulse Agent` shown as the collection method rather than as the pseudo-platform label.
|
||||
When that primary Proxmox source is cluster-backed, the same workspace boundary must render the row under the canonical cluster moniker carried by the backend grouping contract rather than under one sibling node's hostname. That same backend grouping contract must also carry the explicit member-node list for the cluster so the source manager can render child node composition such as `delly` and `minipc` beneath the owning cluster row with per-node coverage/status. Cluster-member node agents belong as augmentations on that owning Proxmox row and its child nodes, not as separate standalone-host peers.
|
||||
That same lifecycle-owned workspace boundary also owns agent version
|
||||
posture on infrastructure settings. The landing table stays compact and
|
||||
should only raise row-level attention when an attached or standalone agent
|
||||
has an update available, while the exact installed version belongs in the
|
||||
add/edit detail surfaces rather than as a permanent top-level table column.
|
||||
That compact fleet-control presentation is now backed by the canonical
|
||||
`/api/connections` `fleet` projection rather than page-local inference:
|
||||
`connectionsTableModel.ts`, `useConnectionsLedger.ts`, and
|
||||
`InfrastructureSourceManager.tsx` may format enrollment, liveness, version
|
||||
drift, adapter health, config rollout, credential status, update posture,
|
||||
and remote-control posture. Desired-versus-applied config drift, staged
|
||||
rollout, credential health/rotation, and command-policy enforcement must
|
||||
come from the explicit nested `fleet` objects on `/api/connections`; Settings
|
||||
surfaces may rank or compact those signals, but they must not reconstruct
|
||||
them from table copy, status badge labels, or provider-local error strings.
|
||||
The connections ledger is a retained-value settings query: polling or manual
|
||||
reloads must preserve the last fulfilled connected-systems rows while the
|
||||
next `/api/connections` request is in flight, and must not route the
|
||||
Infrastructure settings table through app-level Suspense or a blank loading
|
||||
replacement.
|
||||
The lifecycle-owned command-policy projection must preserve desired server
|
||||
policy and applied agent report truth as separate facts. Desired disabled
|
||||
with applied enabled, and desired enabled with applied disabled, are both
|
||||
attention states for lifecycle surfaces, never in-sync shorthand. If the
|
||||
agent has not reported current command capability or applied policy,
|
||||
lifecycle surfaces must leave the applied side pending or unknown with an
|
||||
explicit reason and must not treat `remoteControl` or `commandsEnabled` as
|
||||
proof that the server desired state is live on the agent.
|
||||
Standalone host rows must still be recognizable at a glance, but that
|
||||
identity belongs in the existing row cells rather than new diagnostics
|
||||
columns: the landing table reuses the `System` and `Endpoint` cells for a
|
||||
short host fact such as OS/platform plus a reported endpoint, while the
|
||||
richer agent identity facts stay in the edit/detail surface.
|
||||
Exact Proxmox host-agent attachments remain backend-authored through
|
||||
`/api/connections` even when Proxmox workload inventory is blocked by
|
||||
credentials or reachability; lifecycle surfaces must render that attached
|
||||
agent as part of the API source row and must not re-offer host install or
|
||||
standalone lifecycle actions for the same physical host.
|
||||
Public demo and other read-only settings posture must stay reporting-first
|
||||
on that same lifecycle-owned workspace boundary: infrastructure workspace
|
||||
routes may retain install and platform setup surfaces for manageable
|
||||
sessions, but read-only presentation must collapse back to reporting/control
|
||||
instead of advertising first-system setup on a pre-populated demo estate.
|
||||
Agent-profile suggestion affordances remain adjacent assistant UX, not a
|
||||
second AI settings reader. `frontend-modern/src/components/Settings/useAgentProfilesPanelState.ts`
|
||||
may gate the Ideas action only from the shared assistant-availability fact
|
||||
seeded by `/api/security/status.sessionCapabilities.assistantEnabled`, and
|
||||
must not probe `/api/settings/ai` just to decide whether that affordance
|
||||
should render.
|
||||
9. Preserve canonical token-lifecycle reads in shared `internal/api/` auth/security helpers so lifecycle-adjacent setup and install flows do not revoke a displayed relay pairing token after `lastUsedAt` proves that an already paired device is actively depending on that credential.
|
||||
10. Preserve backend-owned Pulse Mobile relay runtime credential minting in those same shared `internal/api/` auth/security helpers so lifecycle-adjacent setup and install flows reuse the canonical mobile token route instead of reintroducing wildcard or browser-authored runtime token bundles.
|
||||
11. Preserve the dedicated backend-owned `relay:mobile:access` capability and its governed backward-compatible route inventory plus the shared helper call sites around it, so lifecycle-adjacent setup and install flows do not widen the mobile device credential back into general AI chat/execute scope ownership.
|
||||
|
|
@ -2759,6 +2695,12 @@ Proxmox-managed `/root/.ssh/authorized_keys` symlinks when lifecycle setup or
|
|||
removal touches Pulse-managed temperature-monitoring SSH keys: scripts must
|
||||
resolve the real authorized-keys target before filtering `# pulse-` entries and
|
||||
must use that resolved path for both install and uninstall edits.
|
||||
That same generated PVE setup-script boundary also owns the forced-command
|
||||
shape for temperature-monitoring SSH keys: new keys must execute the
|
||||
Pulse-owned `/usr/local/sbin/pulse-sensors` wrapper, not raw `sensors -j`, so
|
||||
lifecycle setup can collect CPU sensor data and SMART disk temperatures through
|
||||
one bounded JSON payload while preserving old forced-key compatibility in the
|
||||
runtime collector.
|
||||
That same generated setup-script boundary must also use exact token-name
|
||||
matching when it decides whether to rotate an existing Pulse-managed token, so
|
||||
reruns do not treat partial-name collisions as the canonical managed token.
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ product API routes free of maintainer commercial analytics.
|
|||
51. `internal/api/recovery_handlers.go`
|
||||
51a. `internal/api/pbs_backups.go`
|
||||
52. `internal/api/config_setup_handlers.go`
|
||||
52a. `internal/api/setup_script_render.go`
|
||||
53. `internal/api/demo_mode_commercial.go`
|
||||
54. `internal/api/demo_mode_operations.go`
|
||||
55. `internal/api/security_status_capabilities.go`
|
||||
|
|
@ -96,7 +97,6 @@ product API routes free of maintainer commercial analytics.
|
|||
60. `internal/api/connections_probe.go`
|
||||
61. `frontend-modern/src/api/connections.ts`
|
||||
62. `frontend-modern/src/utils/connectionErrorPresentation.ts`
|
||||
62. `frontend-modern/src/api/hostedSignup.ts`
|
||||
63. `internal/api/availability_handlers.go`
|
||||
64. `frontend-modern/src/api/availabilityTargets.ts`
|
||||
65. `frontend-modern/src/components/Settings/ConnectionEditor/CredentialSlots/AvailabilityTargetSlot.tsx`
|
||||
|
|
@ -413,14 +413,15 @@ platform page needs source-native backup columns.
|
|||
before minting a `relay:mobile:access` credential. Community installs may
|
||||
receive the standard license-required response, but direct API calls must
|
||||
not bypass Relay entitlement by creating mobile runtime tokens.
|
||||
49. `internal/api/slo.go` shared with `performance-and-scalability`: the SLO endpoint is both an API contract surface and a protected performance hot-path boundary.
|
||||
50. `internal/api/system_settings.go` shared with `security-privacy`: the system settings telemetry and auth controls are both a security/privacy control surface and a canonical API payload contract boundary.
|
||||
51. `internal/api/unified_agent.go` shared with `agent-lifecycle`: unified agent download and installer handlers are both an agent lifecycle control surface and a canonical API payload contract boundary.
|
||||
49. `internal/api/setup_script_render.go` shared with `agent-lifecycle`, `storage-recovery`: the generated Proxmox setup-script is a shared boundary across agent lifecycle (forced-command keys, install/uninstall edits), API contracts (rendered token shape and encoded rerun URL), and storage/recovery (backup visibility grants, Pulse-managed temperature SSH keys, and SMART disk-temperature collection).
|
||||
50. `internal/api/slo.go` shared with `performance-and-scalability`: the SLO endpoint is both an API contract surface and a protected performance hot-path boundary.
|
||||
51. `internal/api/system_settings.go` shared with `security-privacy`: the system settings telemetry and auth controls are both a security/privacy control surface and a canonical API payload contract boundary.
|
||||
52. `internal/api/unified_agent.go` shared with `agent-lifecycle`: unified agent download and installer handlers are both an agent lifecycle control surface and a canonical API payload contract boundary.
|
||||
Development-mode missing-binary responses must report the build command
|
||||
for the requested normalized OS/architecture, not a hard-coded Linux
|
||||
target, so installer preflight failures point operators at the artifact
|
||||
they actually need.
|
||||
52. `internal/api/updates.go` shared with `deployment-installability`: update handlers are both a deployment-installability control surface and a canonical API payload contract boundary.
|
||||
53. `internal/api/updates.go` shared with `deployment-installability`: update handlers are both a deployment-installability control surface and a canonical API payload contract boundary.
|
||||
The platform-connections API contract also owns inactive monitored-system
|
||||
candidate semantics end to end. `enabled=false` on TrueNAS or VMware preview,
|
||||
test, add, and update payloads must serialize through the shared ledger client
|
||||
|
|
@ -3808,6 +3809,13 @@ temperature-monitoring SSH keys: the rendered shell must resolve the symlink
|
|||
target before filtering Pulse-managed `# pulse-` entries, use the resolved path
|
||||
for both install and uninstall edits, and keep this behavior pinned in
|
||||
`internal/api/contract_test.go`.
|
||||
That same rendered PVE setup-script payload must also bind the temperature SSH
|
||||
key to the Pulse-owned `/usr/local/sbin/pulse-sensors` wrapper rather than to
|
||||
raw `sensors -j`. The wrapper is the setup-script API contract for legacy SSH
|
||||
temperature collection: it must emit a bounded JSON object with `sensors` and
|
||||
`smart` members, install or verify `smartmontools` for SATA/SAS/HDD disk
|
||||
temperatures, and keep `sensors -j` only as a compatibility fallback inside
|
||||
the wrapper/runtime collector path.
|
||||
That same generated-script payload must also preserve the canonical encoded
|
||||
rerun URL contract: embedded `SETUP_SCRIPT_URL` values must carry the exact
|
||||
selected `host`, `pulse_url`, and `backup_perms` query state instead of
|
||||
|
|
|
|||
|
|
@ -59,47 +59,36 @@ cloud-specific enforcement rules.
|
|||
36. `frontend-modern/src/App.tsx`
|
||||
37. `frontend-modern/src/AppLayout.tsx`
|
||||
38. `frontend-modern/src/useAppRuntimeState.ts`
|
||||
39. `frontend-modern/src/components/Commercial/MonitoredSystemDefinitionDisclosure.tsx`
|
||||
40. `frontend-modern/src/components/Settings/BillingAdminPanel.tsx`
|
||||
41. `frontend-modern/src/components/Settings/BillingAdminOrganizationsTable.tsx`
|
||||
42. `frontend-modern/src/components/Settings/OrganizationBillingPanel.tsx`
|
||||
43. `frontend-modern/src/components/Settings/OrganizationBillingLoadingState.tsx`
|
||||
44. `frontend-modern/src/components/Settings/MonitoredSystemLedgerPanel.tsx`
|
||||
45. `frontend-modern/src/components/Settings/MonitoredSystemImpactPreview.tsx`
|
||||
46. `frontend-modern/src/components/Settings/ProLicensePanel.tsx`
|
||||
47. `frontend-modern/src/components/Settings/ProLicensePlanSection.tsx`
|
||||
48. `frontend-modern/src/components/Settings/CommercialBillingSections.tsx`
|
||||
49. `frontend-modern/src/components/Settings/SelfHostedCommercialRecoverySection.tsx`
|
||||
50. `frontend-modern/src/components/Settings/RelaySettingsPanel.tsx`
|
||||
51. `frontend-modern/src/components/Settings/RelayPairingSection.tsx`
|
||||
52. `frontend-modern/src/components/Settings/useBillingAdminPanelState.ts`
|
||||
53. `frontend-modern/src/components/Settings/useOrganizationBillingPanelState.ts`
|
||||
54. `frontend-modern/src/components/Settings/useProLicensePanelState.ts`
|
||||
55. `frontend-modern/src/components/Settings/useRelaySettingsPanelState.ts`
|
||||
56. `frontend-modern/src/pages/CloudPricing.tsx`
|
||||
57. `frontend-modern/src/pages/HostedSignup.tsx`
|
||||
58. `frontend-modern/src/pages/PricingHandoff.tsx`
|
||||
59. `frontend-modern/src/utils/apiClient.ts`
|
||||
60. `frontend-modern/src/utils/cloudPlans.ts`
|
||||
61. `frontend-modern/src/utils/commercialBillingModel.ts`
|
||||
62. `frontend-modern/src/utils/licensePresentation.ts`
|
||||
63. `frontend-modern/src/utils/monitoredSystemPresentation.ts`
|
||||
64. `frontend-modern/src/utils/pricingHandoff.ts`
|
||||
65. `frontend-modern/src/utils/selfHostedPlans.ts`
|
||||
66. `frontend-modern/src/utils/upgradePresentation.ts`
|
||||
67. `frontend-modern/src/components/Settings/selfHostedBillingPresentation.ts`
|
||||
68. `pulse-pro:license-server/public_pricing.go`
|
||||
69. `pulse-pro:license-server/v6_checkout.go`
|
||||
70. `pulse-pro:landing-page/thanks.html`
|
||||
71. `pulse-pro:scripts/grandfathered_recurring_cutover_preview.py`
|
||||
72. `pulse-pro:scripts/validate_public_pricing_model.py`
|
||||
73. `pulse-pro:V6_LAUNCH_CHECKLIST.md`
|
||||
74. `pkg/licensing/trial_activation_public_key_override_dev.go`
|
||||
75. `pkg/licensing/trial_activation_public_key_override_release.go`
|
||||
76. `pkg/licensing/testing_helpers.go`
|
||||
77. `pkg/licensing/self_hosted_feature_catalog.go`
|
||||
78. `frontend-modern/src/utils/selfHostedFeatureCatalog.generated.ts`
|
||||
79. `pulse-pro:license-server/self_hosted_feature_catalog.generated.go`
|
||||
39. `frontend-modern/src/components/Settings/BillingAdminPanel.tsx`
|
||||
40. `frontend-modern/src/components/Settings/BillingAdminOrganizationsTable.tsx`
|
||||
41. `frontend-modern/src/components/Settings/OrganizationBillingPanel.tsx`
|
||||
42. `frontend-modern/src/components/Settings/OrganizationBillingLoadingState.tsx`
|
||||
43. `frontend-modern/src/components/Settings/MonitoredSystemImpactPreview.tsx`
|
||||
44. `frontend-modern/src/components/Settings/ProLicensePanel.tsx`
|
||||
45. `frontend-modern/src/components/Settings/ProLicensePlanSection.tsx`
|
||||
46. `frontend-modern/src/components/Settings/CommercialBillingSections.tsx`
|
||||
47. `frontend-modern/src/components/Settings/SelfHostedCommercialRecoverySection.tsx`
|
||||
48. `frontend-modern/src/components/Settings/RelaySettingsPanel.tsx`
|
||||
49. `frontend-modern/src/components/Settings/RelayPairingSection.tsx`
|
||||
50. `frontend-modern/src/components/Settings/useBillingAdminPanelState.ts`
|
||||
51. `frontend-modern/src/components/Settings/useOrganizationBillingPanelState.ts`
|
||||
52. `frontend-modern/src/components/Settings/useProLicensePanelState.ts`
|
||||
53. `frontend-modern/src/components/Settings/useRelaySettingsPanelState.ts`
|
||||
54. `frontend-modern/src/pages/PricingHandoff.tsx`
|
||||
55. `frontend-modern/src/utils/apiClient.ts`
|
||||
56. `frontend-modern/src/utils/cloudPlans.ts`
|
||||
57. `frontend-modern/src/utils/commercialBillingModel.ts`
|
||||
58. `frontend-modern/src/utils/licensePresentation.ts`
|
||||
59. `frontend-modern/src/utils/monitoredSystemPresentation.ts`
|
||||
60. `frontend-modern/src/utils/pricingHandoff.ts`
|
||||
61. `frontend-modern/src/utils/selfHostedPlans.ts`
|
||||
62. `frontend-modern/src/utils/upgradePresentation.ts`
|
||||
63. `frontend-modern/src/components/Settings/selfHostedBillingPresentation.ts`
|
||||
64. `pkg/licensing/trial_activation_public_key_override_dev.go`
|
||||
65. `pkg/licensing/trial_activation_public_key_override_release.go`
|
||||
66. `pkg/licensing/testing_helpers.go`
|
||||
67. `pkg/licensing/self_hosted_feature_catalog.go`
|
||||
68. `frontend-modern/src/utils/selfHostedFeatureCatalog.generated.ts`
|
||||
80. `internal/cloudcp/server.go`, `internal/cloudcp/authz.go`, `internal/cloudcp/commercial_identity.go`, `internal/cloudcp/security.go`
|
||||
81. `internal/cloudcp/health_monitor.go`, `internal/cloudcp/health_stuck_provisioning.go`, `internal/cloudcp/tenant_state_metrics.go`, `internal/cloudcp/ratelimit.go`
|
||||
82. `internal/cloudcp/hosted_entitlement_handlers.go`, `internal/cloudcp/url_helpers.go`
|
||||
|
|
@ -109,7 +98,6 @@ cloud-specific enforcement rules.
|
|||
86. `internal/cloudcp/handoff/handler.go`, `internal/cloudcp/handoff/handoff.go`
|
||||
87. `internal/cloudcp/stripe/grace_enforcer.go`, `internal/cloudcp/stripe/helpers.go`, `internal/cloudcp/stripe/reconciler.go`, `internal/cloudcp/stripe/webhook.go`
|
||||
88. `internal/hosted/hosted_metrics.go`, `internal/hosted/reaper.go`
|
||||
89. `pulse-pro:ops/pulse-cloud/audit/`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
|
|
@ -342,7 +330,6 @@ or other self-hosted uncapped continuity plans.
|
|||
show active historical `subscription_state=trial` entitlement state, but
|
||||
they must not turn `trial_eligible`, `trial_eligibility_reason`, or an
|
||||
expired trial marker into a default Pro CTA or banner.
|
||||
17. Add or change monitored-system ledger, disclosure, or impact-preview presentation through `frontend-modern/src/components/Settings/MonitoredSystemLedgerPanel.tsx`, `frontend-modern/src/components/Settings/MonitoredSystemImpactPreview.tsx`, `frontend-modern/src/components/Commercial/MonitoredSystemDefinitionDisclosure.tsx`, and `frontend-modern/src/utils/monitoredSystemPresentation.ts`
|
||||
18. Add or change paid relay settings and pairing presentation through `frontend-modern/src/components/Settings/RelaySettingsPanel.tsx`, `frontend-modern/src/components/Settings/RelayPairingSection.tsx`, and `frontend-modern/src/components/Settings/useRelaySettingsPanelState.ts`. The retired Dashboard shell must not be restored to carry a Relay onboarding card or equivalent blanket upsell — relay discovery stays inside its owning settings surface.
|
||||
Public demo and other read-only presentation policy states must suppress
|
||||
relay setup and upsell onboarding instead of inviting pairing or commercial
|
||||
|
|
@ -354,22 +341,6 @@ or other self-hosted uncapped continuity plans.
|
|||
Relay settings and public commercial docs must also keep Remote Access
|
||||
positioned as a Relay-and-higher capability, not a Pro-only feature, so the
|
||||
Relay tier remains a tangible standalone paid product.
|
||||
19. Add or change cloud plan presentation through `frontend-modern/src/pages/CloudPricing.tsx`
|
||||
That same presentation boundary also owns truthful customer-entry copy for
|
||||
hosted Cloud pricing and signup. Cloud CTA labels, setup steps, and
|
||||
returning-account wording in `frontend-modern/src/pages/HostedSignup.tsx`,
|
||||
`frontend-modern/src/utils/cloudPlans.ts`, and adjacent public Cloud entry
|
||||
surfaces must describe the real commercial flow as secure checkout ->
|
||||
Pulse Account -> open workspace, not as an immediate workspace creation or
|
||||
trial-only shortcut.
|
||||
Public hosted Cloud trial signup must state the trial duration and
|
||||
checkout economics before Stripe handoff: Stripe may collect a payment
|
||||
method, but the subscription starts with the configured trial period and no
|
||||
upfront charge, then Pulse Account opens the provisioned workspace after
|
||||
checkout completes. The app-facing Cloud pricing and hosted-signup pages
|
||||
must use the same shared copy contract so product, portal, and public entry
|
||||
points do not drift on trial duration, payment-method collection, or upfront
|
||||
charge expectations.
|
||||
20. Add contract tests where runtime and pricing need to stay aligned
|
||||
21. Add or change hosted browser org-context bootstrap through `frontend-modern/src/App.tsx`, `frontend-modern/src/AppLayout.tsx`, `frontend-modern/src/useAppRuntimeState.ts`, and `frontend-modern/src/utils/apiClient.ts`
|
||||
That same hosted bootstrap boundary also owns the runtime-capability JSON
|
||||
|
|
|
|||
|
|
@ -28,82 +28,82 @@ server-side update execution surfaces.
|
|||
6. `internal/cloudcp/docker/manager.go`
|
||||
7. `internal/cloudcp/docker/labels.go`
|
||||
8. `internal/cloudcp/tenant_runtime_rollout.go`
|
||||
8. `.github/workflows/create-release.yml`
|
||||
9. `.github/workflows/deploy-demo-server.yml`
|
||||
10. `.github/workflows/helm-pages.yml`
|
||||
11. `.github/workflows/promote-floating-tags.yml`
|
||||
12. `.github/workflows/publish-docker.yml`
|
||||
13. `.github/workflows/publish-helm-chart.yml`
|
||||
14. `.github/workflows/release-dry-run.yml`
|
||||
15. `.github/workflows/update-demo-server.yml`
|
||||
16. `.github/workflows/validate-release-assets.yml`
|
||||
17. `.github/workflows/install-sh-smoke.yml`
|
||||
16. `.github/ISSUE_TEMPLATE/v6_rc_feedback.yml`
|
||||
17. `docs/RELEASE_NOTES.md`
|
||||
18. `docs/releases/`
|
||||
19. `docs/UPGRADE_v6.md`
|
||||
20. `docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md`
|
||||
21. `docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md`
|
||||
22. `docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md`
|
||||
23. `package.json`
|
||||
24. `package-lock.json`
|
||||
25. `frontend-modern/package.json`
|
||||
26. `frontend-modern/package-lock.json`
|
||||
27. `frontend-modern/vite.config.ts`
|
||||
28. `go.mod`
|
||||
29. `go.sum`
|
||||
30. `scripts/build-release.sh`
|
||||
31. `scripts/check-workflow-dispatch-inputs.py`
|
||||
32. `scripts/clean-mock-alerts.sh`
|
||||
33. `scripts/com.pulse.hot-dev.plist.template`
|
||||
34. `scripts/dev-check.sh`
|
||||
35. `scripts/dev-deploy-agent.sh`
|
||||
36. `scripts/dev-launchd-setup.sh`
|
||||
37. `scripts/dev-launchd-wrapper.sh`
|
||||
38. `scripts/hot-dev-bg.sh`
|
||||
39. `scripts/hot-dev.sh`
|
||||
40. `scripts/lib/hot-dev-runtime.sh`
|
||||
41. `scripts/lib/hot-dev-auth.sh`
|
||||
42. `scripts/install-container-agent.sh`
|
||||
43. `install.sh`
|
||||
44. `scripts/install.ps1`
|
||||
45. `scripts/install.sh`
|
||||
46. `scripts/install-mcp.sh`
|
||||
47. `scripts/install-mcp.ps1`
|
||||
48. `cmd/pulse-mcp/`
|
||||
49. `scripts/pulse-auto-update.sh`
|
||||
50. `scripts/release_control/internal/record_rc_to_ga_rehearsal.py`
|
||||
51. `scripts/release_control/record_rc_to_ga_rehearsal.py`
|
||||
52. `scripts/release_control/release_promotion_policy_support.py`
|
||||
53. `scripts/release_control/resolve_release_promotion.py`
|
||||
54. `scripts/release_ldflags.sh`
|
||||
55. `scripts/run_cloud_public_signup_smoke.sh`
|
||||
56. `scripts/run_demo_public_browser_smoke.sh`
|
||||
57. `scripts/demo_public_browser_smoke.cjs`
|
||||
58. `scripts/run_hosted_staging_smoke.sh`
|
||||
59. `scripts/trigger-release-dry-run.sh`
|
||||
60. `scripts/trigger-release.sh`
|
||||
61. `scripts/toggle-mock.sh`
|
||||
62. `deploy/helm/pulse/`
|
||||
63. `tests/integration/playwright.config.ts`
|
||||
64. `tests/integration/QUICK_START.md`
|
||||
65. `tests/integration/README.md`
|
||||
66. `tests/integration/scripts/bootstrap-hosted-mobile-onboarding.mjs`
|
||||
67. `tests/integration/scripts/hosted-mobile-token-runtime.mjs`
|
||||
68. `tests/integration/scripts/hosted-tenant-approval-store.mjs`
|
||||
69. `tests/integration/scripts/hosted-tenant-runtime.mjs`
|
||||
70. `tests/integration/scripts/hosted-tenant-runtime-restart.mjs`
|
||||
71. `tests/integration/scripts/managed-dev-runtime.mjs`
|
||||
72. `tests/integration/scripts/relay-mobile-token-helper.go`
|
||||
73. `tests/integration/tests/helpers.ts`
|
||||
74. `tests/integration/tests/runtime-defaults.ts`
|
||||
75. `docker-compose.yml`
|
||||
76. `scripts/install-docker.sh`
|
||||
77. `scripts/validate-published-release.sh`
|
||||
78. `scripts/validate-release.sh`
|
||||
79. `scripts/release_asset_common.sh`
|
||||
80. `scripts/backfill-release-assets.sh`
|
||||
81. `.github/workflows/backfill-release-assets.yml`
|
||||
9. `.github/workflows/create-release.yml`
|
||||
10. `.github/workflows/deploy-demo-server.yml`
|
||||
11. `.github/workflows/helm-pages.yml`
|
||||
12. `.github/workflows/promote-floating-tags.yml`
|
||||
13. `.github/workflows/publish-docker.yml`
|
||||
14. `.github/workflows/publish-helm-chart.yml`
|
||||
15. `.github/workflows/release-dry-run.yml`
|
||||
16. `.github/workflows/update-demo-server.yml`
|
||||
17. `.github/workflows/validate-release-assets.yml`
|
||||
18. `.github/workflows/install-sh-smoke.yml`
|
||||
19. `.github/ISSUE_TEMPLATE/v6_rc_feedback.yml`
|
||||
20. `docs/RELEASE_NOTES.md`
|
||||
21. `docs/releases/`
|
||||
22. `docs/UPGRADE_v6.md`
|
||||
23. `docs/release-control/v6/internal/PRE_RELEASE_CHECKLIST.md`
|
||||
24. `docs/release-control/v6/internal/RC_TO_GA_REHEARSAL_TEMPLATE.md`
|
||||
25. `docs/release-control/v6/internal/RELEASE_PROMOTION_POLICY.md`
|
||||
26. `package.json`
|
||||
27. `package-lock.json`
|
||||
28. `frontend-modern/package.json`
|
||||
29. `frontend-modern/package-lock.json`
|
||||
30. `frontend-modern/vite.config.ts`
|
||||
31. `go.mod`
|
||||
32. `go.sum`
|
||||
33. `scripts/build-release.sh`
|
||||
34. `scripts/check-workflow-dispatch-inputs.py`
|
||||
35. `scripts/clean-mock-alerts.sh`
|
||||
36. `scripts/com.pulse.hot-dev.plist.template`
|
||||
37. `scripts/dev-check.sh`
|
||||
38. `scripts/dev-deploy-agent.sh`
|
||||
39. `scripts/dev-launchd-setup.sh`
|
||||
40. `scripts/dev-launchd-wrapper.sh`
|
||||
41. `scripts/hot-dev-bg.sh`
|
||||
42. `scripts/hot-dev.sh`
|
||||
43. `scripts/lib/hot-dev-runtime.sh`
|
||||
44. `scripts/lib/hot-dev-auth.sh`
|
||||
45. `scripts/install-container-agent.sh`
|
||||
46. `install.sh`
|
||||
47. `scripts/install.ps1`
|
||||
48. `scripts/install.sh`
|
||||
49. `scripts/install-mcp.sh`
|
||||
50. `scripts/install-mcp.ps1`
|
||||
51. `cmd/pulse-mcp/`
|
||||
52. `scripts/pulse-auto-update.sh`
|
||||
53. `scripts/release_control/internal/record_rc_to_ga_rehearsal.py`
|
||||
54. `scripts/release_control/record_rc_to_ga_rehearsal.py`
|
||||
55. `scripts/release_control/release_promotion_policy_support.py`
|
||||
56. `scripts/release_control/resolve_release_promotion.py`
|
||||
57. `scripts/release_ldflags.sh`
|
||||
58. `scripts/run_cloud_public_signup_smoke.sh`
|
||||
59. `scripts/run_demo_public_browser_smoke.sh`
|
||||
60. `scripts/demo_public_browser_smoke.cjs`
|
||||
61. `scripts/run_hosted_staging_smoke.sh`
|
||||
62. `scripts/trigger-release-dry-run.sh`
|
||||
63. `scripts/trigger-release.sh`
|
||||
64. `scripts/toggle-mock.sh`
|
||||
65. `deploy/helm/pulse/`
|
||||
66. `tests/integration/playwright.config.ts`
|
||||
67. `tests/integration/QUICK_START.md`
|
||||
68. `tests/integration/README.md`
|
||||
69. `tests/integration/scripts/bootstrap-hosted-mobile-onboarding.mjs`
|
||||
70. `tests/integration/scripts/hosted-mobile-token-runtime.mjs`
|
||||
71. `tests/integration/scripts/hosted-tenant-approval-store.mjs`
|
||||
72. `tests/integration/scripts/hosted-tenant-runtime.mjs`
|
||||
73. `tests/integration/scripts/hosted-tenant-runtime-restart.mjs`
|
||||
74. `tests/integration/scripts/managed-dev-runtime.mjs`
|
||||
75. `tests/integration/scripts/relay-mobile-token-helper.go`
|
||||
76. `tests/integration/tests/helpers.ts`
|
||||
77. `tests/integration/tests/runtime-defaults.ts`
|
||||
78. `docker-compose.yml`
|
||||
79. `scripts/install-docker.sh`
|
||||
80. `scripts/validate-published-release.sh`
|
||||
81. `scripts/validate-release.sh`
|
||||
82. `scripts/release_asset_common.sh`
|
||||
83. `scripts/backfill-release-assets.sh`
|
||||
84. `.github/workflows/backfill-release-assets.yml`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
|
|
@ -255,7 +255,7 @@ server-side update execution surfaces.
|
|||
operator support packet must describe that same candidate instead of leaving
|
||||
the branch on a newer version string while the in-repo packet still speaks
|
||||
for an older RC.
|
||||
Later corrective RCs such as `rc.3`, `rc.4`, and `rc.5` must also carry the live stable
|
||||
Later corrective RCs such as `rc.3`, `rc.4`, `rc.5`, and `rc.6` must also carry the live stable
|
||||
rollback target and any prerelease trust-root continuity caveat in the
|
||||
current release notes, changelog, operator support pack, upgrade guide, and
|
||||
release-control evidence record before the release workflow is dispatched.
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
"registry_file": "docs/release-control/v6/internal/subsystems/registry.json",
|
||||
"dependency_subsystem_ids": [
|
||||
"agent-lifecycle",
|
||||
"cloud-paid",
|
||||
"storage-recovery"
|
||||
]
|
||||
}
|
||||
|
|
@ -85,83 +84,80 @@ work extends shared components instead of creating new local variants.
|
|||
59. `frontend-modern/src/components/shared/FilterBar/index.ts`
|
||||
59a. `frontend-modern/src/components/shared/FilterBar/SavedViewsMenu.tsx`
|
||||
59b. `frontend-modern/src/components/shared/FilterBar/useSavedViews.ts`
|
||||
56. `frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts`
|
||||
57. `frontend-modern/src/features/`
|
||||
58. `frontend-modern/src/components/SetupWizard/SetupWizard.tsx`
|
||||
59. `frontend-modern/src/components/Settings/useSettingsInfrastructurePanelProps.ts`
|
||||
60. `frontend-modern/src/components/SetupWizard/SetupCompletionPreview.tsx`
|
||||
61. `frontend-modern/src/components/SetupWizard/steps/WelcomeStep.tsx`
|
||||
62. `frontend-modern/src/components/SetupWizard/__tests__/SetupWizard.test.tsx`
|
||||
63. `frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPreview.test.tsx`
|
||||
64. `frontend-modern/src/components/SetupWizard/__tests__/WelcomeStep.test.tsx`
|
||||
66. `frontend-modern/src/components/Settings/SystemLogsPanel.tsx`
|
||||
67. `frontend-modern/src/components/Settings/useSystemLogsPanelState.ts`
|
||||
68. `frontend-modern/src/utils/systemLogsPresentation.ts`
|
||||
69. `frontend-modern/src/components/Settings/__tests__/SystemLogsPanel.test.tsx`
|
||||
70. `frontend-modern/src/components/Settings/ResourcePicker.tsx`
|
||||
71. `frontend-modern/src/components/Settings/reportingResourceTypes.ts`
|
||||
72. `frontend-modern/src/utils/reportableResourceTypes.ts`
|
||||
73. `frontend-modern/src/utils/reportingResourceTypes.ts`
|
||||
74. `frontend-modern/src/utils/problemResourcePresentation.ts`
|
||||
75. `frontend-modern/src/utils/workloadEmptyStatePresentation.ts`
|
||||
76. `frontend-modern/src/utils/workloadGuestPresentation.ts`
|
||||
78. `frontend-modern/src/utils/emptyStatePresentation.ts`
|
||||
79. `frontend-modern/src/utils/semanticTonePresentation.ts`
|
||||
80. `frontend-modern/src/components/Toast/Toast.tsx`
|
||||
81. `frontend-modern/src/utils/toast.ts`
|
||||
82. `frontend-modern/src/utils/semanticTonePresentation.ts`
|
||||
83. `frontend-modern/src/utils/emptyStatePresentation.ts`
|
||||
84. `frontend-modern/src/utils/typeColumnPresentation.ts`
|
||||
85. `frontend-modern/src/components/Settings/NetworkBoundarySettingsSection.tsx`
|
||||
86. `frontend-modern/src/components/Settings/networkSettingsModel.ts`
|
||||
87. `frontend-modern/src/components/Settings/useDiscoverySettingsState.ts`
|
||||
88. `frontend-modern/src/components/Settings/useSettingsInfrastructurePanelProps.ts`
|
||||
89. `frontend-modern/src/components/Settings/AvailabilitySettingsPanel.tsx`
|
||||
90. `frontend-modern/src/components/Settings/availabilitySettingsModel.ts`
|
||||
91. `frontend-modern/src/components/Settings/settingsPanelRegistryContext.tsx`
|
||||
92. `frontend-modern/src/components/Settings/settingsPanelRegistryLoaders.ts`
|
||||
93. `frontend-modern/src/components/Settings/settingsNavigationModel.ts`
|
||||
94. `frontend-modern/src/components/Settings/settingsNavCatalog.ts`
|
||||
95. `frontend-modern/src/components/Settings/settingsNavVisibility.ts`
|
||||
96. `frontend-modern/src/components/Settings/settingsRouting.ts`
|
||||
97. `frontend-modern/src/components/Settings/settingsTabSaveBehavior.ts`
|
||||
98. `frontend-modern/src/components/Settings/settingsTypes.ts`
|
||||
99. `frontend-modern/src/components/Settings/useSettingsNavigation.ts`
|
||||
100. `frontend-modern/src/components/Settings/useSettingsPanelRegistry.tsx`
|
||||
101. `frontend-modern/src/components/Settings/useSettingsSystemPanels.tsx`
|
||||
102. `frontend-modern/src/components/Settings/DockerRuntimeSettingsCard.tsx`
|
||||
103. `frontend-modern/src/components/shared/EnvironmentLockBadge.tsx`
|
||||
104. `frontend-modern/src/utils/environmentLockPresentation.ts`
|
||||
105. `frontend-modern/src/utils/docsLinks.ts`
|
||||
106. `tests/integration/tests/20-local-doc-links.spec.ts`
|
||||
107. `frontend-modern/src/index.css`
|
||||
108. `frontend-modern/src/components/shared/summaryInteractionA11y.ts`
|
||||
109. `frontend-modern/src/components/shared/SummaryRowActionButton.tsx`
|
||||
110. `frontend-modern/src/hooks/createNonSuspendingQuery.ts`
|
||||
111. `frontend-modern/src/components/shared/TableCardHeader.tsx`
|
||||
112. `frontend-modern/src/components/shared/SummaryTableCardHeader.tsx`
|
||||
60. `frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts`
|
||||
61. `frontend-modern/src/features/`
|
||||
62. `frontend-modern/src/components/SetupWizard/SetupWizard.tsx`
|
||||
63. `frontend-modern/src/components/Settings/useSettingsInfrastructurePanelProps.ts`
|
||||
64. `frontend-modern/src/components/SetupWizard/SetupCompletionPreview.tsx`
|
||||
65. `frontend-modern/src/components/SetupWizard/steps/WelcomeStep.tsx`
|
||||
66. `frontend-modern/src/components/SetupWizard/__tests__/SetupWizard.test.tsx`
|
||||
67. `frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPreview.test.tsx`
|
||||
68. `frontend-modern/src/components/SetupWizard/__tests__/WelcomeStep.test.tsx`
|
||||
69. `frontend-modern/src/components/Settings/SystemLogsPanel.tsx`
|
||||
70. `frontend-modern/src/components/Settings/useSystemLogsPanelState.ts`
|
||||
71. `frontend-modern/src/utils/systemLogsPresentation.ts`
|
||||
72. `frontend-modern/src/components/Settings/__tests__/SystemLogsPanel.test.tsx`
|
||||
73. `frontend-modern/src/components/Settings/ResourcePicker.tsx`
|
||||
74. `frontend-modern/src/components/Settings/reportingResourceTypes.ts`
|
||||
75. `frontend-modern/src/utils/reportableResourceTypes.ts`
|
||||
76. `frontend-modern/src/utils/reportingResourceTypes.ts`
|
||||
77. `frontend-modern/src/utils/workloadEmptyStatePresentation.ts`
|
||||
78. `frontend-modern/src/utils/workloadGuestPresentation.ts`
|
||||
79. `frontend-modern/src/utils/emptyStatePresentation.ts`
|
||||
80. `frontend-modern/src/utils/semanticTonePresentation.ts`
|
||||
81. `frontend-modern/src/components/Toast/Toast.tsx`
|
||||
82. `frontend-modern/src/utils/toast.ts`
|
||||
83. `frontend-modern/src/utils/semanticTonePresentation.ts`
|
||||
84. `frontend-modern/src/utils/emptyStatePresentation.ts`
|
||||
85. `frontend-modern/src/utils/typeColumnPresentation.ts`
|
||||
86. `frontend-modern/src/components/Settings/NetworkBoundarySettingsSection.tsx`
|
||||
87. `frontend-modern/src/components/Settings/networkSettingsModel.ts`
|
||||
88. `frontend-modern/src/components/Settings/useDiscoverySettingsState.ts`
|
||||
89. `frontend-modern/src/components/Settings/useSettingsInfrastructurePanelProps.ts`
|
||||
90. `frontend-modern/src/components/Settings/AvailabilitySettingsPanel.tsx`
|
||||
91. `frontend-modern/src/components/Settings/availabilitySettingsModel.ts`
|
||||
92. `frontend-modern/src/components/Settings/settingsPanelRegistryContext.tsx`
|
||||
93. `frontend-modern/src/components/Settings/settingsPanelRegistryLoaders.ts`
|
||||
94. `frontend-modern/src/components/Settings/settingsNavigationModel.ts`
|
||||
95. `frontend-modern/src/components/Settings/settingsNavCatalog.ts`
|
||||
96. `frontend-modern/src/components/Settings/settingsNavVisibility.ts`
|
||||
97. `frontend-modern/src/components/Settings/settingsRouting.ts`
|
||||
98. `frontend-modern/src/components/Settings/settingsTabSaveBehavior.ts`
|
||||
99. `frontend-modern/src/components/Settings/settingsTypes.ts`
|
||||
100. `frontend-modern/src/components/Settings/useSettingsNavigation.ts`
|
||||
101. `frontend-modern/src/components/Settings/useSettingsPanelRegistry.tsx`
|
||||
102. `frontend-modern/src/components/Settings/useSettingsSystemPanels.tsx`
|
||||
103. `frontend-modern/src/components/Settings/DockerRuntimeSettingsCard.tsx`
|
||||
104. `frontend-modern/src/components/shared/EnvironmentLockBadge.tsx`
|
||||
105. `frontend-modern/src/utils/environmentLockPresentation.ts`
|
||||
106. `frontend-modern/src/utils/docsLinks.ts`
|
||||
107. `tests/integration/tests/20-local-doc-links.spec.ts`
|
||||
108. `frontend-modern/src/index.css`
|
||||
109. `frontend-modern/src/components/shared/summaryInteractionA11y.ts`
|
||||
110. `frontend-modern/src/components/shared/SummaryRowActionButton.tsx`
|
||||
111. `frontend-modern/src/hooks/createNonSuspendingQuery.ts`
|
||||
112. `frontend-modern/src/components/shared/TableCardHeader.tsx`
|
||||
113. `frontend-modern/src/components/shared/UpgradeLink.tsx`
|
||||
114. `frontend-modern/src/components/shared/useUpgradeNavigation.ts`
|
||||
115. `frontend-modern/src/utils/upgradeNavigation.ts`
|
||||
116. `frontend-modern/src/components/DemoBanner.tsx`
|
||||
117. `frontend-modern/src/components/Login.tsx`
|
||||
118. `frontend-modern/src/stores/demoMode.ts`
|
||||
119. `frontend-modern/src/stores/sessionCapabilities.ts`
|
||||
120. `frontend-modern/src/stores/sessionPresentationPolicy.ts`
|
||||
121. `frontend-modern/src/stores/licenseCommercial.ts`
|
||||
122. `frontend-modern/src/useAppRuntimeState.ts`
|
||||
123. `frontend-modern/src/routing/routePreload.ts`
|
||||
124. `frontend-modern/src/stores/aiChat.ts`
|
||||
125. `frontend-modern/scripts/header-audit.mjs`
|
||||
126. `frontend-modern/src/components/Settings/DataHandlingPanel.tsx`
|
||||
127. `frontend-modern/src/components/Settings/dataHandlingPanelModel.ts`
|
||||
128. `frontend-modern/scripts/canonical-platform-audit.mjs`
|
||||
129. `frontend-modern/scripts/settings-diagnostics-boundary-audit.mjs`
|
||||
130. `frontend-modern/src/utils/platformSupportManifest.generated.ts`
|
||||
131. `frontend-modern/src/utils/platformSupportManifest.ts`
|
||||
132. `frontend-modern/src/utils/sourcePlatformOptions.ts`
|
||||
133. `frontend-modern/src/utils/sourcePlatforms.ts`
|
||||
134. `frontend-modern/src/utils/infrastructureOnboardingPresentation.ts`
|
||||
118. `frontend-modern/src/stores/sessionCapabilities.ts`
|
||||
119. `frontend-modern/src/stores/sessionPresentationPolicy.ts`
|
||||
120. `frontend-modern/src/stores/licenseCommercial.ts`
|
||||
121. `frontend-modern/src/useAppRuntimeState.ts`
|
||||
122. `frontend-modern/src/routing/routePreload.ts`
|
||||
123. `frontend-modern/src/stores/aiChat.ts`
|
||||
124. `frontend-modern/scripts/header-audit.mjs`
|
||||
125. `frontend-modern/src/components/Settings/DataHandlingPanel.tsx`
|
||||
126. `frontend-modern/src/components/Settings/dataHandlingPanelModel.ts`
|
||||
127. `frontend-modern/scripts/canonical-platform-audit.mjs`
|
||||
128. `frontend-modern/scripts/settings-diagnostics-boundary-audit.mjs`
|
||||
129. `frontend-modern/src/utils/platformSupportManifest.generated.ts`
|
||||
130. `frontend-modern/src/utils/platformSupportManifest.ts`
|
||||
131. `frontend-modern/src/utils/sourcePlatformOptions.ts`
|
||||
132. `frontend-modern/src/utils/sourcePlatforms.ts`
|
||||
133. `frontend-modern/src/utils/infrastructureOnboardingPresentation.ts`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
|
|
@ -436,121 +432,6 @@ not a replacement status card, CTA band, or page-local nested card.
|
|||
apply controlled `value` props after options are mounted so settings panels
|
||||
such as workload discovery show the persisted option instead of falling back
|
||||
to the first option while the collapsed summary shows a different value.
|
||||
2. Route new top-level settings surfaces through the canonical settings shell
|
||||
instead of introducing page-local framing.
|
||||
When a new operator-facing concern is closely related to an
|
||||
existing tab's intent, prefer adding it as a sibling
|
||||
`SettingsPanel` inside that tab's container component over
|
||||
minting a new top-level tab. The agent-integrations surface
|
||||
added in slice 59 follows this pattern:
|
||||
`frontend-modern/src/components/Settings/AgentIntegrationsPanel.tsx`
|
||||
ships under the existing API Access tab via
|
||||
`APIAccessPanel.tsx`'s composition, not as its own tab. This
|
||||
keeps the tab inventory bounded, avoids touching
|
||||
`settingsNavigationModel.ts`, the registry, the loaders, and
|
||||
the routing tests for additive sub-surfaces, and presents
|
||||
"tokens + what those tokens unlock" as one operator-facing
|
||||
story.
|
||||
Shared shells and primitives that need websocket or dark-mode context must
|
||||
consume `frontend-modern/src/contexts/appRuntime.ts`; they must not import
|
||||
`frontend-modern/src/App.tsx`, because `App.tsx` owns provider placement
|
||||
while frontend primitives own reusable consumption.
|
||||
That same shared shell boundary now also owns thin public-route handoff
|
||||
presentation in `frontend-modern/src/App.tsx`: compatibility routes such as
|
||||
`/pricing` may stay outside authenticated chrome, but they must remain
|
||||
minimal handoff shells that defer destination truth to the owning subsystem
|
||||
instead of embedding a second copy of public marketing or checkout UI inside
|
||||
the product runtime.
|
||||
Cloud acquisition follows that same app-shell rule: ordinary self-hosted
|
||||
frontend primitives must not register `/cloud` or `/cloud/signup` as public
|
||||
product-runtime routes, because Cloud signup belongs to Pulse Account and
|
||||
the Cloud control plane rather than a local in-product trial page.
|
||||
The former top-level `/infrastructure`, `/workloads`, `/storage`, and
|
||||
`/recovery` operator routes never shipped as stable v6 surfaces and must
|
||||
remain unregistered instead of being kept as compatibility redirects.
|
||||
Workload, storage, and recovery workflows live inside the owning
|
||||
platform/runtime pages and reusable component surfaces; they must not appear
|
||||
in navigation, command palette, shortcut, route-preload, or active-tab
|
||||
owners as standalone aggregate destinations. The old top-level `/ceph`
|
||||
alias is also unregistered; Proxmox owns Ceph at `/proxmox/ceph`.
|
||||
The same settings-shell boundary owns read-only landing posture: when the
|
||||
session presentation policy says the operator cannot manage setup, `/settings`
|
||||
and sidebar navigation must land on the canonical reporting/control surface
|
||||
instead of setup-oriented install routes.
|
||||
Route normalization must wait until that presentation policy has resolved
|
||||
before stripping infrastructure onboarding queries such as `?add=pick`,
|
||||
`?add=agent`, or `?add=detect`, so first-session and explicit add-flow
|
||||
handoffs do not lose their modal target during session bootstrap.
|
||||
When those infrastructure modal targets are preserved, the settings shell
|
||||
must keep the owning add-flow copy intact: the detect target is an API
|
||||
platform probe, not a generic infrastructure-source detector, and its outer
|
||||
dialog frame should match the management-API endpoint language owned by the
|
||||
agent-lifecycle onboarding contract.
|
||||
That same settings-shell boundary also owns explicit organization-route
|
||||
stability. Deep links such as `/settings/organization`,
|
||||
`/settings/organization/access`, and adjacent organization shells must keep
|
||||
their canonical header and page frame when the route itself is allowed,
|
||||
even while runtime capabilities or presentation policy are still settling.
|
||||
Shared shell filtering may hide the sidebar item until the governing state
|
||||
resolves, but `settingsHeaderMeta.ts`, `useSettingsAccess.ts`, and the
|
||||
canonical settings-shell tests must not bounce an allowed organization
|
||||
route back to `Infrastructure` just because nav filtering has not yet
|
||||
surfaced that tab.
|
||||
That same settings-shell boundary also owns authenticated operator identity
|
||||
propagation into organization panels.
|
||||
`frontend-modern/src/components/Settings/settingsPanelRegistryContext.tsx`
|
||||
must derive the effective username from the resolved security status
|
||||
(`proxyAuthUsername`, then `ssoSessionUsername`, then `authUsername`) and
|
||||
pass that identity into the organization overview, access, and sharing
|
||||
panels so deep-linked organization routes do not collapse into anonymous
|
||||
read-only shells under proxy-auth, SSO, or local-auth sessions.
|
||||
That same shared session-presentation boundary also owns alerts read-only
|
||||
posture: `/alerts` may continue exposing reporting tabs such as overview and
|
||||
history, but activation controls plus configuration routes must collapse out
|
||||
of the public-demo shell instead of advertising blocked management actions.
|
||||
That same public-demo presentation boundary also owns Settings support
|
||||
posture: the authenticated demo shell must not advertise `Diagnostics &
|
||||
Health`, `Data & Reports`, or `System Logs` in the Settings navigation, and
|
||||
the retired top-level `/operations/*` browser path must stay unregistered
|
||||
instead of reviving a standalone Operations utility tab or route-local
|
||||
support shell.
|
||||
Because `Data & Reports` is the `advanced_reporting` capability surface
|
||||
rather than a general diagnostics page, `settingsNavCatalog.ts` must hide it
|
||||
when that feature is unavailable; ordinary self-hosted users should see
|
||||
support diagnostics and logs without being shown a Pro-locked reporting tab,
|
||||
while paid instances keep the canonical `/settings/support/reporting` route
|
||||
and panel.
|
||||
Resource Privacy/Data Handling is a route-backed trust surface, not a
|
||||
commercial surface or default settings destination. The Settings shell must
|
||||
keep it governed by the Security registry/header/navigation model without
|
||||
advertising it in the normal sidebar while it remains informational only,
|
||||
and it must avoid trial, upgrade, paid-plan, or monitoring-limit copy when
|
||||
commercial presentation is hidden.
|
||||
General settings runtime cards that present source-platform actions must
|
||||
consume `frontend-modern/src/utils/systemSettingsPresentation.ts` and the
|
||||
shared source-platform vocabulary rather than card-local product names.
|
||||
`frontend-modern/src/components/Settings/DockerRuntimeSettingsCard.tsx`
|
||||
owns the local toggle layout, but Docker and Podman update-action titles,
|
||||
descriptions, environment variable display, and failure copy belong to
|
||||
`systemSettingsPresentation.ts` so settings surfaces do not drift back to
|
||||
generic container wording.
|
||||
Shared sparkline primitives must also stay CSP-safe by construction:
|
||||
`frontend-modern/src/components/shared/InteractiveSparkline.tsx` may use SVG
|
||||
attributes and shared state/model helpers for cursor, axis-label, and
|
||||
tooltip positioning, but it must not write inline `style=` attributes for
|
||||
tick labels, tooltip placement, or per-series transitions on the public
|
||||
shell. Axis labels must render in fixed-size SVG shells or another
|
||||
non-scaled primitive boundary; the shared sparkline must not put axis glyphs
|
||||
inside `preserveAspectRatio="none"` label viewBoxes that stretch text as the
|
||||
chart resizes.
|
||||
The same shared presentation boundary also owns reusable scroll containers:
|
||||
`frontend-modern/src/components/shared/Table.tsx` must keep touch-scroll
|
||||
behavior on classes and shared CSS in `frontend-modern/src/index.css`
|
||||
instead of reintroducing inline `style=` attributes for overflow or mobile
|
||||
scroll behavior. `frontend-modern/src/components/shared/PulseDataGrid.tsx`
|
||||
inherits that same boundary: shared data-grid shells must route scrollbar
|
||||
hiding and table-width sizing through shared classes plus HTML attributes,
|
||||
not inline overflow or min-width styles.
|
||||
3. Add feature-specific presentation only when no shared primitive should own it.
|
||||
Feature surfaces under `frontend-modern/src/features/` that display
|
||||
product labels must consume the owning subsystem's presentation utilities
|
||||
|
|
@ -880,36 +761,9 @@ not a replacement status card, CTA band, or page-local nested card.
|
|||
system badge names a platform with its version, source/method context may
|
||||
still add collection labels such as Pulse Agent, but it must not repeat the
|
||||
same platform again as an unversioned source badge.
|
||||
9. Keep top-of-page summary interaction on shared primitives. Infrastructure, workloads, and storage summary cards must route sticky-shell behavior through `frontend-modern/src/components/shared/StickySummarySection.tsx` and route row-hover or focused-series rendering through shared chart primitives such as `frontend-modern/src/components/shared/InteractiveSparkline.tsx` and `frontend-modern/src/components/shared/DensityMap.tsx`, rather than page-local sticky wrappers or metric-card-specific hover logic. When a page keeps summary charts visible below the desktop breakpoint, it must use the shared `stickyDesktopOnly` mode instead of adding page-local media queries, so wrapped two-column summaries scroll as normal content and only become sticky once the large-screen layout is active. The shared summary-card contract must also own stable summary-card geometry for chart-backed cards so row hover, focus, synchronized readouts, or idle header metadata cannot ratchet the sticky summary taller across rerenders. Shared chart slot geometry belongs in `frontend-modern/src/components/shared/summaryChartLayout.ts` so `SummaryMetricCard` and governed non-summary chart sections can consume the same normal and compact chart heights instead of re-declaring page-local `h-*` sizing.
|
||||
Storage's top-of-page summary scope is limited to the stable chart grid and
|
||||
shared row/group focus affordances. A rolling-history capacity planner must
|
||||
not be bolted onto the sticky summary shell as an extra frontend primitive;
|
||||
if capacity planning returns, it needs an owner-level model that can keep
|
||||
the summary geometry and visible card set stable across refreshes.
|
||||
10. Keep summary chart interaction identity on one shared helper. Summary surfaces that expose row-hover, group-hover, chart-hover, or route-focus-driven chart emphasis must derive page/group/entity scope through `frontend-modern/src/components/shared/summaryCardInteraction.ts` and pass that same resolved scope into card-state, sparkline, and density-map primitives, rather than letting cards read `hovered || focused` while charts listen to a different page-local ID source. Hovering one summary chart must promote that series into the shared active entity so sibling cards highlight the same object instead of keeping chart-local hover islands, and hovering or pinning a workload group header, infrastructure cluster header, or storage pool-group header must scope the matching summary cards through that same shared contract instead of forking a page-local summary filter path. Sibling cards should surface that synchronized hover as one compact header readout through the shared summary-card contract, while the chart under the pointer keeps the only floating tooltip. Recovery is explicitly outside this interaction dialect: its retired posture-card strip must not return with row/group/chart hover behavior without a separate governed product decision.
|
||||
11. Keep page summaries page-scoped when table rows enter contextual focus. Route-backed row selection may add a focused label and shared series emphasis, but infrastructure, workloads, and storage summary cards must continue to render the page-level series set instead of collapsing the summary down to the selected row or replacing the global trend view with row-local empty states.
|
||||
12. Keep contextual row focus on the shared summary primitive. Summary surfaces and same-route table drill-ins must reuse `frontend-modern/src/components/shared/contextualFocus.ts` for interactive-series filtering, focused-name lookup, active-series derivation, local scroll preservation, and deliberate inline-detail reveal instead of rebuilding page-local `Set` filters, focused-label scans, drawer-aware scroll math, or ad hoc scroll restoration in each surface.
|
||||
13. Keep summary-to-table coordination deliberate, explicit, and reversible. Shared summary hover may highlight the matching table row when it is already visible, but transient chart hover must not auto-filter tables, auto-scroll the page, or reshuffle table ordering. Pinned page/group/entity scope on workloads, infrastructure, or storage must stay row-first: the pinned row or group header is the visible scoped state, not a second strip or search-row widget. Page shells therefore must not reintroduce always-on scope banners, preview bars, page-local chips, breadcrumbs, or search/filter-row scope accessories just to explain pinned state. When the active row is off-screen, page owners must still route through `frontend-modern/src/components/shared/summaryTableFocus.ts` and surface a lightweight `Jump to row` affordance that reveals and scrolls only on explicit user action. That same shared table-focus owner now also owns reversible clearing: pinned scope may clear only from governed neutral interaction-surface space or the shared `Escape` path, with page owners binding a broader clear-surface root separately from the row-lookup table root when needed and supplying one page-level reset callback for filters plus summary-linked selections. Row cells, group headers, inline detail, summary cards, and explicit controls must not accidentally clear pinned scope, while governed table/card clear surfaces must still allow real user clicks on neutral whitespace to clear it. Deliberate row focus may reveal inline detail automatically, but that reveal must be drawer-aware: infrastructure and workload row toggles that already have the row in view must hand the current `.app-scroll-shell` position through `frontend-modern/src/utils/appShellScrollRestoration.ts` so the remounted shell in `frontend-modern/src/App.tsx` can reopen the inline detail without looking like a page refresh, and then still route through the shared reveal helper whenever the opened drawer would otherwise land below the fold. Same-route drawers must therefore scroll only enough to keep the row header plus the top of the inline detail visible, never hard-center the row just because the route state changed. The same-route state scheduler owns the lifecycle for its deferred scroll-restore timers and animation frames; page owners must clean it up on unmount instead of leaving replay work attached to a torn-down route.
|
||||
Shared summary-linked rows and group headers must also route their preview
|
||||
semantics through
|
||||
`frontend-modern/src/components/shared/summaryInteractionA11y.ts`.
|
||||
Leaf rows and any explicit row-level control chrome must route deliberate
|
||||
pin/open ownership through
|
||||
`frontend-modern/src/components/shared/SummaryRowActionButton.tsx`, so
|
||||
`aria-expanded`, `aria-controls`, `aria-pressed`, focus treatment, and
|
||||
`Escape` preview clearing stay on the shared control instead of focusable-
|
||||
table-row shims. Group headers are different: they may use the header row
|
||||
itself as the deliberate pin target when that keeps the table chrome
|
||||
native, but they must not grow separate scope/pinned pill buttons or
|
||||
off-screen fallback strips. Workloads, infrastructure,
|
||||
and storage must not rebuild row-as-button keyboard handling or trailing
|
||||
one-off expand columns once the shared action primitive exists.
|
||||
When pinned page, group, or entity scope needs a local explicit reset,
|
||||
the only shared table-chrome owner is
|
||||
`frontend-modern/src/components/shared/SummaryTableCardHeader.tsx`: the
|
||||
reset action stays as one compact header-level `Clear` control with an
|
||||
accessible `Clear selection` label, not a second page-level scope strip,
|
||||
search-row accessory, or filter-bar badge.
|
||||
13. Keep summary-linked table row emphasis on the shared primitive contract. Workloads, infrastructure, and storage rows that mirror the active summary entity must expose that state through `data-summary-row-active` and let the shared presentation in `frontend-modern/src/index.css` render the row emphasis, rather than carrying page-local sky or blue fill classes inside each row renderer. Group-scoped preview and pin must use that same shared presentation boundary: child rows that belong to a hovered or pinned summary group should expose `data-summary-group-member-active="preview|pinned"` so the block-level emphasis stays subtle, consistent, and reversible instead of each table inventing its own outline, badge, or full-strength fill treatment. Static grouped row headers on workloads, infrastructure, storage, recovery, and future grouped tables must use `frontend-modern/src/components/shared/groupedTableRowPresentation.ts` plus the `.grouped-table-row` CSS contract in `frontend-modern/src/index.css`, rather than rebuilding local `bg-surface-alt` variants with subtly different light/dark behavior or page-local left-accent markers. That shared grouped-table primitive owns the subgroup cell padding, typography, small metadata, and badge treatment as well as the row background token, so a future adjustment to the subgroup visual language changes every grouped product table from one owner. Storage-backed reusable row presenters under `frontend-modern/src/features/storageBackups/` must also keep row height and alert accents on class/data-attribute presentation instead of runtime inline style maps, so the shared table contract stays CSP-safe on both steady-state and alert-highlighted routes.
|
||||
14. Keep retained-value data loading honest at the ownership boundary. Helpers
|
||||
that prevent a feature surface from falling through the app-level Suspense
|
||||
|
|
@ -957,12 +811,6 @@ not a replacement status card, CTA band, or page-local nested card.
|
|||
must stay on the app-shell assistant-availability fact instead of
|
||||
re-reading raw AI settings just to decide whether assistant affordances
|
||||
should render.
|
||||
17. Keep optional shared selectors honest about data ownership. Reusable
|
||||
shells such as `frontend-modern/src/components/shared/InfrastructureSelector.tsx`
|
||||
must gate their runtime data hooks on actual surface visibility, passing
|
||||
explicit disabled/null inputs to shared data owners when the selector is
|
||||
hidden instead of hydrating background summary data for chrome the page is
|
||||
not rendering.
|
||||
18. Keep Patrol shell composition and product-first provider vocabulary on the
|
||||
shared feature-presentation boundary.
|
||||
`frontend-modern/src/features/patrol/PatrolIntelligenceSummary.tsx`,
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ truth for live infrastructure data.
|
|||
42. `internal/mock/demo_scenarios.go`
|
||||
43. `internal/kubernetesagent/agent.go`
|
||||
44. `pkg/agents/kubernetes/report.go`
|
||||
45. `internal/monitoring/temperature.go`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
|
|
@ -854,6 +855,12 @@ temperatures. `internal/monitoring/monitor_polling_node_helpers.go` may skip
|
|||
SSH only once the host-agent temperature payload already has SMART disk data,
|
||||
so nodes keep their disk-temperature and SMART augmentation when the host agent
|
||||
is present but lacks SMART support.
|
||||
Legacy SSH temperature collection must also use the Pulse sensor-wrapper
|
||||
contract before falling back to raw lm-sensors output. `internal/monitoring/temperature.go`
|
||||
must request `/usr/local/sbin/pulse-sensors` when it exists, parse the wrapper
|
||||
payload as `{sensors, smart}`, preserve backward compatibility with old forced
|
||||
`sensors -j` keys, and expose SMART disk temperatures through the same
|
||||
`models.Temperature.SMART` path used by the physical-disk merge.
|
||||
That same Proxmox monitoring boundary also owns checked response parsing for
|
||||
polymorphic numeric fields. Shared client parsers such as
|
||||
`pkg/proxmox/replication.go` must use the package's checked integer conversion
|
||||
|
|
|
|||
|
|
@ -24,131 +24,120 @@ regression protection.
|
|||
2. `pkg/metrics/store_query_plan_test.go`
|
||||
3. `pkg/metrics/store_slo_test.go`
|
||||
4. `pkg/metrics/store_additional_test.go`
|
||||
4. `internal/api/slo.go`
|
||||
5. `internal/api/slo_bench_test.go`
|
||||
6. `frontend-modern/src/components/Workloads/WorkloadsSurface.tsx`
|
||||
7. `frontend-modern/src/components/Workloads/WorkloadsStateCards.tsx`
|
||||
5. `internal/api/slo.go`
|
||||
6. `internal/api/slo_bench_test.go`
|
||||
7. `frontend-modern/src/components/Workloads/WorkloadsSurface.tsx`
|
||||
8. `frontend-modern/src/components/Workloads/workloadInventorySourceIssues.ts`
|
||||
9. `frontend-modern/src/components/Workloads/__tests__/workloadInventorySourceIssues.test.ts`
|
||||
10. `frontend-modern/src/components/Workloads/WorkloadsStatsStrip.tsx`
|
||||
9. `frontend-modern/src/components/Workloads/WorkloadsTable.tsx`
|
||||
10. `frontend-modern/src/components/Workloads/WorkloadPanel.tsx`
|
||||
11. `frontend-modern/src/components/Workloads/WorkloadTableHeader.tsx`
|
||||
12. `frontend-modern/src/components/Workloads/useWorkloadsState.ts`
|
||||
13. `frontend-modern/src/hooks/useWorkloads.ts`
|
||||
13. `frontend-modern/src/components/Workloads/useWorkloadsControlsState.ts`
|
||||
14. `frontend-modern/src/components/Workloads/useWorkloadsDerivedState.ts`
|
||||
15. `frontend-modern/src/components/Workloads/useWorkloadGuestMetadataState.ts`
|
||||
16. `frontend-modern/src/components/Workloads/useWorkloadSelectionState.ts`
|
||||
17. `frontend-modern/src/components/Workloads/useWorkloadRouteState.ts`
|
||||
18. `frontend-modern/src/components/Workloads/useWorkloadUrlSync.ts`
|
||||
19. `frontend-modern/src/components/Workloads/WorkloadsFilter.tsx`
|
||||
20. `frontend-modern/src/components/Workloads/workloadsFilterModel.ts`
|
||||
22. `frontend-modern/src/components/Workloads/ThresholdSlider.tsx`
|
||||
23. `frontend-modern/src/components/Workloads/thresholdSliderModel.ts`
|
||||
24. `frontend-modern/src/components/Workloads/useThresholdSliderState.ts`
|
||||
25. `frontend-modern/src/components/Workloads/StackedDiskBar.tsx`
|
||||
26. `frontend-modern/src/components/Workloads/stackedDiskBarModel.ts`
|
||||
27. `frontend-modern/src/components/Workloads/useStackedDiskBarState.ts`
|
||||
28. `frontend-modern/src/components/Workloads/StackedMemoryBar.tsx`
|
||||
29. `frontend-modern/src/components/Workloads/stackedMemoryBarModel.ts`
|
||||
30. `frontend-modern/src/components/Workloads/useStackedMemoryBarState.ts`
|
||||
31. `frontend-modern/src/components/Workloads/MetricBar.tsx`
|
||||
32. `frontend-modern/src/components/Workloads/metricBarModel.ts`
|
||||
32. `frontend-modern/src/components/Workloads/MetricMiniSparkline.tsx`
|
||||
33. `frontend-modern/src/components/Workloads/useMetricBarState.ts`
|
||||
34. `frontend-modern/src/components/Workloads/EnhancedCPUBar.tsx`
|
||||
35. `frontend-modern/src/components/Workloads/enhancedCpuBarModel.ts`
|
||||
36. `frontend-modern/src/components/Workloads/useEnhancedCPUBarState.ts`
|
||||
37. `frontend-modern/src/components/Workloads/DiskList.tsx`
|
||||
38. `frontend-modern/src/components/Workloads/diskListModel.ts`
|
||||
39. `frontend-modern/src/components/Workloads/useDiskListState.ts`
|
||||
40. `frontend-modern/src/components/Workloads/GuestRow.tsx`
|
||||
41. `frontend-modern/src/components/Workloads/GuestRowCells.tsx`
|
||||
42. `frontend-modern/src/components/Workloads/guestRowModel.tsx`
|
||||
43. `frontend-modern/src/components/Workloads/useGuestRowState.ts`
|
||||
44. `frontend-modern/src/components/Workloads/GuestDrawer.tsx`
|
||||
45. `frontend-modern/src/components/Workloads/GuestDrawerOverview.tsx`
|
||||
45. `frontend-modern/src/components/Workloads/GuestDrawerHistory.tsx`
|
||||
46. `frontend-modern/src/components/Workloads/guestDrawerModel.ts`
|
||||
47. `frontend-modern/src/components/Workloads/useGuestDrawerState.ts`
|
||||
48. `frontend-modern/src/components/Workloads/useGroupedTableWindowing.ts`
|
||||
49. `frontend-modern/src/components/Workloads/workloadSelectors.ts`
|
||||
50. `frontend-modern/src/components/Workloads/workloadTopology.ts`
|
||||
51. `frontend-modern/src/components/Workloads/workloadSelectionModel.ts`
|
||||
52. `frontend-modern/src/components/Workloads/workloadRouteModel.ts`
|
||||
53. `frontend-modern/src/components/Workloads/workloadFilterConfigModel.ts`
|
||||
53. `frontend-modern/src/components/Workloads/workloadMetricHistoryModel.ts`
|
||||
54. `frontend-modern/src/components/Workloads/workloadRouteStateModel.ts`
|
||||
55. `frontend-modern/src/components/Workloads/workloadUrlSyncModel.ts`
|
||||
56. `frontend-modern/src/components/Workloads/useWorkloadFilterOptions.ts`
|
||||
57. `frontend-modern/src/components/Workloads/__tests__/workloadSelectionModel.test.ts`
|
||||
58. `frontend-modern/src/components/Workloads/__tests__/workloadFilterConfigModel.test.ts`
|
||||
59. `frontend-modern/src/components/Workloads/__tests__/workloadRouteModel.test.ts`
|
||||
60. `frontend-modern/src/components/Workloads/__tests__/workloadRouteStateModel.test.ts`
|
||||
61. `frontend-modern/src/components/Workloads/__tests__/workloadUrlSyncModel.test.ts`
|
||||
62. `frontend-modern/src/components/Workloads/__tests__/workloadTopology.test.ts`
|
||||
63. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx`
|
||||
64. `frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts`
|
||||
65. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts`
|
||||
66. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts`
|
||||
67. `frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx`
|
||||
68. `frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx`
|
||||
69. `frontend-modern/src/components/Workloads/WorkloadsSummary.tsx`
|
||||
70. `frontend-modern/src/utils/throughputPresentation.ts`
|
||||
71. `frontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsx`
|
||||
72. `frontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx`
|
||||
73. `frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts`
|
||||
74. `frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts`
|
||||
75. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts`
|
||||
76. `frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx`
|
||||
77. `frontend-modern/src/components/Workloads/__tests__/WorkloadsFilter.test.tsx`
|
||||
79. `frontend-modern/src/components/Workloads/__tests__/useWorkloadSelectionState.test.ts`
|
||||
80. `frontend-modern/src/components/Workloads/MetricBar.test.tsx`
|
||||
81. `frontend-modern/src/components/Workloads/__tests__/useMetricBarState.test.tsx`
|
||||
82. `frontend-modern/src/components/Workloads/__tests__/EnhancedCPUBar.test.tsx`
|
||||
83. `frontend-modern/src/components/Workloads/__tests__/useEnhancedCPUBarState.test.tsx`
|
||||
84. `frontend-modern/src/components/Workloads/ThresholdSlider.test.tsx`
|
||||
85. `frontend-modern/src/components/Workloads/__tests__/useThresholdSliderState.test.ts`
|
||||
86. `frontend-modern/src/components/Workloads/__tests__/StackedDiskBar.test.tsx`
|
||||
87. `frontend-modern/src/components/Workloads/__tests__/useStackedDiskBarState.test.tsx`
|
||||
88. `frontend-modern/src/components/Workloads/StackedMemoryBar.test.tsx`
|
||||
89. `frontend-modern/src/components/Workloads/__tests__/useStackedMemoryBarState.test.tsx`
|
||||
90. `frontend-modern/src/components/Workloads/__tests__/DiskList.test.tsx`
|
||||
91. `frontend-modern/src/components/Workloads/__tests__/GuestRow.test.tsx`
|
||||
91. `frontend-modern/src/components/Workloads/__tests__/MetricMiniSparkline.test.tsx`
|
||||
91. `frontend-modern/src/components/Workloads/__tests__/workloadMetricHistoryModel.test.ts`
|
||||
92. `frontend-modern/src/components/Workloads/GuestDrawer.test.tsx`
|
||||
93. `frontend-modern/src/components/Workloads/__tests__/useGroupedTableWindowing.test.ts`
|
||||
94. `frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsx`
|
||||
95. `frontend-modern/src/components/Workloads/useWorkloadViewportSync.ts`
|
||||
96. `frontend-modern/src/components/Workloads/__tests__/useWorkloadViewportSync.test.tsx`
|
||||
97. `frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsx`
|
||||
98. `frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts`
|
||||
99. `frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts`
|
||||
10. `frontend-modern/src/components/Workloads/WorkloadsTable.tsx`
|
||||
11. `frontend-modern/src/components/Workloads/WorkloadPanel.tsx`
|
||||
12. `frontend-modern/src/components/Workloads/WorkloadTableHeader.tsx`
|
||||
13. `frontend-modern/src/components/Workloads/useWorkloadsState.ts`
|
||||
14. `frontend-modern/src/hooks/useWorkloads.ts`
|
||||
15. `frontend-modern/src/components/Workloads/useWorkloadsControlsState.ts`
|
||||
16. `frontend-modern/src/components/Workloads/useWorkloadsDerivedState.ts`
|
||||
17. `frontend-modern/src/components/Workloads/useWorkloadGuestMetadataState.ts`
|
||||
18. `frontend-modern/src/components/Workloads/useWorkloadSelectionState.ts`
|
||||
19. `frontend-modern/src/components/Workloads/useWorkloadRouteState.ts`
|
||||
20. `frontend-modern/src/components/Workloads/useWorkloadUrlSync.ts`
|
||||
21. `frontend-modern/src/components/Workloads/WorkloadsFilter.tsx`
|
||||
22. `frontend-modern/src/components/Workloads/workloadsFilterModel.ts`
|
||||
23. `frontend-modern/src/components/Workloads/ThresholdSlider.tsx`
|
||||
24. `frontend-modern/src/components/Workloads/thresholdSliderModel.ts`
|
||||
25. `frontend-modern/src/components/Workloads/useThresholdSliderState.ts`
|
||||
26. `frontend-modern/src/components/Workloads/StackedDiskBar.tsx`
|
||||
27. `frontend-modern/src/components/Workloads/stackedDiskBarModel.ts`
|
||||
28. `frontend-modern/src/components/Workloads/useStackedDiskBarState.ts`
|
||||
29. `frontend-modern/src/components/Workloads/StackedMemoryBar.tsx`
|
||||
30. `frontend-modern/src/components/Workloads/stackedMemoryBarModel.ts`
|
||||
31. `frontend-modern/src/components/Workloads/useStackedMemoryBarState.ts`
|
||||
32. `frontend-modern/src/components/Workloads/MetricBar.tsx`
|
||||
33. `frontend-modern/src/components/Workloads/metricBarModel.ts`
|
||||
34. `frontend-modern/src/components/Workloads/MetricMiniSparkline.tsx`
|
||||
35. `frontend-modern/src/components/Workloads/useMetricBarState.ts`
|
||||
36. `frontend-modern/src/components/Workloads/EnhancedCPUBar.tsx`
|
||||
37. `frontend-modern/src/components/Workloads/enhancedCpuBarModel.ts`
|
||||
38. `frontend-modern/src/components/Workloads/useEnhancedCPUBarState.ts`
|
||||
39. `frontend-modern/src/components/Workloads/DiskList.tsx`
|
||||
40. `frontend-modern/src/components/Workloads/diskListModel.ts`
|
||||
41. `frontend-modern/src/components/Workloads/useDiskListState.ts`
|
||||
42. `frontend-modern/src/components/Workloads/GuestRow.tsx`
|
||||
43. `frontend-modern/src/components/Workloads/GuestRowCells.tsx`
|
||||
44. `frontend-modern/src/components/Workloads/guestRowModel.tsx`
|
||||
45. `frontend-modern/src/components/Workloads/useGuestRowState.ts`
|
||||
46. `frontend-modern/src/components/Workloads/GuestDrawer.tsx`
|
||||
47. `frontend-modern/src/components/Workloads/GuestDrawerOverview.tsx`
|
||||
48. `frontend-modern/src/components/Workloads/GuestDrawerHistory.tsx`
|
||||
49. `frontend-modern/src/components/Workloads/guestDrawerModel.ts`
|
||||
50. `frontend-modern/src/components/Workloads/useGuestDrawerState.ts`
|
||||
51. `frontend-modern/src/components/Workloads/useGroupedTableWindowing.ts`
|
||||
52. `frontend-modern/src/components/Workloads/workloadSelectors.ts`
|
||||
53. `frontend-modern/src/components/Workloads/workloadTopology.ts`
|
||||
54. `frontend-modern/src/components/Workloads/workloadSelectionModel.ts`
|
||||
55. `frontend-modern/src/components/Workloads/workloadRouteModel.ts`
|
||||
56. `frontend-modern/src/components/Workloads/workloadFilterConfigModel.ts`
|
||||
57. `frontend-modern/src/components/Workloads/workloadMetricHistoryModel.ts`
|
||||
58. `frontend-modern/src/components/Workloads/workloadRouteStateModel.ts`
|
||||
59. `frontend-modern/src/components/Workloads/workloadUrlSyncModel.ts`
|
||||
60. `frontend-modern/src/components/Workloads/useWorkloadFilterOptions.ts`
|
||||
61. `frontend-modern/src/components/Workloads/__tests__/workloadSelectionModel.test.ts`
|
||||
62. `frontend-modern/src/components/Workloads/__tests__/workloadFilterConfigModel.test.ts`
|
||||
63. `frontend-modern/src/components/Workloads/__tests__/workloadRouteModel.test.ts`
|
||||
64. `frontend-modern/src/components/Workloads/__tests__/workloadRouteStateModel.test.ts`
|
||||
65. `frontend-modern/src/components/Workloads/__tests__/workloadUrlSyncModel.test.ts`
|
||||
66. `frontend-modern/src/components/Workloads/__tests__/workloadTopology.test.ts`
|
||||
67. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx`
|
||||
68. `frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts`
|
||||
69. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts`
|
||||
70. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts`
|
||||
71. `frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx`
|
||||
72. `frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx`
|
||||
73. `frontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsx`
|
||||
74. `frontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx`
|
||||
75. `frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts`
|
||||
76. `frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts`
|
||||
77. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts`
|
||||
78. `frontend-modern/src/components/Workloads/__tests__/WorkloadsSurface.performance.contract.test.tsx`
|
||||
79. `frontend-modern/src/components/Workloads/__tests__/WorkloadsFilter.test.tsx`
|
||||
80. `frontend-modern/src/components/Workloads/__tests__/useWorkloadSelectionState.test.ts`
|
||||
81. `frontend-modern/src/components/Workloads/MetricBar.test.tsx`
|
||||
82. `frontend-modern/src/components/Workloads/__tests__/useMetricBarState.test.tsx`
|
||||
83. `frontend-modern/src/components/Workloads/__tests__/EnhancedCPUBar.test.tsx`
|
||||
84. `frontend-modern/src/components/Workloads/__tests__/useEnhancedCPUBarState.test.tsx`
|
||||
85. `frontend-modern/src/components/Workloads/ThresholdSlider.test.tsx`
|
||||
86. `frontend-modern/src/components/Workloads/__tests__/useThresholdSliderState.test.ts`
|
||||
87. `frontend-modern/src/components/Workloads/__tests__/StackedDiskBar.test.tsx`
|
||||
88. `frontend-modern/src/components/Workloads/__tests__/useStackedDiskBarState.test.tsx`
|
||||
89. `frontend-modern/src/components/Workloads/StackedMemoryBar.test.tsx`
|
||||
90. `frontend-modern/src/components/Workloads/__tests__/useStackedMemoryBarState.test.tsx`
|
||||
91. `frontend-modern/src/components/Workloads/__tests__/DiskList.test.tsx`
|
||||
92. `frontend-modern/src/components/Workloads/__tests__/GuestRow.test.tsx`
|
||||
93. `frontend-modern/src/components/Workloads/__tests__/MetricMiniSparkline.test.tsx`
|
||||
94. `frontend-modern/src/components/Workloads/__tests__/workloadMetricHistoryModel.test.ts`
|
||||
95. `frontend-modern/src/components/Workloads/GuestDrawer.test.tsx`
|
||||
96. `frontend-modern/src/components/Workloads/__tests__/useGroupedTableWindowing.test.ts`
|
||||
97. `frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsx`
|
||||
98. `frontend-modern/src/components/Workloads/useWorkloadViewportSync.ts`
|
||||
99. `frontend-modern/src/components/Workloads/__tests__/useWorkloadViewportSync.test.tsx`
|
||||
100. `frontend-modern/src/utils/workloadsSummaryCache.ts`
|
||||
101. `frontend-modern/src/routing/routePreload.ts`
|
||||
102. `frontend-modern/src/useAppRuntimeState.ts`
|
||||
103. `frontend-modern/src/components/Storage/StorageSummary.tsx`
|
||||
104. `frontend-modern/src/utils/storageSummaryCache.ts`
|
||||
105. `frontend-modern/src/components/Workloads/WorkloadsSurface.tsx`
|
||||
103. `frontend-modern/src/utils/storageSummaryCache.ts`
|
||||
104. `frontend-modern/src/components/Workloads/WorkloadsSurface.tsx`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
1. `frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts` shared with `unified-resources`: the infrastructure selector pipeline is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
2. `frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsx` shared with `unified-resources`: the infrastructure summary surface is both a canonical unified-resource consumer and a fleet-scale summary chart hot-path boundary.
|
||||
3. `frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts` shared with `unified-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.
|
||||
4. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts` shared with `unified-resources`: resource detail mappers are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
5. `frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx` shared with `unified-resources`: the unified resource host table card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
6. `frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx` shared with `unified-resources`: the unified resource PBS section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
7. `frontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsx` shared with `unified-resources`: the unified resource PMG section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
8. `frontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx` shared with `unified-resources`: the unified resource service infrastructure card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
9. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx` shared with `unified-resources`: the unified resource table is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
10. `frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts` shared with `unified-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.
|
||||
11. `frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts` shared with `unified-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.
|
||||
12. `frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts` shared with `unified-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.
|
||||
13. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` shared with `unified-resources`: unified resource table state, grouping, and windowing are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
14. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts` shared with `unified-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.
|
||||
2. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts` shared with `unified-resources`: resource detail mappers are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
3. `frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx` shared with `unified-resources`: the unified resource host table card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
4. `frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx` shared with `unified-resources`: the unified resource PBS section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
5. `frontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsx` shared with `unified-resources`: the unified resource PMG section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
6. `frontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx` shared with `unified-resources`: the unified resource service infrastructure card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
7. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx` shared with `unified-resources`: the unified resource table is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
8. `frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts` shared with `unified-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.
|
||||
9. `frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts` shared with `unified-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.
|
||||
10. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` shared with `unified-resources`: unified resource table state, grouping, and windowing are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
11. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts` shared with `unified-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.
|
||||
15. `frontend-modern/src/routing/routePreload.ts` shared with `frontend-primitives`: the app-shell route preload registry is both a canonical frontend shell boundary and an authenticated hot-path performance boundary.
|
||||
16. `frontend-modern/src/useAppRuntimeState.ts` shared with `cloud-paid`: the authenticated app runtime bootstrap is both a hosted commercial org-context boundary and a protected app-shell performance boundary.
|
||||
17. `internal/api/slo.go` shared with `api-contracts`: the SLO endpoint is both an API contract surface and a protected performance hot-path boundary.
|
||||
|
|
@ -377,7 +366,6 @@ regression protection.
|
|||
`prefers-reduced-motion`; hot-path Workloads components must not re-create
|
||||
independent number animation loops.
|
||||
23. Extend grouped workload row windowing, reveal-index clamping, overscan math, and per-group visible-slice derivation through `frontend-modern/src/components/Workloads/useGroupedTableWindowing.ts`, and extend viewport event wiring through `frontend-modern/src/components/Workloads/useWorkloadViewportSync.ts` rather than rebuilding scroll handlers, mounted-row budgets, viewport listeners, or group-slice math inside `frontend-modern/src/components/Workloads/useWorkloadsDerivedState.ts`
|
||||
24. Extend Workloads shell rendering through `frontend-modern/src/components/Workloads/WorkloadsStateCards.tsx`, `frontend-modern/src/components/Workloads/WorkloadsTable.tsx`, and `frontend-modern/src/components/Workloads/WorkloadsStatsStrip.tsx` rather than accreting loading cards, workload table markup, or stats-strip presentation back into `frontend-modern/src/components/Workloads/WorkloadsSurface.tsx`
|
||||
25. Extend workload table shell ownership through `frontend-modern/src/components/Workloads/WorkloadTableHeader.tsx` and `frontend-modern/src/components/Workloads/WorkloadPanel.tsx` rather than rebuilding sortable header markup, grouped node rows, row expansion, or guest-drawer rendering inside `frontend-modern/src/components/Workloads/WorkloadsTable.tsx`
|
||||
`WorkloadPanel` owns the mutually exclusive host/guest drawer handoff:
|
||||
clicking a grouped host row while a guest drawer is open must clear the
|
||||
|
|
@ -398,77 +386,6 @@ regression protection.
|
|||
default filter-option labels must flow through the shared all-option
|
||||
presentation helper via the workload filter config model instead of the
|
||||
hot-path shell hard-coding local `All ...` strings.
|
||||
26. Keep long-range workload chart capping time-proportional across `frontend-modern/src/components/Workloads/WorkloadsSummary.tsx`, `frontend-modern/src/api/charts.ts`, and `internal/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.
|
||||
Workload summary chart caching and app-shell prewarming belong to
|
||||
`frontend-modern/src/utils/workloadsSummaryCache.ts`, not to page-local
|
||||
component state. `frontend-modern/src/components/Workloads/WorkloadsSummary.tsx`
|
||||
may hydrate from that shared in-memory/local cache and refresh it, while
|
||||
`frontend-modern/src/useAppRuntimeState.ts` may warm the same cache after
|
||||
authenticated bootstrap without mounting the Workloads route or starting a
|
||||
second polling loop.
|
||||
27. Keep summary hover/focus and sticky-card behavior on shared hot paths: infrastructure, workloads, and storage summary shells must reuse one page/group/entity scope model plus `frontend-modern/src/components/shared/StickySummarySection.tsx` inside the app scroll shell instead of per-page scroll listeners or per-card hover derivations, so row scrubbing highlights all cards, workload group headers, infrastructure cluster headers, and storage pool-group headers scope the summary coherently, pinned group focus remains route-backed and reversible, and the hot path does not multiply render or scroll work. Pages that keep chart summaries visible below the desktop breakpoint must use the shared desktop-sticky mode on that primitive rather than page-local viewport listeners, so wrapped chart grids do not pin most of the scroll container on narrow screens. That hot path stays row-first rather than adding fallback chrome: the on-screen row or group header is the scoped state, and any explicit reset belongs to one compact shared table-header action plus the shared `Escape` path, not to page-level scope strips, search-row widgets, or filter-bar badges. Background whitespace clearing may exist as a convenience, but the hot path must not depend on brittle dead-space hit testing as the only reversible control. The same hot path must therefore keep one page-level reset owner for filters plus pinned summary selections, and it must keep chart-backed summary-card geometry explicit and stable so hover rerenders, synchronized readouts, or idle header metadata cannot feed layout loops that grow or shrink the top cards over time. Recovery’s summary rail is not part of this interactive hot path; it may share summary-card framing, but it must remain non-interactive until a separately governed model says otherwise.
|
||||
The input path for that hot summary contract must stay shared too:
|
||||
`frontend-modern/src/components/shared/summaryInteractionA11y.ts` owns
|
||||
fine-pointer preview and focus-preview continuity, while
|
||||
`frontend-modern/src/components/shared/SummaryRowActionButton.tsx` owns
|
||||
deliberate open/pin controls for summary-linked leaf rows and explicit row
|
||||
chrome. Group headers may pin through the header row itself when that
|
||||
keeps the hot path visually native, but they must not reintroduce local
|
||||
scope/pinned pill buttons that compete with the summary shell. Workloads,
|
||||
infrastructure, and storage do not rebuild mouse-only hover branches,
|
||||
focusable-row toggles, or touch-hostile synthetic hover behavior inside
|
||||
individual row renderers. The same hot path must also carry block-level
|
||||
group feedback through one shared row-state contract: when a summary group
|
||||
is previewed or pinned, member rows should take a restrained shared
|
||||
preview/pinned wash via `data-summary-group-member-active` rather than
|
||||
per-surface outlines, secondary buttons, or full-strength row fills.
|
||||
Static grouped-row header emphasis on the same workload and infrastructure
|
||||
tables must route through
|
||||
`frontend-modern/src/components/shared/groupedTableRowPresentation.ts` and
|
||||
the shared `.grouped-table-row` CSS contract in `frontend-modern/src/index.css`,
|
||||
rather than local `bg-surface-alt` or hover-fill variants that drift between
|
||||
pages.
|
||||
Framed product-table cards on the same hot-path surfaces must consume the
|
||||
frontend-primitives-owned `TableCard` wrapper and `TableCardHeader`
|
||||
title/action band so Workloads, Infrastructure, Storage, and Recovery keep
|
||||
one border/background/overflow frame and table-section header treatment
|
||||
instead of introducing page-local table shells with different light/dark
|
||||
contrast. The shared `Table` primitive owns the horizontal scroll container
|
||||
for those hot tables; page-local nested `overflow-x-auto` wrappers are not
|
||||
allowed because they add extra scroll and paint surfaces on the row-heavy
|
||||
path.
|
||||
Infrastructure table responsive behavior belongs to that same hot-path
|
||||
owner. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts`
|
||||
must derive column visibility from the measured table surface width, with
|
||||
`frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts`
|
||||
owning the column-priority breakpoints. It must not rely on global viewport
|
||||
width alone, because app chrome can leave the table with tablet-sized space
|
||||
while the window still reports a desktop breakpoint. Live resize proof must
|
||||
show the host and service tables dropping lower-priority columns without
|
||||
introducing horizontal overflow.
|
||||
Dashboard workload table responsive behavior belongs to the same hot-path
|
||||
owner. `frontend-modern/src/components/Workloads/useWorkloadsControlsState.ts`
|
||||
must derive workload table layout stages from live viewport width, and
|
||||
`frontend-modern/src/components/Workloads/guestRowModel.tsx` must own the
|
||||
responsive workload column priority and width model. `WorkloadsTable`,
|
||||
`WorkloadTableHeader`, and `WorkloadPanel` must consume one shared
|
||||
layout-visible column set so headers, colgroups, and rows stay aligned during
|
||||
live resize. Workload rows keep navigation inside owned identity cells
|
||||
rather than trailing action columns: guest custom web-interface URLs render
|
||||
on the workload name, and
|
||||
grouped node web-interface navigation stays on the shared node header name,
|
||||
so responsive colgroups and rows do not carry an otherwise empty link
|
||||
column. View-mode-specific column sets in
|
||||
`frontend-modern/src/components/Workloads/guestRowModel.tsx` must retain
|
||||
core monitoring metrics when narrowing scope: app-container mode keeps CPU,
|
||||
memory, disk, and the responsive Net I/O and Disk I/O columns available,
|
||||
while the layout priority model decides when detail-heavy I/O columns are
|
||||
rendered. Filtering to a workload type must not silently remove capacity or
|
||||
I/O observability that remains available in the all-workloads table. Tablet
|
||||
and compact workload stages must normalize active column widths against the
|
||||
currently visible column IDs, show higher-priority workload information
|
||||
before exposing detail-heavy Net I/O and Disk I/O columns, and avoid
|
||||
horizontal overflow at mobile, tablet, compact, and full desktop widths.
|
||||
28. 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.
|
||||
29. Keep public self-hosted checkout handoff endpoints on the adjacent
|
||||
commercial/router boundary, not the summary-chart hot path. When
|
||||
|
|
@ -586,12 +503,6 @@ shell clickable behind another overlay.
|
|||
canonical dock threshold, the assistant must switch to an overlay drawer so
|
||||
table filters, grouped rows, and other hot-path controls keep their
|
||||
existing layout budget instead of paying a second collapse cost.
|
||||
33. Keep hidden workload selector shells off the hot path. When an owning
|
||||
platform page keeps `frontend-modern/src/components/shared/InfrastructureSelector.tsx`
|
||||
mounted only for layout parity, `frontend-modern/src/components/shared/useInfrastructureSelectorState.ts`
|
||||
must not hydrate `all-resources` or recovery rollups behind a hidden node
|
||||
summary; selector-owned data hooks must be explicitly visibility-gated so
|
||||
workload surfaces only pay for workload-owned transports.
|
||||
34. Keep the retired dashboard page-header path absent from the compact hot
|
||||
path. New page headers must stay pure presentation on their owning route
|
||||
and must not introduce a second data load, widen suspense ownership, or
|
||||
|
|
|
|||
|
|
@ -81,22 +81,6 @@
|
|||
"unified-resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsx",
|
||||
"rationale": "the infrastructure summary surface is both a canonical unified-resource consumer and a fleet-scale summary chart hot-path boundary",
|
||||
"subsystems": [
|
||||
"performance-and-scalability",
|
||||
"unified-resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts",
|
||||
"rationale": "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",
|
||||
"subsystems": [
|
||||
"performance-and-scalability",
|
||||
"unified-resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts",
|
||||
"rationale": "resource detail mappers are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary",
|
||||
|
|
@ -161,14 +145,6 @@
|
|||
"unified-resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts",
|
||||
"rationale": "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",
|
||||
"subsystems": [
|
||||
"performance-and-scalability",
|
||||
"unified-resources"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts",
|
||||
"rationale": "unified resource table state, grouping, and windowing are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary",
|
||||
|
|
@ -585,6 +561,15 @@
|
|||
"security-privacy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "internal/api/setup_script_render.go",
|
||||
"rationale": "the generated Proxmox setup-script is a shared boundary across agent lifecycle (forced-command keys, install/uninstall edits), API contracts (rendered token shape and encoded rerun URL), and storage/recovery (backup visibility grants, Pulse-managed temperature SSH keys, and SMART disk-temperature collection)",
|
||||
"subsystems": [
|
||||
"agent-lifecycle",
|
||||
"api-contracts",
|
||||
"storage-recovery"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "internal/api/slo.go",
|
||||
"rationale": "the SLO endpoint is both an API contract surface and a protected performance hot-path boundary",
|
||||
|
|
@ -687,14 +672,8 @@
|
|||
"cmd/pulse-agent/main.go",
|
||||
"frontend-modern/src/api/agentProfiles.ts",
|
||||
"frontend-modern/src/api/nodes.ts",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/CandidatesStep.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/ConfirmStep.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/DeployingStep.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/PreflightStep.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/ResultsStep.tsx",
|
||||
"frontend-modern/src/components/Settings/agentProfileSettings.ts",
|
||||
"frontend-modern/src/components/Settings/AgentProfilesPanel.tsx",
|
||||
"frontend-modern/src/components/Settings/ConfiguredNodeTables.tsx",
|
||||
"frontend-modern/src/components/Settings/ConnectionEditor/AddressProbeStep.tsx",
|
||||
"frontend-modern/src/components/Settings/ConnectionEditor/ConnectionEditor.tsx",
|
||||
"frontend-modern/src/components/Settings/ConnectionEditor/CredentialSlots/NodeCredentialSlot.tsx",
|
||||
|
|
@ -719,7 +698,6 @@
|
|||
"frontend-modern/src/components/Settings/NodeModalSetupGuideSection.tsx",
|
||||
"frontend-modern/src/components/Settings/NodeModalStatusFooter.tsx",
|
||||
"frontend-modern/src/components/Settings/proxmoxSettingsModel.ts",
|
||||
"frontend-modern/src/components/Settings/SettingsSectionNav.tsx",
|
||||
"frontend-modern/src/components/Settings/useAgentProfilesPanelState.ts",
|
||||
"frontend-modern/src/components/Settings/useConnectionRowActions.ts",
|
||||
"frontend-modern/src/components/Settings/useConnectionsLedger.ts",
|
||||
|
|
@ -736,18 +714,15 @@
|
|||
"frontend-modern/src/utils/agentInstallCommand.ts",
|
||||
"frontend-modern/src/utils/agentProfilesPresentation.ts",
|
||||
"frontend-modern/src/utils/agentProfileSuggestionPresentation.ts",
|
||||
"frontend-modern/src/utils/clusterEndpointPresentation.ts",
|
||||
"frontend-modern/src/utils/configuredNodeCapabilityPresentation.ts",
|
||||
"frontend-modern/src/utils/configuredNodeStatusPresentation.ts",
|
||||
"frontend-modern/src/utils/infrastructureOnboardingPresentation.ts",
|
||||
"frontend-modern/src/utils/infrastructureSettingsPresentation.ts",
|
||||
"frontend-modern/src/utils/nodeModalPresentation.ts",
|
||||
"frontend-modern/src/utils/proxmoxSettingsPresentation.ts",
|
||||
"frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts",
|
||||
"frontend-modern/src/utils/unifiedAgentStatusPresentation.ts",
|
||||
"internal/agenttls/config.go",
|
||||
"internal/api/agent_install_command_shared.go",
|
||||
"internal/api/config_setup_handlers.go",
|
||||
"internal/api/setup_script_render.go",
|
||||
"internal/api/unified_agent.go",
|
||||
"internal/remoteconfig/client.go",
|
||||
"scripts/install.ps1",
|
||||
|
|
@ -779,6 +754,7 @@
|
|||
"match_files": [
|
||||
"internal/api/agent_install_command_shared.go",
|
||||
"internal/api/config_setup_handlers.go",
|
||||
"internal/api/setup_script_render.go",
|
||||
"internal/api/unified_agent.go"
|
||||
],
|
||||
"allow_same_subsystem_tests": false,
|
||||
|
|
@ -975,30 +951,6 @@
|
|||
"frontend-modern/src/components/SetupWizard/__tests__/SetupCompletionPanel.guardrails.test.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "deploy-fallback-install-surface",
|
||||
"label": "deploy wizard surface proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/components/Infrastructure/deploy/CandidatesStep.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/ConfirmStep.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/DeployingStep.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/PreflightStep.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/ResultsStep.tsx"
|
||||
],
|
||||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/DeployStepComponents.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/CandidatesStep.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/ConfirmStep.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/DeployingStep.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/PreflightStep.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/ResultsStep.test.tsx",
|
||||
"frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "unified-agent-settings-surface",
|
||||
"label": "unified agent settings lifecycle proof",
|
||||
|
|
@ -1038,7 +990,6 @@
|
|||
"label": "platform connections workspace lifecycle proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/components/Settings/ConfiguredNodeTables.tsx",
|
||||
"frontend-modern/src/components/Settings/ConnectionEditor/AddressProbeStep.tsx",
|
||||
"frontend-modern/src/components/Settings/ConnectionEditor/ConnectionEditor.tsx",
|
||||
"frontend-modern/src/components/Settings/ConnectionEditor/CredentialSlots/NodeCredentialSlot.tsx",
|
||||
|
|
@ -1054,16 +1005,13 @@
|
|||
"frontend-modern/src/components/Settings/infrastructureWorkspaceModel.ts",
|
||||
"frontend-modern/src/components/Settings/MonitoredSystemImpactPreview.tsx",
|
||||
"frontend-modern/src/components/Settings/proxmoxSettingsModel.ts",
|
||||
"frontend-modern/src/components/Settings/SettingsSectionNav.tsx",
|
||||
"frontend-modern/src/components/Settings/useConnectionRowActions.ts",
|
||||
"frontend-modern/src/components/Settings/useConnectionsLedger.ts",
|
||||
"frontend-modern/src/components/Settings/useInfrastructureConfiguredNodesState.ts",
|
||||
"frontend-modern/src/components/Settings/useInfrastructureDiscoveryRuntimeState.ts",
|
||||
"frontend-modern/src/components/Settings/useInfrastructureSettingsState.ts",
|
||||
"frontend-modern/src/components/Settings/useTrueNASSettingsPanelState.ts",
|
||||
"frontend-modern/src/components/Settings/useVMwareSettingsPanelState.ts",
|
||||
"frontend-modern/src/utils/clusterEndpointPresentation.ts",
|
||||
"frontend-modern/src/utils/proxmoxSettingsPresentation.ts"
|
||||
"frontend-modern/src/components/Settings/useVMwareSettingsPanelState.ts"
|
||||
],
|
||||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
|
|
@ -1073,9 +1021,7 @@
|
|||
"frontend-modern/src/components/Settings/__tests__/useTrueNASSettingsPanelState.test.tsx",
|
||||
"frontend-modern/src/components/Settings/__tests__/useVMwareSettingsPanelState.test.tsx",
|
||||
"frontend-modern/src/components/Settings/ConnectionEditor/__tests__/ConnectionEditor.test.tsx",
|
||||
"frontend-modern/src/utils/__tests__/clusterEndpointPresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/proxmoxSettingsPresentation.test.ts",
|
||||
"tests/integration/tests/21-truenas-settings-platform-connections.spec.ts",
|
||||
"tests/integration/tests/22-vmware-settings-platform-connections.spec.ts"
|
||||
]
|
||||
|
|
@ -1087,8 +1033,6 @@
|
|||
"match_files": [
|
||||
"frontend-modern/src/utils/agentCapabilityPresentation.ts",
|
||||
"frontend-modern/src/utils/agentProfileSuggestionPresentation.ts",
|
||||
"frontend-modern/src/utils/configuredNodeCapabilityPresentation.ts",
|
||||
"frontend-modern/src/utils/configuredNodeStatusPresentation.ts",
|
||||
"frontend-modern/src/utils/unifiedAgentInventoryPresentation.ts",
|
||||
"frontend-modern/src/utils/unifiedAgentStatusPresentation.ts"
|
||||
],
|
||||
|
|
@ -1097,8 +1041,6 @@
|
|||
"exact_files": [
|
||||
"frontend-modern/src/utils/__tests__/agentCapabilityPresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/agentProfileSuggestionPresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/configuredNodeCapabilityPresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/configuredNodeStatusPresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/unifiedAgentInventoryPresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/unifiedAgentStatusPresentation.test.ts"
|
||||
]
|
||||
|
|
@ -1116,7 +1058,8 @@
|
|||
"frontend-modern/src/utils/__tests__/infrastructureSettingsPresentation.test.ts"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1269,7 +1212,8 @@
|
|||
"scripts/release_control/ai_runtime_docs_policy_test.py"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1521,7 +1465,8 @@
|
|||
"internal/alerts/update_alerts_test.go"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1555,6 +1500,7 @@
|
|||
"frontend-modern/src/utils/agentInstallCommand.ts",
|
||||
"frontend-modern/src/utils/apiTokenPresentation.ts",
|
||||
"frontend-modern/src/utils/infrastructureSettingsPresentation.ts",
|
||||
"internal/api/setup_script_render.go",
|
||||
"internal/websocket/hub.go",
|
||||
"pkg/pulsecli/actions.go",
|
||||
"pkg/pulsecli/api_client.go",
|
||||
|
|
@ -1869,7 +1815,8 @@
|
|||
"frontend-modern/src/utils/__tests__/infrastructureSettingsPresentation.test.ts"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1888,12 +1835,10 @@
|
|||
"owned_files": [
|
||||
"frontend-modern/src/App.tsx",
|
||||
"frontend-modern/src/AppLayout.tsx",
|
||||
"frontend-modern/src/components/Commercial/MonitoredSystemDefinitionDisclosure.tsx",
|
||||
"frontend-modern/src/components/Settings/BillingAdminOrganizationsTable.tsx",
|
||||
"frontend-modern/src/components/Settings/BillingAdminPanel.tsx",
|
||||
"frontend-modern/src/components/Settings/CommercialBillingSections.tsx",
|
||||
"frontend-modern/src/components/Settings/MonitoredSystemImpactPreview.tsx",
|
||||
"frontend-modern/src/components/Settings/MonitoredSystemLedgerPanel.tsx",
|
||||
"frontend-modern/src/components/Settings/OrganizationBillingLoadingState.tsx",
|
||||
"frontend-modern/src/components/Settings/OrganizationBillingPanel.tsx",
|
||||
"frontend-modern/src/components/Settings/ProLicensePanel.tsx",
|
||||
|
|
@ -1905,8 +1850,6 @@
|
|||
"frontend-modern/src/components/Settings/useOrganizationBillingPanelState.ts",
|
||||
"frontend-modern/src/components/Settings/useProLicensePanelState.ts",
|
||||
"frontend-modern/src/components/Settings/useRelaySettingsPanelState.ts",
|
||||
"frontend-modern/src/pages/CloudPricing.tsx",
|
||||
"frontend-modern/src/pages/HostedSignup.tsx",
|
||||
"frontend-modern/src/pages/PricingHandoff.tsx",
|
||||
"frontend-modern/src/pages/RuntimeHome.tsx",
|
||||
"frontend-modern/src/useAppRuntimeState.ts",
|
||||
|
|
@ -2415,8 +2358,6 @@
|
|||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/api/__tests__/hostedSignup.test.ts",
|
||||
"frontend-modern/src/pages/__tests__/HostedSignup.test.tsx",
|
||||
"internal/api/billing_state_handlers_test.go",
|
||||
"internal/api/contract_test.go",
|
||||
"internal/api/licensing_handlers_auto_migrate_test.go",
|
||||
|
|
@ -2460,7 +2401,6 @@
|
|||
"label": "pro license surface proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/components/Settings/MonitoredSystemLedgerPanel.tsx",
|
||||
"frontend-modern/src/components/Settings/ProLicensePanel.tsx",
|
||||
"frontend-modern/src/components/Settings/ProLicensePlanSection.tsx",
|
||||
"frontend-modern/src/components/Settings/selfHostedBillingPresentation.ts",
|
||||
|
|
@ -2470,7 +2410,6 @@
|
|||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/Settings/__tests__/MonitoredSystemLedgerPanel.test.tsx",
|
||||
"frontend-modern/src/components/Settings/__tests__/ProLicensePanel.test.tsx"
|
||||
]
|
||||
},
|
||||
|
|
@ -2510,7 +2449,6 @@
|
|||
"label": "commercial plan model proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/components/Commercial/MonitoredSystemDefinitionDisclosure.tsx",
|
||||
"frontend-modern/src/components/Settings/CommercialBillingSections.tsx",
|
||||
"frontend-modern/src/utils/cloudPlans.ts",
|
||||
"frontend-modern/src/utils/commercialBillingModel.ts",
|
||||
|
|
@ -2519,11 +2457,8 @@
|
|||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/Commercial/__tests__/MonitoredSystemDefinitionDisclosure.test.tsx",
|
||||
"frontend-modern/src/components/Settings/__tests__/OrganizationBillingPanel.test.tsx",
|
||||
"frontend-modern/src/components/Settings/__tests__/ProLicensePanel.test.tsx",
|
||||
"frontend-modern/src/pages/__tests__/CloudPricing.test.tsx",
|
||||
"frontend-modern/src/pages/__tests__/HostedSignup.test.tsx",
|
||||
"frontend-modern/src/utils/__tests__/selfHostedPlans.test.ts"
|
||||
]
|
||||
},
|
||||
|
|
@ -2582,17 +2517,12 @@
|
|||
"label": "pricing route and page proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/pages/CloudPricing.tsx",
|
||||
"frontend-modern/src/pages/HostedSignup.tsx",
|
||||
"frontend-modern/src/pages/PricingHandoff.tsx",
|
||||
"frontend-modern/src/utils/pricingHandoff.ts"
|
||||
],
|
||||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/api/__tests__/hostedSignup.test.ts",
|
||||
"frontend-modern/src/pages/__tests__/CloudPricing.test.tsx",
|
||||
"frontend-modern/src/pages/__tests__/HostedSignup.test.tsx",
|
||||
"frontend-modern/src/pages/__tests__/PricingHandoff.test.tsx",
|
||||
"frontend-modern/src/utils/__tests__/pricingHandoff.test.ts"
|
||||
]
|
||||
|
|
@ -2645,7 +2575,8 @@
|
|||
"tests/integration/tests/53-demo-mode-commercial-boundary.spec.ts"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -2999,7 +2930,8 @@
|
|||
"scripts/installtests/install_sh_test.go"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -3089,7 +3021,6 @@
|
|||
"frontend-modern/src/utils/environmentLockPresentation.ts",
|
||||
"frontend-modern/src/utils/platformSupportManifest.generated.ts",
|
||||
"frontend-modern/src/utils/platformSupportManifest.ts",
|
||||
"frontend-modern/src/utils/problemResourcePresentation.ts",
|
||||
"frontend-modern/src/utils/reportableResourceTypes.ts",
|
||||
"frontend-modern/src/utils/reportingPresentation.ts",
|
||||
"frontend-modern/src/utils/reportingResourceTypes.ts",
|
||||
|
|
@ -3112,7 +3043,6 @@
|
|||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/shared/PageControls.guardrails.test.ts",
|
||||
"frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts"
|
||||
],
|
||||
"require_explicit_path_policy_coverage": true,
|
||||
|
|
@ -3137,7 +3067,6 @@
|
|||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/components/shared/FilterToolbar.tsx",
|
||||
"frontend-modern/src/components/shared/PageControls.tsx",
|
||||
"frontend-modern/src/components/shared/SettingsPanel.tsx",
|
||||
"frontend-modern/src/components/shared/Subtabs.tsx",
|
||||
"frontend-modern/src/components/shared/Toggle.tsx"
|
||||
|
|
@ -3146,9 +3075,7 @@
|
|||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/Settings/__tests__/settingsArchitecture.test.ts",
|
||||
"frontend-modern/src/components/shared/FilterToolbar.test.tsx",
|
||||
"frontend-modern/src/components/shared/PageControls.guardrails.test.ts",
|
||||
"frontend-modern/src/components/shared/PageControls.test.tsx"
|
||||
"frontend-modern/src/components/shared/FilterToolbar.test.tsx"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3322,7 +3249,6 @@
|
|||
"match_files": [
|
||||
"frontend-modern/src/components/Toast/Toast.tsx",
|
||||
"frontend-modern/src/utils/emptyStatePresentation.ts",
|
||||
"frontend-modern/src/utils/problemResourcePresentation.ts",
|
||||
"frontend-modern/src/utils/semanticTonePresentation.ts",
|
||||
"frontend-modern/src/utils/toast.ts",
|
||||
"frontend-modern/src/utils/typeColumnPresentation.ts"
|
||||
|
|
@ -3333,7 +3259,6 @@
|
|||
"frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts",
|
||||
"frontend-modern/src/components/Toast/__tests__/Toast.test.tsx",
|
||||
"frontend-modern/src/utils/__tests__/emptyStatePresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/problemResourcePresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/semanticTonePresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/typeColumnPresentation.test.ts"
|
||||
]
|
||||
|
|
@ -3499,7 +3424,6 @@
|
|||
"label": "search input proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/components/shared/CollapsibleSearchInput.tsx",
|
||||
"frontend-modern/src/components/shared/SearchField.tsx",
|
||||
"frontend-modern/src/components/shared/SearchInput.tsx",
|
||||
"frontend-modern/src/components/shared/SearchInputEnhancements.tsx",
|
||||
|
|
@ -3517,17 +3441,12 @@
|
|||
"label": "data grid and summary proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/components/shared/InfrastructureSummaryTable.tsx",
|
||||
"frontend-modern/src/components/shared/infrastructureSummaryTableModel.ts",
|
||||
"frontend-modern/src/components/shared/InfrastructureSummaryTableRow.tsx",
|
||||
"frontend-modern/src/components/shared/PulseDataGrid.tsx",
|
||||
"frontend-modern/src/components/shared/Table.tsx",
|
||||
"frontend-modern/src/components/shared/useInfrastructureSummaryTableState.ts"
|
||||
"frontend-modern/src/components/shared/Table.tsx"
|
||||
],
|
||||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/shared/__tests__/InfrastructureSummaryTable.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/PulseDataGrid.test.tsx"
|
||||
]
|
||||
},
|
||||
|
|
@ -3543,12 +3462,9 @@
|
|||
"exact_files": [
|
||||
"frontend-modern/src/components/shared/__tests__/CommandPaletteModal.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/ContainerUpdateBadge.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/DensityMap.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/Dialog.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/HelpIcon.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/HistoryChart.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/InfrastructureSelector.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/InfrastructureSummaryTable.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/MobileNavBar.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/PulseDataGrid.test.tsx",
|
||||
"frontend-modern/src/components/shared/__tests__/SearchField.test.tsx",
|
||||
|
|
@ -3558,13 +3474,12 @@
|
|||
"frontend-modern/src/components/shared/__tests__/WebInterfaceUrlField.test.tsx",
|
||||
"frontend-modern/src/components/shared/ColumnPicker.test.tsx",
|
||||
"frontend-modern/src/components/shared/FilterToolbar.test.tsx",
|
||||
"frontend-modern/src/components/shared/PageControls.guardrails.test.ts",
|
||||
"frontend-modern/src/components/shared/PageControls.test.tsx",
|
||||
"frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts",
|
||||
"frontend-modern/src/components/shared/TypeColumn.guardrails.test.ts"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -3873,7 +3788,8 @@
|
|||
"internal/unifiedresources/code_standards_test.go"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -3922,7 +3838,8 @@
|
|||
],
|
||||
"exact_files": []
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -4091,7 +4008,8 @@
|
|||
"internal/api/org_validation_test.go"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -4272,7 +4190,8 @@
|
|||
"frontend-modern/src/utils/__tests__/patrolSummaryPresentation.test.ts"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -4284,8 +4203,6 @@
|
|||
],
|
||||
"owned_files": [
|
||||
"frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts",
|
||||
"frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts",
|
||||
"frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx",
|
||||
|
|
@ -4294,7 +4211,6 @@
|
|||
"frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts",
|
||||
"frontend-modern/src/components/Workloads/DiskList.tsx",
|
||||
|
|
@ -4343,9 +4259,6 @@
|
|||
"frontend-modern/src/components/Workloads/workloadSelectors.ts",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsFilter.tsx",
|
||||
"frontend-modern/src/components/Workloads/workloadsFilterModel.ts",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsStateCards.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsStatsStrip.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsSummary.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsSurface.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsTable.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadTableHeader.tsx",
|
||||
|
|
@ -4355,7 +4268,6 @@
|
|||
"frontend-modern/src/routing/routePreload.ts",
|
||||
"frontend-modern/src/useAppRuntimeState.ts",
|
||||
"frontend-modern/src/utils/thresholdSliderPresentation.ts",
|
||||
"frontend-modern/src/utils/throughputPresentation.ts",
|
||||
"frontend-modern/src/utils/workloadsSummaryCache.ts",
|
||||
"internal/api/router_bench_test.go",
|
||||
"internal/api/slo.go",
|
||||
|
|
@ -4386,7 +4298,6 @@
|
|||
"frontend-modern/src/components/Workloads/MetricBar.test.tsx",
|
||||
"frontend-modern/src/components/Workloads/StackedMemoryBar.test.tsx",
|
||||
"frontend-modern/src/components/Workloads/ThresholdSlider.test.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsSummary.test.tsx",
|
||||
"frontend-modern/src/hooks/__tests__/useWorkloads.test.ts",
|
||||
"internal/api/router_bench_test.go",
|
||||
"internal/api/slo_bench_test.go",
|
||||
|
|
@ -4434,8 +4345,6 @@
|
|||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts",
|
||||
"frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts",
|
||||
"frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx",
|
||||
|
|
@ -4444,7 +4353,6 @@
|
|||
"frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts",
|
||||
"frontend-modern/src/components/Workloads/DiskList.tsx",
|
||||
|
|
@ -4493,9 +4401,6 @@
|
|||
"frontend-modern/src/components/Workloads/workloadSelectors.ts",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsFilter.tsx",
|
||||
"frontend-modern/src/components/Workloads/workloadsFilterModel.ts",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsStateCards.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsStatsStrip.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsSummary.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsSurface.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsTable.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadTableHeader.tsx",
|
||||
|
|
@ -4508,7 +4413,6 @@
|
|||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/infrastructureSummaryModel.test.ts",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/unifiedResourceTableStateModel.test.ts",
|
||||
"frontend-modern/src/components/Workloads/__tests__/DiskList.test.tsx",
|
||||
|
|
@ -4538,25 +4442,11 @@
|
|||
"frontend-modern/src/components/Workloads/MetricBar.test.tsx",
|
||||
"frontend-modern/src/components/Workloads/StackedMemoryBar.test.tsx",
|
||||
"frontend-modern/src/components/Workloads/ThresholdSlider.test.tsx",
|
||||
"frontend-modern/src/components/Workloads/WorkloadsSummary.test.tsx",
|
||||
"frontend-modern/src/hooks/__tests__/useWorkloads.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/thresholdSliderPresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/workloadsSummaryCache.test.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "throughput-presentation-helper",
|
||||
"label": "throughput presentation helper proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/utils/throughputPresentation.ts"
|
||||
],
|
||||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/utils/__tests__/throughputPresentation.test.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "api-history-slo",
|
||||
"label": "API history SLO proof",
|
||||
|
|
@ -4570,7 +4460,8 @@
|
|||
"internal/api/slo_bench_test.go"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -4665,7 +4556,8 @@
|
|||
"pulse-mobile:src/relay/__tests__/proxy.test.ts"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -4875,7 +4767,8 @@
|
|||
"internal/api/system_settings_telemetry_test.go"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -4883,9 +4776,7 @@
|
|||
"lane": "L15",
|
||||
"contract": "docs/release-control/v6/internal/subsystems/storage-recovery.md",
|
||||
"owned_prefixes": [
|
||||
"frontend-modern/src/components/Recovery/",
|
||||
"frontend-modern/src/components/Storage/",
|
||||
"frontend-modern/src/features/recovery/",
|
||||
"frontend-modern/src/features/storageBackups/",
|
||||
"internal/recovery/"
|
||||
],
|
||||
|
|
@ -4897,31 +4788,20 @@
|
|||
"frontend-modern/src/features/proxmox/ProxmoxBackupsTable.tsx",
|
||||
"frontend-modern/src/features/proxmox/proxmoxBackupSummaryPresentation.ts",
|
||||
"frontend-modern/src/features/proxmox/ProxmoxPageSurface.tsx",
|
||||
"frontend-modern/src/features/recovery/useRecoverySurfaceState.ts",
|
||||
"frontend-modern/src/hooks/useRecoveryPoints.ts",
|
||||
"frontend-modern/src/hooks/useRecoveryPointsFacets.ts",
|
||||
"frontend-modern/src/hooks/useRecoveryPointsSeries.ts",
|
||||
"frontend-modern/src/hooks/useRecoveryRollups.ts",
|
||||
"frontend-modern/src/types/recovery.ts",
|
||||
"frontend-modern/src/utils/recoveryActionPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryArtifactModePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryDatePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryEmptyStatePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryFilterChipPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryIssuePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryItemTypePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryOutcomePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryRecordPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryStatusPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryTablePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryTimelineChartPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryTimelinePresentation.ts"
|
||||
"frontend-modern/src/utils/recoveryTimelinePresentation.ts",
|
||||
"internal/api/setup_script_render.go"
|
||||
],
|
||||
"verification": {
|
||||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx",
|
||||
"frontend-modern/src/components/Storage/code_standards.test.ts",
|
||||
"internal/recovery/recovery_test.go"
|
||||
],
|
||||
|
|
@ -4949,34 +4829,20 @@
|
|||
{
|
||||
"id": "recovery-product-surface",
|
||||
"label": "recovery product surface proof",
|
||||
"match_prefixes": [
|
||||
"frontend-modern/src/components/Recovery/"
|
||||
],
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/features/recovery/useRecoverySurfaceState.ts",
|
||||
"frontend-modern/src/hooks/useRecoveryPoints.ts",
|
||||
"frontend-modern/src/hooks/useRecoveryPointsFacets.ts",
|
||||
"frontend-modern/src/hooks/useRecoveryPointsSeries.ts",
|
||||
"frontend-modern/src/hooks/useRecoveryRollups.ts",
|
||||
"frontend-modern/src/types/recovery.ts",
|
||||
"frontend-modern/src/utils/recoveryActionPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryArtifactModePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryDatePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryEmptyStatePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryFilterChipPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryIssuePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryItemTypePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryOutcomePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryRecordPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryStatusPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryTablePresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryTimelineChartPresentation.ts",
|
||||
"frontend-modern/src/utils/recoveryTimelinePresentation.ts"
|
||||
],
|
||||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx",
|
||||
"frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts",
|
||||
"tests/integration/tests/17-recovery-layout.spec.ts"
|
||||
]
|
||||
|
|
@ -4997,7 +4863,6 @@
|
|||
"frontend-modern/src/components/Storage/__tests__/Storage.test.tsx",
|
||||
"frontend-modern/src/components/Storage/__tests__/StorageGroupRow.test.tsx",
|
||||
"frontend-modern/src/components/Storage/__tests__/StoragePoolDetail.test.tsx",
|
||||
"frontend-modern/src/components/Storage/__tests__/useStoragePageSummary.test.ts",
|
||||
"frontend-modern/src/components/Storage/code_standards.test.ts",
|
||||
"frontend-modern/src/features/storageBackups/__tests__/resourceStorageMapping.test.ts",
|
||||
"frontend-modern/src/features/storageBackups/__tests__/storageAdapters.test.ts",
|
||||
|
|
@ -5030,8 +4895,22 @@
|
|||
"frontend-modern/src/features/proxmox/__tests__/ProxmoxBackupsTable.test.tsx",
|
||||
"frontend-modern/src/features/proxmox/__tests__/proxmoxBackupSummaryPresentation.test.ts"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "shared-setup-script-boundary",
|
||||
"label": "shared Proxmox setup-script storage/recovery boundary proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"internal/api/setup_script_render.go"
|
||||
],
|
||||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"internal/api/contract_test.go"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -5046,10 +4925,7 @@
|
|||
"frontend-modern/src/components/Discovery/useDiscoveryTabState.ts",
|
||||
"frontend-modern/src/components/Docker/SwarmServicesDrawer.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts",
|
||||
"frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/ResourceActionHistory.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/resourceBadges.ts",
|
||||
"frontend-modern/src/components/Infrastructure/ResourceChangeSummary.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/ResourceCorrelationSummary.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/resourceDetailDiscoveryModel.ts",
|
||||
|
|
@ -5070,7 +4946,6 @@
|
|||
"frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDerivedState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDockerActionsState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useResourceDetailDrawerHistoryState.ts",
|
||||
|
|
@ -5079,10 +4954,6 @@
|
|||
"frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts",
|
||||
"frontend-modern/src/components/Kubernetes/K8sDeploymentsDrawer.tsx",
|
||||
"frontend-modern/src/components/Kubernetes/K8sNamespacesDrawer.tsx",
|
||||
"frontend-modern/src/components/PMG/MailGateway.tsx",
|
||||
"frontend-modern/src/components/PMG/PMGInstanceDrawer.tsx",
|
||||
"frontend-modern/src/components/PMG/PMGInstancePanel.tsx",
|
||||
"frontend-modern/src/components/PMG/ServiceHealthBadge.tsx",
|
||||
"frontend-modern/src/features/docker/DockerConfigsTable.tsx",
|
||||
"frontend-modern/src/features/docker/DockerContainersTable.tsx",
|
||||
"frontend-modern/src/features/docker/DockerImagesTable.tsx",
|
||||
|
|
@ -5193,8 +5064,6 @@
|
|||
"frontend-modern/src/components/Discovery/useDiscoveryTabState.ts",
|
||||
"frontend-modern/src/components/Docker/SwarmServicesDrawer.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts",
|
||||
"frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/ResourceActionHistory.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/ResourceChangeSummary.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/ResourceCorrelationSummary.tsx",
|
||||
|
|
@ -5216,7 +5085,6 @@
|
|||
"frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDerivedState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDockerActionsState.ts",
|
||||
"frontend-modern/src/components/Infrastructure/useResourceDetailDrawerHistoryState.ts",
|
||||
|
|
@ -5225,9 +5093,6 @@
|
|||
"frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts",
|
||||
"frontend-modern/src/components/Kubernetes/K8sDeploymentsDrawer.tsx",
|
||||
"frontend-modern/src/components/Kubernetes/K8sNamespacesDrawer.tsx",
|
||||
"frontend-modern/src/components/PMG/MailGateway.tsx",
|
||||
"frontend-modern/src/components/PMG/PMGInstanceDrawer.tsx",
|
||||
"frontend-modern/src/components/PMG/PMGInstancePanel.tsx",
|
||||
"frontend-modern/src/features/docker/DockerConfigsTable.tsx",
|
||||
"frontend-modern/src/features/docker/DockerContainersTable.tsx",
|
||||
"frontend-modern/src/features/docker/DockerImagesTable.tsx",
|
||||
|
|
@ -5263,7 +5128,6 @@
|
|||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/infrastructureSelectors.test.ts",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/infrastructureSummaryModel.test.ts",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/ResourceChangeSummary.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/ResourceCorrelationSummary.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.discovery.test.ts",
|
||||
|
|
@ -5375,8 +5239,6 @@
|
|||
"label": "resource type, badge, and service-health presentation helper proof",
|
||||
"match_prefixes": [],
|
||||
"match_files": [
|
||||
"frontend-modern/src/components/Infrastructure/resourceBadges.ts",
|
||||
"frontend-modern/src/components/PMG/ServiceHealthBadge.tsx",
|
||||
"frontend-modern/src/utils/canonicalResourceTypes.ts",
|
||||
"frontend-modern/src/utils/resourceBadgePresentation.ts",
|
||||
"frontend-modern/src/utils/resourceTypeCompat.ts",
|
||||
|
|
@ -5388,7 +5250,6 @@
|
|||
"allow_same_subsystem_tests": false,
|
||||
"test_prefixes": [],
|
||||
"exact_files": [
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/resourceBadges.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/canonicalResourceTypes.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/resourceBadgePresentation.test.ts",
|
||||
|
|
@ -5489,7 +5350,8 @@
|
|||
"internal/unifiedresources/store_test.go"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"match_files": null
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -26,10 +26,6 @@ for Pulse instance bridging.
|
|||
2. `internal/relay/protocol.go`
|
||||
3. `internal/config/persistence_relay.go`
|
||||
4. `internal/api/relay_mobile_capability.go`
|
||||
5. `pulse-mobile:src/relay/client.ts`
|
||||
6. `pulse-mobile:src/relay/protocol.ts`
|
||||
7. `pulse-mobile:src/relay/proxy.ts`
|
||||
8. `pulse-mobile:src/relay/encryption.ts`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
|
|
@ -51,7 +47,6 @@ for Pulse instance bridging.
|
|||
from the UI is allowed to persist the env-effective state to disk;
|
||||
the override is not stripped before save.
|
||||
4. Add or change the backend-owned mobile relay capability inventory and compatibility scope mapping through `internal/api/relay_mobile_capability.go`
|
||||
5. Add or change mobile relay reconnect, drain, channel, encryption, proxy, or identity behavior through `pulse-mobile:src/relay/`
|
||||
6. Keep desktop and mobile relay changes aligned with the governed server relay surfaces represented by the L7 lane evidence
|
||||
|
||||
## Forbidden Paths
|
||||
|
|
|
|||
|
|
@ -30,45 +30,30 @@ state.
|
|||
1. `internal/recovery/index.go`
|
||||
2. `internal/recovery/manager/manager.go`
|
||||
3. `internal/recovery/store/store.go`
|
||||
4. `frontend-modern/src/components/Recovery/Recovery.tsx`
|
||||
5. `frontend-modern/src/features/recovery/useRecoverySurfaceState.ts`
|
||||
6. `frontend-modern/src/components/Recovery/RecoveryProtectedInventorySection.tsx`
|
||||
7. `frontend-modern/src/components/Recovery/RecoveryActivitySection.tsx`
|
||||
8. `frontend-modern/src/components/Recovery/RecoveryHistorySection.tsx`
|
||||
9. `frontend-modern/src/components/Recovery/RecoveryHistoryTable.tsx`
|
||||
10. `frontend-modern/src/components/Recovery/RecoveryHistoryItemFilter.tsx`
|
||||
11. `frontend-modern/src/components/Recovery/RecoveryPointDetails.tsx`
|
||||
12. `frontend-modern/src/components/Recovery/useRecoveryHistorySectionState.ts`
|
||||
13. `frontend-modern/src/components/Storage/Storage.tsx`
|
||||
14. `frontend-modern/src/features/storageBackups/storageModelCore.ts`
|
||||
15. `frontend-modern/src/utils/storageSources.ts`
|
||||
16. `frontend-modern/src/hooks/useRecoveryPoints.ts`
|
||||
17. `frontend-modern/src/hooks/useRecoveryRollups.ts`
|
||||
18. `frontend-modern/src/hooks/useRecoveryPointsFacets.ts`
|
||||
19. `frontend-modern/src/hooks/useRecoveryPointsSeries.ts`
|
||||
20. `frontend-modern/src/routing/resourceLinks.ts`
|
||||
21. `frontend-modern/src/types/recovery.ts`
|
||||
22. `frontend-modern/src/utils/recoveryDatePresentation.ts`
|
||||
23. `frontend-modern/src/utils/recoveryEmptyStatePresentation.ts`
|
||||
24. `frontend-modern/src/utils/recoveryTablePresentation.ts`
|
||||
25. `frontend-modern/src/utils/recoveryTimelinePresentation.ts`
|
||||
26. `frontend-modern/src/utils/recoveryItemTypePresentation.ts`
|
||||
27. `frontend-modern/src/utils/textPresentation.ts`
|
||||
28. `frontend-modern/src/components/Storage/StorageSummary.tsx`
|
||||
29. `frontend-modern/src/utils/storageSummaryCache.ts`
|
||||
30. `frontend-modern/src/components/Storage/useStorageSummaryCharts.ts`
|
||||
31. `frontend-modern/src/features/storageBackups/storageCapacityDeltaPresentation.ts`
|
||||
32. `frontend-modern/src/features/proxmox/BackupActivityChart.tsx`
|
||||
33. `frontend-modern/src/features/proxmox/ProxmoxBackupsCoverageStrip.tsx`
|
||||
34. `frontend-modern/src/features/proxmox/ProxmoxBackupsTable.tsx`
|
||||
35. `frontend-modern/src/features/proxmox/proxmoxBackupActivityPresentation.ts`
|
||||
36. `frontend-modern/src/features/proxmox/proxmoxBackupRecoveryModel.ts`
|
||||
37. `frontend-modern/src/features/proxmox/proxmoxBackupSummaryPresentation.ts`
|
||||
38. `frontend-modern/src/features/proxmox/ProxmoxPageSurface.tsx`
|
||||
4. `frontend-modern/src/components/Storage/Storage.tsx`
|
||||
5. `frontend-modern/src/features/storageBackups/storageModelCore.ts`
|
||||
6. `frontend-modern/src/utils/storageSources.ts`
|
||||
7. `frontend-modern/src/hooks/useRecoveryPoints.ts`
|
||||
8. `frontend-modern/src/routing/resourceLinks.ts`
|
||||
9. `frontend-modern/src/types/recovery.ts`
|
||||
10. `frontend-modern/src/utils/recoveryDatePresentation.ts`
|
||||
11. `frontend-modern/src/utils/recoveryTimelinePresentation.ts`
|
||||
12. `frontend-modern/src/utils/recoveryItemTypePresentation.ts`
|
||||
13. `frontend-modern/src/utils/textPresentation.ts`
|
||||
14. `frontend-modern/src/utils/storageSummaryCache.ts`
|
||||
15. `frontend-modern/src/components/Storage/useStorageSummaryCharts.ts`
|
||||
16. `frontend-modern/src/features/storageBackups/storageCapacityDeltaPresentation.ts`
|
||||
17. `frontend-modern/src/features/proxmox/BackupActivityChart.tsx`
|
||||
18. `frontend-modern/src/features/proxmox/ProxmoxBackupsCoverageStrip.tsx`
|
||||
19. `frontend-modern/src/features/proxmox/ProxmoxBackupsTable.tsx`
|
||||
20. `frontend-modern/src/features/proxmox/proxmoxBackupActivityPresentation.ts`
|
||||
21. `frontend-modern/src/features/proxmox/proxmoxBackupRecoveryModel.ts`
|
||||
22. `frontend-modern/src/features/proxmox/proxmoxBackupSummaryPresentation.ts`
|
||||
23. `frontend-modern/src/features/proxmox/ProxmoxPageSurface.tsx`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
1. None.
|
||||
1. `internal/api/setup_script_render.go` shared with `agent-lifecycle`, `api-contracts`: the generated Proxmox setup-script is a shared boundary across agent lifecycle (forced-command keys, install/uninstall edits), API contracts (rendered token shape and encoded rerun URL), and storage/recovery (backup visibility grants, Pulse-managed temperature SSH keys, and SMART disk-temperature collection).
|
||||
|
||||
## Extension Points
|
||||
|
||||
|
|
@ -216,176 +201,6 @@ outside the storage/recovery contract and must not become restore material,
|
|||
recovery scope, or a storage/recovery-owned secret source.
|
||||
|
||||
1. Add or change recovery-point persistence, rollups, or series derivation through `internal/recovery/`
|
||||
2. Add or change recovery page UX through `frontend-modern/src/components/Recovery/` and keep canonical route/query/filter state ownership in `frontend-modern/src/features/recovery/useRecoverySurfaceState.ts`
|
||||
`/recovery` is no longer an authenticated top-level aggregate workspace.
|
||||
`frontend-modern/src/App.tsx`, `frontend-modern/src/AppLayout.tsx`, the command
|
||||
palette, keyboard shortcuts, route preloading, and active-tab routing must
|
||||
keep Recovery unregistered as standalone product navigation rather than as
|
||||
hidden compatibility. `/storage` has the same retired top-level status for
|
||||
the Storage owner surface. Storage/recovery state remains owned by the
|
||||
reusable surfaces that platform pages embed; the app shell must not
|
||||
duplicate that state or expose it as a separate aggregate route.
|
||||
Recovery table surfaces must consume the frontend-primitives-owned
|
||||
`TableCard` frame and `TableCardHeader` header band for protected-item,
|
||||
recovery-event, and adjacent table-fallback chrome. Storage/recovery may own
|
||||
table content, filters, columns, and rows, but it must not fork
|
||||
border/background/overflow table shells, page-local table-title bands, or
|
||||
lighter open-sided Recovery table frames. Recovery and storage tables must
|
||||
use the shared `Table` scroll shell directly; if a table needs the card body
|
||||
surface fill it may pass `wrapperClass`, but it must not nest a local
|
||||
`overflow-x-auto` div around the shared table. Storage pools and physical
|
||||
disks inherit the surrounding `StorageContentCard` frame and must not add
|
||||
a nested `Card` or second scroll wrapper.
|
||||
Recovery is event-first: recovery surfaces open on recovery events history
|
||||
by default, and protected-item rollups are a secondary Protection coverage
|
||||
review reached from the explicit header action or route state owned by the
|
||||
embedding surface. Recovery must not present
|
||||
protected rollups and recovery events as equal default sub-tabs because
|
||||
workload backup posture already belongs on Workloads, while Recovery owns
|
||||
concrete backup/snapshot/replication evidence. Both surfaces still opt into
|
||||
shared saved views (`savedViewsKey="recovery-protected"` and
|
||||
`"recovery-events"`) so operators can save and recall named filter combos
|
||||
through the shared `SavedViewsMenu`.
|
||||
Recovery must not restore the retired top-level RecoverySummary metric card
|
||||
strip. Aggregate recovery counts, success/failure mix, and selected-day
|
||||
context belong inside the Recovery activity and event-history surfaces that
|
||||
already own the chart and table filters, rather than as a separate summary
|
||||
helper that competes with the event-first page hierarchy.
|
||||
Recovery event filters now compose the shared chip-based `FilterBar`
|
||||
(`frontend-modern/src/components/shared/FilterBar/FilterBar.tsx`) with a
|
||||
`FilterDef[]` catalog. The legacy "advanced filter popover" retired: scope,
|
||||
method, verification, cluster, node, and namespace fold into the same chip
|
||||
catalog as Item Type, Platform, and Status. Page-level search, column
|
||||
visibility, and the rollup item filter live in the shared search row; the
|
||||
chip row appears below it only when filters are active. Recovery must not
|
||||
reintroduce a parallel `PageControls` toolbar or local no-wrap overrides
|
||||
that bypass the FilterBar shell.
|
||||
Compact stable recovery-event filters, such as event outcome/status, ride
|
||||
the same chip popover affordance the rest of the catalog uses, with
|
||||
type-ahead in the "+ Filter" menu and chip popovers, but Recovery must keep
|
||||
route-backed event filter state and query semantics in its recovery owner
|
||||
rather than introducing a page-local presentation state path.
|
||||
Recovery inventory protection posture and recovery-event outcome filtering
|
||||
must stay separate in that owner: protection coverage uses the route-backed
|
||||
`state` query for health, stale, failed, warning, running, unknown, and
|
||||
never-succeeded states, while recovery events use `status` for event
|
||||
outcomes. Legacy `stale=1` input may hydrate the inventory `state=stale`
|
||||
compatibility path, but event views and event drill-ins must drop
|
||||
protected-inventory-only state so hidden filters cannot make valid history
|
||||
look empty.
|
||||
Recovery activity timeline state is also storage/recovery-owned. The
|
||||
route-backed range, selected day, and viewport-derived mobile cadence must
|
||||
stay in `frontend-modern/src/features/recovery/useRecoverySurfaceState.ts`
|
||||
and the Recovery page owner, with one shared transport-query builder feeding
|
||||
the chart window to rollups/series and the table window to points/facets.
|
||||
The series query may append timezone offset for bucket alignment, but
|
||||
presentation components must not rebuild a second query contract or conflate
|
||||
the chart and table windows. The activity chart must preserve readable
|
||||
bucket density across the governed 7, 30, 90, and 365 day ranges: seven-day
|
||||
timelines fit the available viewport without forced horizontal overflow,
|
||||
thirty-day timelines may widen on mobile only, and longer ranges scroll in a
|
||||
bounded chart viewport with sparser labels so first, last, and selected-day
|
||||
context remain visible without overlapping labels. Selecting a timeline
|
||||
column remains route-backed and must not become component-local ephemeral
|
||||
state. The Recovery activity bar chart must use the frontend-primitives
|
||||
shared chart slot height and matching plot-area height so it keeps visual
|
||||
parity with the Workloads, Storage, and Infrastructure summary charts
|
||||
without copying page-local chart sizing.
|
||||
A selected timeline day is an active event-history filter: table totals,
|
||||
footer ranges, empty states, and search/date matching must describe the
|
||||
visible filtered recovery points, not the unfiltered API page metadata.
|
||||
3. Add or change storage UX through `frontend-modern/src/components/Storage/Storage.tsx` (the canonical `StorageSurface`, embedded inside platform pages), `frontend-modern/src/components/Storage/`, `frontend-modern/src/features/storageBackups/`, the shared storage-source contract in `frontend-modern/src/utils/storageSources.ts`, and the Proxmox-native Ceph table at `frontend-modern/src/features/proxmox/ProxmoxCephTable.tsx`. The old standalone page wrappers under the legacy frontend-modern pages directory were retired with the platform-first primary nav (2026-05-16), and the top-level aggregate Workloads / Storage / Recovery routes were unregistered on 2026-05-25; the canonical component surfaces remain alive as embedded views inside matching platform page sub-tabs. The old top-level Ceph alias is unregistered; Proxmox owns the Ceph tab.
|
||||
The retired dashboard route must not reintroduce storage or recovery
|
||||
widgets as compatibility panels. Storage capacity, storage health,
|
||||
protected-item, and recovery-outcome readiness claims belong on the Storage
|
||||
and Recovery surfaces or their shared summary components, not in a restored
|
||||
dashboard panel cluster or Assistant brief.
|
||||
Storage filters now compose the shared `FilterBar` shell
|
||||
through `frontend-modern/src/components/Storage/StoragePageControls.tsx`.
|
||||
The legacy three-layer indirection
|
||||
(`StoragePageControls` → `StorageControls` → `StorageFilter`) and the
|
||||
bare unlabelled Node `<select>` retired with the migration; Node, Source,
|
||||
Status, Group by, and the disk-role / disk-group filters all enter the
|
||||
`FilterDef[]` catalog. Low-cardinality Group by and Status filters render
|
||||
as unlabeled inline primary controls from that catalog in the same compact
|
||||
second-row rail as sort, charts, and reset, while Node, Source, Role, and
|
||||
Group remain menu/chip filters because their option sets are scope- or
|
||||
data-driven. Embedded platform storage surfaces must provide page-owned
|
||||
filter aria labels, search placeholders, and empty-search copy for the
|
||||
visible storage model (for example Proxmox storage, TrueNAS pools and
|
||||
datasets, or vSphere datastores) while preserving the canonical
|
||||
`FilterDef[]` route-state contract in `StoragePageControls`. Forced source
|
||||
storage surfaces must derive Node facet options from nodes that match the
|
||||
same canonical source scope, and empty filtered storage record sets must
|
||||
render the storage empty state instead of a synthetic empty "All" group.
|
||||
Subtabs (Pools / Physical Disks) sit above the bar as navigation, not
|
||||
filters.
|
||||
Storage pool table header sorting is storage/recovery-owned and must bind
|
||||
visible pool columns to the canonical storage sort state instead of
|
||||
introducing platform-local or table-local sort state. Header clicks must
|
||||
update the same `sort` / `order` model as the toolbar select, expose
|
||||
`aria-sort` on the active column, and cover displayed pool columns
|
||||
including state, source, type, host, protection, usage, and growth. Growth
|
||||
sorting may consume summary delta data, but non-growth sorts must not track
|
||||
chart delta maps or re-render row order when chart data refreshes.
|
||||
Platform-page storage and recovery section tabs
|
||||
are still capability-gated navigation: Proxmox Storage,
|
||||
Backups, Ceph, Replication, and adjacent recovery sections may appear only
|
||||
when the platform page model has matching storage, backup, Ceph,
|
||||
replication, or provider evidence. Empty capability tabs must not remain as
|
||||
disabled placeholders on platform pages.
|
||||
Storage summary chart visibility remains a
|
||||
page-level display preference, but it now rides the shared
|
||||
`FilterBar.viewOptionsTrailing` slot together with the sort key/direction
|
||||
controls. The charts toggle must read as an explicit `Show charts` /
|
||||
`Hide charts` pressed display action, and the off state must remove the
|
||||
summary section fully instead of leaving a collapsed summary shell in the
|
||||
interface. When the storage summary remains visible below the desktop
|
||||
breakpoint, it must use the frontend-primitives-owned
|
||||
`StickySummarySection` desktop-sticky mode so the wrapped 2x2 chart grid
|
||||
scrolls with the page instead of pinning most of a narrow viewport.
|
||||
Storage must not reintroduce a sticky, frontend-only growth planner or
|
||||
runway card derived directly from rolling summary chart deltas. Capacity
|
||||
pressure planning may return as a governed storage/recovery model only when
|
||||
the signal is stable, backend-owned, and action-oriented enough not to churn
|
||||
the primary monitoring surface during ordinary refreshes.
|
||||
Ceph table shells on the storage route share the same frontend-primitives
|
||||
table contract: `frontend-modern/src/pages/Ceph.tsx` may own Ceph-specific
|
||||
columns and rows, but horizontal overflow and scrollbar hiding must route
|
||||
through the shared `Table` wrapper rather than page-local scroll divs or
|
||||
inline overflow styles.
|
||||
Storage capacity bars may consume alert-backed disk thresholds, but storage
|
||||
surfaces do not own threshold selection. `EnhancedStorageBar` and its model
|
||||
must pass resolved thresholds from the alerts activation boundary into the
|
||||
shared metric-color helper instead of carrying storage-local usage color
|
||||
bands.
|
||||
Storage presentation is topology-first and factual. The Storage page should
|
||||
show each platform's main storage shape in recognizable platform terms
|
||||
(arrays, cache pools, pools, datastores, repositories, and physical media)
|
||||
with capacity and health facts attached to that shape; it must not collapse
|
||||
non-Proxmox platforms into Proxmox-shaped pool rows or turn factual topology
|
||||
into prescriptive remediation copy.
|
||||
Storage state presentation must stay incident/risk-owned. Composite
|
||||
posture summaries from unified resources may include dependency or protected
|
||||
workload impact, so `frontend-modern/src/features/storageBackups/` must not
|
||||
use `storage.postureSummary` or `pbs.postureSummary` as primary issue copy
|
||||
for healthy resources. Dependency impact belongs to impact summaries and
|
||||
detail context, while visible state must derive from explicit incidents,
|
||||
storage risk summaries, or storage-risk reasons.
|
||||
Unraid storage posture follows that same rule even when it reaches
|
||||
infrastructure through the agent facet instead of the dedicated Storage
|
||||
page: no-parity, parity-unavailable, disabled/missing disk, and sync/check
|
||||
explanations must come from canonical `storage` or `agent.unraid`
|
||||
storage-risk fields. Storage/recovery-adjacent consumers may render those
|
||||
summaries, but they must not infer Unraid array health from generic
|
||||
frontend status labels or from empty no-present slots.
|
||||
Unraid storage presentation must also consume the canonical Unraid
|
||||
topology published by unified resources. Array disks, cache/pool storage,
|
||||
native used/free capacity, device model/transport, temperature, spin state,
|
||||
and error counters belong in `storage`, `physical_disk`, and `agent.unraid`
|
||||
payloads before they reach Storage. The Storage page must not attempt to
|
||||
reconstruct Unraid pools from generic SMART-only rows or treat missing SMART
|
||||
scans on spun-down disks as missing storage topology.
|
||||
4. Route transport changes for storage and recovery endpoints through `internal/api/` and the owning `api-contracts` proof routes
|
||||
Shared API-token transport helpers may be consumed by storage/recovery-
|
||||
adjacent flows, but `owner_user_id` remains server-authored token identity
|
||||
|
|
@ -855,13 +670,6 @@ recovery scope, or a storage/recovery-owned secret source.
|
|||
In mock mode, that same compact route must stay aggregate-only and
|
||||
sampler-prewarmed; storage and recovery must not trigger per-pool chart
|
||||
reconstruction on the first dashboard request after each mock refresh.
|
||||
35. Keep storage and recovery websocket reads on the neutral app-runtime boundary. `frontend-modern/src/components/Recovery/RecoveryPointDetails.tsx`, `frontend-modern/src/components/Storage/useStoragePageResources.ts`, and adjacent summary/detail composition may consume live websocket state only through `frontend-modern/src/contexts/appRuntime.ts`, not by importing `frontend-modern/src/App.tsx` or rebuilding shell-local providers.
|
||||
That same dashboard composition boundary is now a retired negative space.
|
||||
Storage and recovery-adjacent summaries may reuse
|
||||
`/api/charts/storage-summary` through their owning summary components, but
|
||||
they must not restore `/api/resources/dashboard-summary`, paginated
|
||||
`useUnifiedResources()` transport, or per-pool `/api/metrics-store/history`
|
||||
fan-out under a dashboard hot path.
|
||||
36. Keep shared `frontend-modern/src/App.tsx` public-route ownership explicit by
|
||||
surface. Storage/recovery preview entrypoints such as
|
||||
`/preview/setup-complete` may remain public app-shell routes, but unrelated
|
||||
|
|
@ -964,14 +772,6 @@ recovery scope, or a storage/recovery-owned secret source.
|
|||
runtime as populated mock inventory, but they must not expose
|
||||
`demo_fixtures`, billing identity, or alternate entitlement semantics as
|
||||
recovery-local transport or operator-facing storage metadata.
|
||||
38. Keep storage summary fetches scope-owned on the shared summary caches.
|
||||
`frontend-modern/src/components/Storage/StorageSummary.tsx`,
|
||||
`frontend-modern/src/utils/storageSummaryCache.ts`,
|
||||
and `frontend-modern/src/utils/storageSummaryTrendCache.ts` may reuse
|
||||
cached org/range storage summaries for first paint, but they must not
|
||||
refetch the full `/api/storage-charts` payload once per adjacent summary
|
||||
card or invent a dashboard-only storage summary transport path outside the
|
||||
canonical cache owners.
|
||||
39. Keep storage and recovery route framing additive and owner-neutral.
|
||||
`frontend-modern/src/components/Storage/Storage.tsx` and storage/recovery-
|
||||
adjacent route composition may use the shared `PageHeader` shell for
|
||||
|
|
@ -2737,6 +2537,12 @@ setup and removal preserve Proxmox-managed `/root/.ssh/authorized_keys`
|
|||
symlinks: adjacent storage and recovery setup flows may depend on the shared
|
||||
script renderer, but they must not replace the symlink path with a local file
|
||||
when filtering Pulse-managed `# pulse-` SSH key entries.
|
||||
That same dependency also assumes the shared PVE setup script binds
|
||||
temperature-monitoring SSH keys to `/usr/local/sbin/pulse-sensors` and emits
|
||||
SMART disk temperatures in the wrapper payload. Storage and recovery disk
|
||||
temperature surfaces may depend on that monitoring-owned SMART merge path, but
|
||||
they must not reintroduce raw `sensors -j` as the setup contract or build a
|
||||
storage-local disk-temperature collector.
|
||||
That same shared discovery dependency also assumes runtime discovery state owns
|
||||
only structured errors, while adjacent API and WebSocket payloads may derive
|
||||
the deprecated string `errors` list only as a compatibility field from those
|
||||
|
|
|
|||
|
|
@ -9,9 +9,7 @@
|
|||
"contract_file": "docs/release-control/v6/internal/subsystems/unified-resources.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"
|
||||
]
|
||||
"dependency_subsystem_ids": []
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -67,81 +65,73 @@ cross-source deduplication.
|
|||
43. `frontend-modern/src/features/docker/dockerPageModel.ts`
|
||||
44. `frontend-modern/src/components/Kubernetes/K8sDeploymentsDrawer.tsx`
|
||||
45. `frontend-modern/src/components/Kubernetes/K8sNamespacesDrawer.tsx`
|
||||
46. `frontend-modern/src/components/PMG/PMGInstanceDrawer.tsx`
|
||||
47. `frontend-modern/src/components/PMG/MailGateway.tsx`
|
||||
48. `frontend-modern/src/components/PMG/PMGInstancePanel.tsx`
|
||||
49. `frontend-modern/src/components/Infrastructure/ResourceActionHistory.tsx`
|
||||
50. `frontend-modern/src/components/Infrastructure/ResourceFacetSummary.tsx`
|
||||
51. `frontend-modern/src/components/Infrastructure/ResourceChangeSummary.tsx`
|
||||
52. `frontend-modern/src/components/Infrastructure/ResourceCorrelationSummary.tsx`
|
||||
53. `frontend-modern/src/components/Infrastructure/ResourcePolicySummary.tsx`
|
||||
54. `frontend-modern/src/components/Infrastructure/resourceBadges.ts`
|
||||
55. `frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx`
|
||||
56. `frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx`
|
||||
57. `frontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsx`
|
||||
58. `frontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx`
|
||||
59. `frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts`
|
||||
60. `frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts`
|
||||
61. `frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDerivedState.ts`
|
||||
62. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerServiceModel.ts`
|
||||
63. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerVmwareModel.ts`
|
||||
64. `frontend-modern/src/components/Infrastructure/resourceDetailDiscoveryModel.ts`
|
||||
65. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerOperationalModel.ts`
|
||||
66. `frontend-modern/src/components/Infrastructure/useResourceDetailDrawerHistoryState.ts`
|
||||
67. `frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDockerActionsState.ts`
|
||||
68. `frontend-modern/src/components/Infrastructure/useResourceDetailDrawerState.ts`
|
||||
69. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts`
|
||||
70. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts`
|
||||
71. `frontend-modern/src/components/Discovery/DiscoveryTab.tsx`
|
||||
72. `frontend-modern/src/components/Discovery/useDiscoveryTabState.ts`
|
||||
73. `frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsx`
|
||||
74. `frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts`
|
||||
75. `frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts`
|
||||
76. `frontend-modern/src/utils/agentResources.ts`
|
||||
77. `frontend-modern/src/utils/canonicalResourceTypes.ts`
|
||||
78. `frontend-modern/src/utils/resourceBadgePresentation.ts`
|
||||
79. `frontend-modern/src/utils/resourceChangePresentation.ts`
|
||||
80. `frontend-modern/src/utils/actionAuditPresentation.ts`
|
||||
81. `frontend-modern/src/utils/resourceCorrelationPresentation.ts`
|
||||
82. `frontend-modern/src/utils/resourcePlatformData.ts`
|
||||
83. `frontend-modern/src/utils/resourcePolicyPresentation.ts`
|
||||
84. `frontend-modern/src/utils/resourceStateAdapters.ts`
|
||||
85. `frontend-modern/src/utils/resourceTypeCompat.ts`
|
||||
86. `frontend-modern/src/utils/resourceTypePresentation.ts`
|
||||
87. `frontend-modern/src/utils/serviceHealthPresentation.ts`
|
||||
88. `frontend-modern/src/utils/sourceTypePresentation.ts`
|
||||
89. `frontend-modern/src/utils/workloadTypePresentation.ts`
|
||||
90. `frontend-modern/src/components/PMG/ServiceHealthBadge.tsx`
|
||||
91. `frontend-modern/src/utils/resourceIdentity.ts`
|
||||
92. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerIdentityModel.ts`
|
||||
93. `frontend-modern/src/hooks/useUnifiedResources.ts`
|
||||
94. `frontend-modern/src/types/resource.ts`
|
||||
95. `frontend-modern/src/utils/sourcePlatforms.ts`
|
||||
96. `frontend-modern/src/utils/platformSupportManifest.generated.ts`
|
||||
97. `internal/unifiedresources/kubernetes_metric_ids.go`
|
||||
98. `internal/unifiedresources/policy_posture.go`
|
||||
99. `internal/unifiedresources/clone.go`
|
||||
100. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerPresentation.ts`
|
||||
101. `internal/unifiedresources/storage_consumers.go`
|
||||
102. `frontend-modern/src/features/standalone/standalonePageModel.ts`
|
||||
103. `frontend-modern/src/features/standalone/StandalonePageSurface.tsx`
|
||||
104. `frontend-modern/src/features/standalone/AgentsMachinesTable.tsx`
|
||||
105. `frontend-modern/src/features/standalone/AvailabilityChecksTable.tsx`
|
||||
106. `internal/platformsupport/manifest_generated.go`
|
||||
107. `frontend-modern/src/features/kubernetes/KubernetesControllersTable.tsx`
|
||||
108. `frontend-modern/src/features/kubernetes/KubernetesPageSurface.tsx`
|
||||
109. `frontend-modern/src/features/kubernetes/kubernetesPageModel.ts`
|
||||
110. `frontend-modern/src/features/kubernetes/KubernetesClustersTable.tsx`
|
||||
111. `frontend-modern/src/features/kubernetes/KubernetesDeploymentsTable.tsx`
|
||||
112. `frontend-modern/src/features/kubernetes/KubernetesNodesTable.tsx`
|
||||
113. `frontend-modern/src/features/kubernetes/KubernetesPodsTable.tsx`
|
||||
114. `frontend-modern/src/features/kubernetes/KubernetesStorageTable.tsx`
|
||||
115. `frontend-modern/src/features/kubernetes/KubernetesNetworkingTable.tsx`
|
||||
116. `frontend-modern/src/features/kubernetes/KubernetesServicesTable.tsx`
|
||||
117. `frontend-modern/src/features/kubernetes/KubernetesConfigTable.tsx`
|
||||
118. `frontend-modern/src/features/kubernetes/KubernetesPolicyTable.tsx`
|
||||
119. `frontend-modern/src/features/kubernetes/KubernetesAutoscalingTable.tsx`
|
||||
120. `frontend-modern/src/features/kubernetes/KubernetesEventsTable.tsx`
|
||||
46. `frontend-modern/src/components/Infrastructure/ResourceActionHistory.tsx`
|
||||
47. `frontend-modern/src/components/Infrastructure/ResourceFacetSummary.tsx`
|
||||
48. `frontend-modern/src/components/Infrastructure/ResourceChangeSummary.tsx`
|
||||
49. `frontend-modern/src/components/Infrastructure/ResourceCorrelationSummary.tsx`
|
||||
50. `frontend-modern/src/components/Infrastructure/ResourcePolicySummary.tsx`
|
||||
51. `frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx`
|
||||
52. `frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx`
|
||||
53. `frontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsx`
|
||||
54. `frontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx`
|
||||
55. `frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts`
|
||||
56. `frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts`
|
||||
57. `frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDerivedState.ts`
|
||||
58. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerServiceModel.ts`
|
||||
59. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerVmwareModel.ts`
|
||||
60. `frontend-modern/src/components/Infrastructure/resourceDetailDiscoveryModel.ts`
|
||||
61. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerOperationalModel.ts`
|
||||
62. `frontend-modern/src/components/Infrastructure/useResourceDetailDrawerHistoryState.ts`
|
||||
63. `frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDockerActionsState.ts`
|
||||
64. `frontend-modern/src/components/Infrastructure/useResourceDetailDrawerState.ts`
|
||||
65. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts`
|
||||
66. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts`
|
||||
67. `frontend-modern/src/components/Discovery/DiscoveryTab.tsx`
|
||||
68. `frontend-modern/src/components/Discovery/useDiscoveryTabState.ts`
|
||||
69. `frontend-modern/src/utils/agentResources.ts`
|
||||
70. `frontend-modern/src/utils/canonicalResourceTypes.ts`
|
||||
71. `frontend-modern/src/utils/resourceBadgePresentation.ts`
|
||||
72. `frontend-modern/src/utils/resourceChangePresentation.ts`
|
||||
73. `frontend-modern/src/utils/actionAuditPresentation.ts`
|
||||
74. `frontend-modern/src/utils/resourceCorrelationPresentation.ts`
|
||||
75. `frontend-modern/src/utils/resourcePlatformData.ts`
|
||||
76. `frontend-modern/src/utils/resourcePolicyPresentation.ts`
|
||||
77. `frontend-modern/src/utils/resourceStateAdapters.ts`
|
||||
78. `frontend-modern/src/utils/resourceTypeCompat.ts`
|
||||
79. `frontend-modern/src/utils/resourceTypePresentation.ts`
|
||||
80. `frontend-modern/src/utils/serviceHealthPresentation.ts`
|
||||
81. `frontend-modern/src/utils/sourceTypePresentation.ts`
|
||||
82. `frontend-modern/src/utils/workloadTypePresentation.ts`
|
||||
83. `frontend-modern/src/utils/resourceIdentity.ts`
|
||||
84. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerIdentityModel.ts`
|
||||
85. `frontend-modern/src/hooks/useUnifiedResources.ts`
|
||||
86. `frontend-modern/src/types/resource.ts`
|
||||
87. `frontend-modern/src/utils/sourcePlatforms.ts`
|
||||
88. `frontend-modern/src/utils/platformSupportManifest.generated.ts`
|
||||
89. `internal/unifiedresources/kubernetes_metric_ids.go`
|
||||
90. `internal/unifiedresources/policy_posture.go`
|
||||
91. `internal/unifiedresources/clone.go`
|
||||
92. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerPresentation.ts`
|
||||
93. `internal/unifiedresources/storage_consumers.go`
|
||||
94. `frontend-modern/src/features/standalone/standalonePageModel.ts`
|
||||
95. `frontend-modern/src/features/standalone/StandalonePageSurface.tsx`
|
||||
96. `frontend-modern/src/features/standalone/AgentsMachinesTable.tsx`
|
||||
97. `frontend-modern/src/features/standalone/AvailabilityChecksTable.tsx`
|
||||
98. `internal/platformsupport/manifest_generated.go`
|
||||
99. `frontend-modern/src/features/kubernetes/KubernetesControllersTable.tsx`
|
||||
100. `frontend-modern/src/features/kubernetes/KubernetesPageSurface.tsx`
|
||||
101. `frontend-modern/src/features/kubernetes/kubernetesPageModel.ts`
|
||||
102. `frontend-modern/src/features/kubernetes/KubernetesClustersTable.tsx`
|
||||
103. `frontend-modern/src/features/kubernetes/KubernetesDeploymentsTable.tsx`
|
||||
104. `frontend-modern/src/features/kubernetes/KubernetesNodesTable.tsx`
|
||||
105. `frontend-modern/src/features/kubernetes/KubernetesPodsTable.tsx`
|
||||
106. `frontend-modern/src/features/kubernetes/KubernetesStorageTable.tsx`
|
||||
107. `frontend-modern/src/features/kubernetes/KubernetesNetworkingTable.tsx`
|
||||
108. `frontend-modern/src/features/kubernetes/KubernetesServicesTable.tsx`
|
||||
109. `frontend-modern/src/features/kubernetes/KubernetesConfigTable.tsx`
|
||||
110. `frontend-modern/src/features/kubernetes/KubernetesPolicyTable.tsx`
|
||||
111. `frontend-modern/src/features/kubernetes/KubernetesAutoscalingTable.tsx`
|
||||
112. `frontend-modern/src/features/kubernetes/KubernetesEventsTable.tsx`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
|
|
@ -218,19 +208,16 @@ engine storage rows must stay host-scoped with table proof hooks so browser
|
|||
proof can distinguish a populated disk-usage tab from an empty fixture.
|
||||
|
||||
1. `frontend-modern/src/components/Infrastructure/infrastructureSelectors.ts` shared with `performance-and-scalability`: the infrastructure selector pipeline is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
2. `frontend-modern/src/components/Infrastructure/InfrastructureSummary.tsx` shared with `performance-and-scalability`: the infrastructure summary surface is both a canonical unified-resource consumer and a fleet-scale summary chart hot-path boundary.
|
||||
3. `frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts` shared with `performance-and-scalability`: 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.
|
||||
4. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts` shared with `performance-and-scalability`: resource detail mappers are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
5. `frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx` shared with `performance-and-scalability`: the unified resource host table card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
6. `frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx` shared with `performance-and-scalability`: the unified resource PBS section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
7. `frontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsx` shared with `performance-and-scalability`: the unified resource PMG section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
8. `frontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx` shared with `performance-and-scalability`: the unified resource service infrastructure card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
9. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx` shared with `performance-and-scalability`: the unified resource table is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
10. `frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts` shared with `performance-and-scalability`: 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.
|
||||
11. `frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts` shared with `performance-and-scalability`: 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.
|
||||
12. `frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts` shared with `performance-and-scalability`: 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.
|
||||
13. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` shared with `performance-and-scalability`: unified resource table state, grouping, and windowing are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
14. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts` shared with `performance-and-scalability`: 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.
|
||||
2. `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts` shared with `performance-and-scalability`: resource detail mappers are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
3. `frontend-modern/src/components/Infrastructure/UnifiedResourceHostTableCard.tsx` shared with `performance-and-scalability`: the unified resource host table card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
4. `frontend-modern/src/components/Infrastructure/UnifiedResourcePBSTableSection.tsx` shared with `performance-and-scalability`: the unified resource PBS section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
5. `frontend-modern/src/components/Infrastructure/UnifiedResourcePMGTableSection.tsx` shared with `performance-and-scalability`: the unified resource PMG section is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
6. `frontend-modern/src/components/Infrastructure/UnifiedResourceServiceInfrastructureCard.tsx` shared with `performance-and-scalability`: the unified resource service infrastructure card is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
7. `frontend-modern/src/components/Infrastructure/UnifiedResourceTable.tsx` shared with `performance-and-scalability`: the unified resource table is both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
8. `frontend-modern/src/components/Infrastructure/unifiedResourceTableModel.ts` shared with `performance-and-scalability`: 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.
|
||||
9. `frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts` shared with `performance-and-scalability`: 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.
|
||||
10. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` shared with `performance-and-scalability`: unified resource table state, grouping, and windowing are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
11. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts` shared with `performance-and-scalability`: 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.
|
||||
15. `frontend-modern/src/utils/platformSupportManifest.generated.ts` shared with `frontend-primitives`: the generated platform support projection is both a canonical unified-resource platform union boundary and a shared frontend source/platform vocabulary boundary.
|
||||
It must carry the manifest `surface_kind` distinction so `docker` remains
|
||||
machine-readable as a `runtime-lens` while owning infrastructure sources
|
||||
|
|
@ -388,112 +375,6 @@ proof can distinguish a populated disk-usage tab from an empty fixture.
|
|||
tables must not render ConfigMap or Secret payload values, and metadata-only
|
||||
rows must not expose key names as if payload fields had been read.
|
||||
2. Add typed accessors and views in `internal/unifiedresources/views.go`
|
||||
3. Add source ingestion/adaptation in the adapter layer only
|
||||
Frontend resource platform contracts in
|
||||
`frontend-modern/src/types/resource.ts` must include platform ids that the
|
||||
canonical source/platform adapters can emit. Agent-native storage sources
|
||||
such as Unraid are first-class platform ids for typing, filtering, tests,
|
||||
and storage/recovery presentation; consumers must not hide them behind
|
||||
Proxmox-only or generic agent-only frontend unions when unified resources
|
||||
has already published explicit platform evidence.
|
||||
Infrastructure table platform presentation extends through
|
||||
`frontend-modern/src/utils/resourceBadgePresentation.ts`,
|
||||
`frontend-modern/src/components/Infrastructure/resourceBadges.ts`, and the
|
||||
unified resource table sections. Visible infrastructure table headers,
|
||||
filters, sort keys, and compact row badges must present the owning
|
||||
infrastructure platform first, while full merged-source detail remains
|
||||
available for tooltips, accessibility metadata, and routing. Agent telemetry
|
||||
is collection-method detail when a provider/API platform is also present.
|
||||
When the primary system identity includes a platform version, table metadata
|
||||
must suppress an otherwise duplicate unversioned platform source badge while
|
||||
preserving non-duplicate collection context such as Pulse Agent.
|
||||
Infrastructure table presentation controls must describe the table mode
|
||||
rather than a platform-specific resource concept: the grouped/flat toggle
|
||||
uses operator-facing `Grouped` and `List` wording with a `Group by`
|
||||
accessible group label, while Proxmox, Kubernetes, and other platform
|
||||
clusters stay reserved for actual resource identity, filters, and detail
|
||||
surfaces.
|
||||
Infrastructure row drawer expansion and summary group focus are local table
|
||||
interaction state. Inbound infrastructure deep links may hydrate `resource`
|
||||
and `summaryGroup` into the focused resource or group, but local expansion,
|
||||
closing, and clearing must not rewrite those params or navigate. Route sync
|
||||
for this surface is limited to filter-owned `source` and `q` state so
|
||||
unified-resource rows open inline without refreshing the page shell.
|
||||
Resource detail drawers must declare their presentation context explicitly.
|
||||
The default full presentation owns the canonical resource-change,
|
||||
operator-override, maintenance-verification, and action-audit surfaces. The
|
||||
`table-row` presentation is reserved for inline platform and resource table
|
||||
expansion: it presents current-state and identity details from the local
|
||||
resource payload, may show preloaded change data when present, and must not
|
||||
start remote history, intelligence, or action-audit reads only to render
|
||||
empty advanced governance panels inside a table row.
|
||||
Cluster group headers may use a compact `Cluster` type chip when the group
|
||||
name itself is only an estate label, but `unifiedResourceTableStateModel.ts`
|
||||
must suppress that chip when the visible group name already ends in
|
||||
`Cluster`, so rows do not read as duplicated labels such as `Production
|
||||
Cluster Cluster`.
|
||||
Infrastructure host and service table cards must consume the
|
||||
frontend-primitives-owned `TableCard` frame and `TableCardHeader` header
|
||||
band; unified resources owns the resource identity, rows, grouping, and
|
||||
detail presentation, not page-local table-shell chrome. The nested
|
||||
infrastructure tables must use the shared `Table` primitive's scroll frame
|
||||
directly instead of reintroducing page-local `overflow-x-auto` wrappers
|
||||
inside the canonical card shell.
|
||||
Unified resource host metric cells may consume alert-backed agent
|
||||
thresholds, but resource consumers must not resolve alert defaults or
|
||||
overrides locally. Host table state exposes the alerts-owned threshold
|
||||
resolver and row renderers pass the resolved values into metric bars while
|
||||
preserving unified-resource ownership over identity, rows, grouping, and
|
||||
detail presentation.
|
||||
Docker Swarm service, Kubernetes namespace/deployment, and PMG detail
|
||||
tables follow that same shell boundary: their platform-specific rows and
|
||||
actions are unified-resource-owned, while horizontal overflow is owned by
|
||||
the shared `Table` wrapper rather than drawer-local scroll divs. This
|
||||
includes both current resource drawers and legacy PMG resource panels that
|
||||
still consume unified-resource PMG state.
|
||||
Realtime resource payloads are part of the same consumer contract as REST:
|
||||
websocket broadcasts must carry canonical identity, discovery targets,
|
||||
metrics targets, incident rollups, facet counts, and source-specific raw
|
||||
facets such as `agent`, `storage`, `docker`, and provider API facets. Host
|
||||
rows and drawers may present compact issue labels such as Unraid
|
||||
no-parity posture, but those labels must derive from canonical incident or
|
||||
storage-risk summaries already present on the resource rather than local
|
||||
platform heuristics or generic status-only wording.
|
||||
Agent-backed Unraid topology belongs in the canonical adapter layer, not in
|
||||
storage-page inference. Assigned Unraid array members must produce physical
|
||||
disk resources even when SMART telemetry is absent, Unraid cache/pool members
|
||||
must produce agent-backed storage resources with native capacity metrics, and
|
||||
SMART rows may enrich or merge with those resources only through normalized
|
||||
device or serial identity. Generic SMART status must not overwrite stronger
|
||||
Unraid health/risk, and physical-disk metric IDs must prefer stable serials
|
||||
while normalizing device tokens such as `/dev/sdd` and `sdd [sat]` to the
|
||||
same fallback identity.
|
||||
Frontend canonicalization must treat top-level source facets as source
|
||||
evidence when `platformData.sources` is absent, but it must not invent
|
||||
provider facets from generic agent telemetry: flat agent disk payloads stay
|
||||
under the agent source and do not become Proxmox facets without explicit
|
||||
Proxmox source, node, or workload-shape evidence.
|
||||
Realtime resource adapters must also apply the canonical host source-bridge
|
||||
rule to incoming websocket snapshots: agent plus platform/API evidence for
|
||||
the same host coalesces into one hybrid infrastructure resource, while
|
||||
same-name agent-only records remain separate until stronger identity or
|
||||
platform evidence exists.
|
||||
Proxmox child resources must derive their canonical parent from the owning
|
||||
node identity across all supported source-key shapes. Guests, storage pools,
|
||||
and physical disks may arrive with instance-node, cluster-node, or bare-node
|
||||
parent evidence, and both snapshot ingest and already-unified registry seed
|
||||
paths must attach them to the same merged host resource before REST,
|
||||
websocket, Workloads, or Infrastructure consumers render the estate.
|
||||
This derivation must tolerate node source IDs that retain a previous cluster
|
||||
alias while the current Proxmox metadata exposes a renamed instance or
|
||||
cluster label; current node metadata is the fallback source of truth when
|
||||
source-key lookup misses.
|
||||
Platform pages that bucket Docker / Podman or Kubernetes resources must use
|
||||
these canonical resource types and source facets directly. Page-local
|
||||
scraping, generic type coercion, or "single table for every native object"
|
||||
fallbacks are not a substitute for adapter-owned image, volume, network,
|
||||
service, controller, storage, ingress, and event resource projections.
|
||||
|
||||
Resource detail mappers now reuse the shared
|
||||
`frontend-modern/src/utils/textPresentation.ts` title-case helper for sensor
|
||||
labels so the canonical unified-resource presentation layer owns the wording.
|
||||
|
|
@ -595,7 +476,6 @@ AI-only summary payloads, or page-local heuristics.
|
|||
generic disk-count aggregate, so resource drawers and incidents do not hide
|
||||
the actual protection boundary behind a broader count phrase.
|
||||
6. Add canonical governed name-resolution or policy-aware resource lookup behavior through `internal/unifiedresources/resolve.go` and `internal/unifiedresources/resolve_context.go`
|
||||
7. Add or change resource drawer timeline/facet/action-history presentation through `frontend-modern/src/components/Infrastructure/ResourceDetailDrawer.tsx`, `frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx`, `frontend-modern/src/components/Infrastructure/ResourceDetailDrawerDebugTab.tsx`, `frontend-modern/src/components/Docker/SwarmServicesDrawer.tsx`, `frontend-modern/src/components/Kubernetes/K8sDeploymentsDrawer.tsx`, `frontend-modern/src/components/Kubernetes/K8sNamespacesDrawer.tsx`, `frontend-modern/src/components/PMG/PMGInstanceDrawer.tsx`, `frontend-modern/src/components/PMG/MailGateway.tsx`, `frontend-modern/src/components/PMG/PMGInstancePanel.tsx`, `frontend-modern/src/components/Infrastructure/ResourceActionHistory.tsx`, `frontend-modern/src/components/Infrastructure/useResourceDetailDrawerState.ts`, `frontend-modern/src/components/Infrastructure/ResourceFacetSummary.tsx`, `frontend-modern/src/components/Infrastructure/resourceDetailMappers.ts`, and the governed `internal/api/resources.go` facet/timeline plus `internal/api/activity_audit_handlers.go` action-audit contracts together
|
||||
8. Add or change discovery-support runtime under the resource drawer through `frontend-modern/src/components/Discovery/DiscoveryTab.tsx` for shell/presentation ownership and `frontend-modern/src/components/Discovery/useDiscoveryTabState.ts` for fetch, websocket-progress, manual-run triggering, and notes-mutation ownership. Embedded drawers may expose the top-level run action through this shared Discovery tab, but they must still call the canonical discovery trigger state path instead of introducing drawer-local API mutations.
|
||||
9. Keep dashboard and infrastructure freshness on the canonical unified-resource
|
||||
ownership path. `frontend-modern/src/stores/websocket.ts`,
|
||||
|
|
@ -638,24 +518,6 @@ AI-only summary payloads, or page-local heuristics.
|
|||
explicit cluster identity such as Kubernetes context or platform cluster
|
||||
labels; standalone resource names must never be repurposed as synthetic
|
||||
`clusterId` values.
|
||||
10. Keep the retired dashboard overview shell absent from unified-resource
|
||||
consumers. `frontend-modern/src/pages/Dashboard.tsx`,
|
||||
`frontend-modern/src/hooks/useDashboardOverview.ts`, and
|
||||
`/api/resources/dashboard-summary` must not be restored as compatibility
|
||||
readers for KPI cards, problem-resource rows, or top-resource identity.
|
||||
Infrastructure and Workloads must consume their owning unified-resource
|
||||
projections directly.
|
||||
11. Keep summary consumers on the payload they were already given.
|
||||
`frontend-modern/src/components/Infrastructure/useInfrastructureSummaryState.ts`
|
||||
may derive chart identity, storage presence, and infrastructure rollups
|
||||
from the resource snapshot it already owns, but it must not reopen
|
||||
`useResources()` or start a second unfiltered unified-resource fetch path
|
||||
as a replacement dashboard summary surface.
|
||||
12. Keep shared selector hydration visibility-bound. Reusable shells such as
|
||||
`frontend-modern/src/components/shared/useInfrastructureSelectorState.ts`
|
||||
may consume `frontend-modern/src/hooks/useUnifiedResources.ts`, but hidden
|
||||
selectors must pass an explicit `enabled` gate instead of booting the
|
||||
`all-resources` transport behind a collapsed or non-rendered summary shell.
|
||||
13. Keep operator-facing resource analysis vocabulary task-first on unified-resource
|
||||
surfaces. `frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx`,
|
||||
`frontend-modern/src/components/Infrastructure/useResourceDetailDrawerDerivedState.ts`,
|
||||
|
|
|
|||
|
|
@ -91,9 +91,14 @@ Canonical short reply:
|
|||
|
||||
### Will old bookmarks and familiar v5 pages still work?
|
||||
|
||||
Not necessarily. v6 reorganizes the product around Infrastructure, Workloads,
|
||||
Storage, and Recovery, with Infrastructure as the default landing surface. Old
|
||||
platform-era aliases and runbook links should be updated to canonical v6 routes.
|
||||
Yes for the platform-shaped top-level pages (`/proxmox`, `/docker`,
|
||||
`/kubernetes`, `/truenas`, `/vmware`, `/standalone`). v6 keeps the
|
||||
platform-shaped top-level navigation existing v5 operators already
|
||||
know, on a unified resource model backend (`/api/resources`). The v6
|
||||
line briefly shipped a unified `Infrastructure` / `Workloads` /
|
||||
`Storage` / `Recovery` layout across `rc.1`-`rc.5` that was reverted
|
||||
in `rc.6`; bookmarks into those unified routes should move to the
|
||||
platform-shaped equivalents.
|
||||
|
||||
## Recommended Evaluation Path
|
||||
|
||||
|
|
|
|||
|
|
@ -92,7 +92,8 @@ docker exec pulse rm -rf /home/pulse/.ssh/id_ed25519*
|
|||
|
||||
If you fully understand the risk and are **not** containerized (VM/bare-metal
|
||||
install), the legacy SSH flow still works. Use a dedicated monitoring user,
|
||||
restrict the key with `command="sensors -j"` and `from="<pulse-ip>"`, and
|
||||
restrict the key to the Pulse sensor wrapper with
|
||||
`command="/usr/local/sbin/pulse-sensors"` and `from="<pulse-ip>"`, and
|
||||
rotate keys regularly.
|
||||
|
||||
#### Auditing Your Deployment
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ func TestHandleSetupScriptUsesCanonicalShellDownloadHeaders(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPVESetupScriptQuotesTemperatureMonitoringAuthorizedKeyEntry(t *testing.T) {
|
||||
func TestPVESetupScriptRestrictsTemperatureMonitoringToPulseSensorWrapper(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
cfg := &config.Config{
|
||||
DataPath: tempDir,
|
||||
|
|
@ -173,14 +173,20 @@ func TestPVESetupScriptQuotesTemperatureMonitoringAuthorizedKeyEntry(t *testing.
|
|||
}
|
||||
|
||||
script := rr.Body.String()
|
||||
if !containsString(
|
||||
script,
|
||||
`SSH_SENSORS_KEY_ENTRY="command=\"sensors -j\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty $SSH_SENSORS_PUBLIC_KEY # pulse-sensors"`,
|
||||
) {
|
||||
t.Fatalf("expected temperature monitoring key entry to escape forced-command quotes, got:\n%s", truncate(script, 900))
|
||||
required := []string{
|
||||
`PULSE_SENSORS_WRAPPER="/usr/local/sbin/pulse-sensors"`,
|
||||
`install_pulse_sensors_wrapper() {`,
|
||||
`"smart": collect_smart(),`,
|
||||
`SSH_SENSORS_KEY_ENTRY="command=\"$PULSE_SENSORS_WRAPPER\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty $SSH_SENSORS_PUBLIC_KEY # pulse-sensors"`,
|
||||
}
|
||||
if containsString(script, `SSH_SENSORS_KEY_ENTRY="command="sensors -j",`) {
|
||||
t.Fatalf("unexpected unescaped temperature monitoring key entry in generated script:\n%s", truncate(script, 900))
|
||||
for _, want := range required {
|
||||
if !containsString(script, want) {
|
||||
t.Fatalf("expected setup script to contain %q, got:\n%s", want, truncate(script, 1800))
|
||||
}
|
||||
}
|
||||
if containsString(script, `SSH_SENSORS_KEY_ENTRY="command=\"sensors -j\"`) ||
|
||||
containsString(script, `SSH_SENSORS_KEY_ENTRY="command="sensors -j",`) {
|
||||
t.Fatalf("unexpected raw sensors forced-command key entry in generated script:\n%s", truncate(script, 1800))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5529,6 +5529,18 @@ func TestContract_SetupScriptEmbedsFailFastGuidance(t *testing.T) {
|
|||
if strings.Contains(script, `/root/.ssh/authorized_keys.tmp`) || strings.Contains(script, `echo "$SSH_SENSORS_KEY_ENTRY" >> /root/.ssh/authorized_keys`) {
|
||||
t.Fatalf("setup script preserved symlink-breaking authorized_keys rewrite: %s", script)
|
||||
}
|
||||
if !strings.Contains(script, `PULSE_SENSORS_WRAPPER="/usr/local/sbin/pulse-sensors"`) {
|
||||
t.Fatalf("setup script missing canonical Pulse sensor wrapper path: %s", script)
|
||||
}
|
||||
if !strings.Contains(script, `SSH_SENSORS_KEY_ENTRY="command=\"$PULSE_SENSORS_WRAPPER\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty $SSH_SENSORS_PUBLIC_KEY # pulse-sensors"`) {
|
||||
t.Fatalf("setup script must force temperature SSH keys to the Pulse sensor wrapper: %s", script)
|
||||
}
|
||||
if !strings.Contains(script, `"smart": collect_smart(),`) || !strings.Contains(script, `apt-get install -y smartmontools`) {
|
||||
t.Fatalf("setup script missing SMART temperature wrapper contract: %s", script)
|
||||
}
|
||||
if strings.Contains(script, `SSH_SENSORS_KEY_ENTRY="command=\"sensors -j\"`) {
|
||||
t.Fatalf("setup script preserved stale raw sensors forced command: %s", script)
|
||||
}
|
||||
if strings.Contains(script, `echo "Please run this script as root"`) {
|
||||
t.Fatalf("setup script preserved stale root-only guidance: %s", script)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -606,16 +606,263 @@ echo "━━━━━━━━━━━━━━━━━━━━━━━━
|
|||
echo ""
|
||||
|
||||
SSH_SENSORS_PUBLIC_KEY="%s"
|
||||
SSH_SENSORS_KEY_ENTRY="command=\"sensors -j\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty $SSH_SENSORS_PUBLIC_KEY # pulse-sensors"
|
||||
PULSE_SENSORS_WRAPPER="/usr/local/sbin/pulse-sensors"
|
||||
SSH_SENSORS_KEY_ENTRY="command=\"$PULSE_SENSORS_WRAPPER\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty $SSH_SENSORS_PUBLIC_KEY # pulse-sensors"
|
||||
TEMPERATURE_ENABLED=false
|
||||
|
||||
install_pulse_sensors_wrapper() {
|
||||
mkdir -p "$(dirname "$PULSE_SENSORS_WRAPPER")"
|
||||
cat > "$PULSE_SENSORS_WRAPPER" <<'PULSE_SENSORS_WRAPPER_EOF'
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
python3 - <<'PY'
|
||||
import datetime
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def run_command(args, timeout=8):
|
||||
try:
|
||||
return subprocess.run(
|
||||
args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.DEVNULL,
|
||||
text=True,
|
||||
timeout=timeout,
|
||||
check=False,
|
||||
)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def load_sensors():
|
||||
if shutil.which("sensors"):
|
||||
result = run_command(["sensors", "-j"])
|
||||
if result and result.stdout.strip():
|
||||
try:
|
||||
return json.loads(result.stdout)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
thermal_path = "/sys/class/thermal/thermal_zone0/temp"
|
||||
try:
|
||||
with open(thermal_path, "r", encoding="utf-8") as handle:
|
||||
raw = handle.read().strip()
|
||||
value = float(raw)
|
||||
if value > 1000:
|
||||
value = value / 1000
|
||||
return {"rpitemp": {"temp1": {"temp1_input": value}}}
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def smartctl_path():
|
||||
return shutil.which("smartctl")
|
||||
|
||||
|
||||
def smart_targets(path):
|
||||
result = run_command([path, "--scan-open"])
|
||||
if not result or not result.stdout.strip():
|
||||
return []
|
||||
|
||||
targets = []
|
||||
seen = set()
|
||||
typed_by_path = set()
|
||||
for raw_line in result.stdout.splitlines():
|
||||
line = raw_line.split("#", 1)[0].strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
fields = shlex.split(line)
|
||||
except ValueError:
|
||||
fields = line.split()
|
||||
if not fields:
|
||||
continue
|
||||
|
||||
device = fields[0].strip()
|
||||
if not device.startswith("/"):
|
||||
continue
|
||||
|
||||
device_type = ""
|
||||
for idx, field in enumerate(fields[:-1]):
|
||||
if field == "-d":
|
||||
device_type = fields[idx + 1].strip()
|
||||
break
|
||||
|
||||
key = (device, device_type)
|
||||
if key in seen:
|
||||
continue
|
||||
seen.add(key)
|
||||
if device_type:
|
||||
typed_by_path.add(device)
|
||||
targets.append(key)
|
||||
|
||||
return [(device, dtype) for device, dtype in targets if dtype or device not in typed_by_path]
|
||||
|
||||
|
||||
def disk_type(data):
|
||||
device = data.get("device") if isinstance(data.get("device"), dict) else {}
|
||||
protocol = str(device.get("protocol") or "").lower()
|
||||
dtype = str(device.get("type") or "").lower()
|
||||
if "nvme" in protocol or "nvme" in dtype:
|
||||
return "nvme"
|
||||
if "sas" in protocol or "scsi" in protocol or "sas" in dtype:
|
||||
return "sas"
|
||||
if "ata" in protocol or "sata" in protocol or "sat" in dtype:
|
||||
return "sata"
|
||||
return dtype
|
||||
|
||||
|
||||
def smart_health(data):
|
||||
status = data.get("smart_status")
|
||||
if isinstance(status, dict) and "passed" in status:
|
||||
return "PASSED" if status.get("passed") else "FAILED"
|
||||
return "UNKNOWN"
|
||||
|
||||
|
||||
def format_wwn(data):
|
||||
wwn = data.get("wwn")
|
||||
if not isinstance(wwn, dict) or not wwn.get("naa"):
|
||||
return ""
|
||||
try:
|
||||
naa = int(wwn.get("naa") or 0)
|
||||
oui = int(wwn.get("oui") or 0)
|
||||
ident = int(wwn.get("id") or 0)
|
||||
except Exception:
|
||||
return ""
|
||||
return f"{naa:x}-{oui:x}-{ident:x}"
|
||||
|
||||
|
||||
def first_valid_temperature(candidates):
|
||||
for value in candidates:
|
||||
try:
|
||||
temp = int(float(value))
|
||||
except Exception:
|
||||
continue
|
||||
if 0 < temp < 150:
|
||||
return temp
|
||||
return 0
|
||||
|
||||
|
||||
def raw_attribute_temperature(data):
|
||||
attrs = data.get("ata_smart_attributes")
|
||||
if not isinstance(attrs, dict):
|
||||
return 0
|
||||
table = attrs.get("table")
|
||||
if not isinstance(table, list):
|
||||
return 0
|
||||
|
||||
for attr in table:
|
||||
if not isinstance(attr, dict) or attr.get("id") not in (190, 194):
|
||||
continue
|
||||
raw = attr.get("raw") if isinstance(attr.get("raw"), dict) else {}
|
||||
candidates = []
|
||||
raw_string = raw.get("string")
|
||||
if isinstance(raw_string, str):
|
||||
match = re.search(r"(-?\d{1,3})", raw_string)
|
||||
if match:
|
||||
candidates.append(match.group(1))
|
||||
if "value" in raw:
|
||||
candidates.append(raw.get("value"))
|
||||
temperature = first_valid_temperature(candidates)
|
||||
if temperature > 0:
|
||||
return temperature
|
||||
return 0
|
||||
|
||||
|
||||
def smart_temperature(data):
|
||||
temperatures = []
|
||||
temp = data.get("temperature")
|
||||
if isinstance(temp, dict):
|
||||
temperatures.append(temp.get("current"))
|
||||
nvme = data.get("nvme_smart_health_information_log")
|
||||
if isinstance(nvme, dict):
|
||||
temperatures.append(nvme.get("temperature"))
|
||||
sct = data.get("ata_sct_status")
|
||||
if isinstance(sct, dict):
|
||||
current = sct.get("current")
|
||||
if isinstance(current, dict):
|
||||
temperatures.append(current.get("value"))
|
||||
|
||||
temperature = first_valid_temperature(temperatures)
|
||||
if temperature > 0:
|
||||
return temperature
|
||||
return raw_attribute_temperature(data)
|
||||
|
||||
|
||||
def collect_smart():
|
||||
path = smartctl_path()
|
||||
if not path:
|
||||
return []
|
||||
|
||||
entries = []
|
||||
observed_at = datetime.datetime.now(datetime.timezone.utc).replace(microsecond=0).isoformat().replace("+00:00", "Z")
|
||||
for device, device_type in smart_targets(path):
|
||||
args = [path]
|
||||
if device_type:
|
||||
args.extend(["-d", device_type])
|
||||
args.extend(["-n", "standby,3", "-i", "-A", "-H", "--json=o", device])
|
||||
|
||||
result = run_command(args)
|
||||
if not result or not result.stdout.strip():
|
||||
continue
|
||||
try:
|
||||
data = json.loads(result.stdout)
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
power_mode = str(data.get("power_mode") or "").lower()
|
||||
entries.append({
|
||||
"device": device,
|
||||
"model": str(data.get("model_name") or data.get("model_family") or "").strip(),
|
||||
"serial": str(data.get("serial_number") or "").strip(),
|
||||
"wwn": format_wwn(data),
|
||||
"type": disk_type(data),
|
||||
"temperature": smart_temperature(data),
|
||||
"health": smart_health(data),
|
||||
"standbySkipped": "standby" in power_mode or "sleep" in power_mode,
|
||||
"lastUpdated": observed_at,
|
||||
})
|
||||
return entries
|
||||
|
||||
|
||||
payload = {
|
||||
"sensors": load_sensors(),
|
||||
"smart": collect_smart(),
|
||||
}
|
||||
json.dump(payload, sys.stdout, separators=(",", ":"))
|
||||
sys.stdout.write("\n")
|
||||
PY
|
||||
exit 0
|
||||
fi
|
||||
|
||||
sensors_json="{}"
|
||||
if command -v sensors >/dev/null 2>&1; then
|
||||
sensors_json="$(sensors -j 2>/dev/null || printf '{}')"
|
||||
fi
|
||||
if [ -z "$sensors_json" ]; then
|
||||
sensors_json="{}"
|
||||
fi
|
||||
printf '{"sensors":%%s,"smart":[]}\n' "$sensors_json"
|
||||
PULSE_SENSORS_WRAPPER_EOF
|
||||
chown root:root "$PULSE_SENSORS_WRAPPER" 2>/dev/null || true
|
||||
chmod 755 "$PULSE_SENSORS_WRAPPER"
|
||||
}
|
||||
|
||||
if [ -n "$SSH_SENSORS_PUBLIC_KEY" ]; then
|
||||
echo "📊 Enable Temperature Monitoring?"
|
||||
echo ""
|
||||
echo "Collect CPU and drive temperatures via secure SSH connection."
|
||||
echo ""
|
||||
echo "Security:"
|
||||
echo " • SSH key authentication with forced command (sensors -j only)"
|
||||
echo " • SSH key authentication with forced command (Pulse sensor wrapper only)"
|
||||
echo " • No shell access, port forwarding, or other SSH features"
|
||||
echo " • Keys stored in Pulse service user's home directory"
|
||||
echo ""
|
||||
|
|
@ -641,6 +888,14 @@ if [ -n "$SSH_SENSORS_PUBLIC_KEY" ]; then
|
|||
if [[ $SSH_REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Configuring temperature monitoring..."
|
||||
|
||||
SENSORS_WRAPPER_OK=false
|
||||
if install_pulse_sensors_wrapper; then
|
||||
SENSORS_WRAPPER_OK=true
|
||||
echo " ✓ Pulse sensor wrapper installed"
|
||||
else
|
||||
echo " ⚠️ Failed to install Pulse sensor wrapper"
|
||||
fi
|
||||
|
||||
# Add key to root's authorized_keys
|
||||
AUTH_KEYS="$(resolve_authorized_keys_path)"
|
||||
mkdir -p "$(dirname "$AUTH_KEYS")"
|
||||
|
|
@ -650,7 +905,7 @@ if [ -n "$SSH_SENSORS_PUBLIC_KEY" ]; then
|
|||
# Remove any old pulse keys
|
||||
SENSORS_KEY_OK=false
|
||||
TMP_AUTH_KEYS="$(mktemp /tmp/.pulse-authorized-keys.XXXXXX 2>/dev/null)" || TMP_AUTH_KEYS=""
|
||||
if [ -n "$TMP_AUTH_KEYS" ] && [ -f "$TMP_AUTH_KEYS" ]; then
|
||||
if [ "$SENSORS_WRAPPER_OK" = true ] && [ -n "$TMP_AUTH_KEYS" ] && [ -f "$TMP_AUTH_KEYS" ]; then
|
||||
if [ -f "$AUTH_KEYS" ]; then
|
||||
grep -vF "# pulse-" "$AUTH_KEYS" > "$TMP_AUTH_KEYS" 2>/dev/null
|
||||
GREP_EXIT=$?
|
||||
|
|
@ -671,10 +926,16 @@ if [ -n "$SSH_SENSORS_PUBLIC_KEY" ]; then
|
|||
fi
|
||||
fi
|
||||
else
|
||||
echo " ⚠️ Failed to create temp file - cannot update authorized_keys"
|
||||
if [ "$SENSORS_WRAPPER_OK" = true ]; then
|
||||
echo " ⚠️ Failed to create temp file - cannot update authorized_keys"
|
||||
elif [ -n "$TMP_AUTH_KEYS" ]; then
|
||||
rm -f "$TMP_AUTH_KEYS" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
if [ "$SENSORS_KEY_OK" = true ]; then
|
||||
echo " ✓ Sensors key configured (restricted to sensors -j)"
|
||||
echo " ✓ Sensors key configured (restricted to Pulse sensor wrapper)"
|
||||
else
|
||||
echo " ⚠️ Sensors key was not configured"
|
||||
fi
|
||||
|
||||
# Check if this is a Raspberry Pi
|
||||
|
|
@ -733,8 +994,21 @@ if [ -n "$SSH_SENSORS_PUBLIC_KEY" ]; then
|
|||
TEMPERATURE_SETUP_SUCCESS=true
|
||||
fi
|
||||
|
||||
if ! command -v smartctl &> /dev/null; then
|
||||
echo " ✓ Installing smartmontools for disk SMART temperatures..."
|
||||
apt-get update -qq > /dev/null 2>&1 || true
|
||||
if apt-get install -y smartmontools > /dev/null 2>&1; then
|
||||
echo " ✓ smartmontools installed successfully"
|
||||
else
|
||||
echo " ⚠️ Could not install smartmontools"
|
||||
echo " HDD/SATA/SAS disk temperatures require smartctl or the unified agent."
|
||||
fi
|
||||
else
|
||||
echo " ✓ smartmontools package verified"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
if [ "$TEMPERATURE_SETUP_SUCCESS" = true ]; then
|
||||
if [ "$TEMPERATURE_SETUP_SUCCESS" = true ] && [ "$SENSORS_KEY_OK" = true ]; then
|
||||
echo "✓ Temperature monitoring enabled"
|
||||
if [ "$IS_RPI" = true ]; then
|
||||
echo " Using Raspberry Pi native temperature interface"
|
||||
|
|
@ -743,7 +1017,7 @@ if [ -n "$SSH_SENSORS_PUBLIC_KEY" ]; then
|
|||
TEMPERATURE_ENABLED=true
|
||||
else
|
||||
echo "⚠️ Temperature monitoring setup incomplete"
|
||||
echo " You can re-run this script after installing lm-sensors"
|
||||
echo " You can re-run this script after installing lm-sensors and smartmontools"
|
||||
fi
|
||||
else
|
||||
echo "Skipping temperature monitoring."
|
||||
|
|
|
|||
|
|
@ -160,6 +160,18 @@ func TestPVEBackupPermissionWarningsPreserveTokenACLRepair(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestLegacySSHTemperatureUsesPulseSensorWrapperContract(t *testing.T) {
|
||||
if !strings.Contains(pulseSensorsSSHCommand, "/usr/local/sbin/pulse-sensors") {
|
||||
t.Fatalf("legacy SSH temperature command must prefer Pulse sensor wrapper, got %q", pulseSensorsSSHCommand)
|
||||
}
|
||||
if !strings.Contains(pulseSensorsSSHCommand, "sensors -j") {
|
||||
t.Fatalf("legacy SSH temperature command must preserve sensors -j fallback for old forced keys, got %q", pulseSensorsSSHCommand)
|
||||
}
|
||||
if strings.Contains(pulseSensorsSSHCommand, "smartctl") {
|
||||
t.Fatalf("SMART collection belongs inside the remote wrapper, not the local SSH command: %q", pulseSensorsSSHCommand)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPBSBackupsSnapshotPreservesSourceArtifactFields(t *testing.T) {
|
||||
state := models.NewState()
|
||||
backupTime := time.Date(2026, 5, 25, 1, 34, 25, 0, time.UTC)
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
const maxTemperatureCommandOutputSize = 1 << 20 // 1 MiB
|
||||
const defaultSSHCommandTimeout = 15 * time.Second
|
||||
const pulseSensorsSSHCommand = "if command -v /usr/local/sbin/pulse-sensors >/dev/null 2>&1; then /usr/local/sbin/pulse-sensors; else sensors -j 2>/dev/null || true; fi"
|
||||
|
||||
var errTemperatureCommandOutputTooLarge = errors.New("temperature command output exceeded limit")
|
||||
|
||||
|
|
@ -150,10 +151,11 @@ func (tc *TemperatureCollector) CollectTemperature(ctx context.Context, nodeHost
|
|||
return &models.Temperature{Available: false}, nil
|
||||
}
|
||||
|
||||
// Direct SSH (legacy method for non-containerized deployments)
|
||||
// Try sensors first, fall back to Raspberry Pi method if that fails
|
||||
// sensors exits non-zero when optional subfeatures fail; "|| true" keeps the JSON for parsing (#600)
|
||||
output, err := tc.runSSHCommand(ctx, host, "sensors -j 2>/dev/null || true")
|
||||
// Direct SSH (legacy method for non-containerized deployments).
|
||||
// New setup scripts restrict the key to /usr/local/sbin/pulse-sensors, which emits
|
||||
// the canonical {sensors, smart} payload. Older keys ignore the requested command
|
||||
// and still force sensors -j, so keep the parser backward-compatible.
|
||||
output, err := tc.runSSHCommand(ctx, host, pulseSensorsSSHCommand)
|
||||
if err != nil || strings.TrimSpace(output) == "" {
|
||||
if tc.disableLegacySSHOnAuthFailure(err, nodeName, host) {
|
||||
return &models.Temperature{Available: false}, nil
|
||||
|
|
|
|||
|
|
@ -170,6 +170,39 @@ func TestTemperatureCollector_ParseSensorsJSON_StringTemps(t *testing.T) {
|
|||
assert.InDelta(t, 42.0, temp.NVMe[0].Temp, 0.0001)
|
||||
}
|
||||
|
||||
func TestTemperatureCollector_ParseSensorsJSON_WrapperSMARTTemps(t *testing.T) {
|
||||
tc := &TemperatureCollector{}
|
||||
jsonStr := `{
|
||||
"sensors": {
|
||||
"coretemp-isa-0000": {
|
||||
"Package id 0": { "temp1_input": 46.0 }
|
||||
}
|
||||
},
|
||||
"smart": [
|
||||
{
|
||||
"device": "/dev/sda",
|
||||
"model": "Samsung SSD 860 EVO",
|
||||
"serial": "SATA-SERIAL-1",
|
||||
"wwn": "5-c50-1234",
|
||||
"type": "sata",
|
||||
"temperature": 34,
|
||||
"lastUpdated": "2026-05-26T18:00:00Z"
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
temp, err := tc.parseSensorsJSON(jsonStr)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, temp)
|
||||
assert.True(t, temp.Available)
|
||||
assert.True(t, temp.HasSMART)
|
||||
require.Len(t, temp.SMART, 1)
|
||||
assert.Equal(t, "/dev/sda", temp.SMART[0].Device)
|
||||
assert.Equal(t, "SATA-SERIAL-1", temp.SMART[0].Serial)
|
||||
assert.Equal(t, 34, temp.SMART[0].Temperature)
|
||||
assert.Equal(t, "sata", temp.SMART[0].Type)
|
||||
}
|
||||
|
||||
func TestTemperatureCollector_HelperMethods(t *testing.T) {
|
||||
// extractCoreNumber
|
||||
// Private methods are hard to test directly from separate package if using _test,
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -206,7 +206,14 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
|||
self.assertNotIn("guest-capacity continuity", support_pack)
|
||||
self.assertNotIn("core monitoring unlimited", normalize_ws(support_pack))
|
||||
|
||||
def test_stable_release_packet_keeps_infrastructure_as_current_landing_surface(self) -> None:
|
||||
def test_stable_release_packet_describes_platform_shaped_frontend_on_unified_backend(self) -> None:
|
||||
"""After the rc.6 IA revert, the stable v6 release docs must describe
|
||||
the frontend as platform-shaped (Proxmox, Docker, Kubernetes, TrueNAS,
|
||||
vSphere, Standalone) on a unified resource backend. Drift back to the
|
||||
rc.1-rc.5 unified Infrastructure/Workloads/Storage/Recovery framing in
|
||||
the stable packet would mislead operators reading the canonical v6
|
||||
release notes.
|
||||
"""
|
||||
stable_docs = {
|
||||
"release_notes": read("docs/releases/RELEASE_NOTES_v6.md"),
|
||||
"changelog": read("docs/releases/V6_CHANGELOG.md"),
|
||||
|
|
@ -216,7 +223,8 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
|||
for name, content in stable_docs.items():
|
||||
with self.subTest(name=name):
|
||||
normalized = normalize_ws(content)
|
||||
self.assertIn("Infrastructure", content)
|
||||
# Anti-patterns for prior product shapes the stable packet
|
||||
# must not describe as current truth.
|
||||
self.assertNotIn("default route lands on `Dashboard`", normalized)
|
||||
self.assertNotIn("around Dashboard, Infrastructure", normalized)
|
||||
self.assertNotIn(
|
||||
|
|
@ -224,15 +232,32 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
|||
content,
|
||||
)
|
||||
self.assertNotIn("- `Dashboard`", content)
|
||||
# Anti-patterns for the reverted unified IA so the stable
|
||||
# packet does not silently drift back to it.
|
||||
self.assertNotIn(
|
||||
"Authenticated users now land on `Infrastructure`",
|
||||
normalized,
|
||||
)
|
||||
self.assertNotIn(
|
||||
"default route lands on `Infrastructure`",
|
||||
normalized,
|
||||
)
|
||||
self.assertNotIn(
|
||||
"Infrastructure as the default landing surface",
|
||||
content,
|
||||
)
|
||||
|
||||
self.assertIn(
|
||||
"Authenticated users now land on `Infrastructure`",
|
||||
"platform-shaped top-level navigation",
|
||||
normalize_ws(stable_docs["release_notes"]),
|
||||
)
|
||||
self.assertIn("default route lands on `Infrastructure`", normalize_ws(stable_docs["changelog"]))
|
||||
self.assertIn(
|
||||
"Infrastructure as the default landing surface",
|
||||
stable_docs["operator_support_pack"],
|
||||
"platform-shaped",
|
||||
normalize_ws(stable_docs["changelog"]),
|
||||
)
|
||||
self.assertIn(
|
||||
"platform-shaped top-level pages",
|
||||
normalize_ws(stable_docs["operator_support_pack"]),
|
||||
)
|
||||
|
||||
def test_rc1_changelog_keeps_current_free_first_licensing_posture(self) -> None:
|
||||
|
|
|
|||
|
|
@ -334,62 +334,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
unified_resources_match["verification_requirement"]["exact_files"],
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_infrastructure_summary_model_to_shared_infrastructure_hot_path(
|
||||
self,
|
||||
) -> None:
|
||||
result = lookup_paths(
|
||||
["frontend-modern/src/components/Infrastructure/infrastructureSummaryModel.ts"]
|
||||
)
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"performance-and-scalability", "unified-resources"},
|
||||
)
|
||||
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"performance-and-scalability", "unified-resources"},
|
||||
)
|
||||
self.assertEqual(
|
||||
file_entry["shared_ownership"]["subsystems"],
|
||||
["performance-and-scalability", "unified-resources"],
|
||||
)
|
||||
|
||||
matches_by_subsystem = {
|
||||
match["subsystem"]: match for match in file_entry["matches"]
|
||||
}
|
||||
performance_match = matches_by_subsystem["performance-and-scalability"]
|
||||
self.assertEqual(
|
||||
performance_match["contract"],
|
||||
"docs/release-control/v6/internal/subsystems/performance-and-scalability.md",
|
||||
)
|
||||
self.assertEqual(performance_match["lane_context"]["lane_id"], "L10")
|
||||
self.assertEqual(
|
||||
performance_match["verification_requirement"]["id"],
|
||||
"workloads-hot-path",
|
||||
)
|
||||
self.assertIn(
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/infrastructureSummaryModel.test.ts",
|
||||
performance_match["verification_requirement"]["exact_files"],
|
||||
)
|
||||
|
||||
unified_resources_match = matches_by_subsystem["unified-resources"]
|
||||
self.assertEqual(
|
||||
unified_resources_match["contract"],
|
||||
"docs/release-control/v6/internal/subsystems/unified-resources.md",
|
||||
)
|
||||
self.assertEqual(unified_resources_match["lane_context"]["lane_id"], "L13")
|
||||
self.assertEqual(
|
||||
unified_resources_match["verification_requirement"]["id"],
|
||||
"resource-consumers",
|
||||
)
|
||||
self.assertIn(
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/infrastructureSummaryModel.test.ts",
|
||||
unified_resources_match["verification_requirement"]["exact_files"],
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_resource_detail_drawer_discovery_model_to_unified_resources(self) -> None:
|
||||
result = lookup_paths(
|
||||
["frontend-modern/src/components/Infrastructure/resourceDetailDiscoveryModel.ts"]
|
||||
|
|
@ -527,34 +471,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
"organization-billing-surface",
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_pro_license_panel_to_cloud_paid(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Settings/ProLicensePanel.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"cloud-paid"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"cloud-paid"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/cloud-paid.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L3")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["id"],
|
||||
"pro-license-surface",
|
||||
)
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
[
|
||||
"frontend-modern/src/components/Settings/__tests__/MonitoredSystemLedgerPanel.test.tsx",
|
||||
"frontend-modern/src/components/Settings/__tests__/ProLicensePanel.test.tsx",
|
||||
],
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_pro_license_state_owner_to_cloud_paid(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Settings/useProLicensePanelState.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
|
|
@ -576,24 +492,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
"pro-license-surface",
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_monitored_system_ledger_panel_to_cloud_paid(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Settings/MonitoredSystemLedgerPanel.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"cloud-paid"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"cloud-paid"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/cloud-paid.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L3")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "pro-license-surface")
|
||||
|
||||
def test_lookup_paths_assigns_pricing_handoff_to_cloud_paid(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/pages/PricingHandoff.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
|
|
@ -630,26 +528,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
self.assertEqual(match["lane_context"]["lane_id"], "L3")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "commercial-plan-models")
|
||||
|
||||
def test_lookup_paths_assigns_monitored_system_definition_disclosure_to_cloud_paid(self) -> None:
|
||||
result = lookup_paths(
|
||||
["frontend-modern/src/components/Commercial/MonitoredSystemDefinitionDisclosure.tsx"]
|
||||
)
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"cloud-paid"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"cloud-paid"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/cloud-paid.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L3")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "commercial-plan-models")
|
||||
|
||||
def test_lookup_paths_assigns_relay_settings_state_owner_to_cloud_paid(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Settings/useRelaySettingsPanelState.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
|
|
@ -671,31 +549,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
"relay-frontend-surfaces",
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_surface_to_storage_recovery(self) -> None:
|
||||
# The legacy /recovery route shell (pages/Recovery.tsx) was retired
|
||||
# with the platform-first migration; recovery is now exercised via
|
||||
# the embedded surface at components/Recovery/Recovery.tsx.
|
||||
result = lookup_paths(["frontend-modern/src/components/Recovery/Recovery.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_reports_retired_dashboard_page_as_unowned(self) -> None:
|
||||
path = "frontend-modern/src/pages/Dashboard.tsx"
|
||||
result = lookup_paths([path])
|
||||
|
|
@ -741,60 +594,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
|
||||
def test_lookup_paths_assigns_recovery_points_facets_hook_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/hooks/useRecoveryPointsFacets.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
|
||||
def test_lookup_paths_assigns_recovery_points_series_hook_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/hooks/useRecoveryPointsSeries.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
|
||||
def test_lookup_paths_assigns_recovery_rollups_hook_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/hooks/useRecoveryRollups.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
|
||||
def test_lookup_paths_reports_retired_dashboard_recovery_hook_as_unowned(self) -> None:
|
||||
path = "frontend-modern/src/hooks/useDashboardRecovery.ts"
|
||||
result = lookup_paths([path])
|
||||
|
|
@ -804,24 +603,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(file_entry["matches"], [])
|
||||
|
||||
def test_lookup_paths_assigns_recovery_summary_component_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Recovery/RecoverySummary.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
|
||||
def test_lookup_paths_reports_retired_dashboard_recovery_presentation_as_unowned(self) -> None:
|
||||
path = "frontend-modern/src/utils/dashboardRecoveryPresentation.ts"
|
||||
result = lookup_paths([path])
|
||||
|
|
@ -831,44 +612,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(file_entry["matches"], [])
|
||||
|
||||
def test_lookup_paths_assigns_storage_panel_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Storage/Storage.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "storage-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
[
|
||||
"frontend-modern/src/components/Storage/__tests__/DiskList.test.tsx",
|
||||
"frontend-modern/src/components/Storage/__tests__/Storage.test.tsx",
|
||||
"frontend-modern/src/components/Storage/__tests__/StorageGroupRow.test.tsx",
|
||||
"frontend-modern/src/components/Storage/__tests__/StoragePoolDetail.test.tsx",
|
||||
"frontend-modern/src/components/Storage/__tests__/useStoragePageSummary.test.ts",
|
||||
"frontend-modern/src/components/Storage/code_standards.test.ts",
|
||||
"frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts",
|
||||
"frontend-modern/src/features/storageBackups/__tests__/resourceStorageMapping.test.ts",
|
||||
"frontend-modern/src/features/storageBackups/__tests__/storageAdapters.test.ts",
|
||||
"frontend-modern/src/features/storageBackups/__tests__/storageAlertState.test.ts",
|
||||
"frontend-modern/src/features/storageBackups/__tests__/storageDomain.test.ts",
|
||||
"frontend-modern/src/features/storageBackups/__tests__/storageModelCore.test.ts",
|
||||
"frontend-modern/src/features/storageBackups/__tests__/storagePagePresentation.test.ts",
|
||||
"frontend-modern/src/features/storageBackups/__tests__/storagePoolsTablePresentation.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts",
|
||||
],
|
||||
)
|
||||
|
||||
def test_lookup_paths_reports_retired_dashboard_storage_presentation_as_unowned(self) -> None:
|
||||
path = "frontend-modern/src/utils/dashboardStoragePresentation.ts"
|
||||
result = lookup_paths([path])
|
||||
|
|
@ -902,72 +645,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "storage-product-surface")
|
||||
|
||||
def test_lookup_paths_assigns_recovery_types_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/types/recovery.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_date_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryDatePresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_status_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryStatusPresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_reports_retired_recovery_summary_presentation_as_unowned(self) -> None:
|
||||
path = "frontend-modern/src/utils/recoverySummaryPresentation.ts"
|
||||
result = lookup_paths([path])
|
||||
|
|
@ -977,226 +654,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(file_entry["matches"], [])
|
||||
|
||||
def test_lookup_paths_assigns_recovery_record_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryRecordPresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_outcome_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryOutcomePresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_action_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryActionPresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_artifact_mode_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryArtifactModePresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_empty_state_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryEmptyStatePresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_filter_chip_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryFilterChipPresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_issue_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryIssuePresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_table_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryTablePresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_timeline_chart_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryTimelineChartPresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_recovery_timeline_presentation_to_storage_recovery(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/utils/recoveryTimelinePresentation.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"storage-recovery"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["contract"], "docs/release-control/v6/internal/subsystems/storage-recovery.md")
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L15")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "recovery-product-surface")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
RECOVERY_PRODUCT_SURFACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_api_token_manager_to_api_contracts(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Settings/APITokenManager.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
|
|
@ -1516,43 +973,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_results_step_to_agent_lifecycle(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Infrastructure/deploy/ResultsStep.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(
|
||||
match["contract"],
|
||||
"docs/release-control/v6/internal/subsystems/agent-lifecycle.md",
|
||||
)
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L16")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["id"],
|
||||
"deploy-fallback-install-surface",
|
||||
)
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
[
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/DeployStepComponents.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/CandidatesStep.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/ConfirmStep.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/DeployingStep.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/PreflightStep.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/deploy/__tests__/ResultsStep.test.tsx",
|
||||
"frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts",
|
||||
],
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_agent_profiles_panel_to_agent_lifecycle(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Settings/AgentProfilesPanel.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
|
|
@ -1619,70 +1039,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_infrastructure_workspace_model_to_agent_lifecycle(self) -> None:
|
||||
result = lookup_paths(
|
||||
["frontend-modern/src/components/Settings/infrastructureWorkspaceModel.ts"]
|
||||
)
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(
|
||||
match["contract"],
|
||||
"docs/release-control/v6/internal/subsystems/agent-lifecycle.md",
|
||||
)
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L16")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["id"],
|
||||
"platform-connections-workspace-surface",
|
||||
)
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
PLATFORM_CONNECTIONS_WORKSPACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_infrastructure_workspace_to_agent_lifecycle(
|
||||
self,
|
||||
) -> None:
|
||||
result = lookup_paths(
|
||||
[
|
||||
"frontend-modern/src/components/Settings/InfrastructureWorkspace.tsx"
|
||||
]
|
||||
)
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(
|
||||
match["contract"],
|
||||
"docs/release-control/v6/internal/subsystems/agent-lifecycle.md",
|
||||
)
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L16")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["id"],
|
||||
"platform-connections-workspace-surface",
|
||||
)
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
PLATFORM_CONNECTIONS_WORKSPACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_connections_table_model_to_agent_lifecycle(self) -> None:
|
||||
result = lookup_paths(
|
||||
["frontend-modern/src/components/Settings/connectionsTableModel.ts"]
|
||||
|
|
@ -1713,31 +1069,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
CONNECTIONS_LEDGER_WORKSPACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_infrastructure_settings_model_to_agent_lifecycle(self) -> None:
|
||||
result = lookup_paths(
|
||||
["frontend-modern/src/components/Settings/infrastructureSettingsModel.ts"]
|
||||
)
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
self.assertEqual(
|
||||
{item["subsystem"] for item in result["impacted_subsystems"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(
|
||||
{match["subsystem"] for match in file_entry["matches"]},
|
||||
{"agent-lifecycle"},
|
||||
)
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["id"],
|
||||
"platform-connections-workspace-surface",
|
||||
)
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
PLATFORM_CONNECTIONS_WORKSPACE_EXACT_FILES,
|
||||
)
|
||||
|
||||
def test_lookup_paths_reports_agent_install_backend_as_shared_boundary(self) -> None:
|
||||
result = lookup_paths(["internal/api/agent_install_command_shared.go"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
|
|
@ -4713,63 +4044,6 @@ class SubsystemLookupTest(unittest.TestCase):
|
|||
],
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_discovery_tab_to_unified_resources(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Discovery/DiscoveryTab.tsx"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
|
||||
file_entry = result["files"][0]
|
||||
self.assertEqual(file_entry["classification"], "runtime")
|
||||
self.assertEqual(len(file_entry["matches"]), 1)
|
||||
|
||||
match = file_entry["matches"][0]
|
||||
self.assertEqual(match["subsystem"], "unified-resources")
|
||||
self.assertEqual(
|
||||
match["contract"],
|
||||
"docs/release-control/v6/internal/subsystems/unified-resources.md",
|
||||
)
|
||||
self.assertEqual(match["lane_context"]["lane_id"], "L13")
|
||||
self.assertEqual(match["verification_requirement"]["id"], "resource-consumers")
|
||||
self.assertEqual(
|
||||
match["verification_requirement"]["exact_files"],
|
||||
[
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/ResourceChangeSummary.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/ResourceCorrelationSummary.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.discovery.test.ts",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.history.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/ResourcePolicySummary.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.performance.contract.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.workloads-link.test.tsx",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/infrastructureSelectors.test.ts",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/infrastructureSummaryModel.test.ts",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/resourceDetailDrawerIdentityModel.test.ts",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/resourceDetailDrawerOperationalModel.test.ts",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/resourceDetailMappers.test.ts",
|
||||
"frontend-modern/src/components/Infrastructure/__tests__/unifiedResourceTableStateModel.test.ts",
|
||||
"frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts",
|
||||
"frontend-modern/src/features/docker/__tests__/DockerNativeTables.test.tsx",
|
||||
"frontend-modern/src/features/docker/__tests__/DockerPageSurface.test.tsx",
|
||||
"frontend-modern/src/features/docker/__tests__/dockerPageModel.test.ts",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesAutoscalingTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesClustersTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesConfigTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesControllersTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesEventsTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesNetworkingTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesPageSurface.contract.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesPodsTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesPolicyTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesServicesTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/KubernetesStorageTable.test.tsx",
|
||||
"frontend-modern/src/features/kubernetes/__tests__/kubernetesPageModel.test.ts",
|
||||
"frontend-modern/src/hooks/__tests__/useUnifiedResources.test.ts",
|
||||
"frontend-modern/src/routing/__tests__/resourceLinks.test.ts",
|
||||
"frontend-modern/src/stores/__tests__/websocket-unified.test.ts",
|
||||
"frontend-modern/src/types/__tests__/resource.test.ts",
|
||||
"frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts",
|
||||
"internal/unifiedresources/code_standards_test.go",
|
||||
],
|
||||
)
|
||||
|
||||
def test_lookup_paths_assigns_discovery_tab_state_owner_to_unified_resources(self) -> None:
|
||||
result = lookup_paths(["frontend-modern/src/components/Discovery/useDiscoveryTabState.ts"])
|
||||
self.assertEqual(result["unowned_runtime_files"], [])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue