diff --git a/docs/release-control/v6/internal/subsystems/agent-lifecycle.md b/docs/release-control/v6/internal/subsystems/agent-lifecycle.md
index b2358b3fa..4aedda46c 100644
--- a/docs/release-control/v6/internal/subsystems/agent-lifecycle.md
+++ b/docs/release-control/v6/internal/subsystems/agent-lifecycle.md
@@ -240,11 +240,11 @@ pause, test, edit, and remove.
An availability target classified as `machine` is still agentless unless a
Pulse Agent actually registers for that host. That classification exists so
servers, desktops, laptops, and comparable computers such as a Mac mini can
-appear in Standalone Machines when monitored by reachability probes; it must
-not create lifecycle authority, install state, agent profile membership, or
-host-command capability. A `targetKind=machine` add-dialog handoff is only a
-preselected availability-resource creation path, not an agent install or
-lifecycle onboarding state.
+use machine-specific reachability copy in Availability checks; it must not
+create Standalone Machines membership, lifecycle authority, install state,
+agent profile membership, or host-command capability. A `targetKind=machine`
+add-dialog handoff is only a preselected availability-resource creation path,
+not an agent install or lifecycle onboarding state.
The lifecycle-owned onboarding presentation helper must consume the governed
platform support manifest for readiness stage, primary mode, canonical
projections, and support-floor posture.
diff --git a/docs/release-control/v6/internal/subsystems/api-contracts.md b/docs/release-control/v6/internal/subsystems/api-contracts.md
index 50fbe5ed6..fd47d3c3b 100644
--- a/docs/release-control/v6/internal/subsystems/api-contracts.md
+++ b/docs/release-control/v6/internal/subsystems/api-contracts.md
@@ -436,12 +436,13 @@ the canonical monitored-system blocked payload.
`frontend-modern/src/api/availabilityTargets.ts`, and the unified-resource
availability payload together. The bounded `targetKind` vocabulary is
`machine`, `service`, and `device`; missing legacy values default to
- `service`, and browser consumers may place only explicitly classified
- `machine` targets into Standalone Machines. Browser add-dialog routes may
- carry a `targetKind` query value to preselect that bounded kind, but the
- persisted contract remains the `AvailabilityTarget.targetKind` payload.
- API clients must not infer that classification from protocol, hostname,
- port, or row label.
+ `service`. Browser add-dialog routes may carry a `targetKind` query value
+ to preselect that bounded kind, but the persisted contract remains the
+ `AvailabilityTarget.targetKind` payload. Browser consumers must not place
+ availability targets into Standalone Machines from that classification;
+ Machines membership requires Pulse Agent resource evidence. API clients
+ must not infer that classification from protocol, hostname, port, or row
+ label.
3. Add dedicated contract tests for new stable payloads
Unified resource type-filter and organization-share resource type additions
must route through `internal/api/resources.go`, `internal/api/org_handlers.go`,
diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md
index e2545b762..33667dca1 100644
--- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md
+++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md
@@ -2836,7 +2836,9 @@ availability settings at `/settings/monitoring/availability`, with
Machine entry points must add `targetKind=machine`, while the focused
availability checks entry points for services and devices must add
`targetKind=service`, so deep links open the same owned dialog with the correct
-bounded target kind already selected.
+bounded target kind already selected. That target kind only scopes the
+availability form copy and payload; it must not make agentless reachability
+targets eligible for the Machines table.
Former nested aliases such as `/settings/infrastructure/install`,
`/settings/infrastructure/platforms/proxmox/pbs`,
`/settings/infrastructure/api/pve`, and `/settings/workloads/docker` must fail
@@ -3590,16 +3592,16 @@ metric slot, while keeping recent check timing and fuller failure context in
the tooltip or drawer so operators can understand what was measured without
duplicated row chrome.
Operational navigation for those agentless endpoints belongs to the
-frontend-primitives-owned Machines surface rather than a new primary nav item.
-The page may show availability checks beside standalone Pulse Agent machines and
-provide a focused availability tab, but Settings remains the add/edit owner and
+frontend-primitives-owned Machines surface as a focused Availability checks tab
+rather than a new primary nav item. The page may show availability checks beside
+standalone Pulse Agent machines, but Settings remains the add/edit owner and
the app shell must not add a separate top-level Availability destination.
The Machines page must not pretend its machine list is a generic overview:
-the default tab is `Machines`, and the full availability-check row list belongs
+the default tab is `Machines`, the Machines table is only for Pulse Agent-backed
+resources with host telemetry, and the full availability-check row list belongs
to the `Availability checks` tab. Servers, laptops, desktops, and comparable
-computers that are monitored by agentless reachability checks are still
-machines when the availability target is classified as `machine`; service and
-device checks stay in the focused availability tab and may only trigger a
-compact handoff from Machines. The Machines empty and handoff actions must use
-the machine-targeted availability add route, while Availability checks actions
-must use the service/device-targeted route.
+computers monitored only by agentless reachability checks may use
+`targetKind=machine` in the availability form, but they stay in Availability
+checks until a Pulse Agent registers and supplies CPU, memory, disk, and network
+telemetry. Machines empty and handoff actions must lead to Pulse Agent install
+or the Availability checks tab, not to an agentless machine row in Machines.
diff --git a/docs/release-control/v6/internal/subsystems/storage-recovery.md b/docs/release-control/v6/internal/subsystems/storage-recovery.md
index 9da474408..ebee0b387 100644
--- a/docs/release-control/v6/internal/subsystems/storage-recovery.md
+++ b/docs/release-control/v6/internal/subsystems/storage-recovery.md
@@ -801,9 +801,10 @@ recovery scope, or a storage/recovery-owned secret source.
32. Keep agentless availability endpoints neutral on the shared unified-resource and API contracts. When `internal/api/availability_handlers.go`, `internal/api/connections_handlers.go`, `internal/api/platform_mock_connections.go`, or `frontend-modern/src/hooks/useUnifiedResources.ts` surface `network-endpoint` availability resources, storage and recovery may consume their liveness as infrastructure context only; they must not reinterpret ping/TCP/HTTP endpoints as storage providers, backup targets, recovery repositories, or protected-workload evidence.
That neutrality includes availability targets whose `targetKind` is
`machine`. A Linux server, desktop, laptop, or Mac mini monitored by an
- agentless reachability check may appear in Standalone Machines, but storage
- and recovery must still treat the row as liveness context unless a separate
- storage/recovery-owned relationship ties it to backup or restore evidence.
+ agentless reachability check still belongs to Availability checks rather
+ than Standalone Machines; storage and recovery must treat the row as
+ liveness context unless a separate storage/recovery-owned relationship ties
+ it to backup or restore evidence.
33. Keep infrastructure summary chart bucketing and short response caching presentation-only on the adjacent shared API boundary. When `internal/api/router.go` normalizes mixed-cadence infrastructure history into equal-time summary buckets or serves a cached summary payload for repeated operator-facing summary-card requests, storage and recovery may consume the resulting visual context only; they must not reinterpret those normalized chart samples, cached timestamps, or cache hits as recovery freshness windows, backup cadence, or restore evidence.
34. Keep workload chart downsampling and short response caching presentation-only on that same adjacent shared API boundary. When `internal/api/router.go` caps mixed-cadence workload history into equal-time buckets or serves a cached workload-summary payload for repeated operator-facing workload-card requests, storage and recovery may consume the resulting visual context only; they must not reinterpret those shaped chart samples, cached timestamps, or cache hits as recovery freshness windows, backup cadence, or restore evidence.
The same adjacent chart boundary now covers compact storage capacity
@@ -1363,10 +1364,10 @@ storage or recovery inventory. Storage/recovery consumers may receive
they must not fold those endpoints into protected-item counts, storage health
rollups, recovery evidence, or storage/recovery licensing or readiness
messages unless a separately governed storage/recovery relationship is added.
-The agentless `machine` target kind does not change that boundary: it is a
-Standalone presentation classification for computer-shaped reachability targets,
-not storage ownership, repository membership, backup coverage, or restore
-authority.
+The agentless `machine` target kind does not change that boundary: it is
+availability presentation vocabulary for computer-shaped reachability targets,
+not Standalone Machines membership, storage ownership, repository membership,
+backup coverage, or restore authority.
That same owned summary path now also runs through
`useStorageSummaryCharts.ts`: the storage page owns one page-scoped summary
range and one shared storage-summary history fetch, and both the sticky
diff --git a/docs/release-control/v6/internal/subsystems/unified-resources.md b/docs/release-control/v6/internal/subsystems/unified-resources.md
index 4e6319bd6..4ddd191bf 100644
--- a/docs/release-control/v6/internal/subsystems/unified-resources.md
+++ b/docs/release-control/v6/internal/subsystems/unified-resources.md
@@ -742,8 +742,9 @@ AI-only summary payloads, or page-local heuristics.
add handoffs must include `targetKind=machine`; service and device check
handoffs must include `targetKind=service`. Saved availability targets carry
a `targetKind` so agentless servers, laptops, desktops, and comparable
- computers can participate in the Machines inventory without reclassifying
- service or device checks as machines.
+ computers can use machine-specific reachability copy in Availability checks
+ without reclassifying service or device checks as machines. Machines
+ inventory membership still requires Pulse Agent resource evidence.
6. Keep infrastructure source visibility on canonical unified-resource truth.
Settings infrastructure source filters and summaries must preserve known
sources such as `truenas` and `availability` through the shared source
@@ -2804,8 +2805,9 @@ redirect. Canonical infrastructure management lives under
lives under `/settings/monitoring/availability`; day-to-day resource
inspection lives on the platform/runtime pages named by the
frontend-primitives-owned IA contract, with unified resources projecting
-standalone agent machines and agentless endpoint checks for the Machines
-consumer. Future infrastructure work must extend those owners rather than
+standalone agent machines for the Machines consumer and agentless endpoint
+checks for the Availability checks consumer. Future infrastructure work must
+extend those owners rather than
recreating
`frontend-modern/src/features/infrastructure/`, a `/infrastructure` route, or
a separate top-level availability route.
diff --git a/frontend-modern/src/features/standalone/AgentsMachinesTable.tsx b/frontend-modern/src/features/standalone/AgentsMachinesTable.tsx
index 0142d078c..b0dc1cbad 100644
--- a/frontend-modern/src/features/standalone/AgentsMachinesTable.tsx
+++ b/frontend-modern/src/features/standalone/AgentsMachinesTable.tsx
@@ -204,7 +204,7 @@ export const AgentsMachinesTable: Component<{
}
>
diff --git a/frontend-modern/src/features/standalone/StandalonePageSurface.tsx b/frontend-modern/src/features/standalone/StandalonePageSurface.tsx
index 50608f9ae..5b8e1267f 100644
--- a/frontend-modern/src/features/standalone/StandalonePageSurface.tsx
+++ b/frontend-modern/src/features/standalone/StandalonePageSurface.tsx
@@ -1,10 +1,8 @@
import { Show, createEffect, createMemo, createSignal } from 'solid-js';
import { A, useLocation, useNavigate } from '@solidjs/router';
import ActivityIcon from 'lucide-solid/icons/activity';
-import PlusIcon from 'lucide-solid/icons/plus';
import ServerIcon from 'lucide-solid/icons/server';
import SettingsIcon from 'lucide-solid/icons/settings';
-import { buildAvailabilityTargetAddPath } from '@/components/Settings/availabilitySettingsModel';
import { buildInfrastructureOnboardingPath } from '@/components/Settings/infrastructureWorkspaceModel';
import {
PlatformErrorState,
@@ -89,7 +87,7 @@ export function StandalonePageSurface() {
fallback={
}
>
@@ -118,8 +116,8 @@ export function StandalonePageSurface() {
fallback={
Add agent
-
-
- Add machine check
+
+
+ View checks
}
@@ -149,10 +144,18 @@ export function StandalonePageSurface() {
0}>
+
View checks
-
-
- Add machine check
-
}
/>
@@ -177,7 +173,7 @@ export function StandalonePageSurface() {
resources={model().machines}
emptyIcon={machineIcon()}
emptyTitle="No machines"
- emptyDescription="Install the Pulse Agent on Linux, macOS, Windows, or Unraid systems for full telemetry, or add an agentless machine check when reachability is enough."
+ emptyDescription="Install Pulse Agent on Linux, macOS, Windows, or Unraid systems for full CPU, memory, disk, and network telemetry."
/>
diff --git a/frontend-modern/src/features/standalone/__tests__/StandalonePageSurface.test.tsx b/frontend-modern/src/features/standalone/__tests__/StandalonePageSurface.test.tsx
index 514593d33..8cafd0b70 100644
--- a/frontend-modern/src/features/standalone/__tests__/StandalonePageSurface.test.tsx
+++ b/frontend-modern/src/features/standalone/__tests__/StandalonePageSurface.test.tsx
@@ -112,7 +112,7 @@ afterEach(() => {
});
describe('StandalonePageSurface', () => {
- it('keeps overview focused on standalone machines, including agentless machines only', () => {
+ it('keeps overview focused on Pulse Agent machines only', () => {
render(() => );
expect(mocks.useUnifiedResources).toHaveBeenCalledWith(
@@ -124,7 +124,7 @@ describe('StandalonePageSurface', () => {
'data-tabs',
'machines,availability',
);
- expect(screen.getByTestId('agents-machines-table')).toHaveAttribute('data-resource-count', '2');
+ expect(screen.getByTestId('agents-machines-table')).toHaveAttribute('data-resource-count', '1');
expect(screen.queryByTestId('availability-checks-table')).not.toBeInTheDocument();
});
@@ -176,18 +176,16 @@ describe('StandalonePageSurface', () => {
expect(screen.queryByTestId('agents-machines-table')).not.toBeInTheDocument();
expect(screen.queryByTestId('availability-checks-table')).not.toBeInTheDocument();
- expect(screen.getByText('No machines')).toBeInTheDocument();
+ expect(screen.getByText('No Pulse Agent machines')).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: 'Add agent' })).toBeInTheDocument();
expect(screen.getByRole('link', { name: 'View checks' })).toHaveAttribute(
'href',
'/standalone/availability',
);
- expect(screen.getByRole('link', { name: 'Add machine check' })).toHaveAttribute(
- 'href',
- '/settings/monitoring/availability?add=target&targetKind=machine',
- );
+ expect(screen.queryByRole('link', { name: 'Add machine check' })).not.toBeInTheDocument();
});
- it('renders the machines table when only an agentless machine is present', () => {
+ it('keeps agentless machine checks in the availability handoff', () => {
mocks.useUnifiedResources.mockReturnValue({
resources: () => [
resource({
@@ -205,7 +203,11 @@ describe('StandalonePageSurface', () => {
render(() => );
- expect(screen.getByTestId('agents-machines-table')).toHaveAttribute('data-resource-count', '1');
- expect(screen.queryByText('No machines')).not.toBeInTheDocument();
+ expect(screen.queryByTestId('agents-machines-table')).not.toBeInTheDocument();
+ expect(screen.getByText('No Pulse Agent machines')).toBeInTheDocument();
+ expect(screen.getByRole('link', { name: 'View checks' })).toHaveAttribute(
+ 'href',
+ '/standalone/availability',
+ );
});
});
diff --git a/frontend-modern/src/features/standalone/__tests__/standalonePageModel.test.ts b/frontend-modern/src/features/standalone/__tests__/standalonePageModel.test.ts
index da73a0642..15f0ff155 100644
--- a/frontend-modern/src/features/standalone/__tests__/standalonePageModel.test.ts
+++ b/frontend-modern/src/features/standalone/__tests__/standalonePageModel.test.ts
@@ -66,7 +66,7 @@ describe('standalonePageModel', () => {
expect(model.availabilityChecks).toEqual([]);
});
- it('keeps agentless availability checks beside standalone machines', () => {
+ it('keeps agentless availability checks out of standalone machines', () => {
const model = buildStandalonePageModel([
resource({ id: 'mac-mini', platformType: 'agent', type: 'agent', sources: ['agent'] }),
resource({
@@ -85,8 +85,8 @@ describe('standalonePageModel', () => {
}),
]);
- expect(model.machines.map((item) => item.id)).toEqual(['mac-mini', 'router-ping']);
+ expect(model.machines.map((item) => item.id)).toEqual(['mac-mini']);
expect(model.availabilityChecks.map((item) => item.id)).toEqual(['router-ping', 'endpoint-1']);
- expect(model.resources.map((item) => item.id)).toEqual(['mac-mini', 'router-ping']);
+ expect(model.resources.map((item) => item.id)).toEqual(['mac-mini']);
});
});
diff --git a/frontend-modern/src/features/standalone/standalonePageModel.ts b/frontend-modern/src/features/standalone/standalonePageModel.ts
index bc0869695..4df4f4fcd 100644
--- a/frontend-modern/src/features/standalone/standalonePageModel.ts
+++ b/frontend-modern/src/features/standalone/standalonePageModel.ts
@@ -15,22 +15,8 @@ export const isAgentlessAvailabilityResource = (resource: Resource): boolean =>
resource.platformType === 'availability' ||
resource.sources?.includes('availability') === true;
-const availabilityTargetKindFor = (resource: Resource): string =>
- String(
- resource.availability?.targetKind ??
- (resource.platformData?.availability as { targetKind?: string } | undefined)?.targetKind ??
- '',
- )
- .trim()
- .toLowerCase();
-
-export const isAgentlessMachineResource = (resource: Resource): boolean =>
- isAgentlessAvailabilityResource(resource) && availabilityTargetKindFor(resource) === 'machine';
-
export function buildStandalonePageModel(resources: readonly Resource[]): StandalonePageModel {
- const machines = resources.filter(
- (resource) => isStandaloneMachineResource(resource) || isAgentlessMachineResource(resource),
- );
+ const machines = resources.filter(isStandaloneMachineResource);
const availabilityChecks = resources.filter(isAgentlessAvailabilityResource);
return {
machines,