Audit pass against the live mock backend (PULSE_MOCK_MODE=true) revealed
three platform sub-tabs that could never populate from canonical
resources today, even with a mature fixture environment:
- Docker > Swarm services: no `docker-service` resource is emitted by
the unified resource adapter at the /api/resources boundary.
- Kubernetes > Services: no `k8s-service` resource type is defined in
internal/unifiedresources; only k8s-cluster, k8s-node, pod, and
k8s-deployment are projected.
- TrueNAS > Hosts: TrueNAS connections produce storage, datasets,
physical disks, and app-containers but no top-level `agent` row
tagged with the `truenas` platform.
Per the platform-pages goal ("if a platform lacks enough canonical data
model support to make a useful page even after fixture work, do not
invent speculative UI — report the data-model gap and skip or gate
that surface deliberately"), the three sub-tabs are removed from the
page navigation and the resource queries are tightened to drop the
unused types. TrueNAS now defaults to /truenas/storage as the first
canonical operator entry point.
Kubernetes Nodes now also includes agent rows whose `sources` array
reports `kubernetes`, because the backend registry merges Pulse-Agent-
linked Kubernetes nodes onto the linked agent row. The merged agents
are the canonical projection of K8s nodes when an agent is installed
on them; treating them as Nodes makes the tab populate against mock
mode and live agent fleets alike.
Browser verification (Playwright, chromium, against live mock-mode
Pulse dev runtime):
- 8 tests, all pass. Every declared platform sub-tab now asserts at
least one canonical row populates under mock mode:
- docker: /docker/overview (2 hosts), /docker/containers
- kubernetes: /kubernetes/overview (1 cluster),
/kubernetes/nodes (3 merged agents), /kubernetes/pods (10),
/kubernetes/deployments (4)
- truenas: /truenas/storage (9), /truenas/apps (5)
- vmware: /vmware/overview (4 ESXi hosts), /vmware/vms (8),
/vmware/storage (datastores)
Targeted tests:
- dockerPageModel, kubernetesPageModel, truenasPageModel suites
updated and passing.
- resourceLinks.test.ts asserts the new TrueNAS default sub-tab.
Contracts updated:
- unified-resources.md Extension Points: platform default sub-tab must
land on a canonical surface that actually populates.
- storage-recovery.md Shared Boundaries: same; calls out TrueNAS
defaulting to /truenas/storage today.
Remaining canonical data-model gaps (intentionally not surfaced as
empty platform sub-tabs in the UI):
- internal/unifiedresources does not emit `docker-service` resources
even though mock.generateDockerServicesAndTasks() generates them in
the StateSnapshot; revisit when adding a docker-service projection.
- internal/unifiedresources does not define ResourceTypeK8sService;
revisit when k8s-service rows are added to the canonical model.
- internal/unifiedresources does not project a top-level TrueNAS
system as an `agent` row; revisit when the TrueNAS adapter promotes
the connection target into a canonical infrastructure row.
The unified resource projection returned by /api/resources leaves
`platformType` empty on several canonical resource types (storage,
agent, pbs, app-container, vm, k8s-deployment, pod, etc.) under the
mock fixture path and parts of the live backend. Platform-first pages
were filtering on `resource.platformType` directly, so Docker /
Kubernetes / TrueNAS / vSphere pages rendered empty under mock mode
even though the resources existed and were tagged with the right
`sources` array (['docker'], ['kubernetes'], ['truenas'], ['vmware']).
Introduce `resolveResourcePlatformType(resource)` in
`frontend-modern/src/utils/sourcePlatforms.ts` as the canonical reader
for "what platform family does this unified resource belong to". It
prefers `resource.platformType` when present and falls back to the
resource's `sources` array via the existing
`resolvePlatformTypeFromSources` normalization, so client-side family
grouping behaves identically against mock fixtures and live backends.
Each platform page model now buckets resources through that helper:
- dockerPageModel.ts
- kubernetesPageModel.ts
- truenasPageModel.ts
- vmwarePageModel.ts
Browser verification (Playwright, chromium, against live mock-mode
Pulse dev runtime):
- 4 no-data tests (stubbed empty /api/resources): all 4 pages render
sub-tab chrome and surface empty state.
- 4 populated tests (live mock backend): each platform asserts at
least one canonical row renders on its data-bearing sub-tabs:
- docker: /docker/overview (Hosts), /docker/containers
- kubernetes: /kubernetes/pods, /kubernetes/deployments
- truenas: /truenas/storage
- vmware: /vmware/vms, /vmware/storage
All 8 tests pass.
Verification artifacts staged:
- sourcePlatforms.test.ts extended with resolveResourcePlatformType
cases (19 tests pass).
- 68-platform-pages-shell.spec.ts extended with populated-state
assertions per platform.
Contracts updated:
- unified-resources.md Shared Boundaries: resolveResourcePlatformType
is the canonical reader for unified-resource platform family.
- frontend-primitives.md Extension Points: same.
Remaining mock fixture gaps (intentionally not asserted populated in
this commit; tracked for fixture extension):
- docker/services: default mock fixtures do not expose docker-service
resources at the /api/resources boundary.
- kubernetes/overview, kubernetes/nodes, kubernetes/services:
KubernetesClusters are generated but k8s-cluster, k8s-node, and
k8s-service resource projections are not surfaced.
- truenas/overview, truenas/apps: no TrueNAS agent or TrueNAS-scoped
app-container resources in default fixtures.
- vmware/overview: no VMware ESXi-host agent resources in default
fixtures.
Introduce a shared platform-page primitive and four new top-level family
pages that mirror the v5-style Proxmox surface: chrome only, embedding
the canonical WorkloadsSurface, StorageSurface, RecoverySurface, and
UnifiedResourceTable in tableOnly/embedded mode with forced platform or
source filters. No dashboard cards, no fake data, no bespoke per-family
tables.
Pages added:
- /docker Hosts / Containers / Swarm services
- /kubernetes Clusters / Nodes / Pods / Deployments / Services
- /truenas Hosts / Storage / Apps
- /vmware Hosts / VMs / Storage (vSphere, first-lab-ready)
Top-level navigation entries are gated on platform presence in
state.resources, so empty platforms stay hidden by default; Proxmox
remains alwaysShow. Infrastructure, Workloads, Storage, and Recovery
remain available unchanged. Routing, navigation tab IDs, and the
document-title map are extended to match. Route preload and mobile-nav
priority changes are deliberately deferred to a follow-up commit to
avoid wider entanglement with parallel-agent edits to those shared
shell files.
Contracts extended for the new platform-page boundary:
- cloud-paid.md
- unified-resources.md
- storage-recovery.md
- ai-runtime.md
- frontend-primitives.md
Tests:
- dockerPageModel, kubernetesPageModel, truenasPageModel, vmwarePageModel
vitest suites (12 new tests).
- resourceLinks.test.ts extended for the new platform path builders.
- App.architecture.test.ts extended for the new lazy imports and routes.
- 68-platform-pages-shell.spec.ts Playwright smoke covering all four
pages and every sub-tab link against the live Pulse dev runtime.
- App.architecture, proxmox model, and Workloads suites continue to pass.
Skipped (canonical model not ready):
- Unraid as a top-level page: an agentHostProfile, no platform
projections; already surfaces through the Pulse-managed Hosts / Storage
views.
- Synology DSM, Microsoft Hyper-V, AWS, Azure, GCP:
governanceState=presentation-only, no canonical projections.
Present stable refusal prefixes through shared frontend helpers and show verification outcomes in resource action history without exposing raw refusal tokens. Extend action audit tests, drawer coverage, and VMware history spec evidence.
Classify Assistant and Patrol provider-test failures through the Patrol runtime failure taxonomy, redact secret-shaped provider evidence, and preserve safe recommendations in the settings shell.
Refs #1463
The four-step coachmark over the top tabs was a tour pretending to be
guidance: each step duplicated the tab title in one sentence, and the
Reopen control on /settings/system-general spawned a centered panel with
no spotlight target because the tabs only exist on dashboard routes.
Delete the modal, the localStorage dismissal key, the reopen event, the
Reopen row in General settings, and the matching guardrails so the
shared-primitives tests stop pinning the deleted owner split. Drop the
WhatsNew dismissal helpers and addInitScript bypasses from the
integration suite, and the dedicated tour test in
19-telemetry-disclosure.
Treat OIDC, SAML, and multi-provider SSO as included Community capabilities while retaining advanced_sso as a compatibility key. Remove SAML-specific paywalls and paid-upgrade copy from runtime, settings UI, entitlement snapshots, docs, journey proof, and subsystem contracts.
Refs #1449