Commit graph

365 commits

Author SHA1 Message Date
rcourtman
8355335e08 Clarify v5 migration recovery states 2026-07-07 21:46:07 +01:00
rcourtman
1a160eca44 Stabilize multi-tenant integration org reloads 2026-07-04 12:38:15 +01:00
rcourtman
c2729327c0 Keep Patrol calm-day queue plain
- remove the calm-day protection posture strip from Patrol Open work
- keep monitor-context Patrol posture suppressed for active or failed checks
2026-07-03 21:08:26 +01:00
rcourtman
887855e5e5 Remove Proxmox overview Patrol coverage strip 2026-06-30 17:05:06 +01:00
rcourtman
f0c81de00e Add Patrol safe workflow row guidance 2026-06-30 16:47:55 +01:00
rcourtman
4dacd93078 Add monitor-context Patrol coverage 2026-06-30 15:40:20 +01:00
rcourtman
238c806d1f Add Patrol row issue scaffolding 2026-06-30 15:20:42 +01:00
rcourtman
a8726a7bc7 Add Patrol calm-day protection posture 2026-06-30 15:06:25 +01:00
rcourtman
9ba5cf1e0f Group Patrol work signals in the workbench 2026-06-30 14:46:04 +01:00
rcourtman
d4e4c7ed79 Add monitor-first Patrol browser proof 2026-06-30 11:44:57 +01:00
rcourtman
ee8a24e14a backend and governance: MCP contract, agent capabilities, API, and release-control
Manifest-backed MCP tools, prompts, and resources with surface affordance contracts; agent capability manifest and governance projection; API contract tests and capability route projection; operations-loop and intelligence-funnel telemetry; release-control subsystem documentation, registry, and tooling; licensing and configuration.
2026-06-23 17:26:15 +01:00
rcourtman
7235dcf504 Clarify Patrol event trigger runtime state
Expose runtime-blocked event triggers in Patrol status and surface the user-facing reason in the Patrol UI.
2026-06-15 10:08:54 +01:00
rcourtman
54b7e9933d Harden integration bootstrap token seed
Some checks are pending
Build and Test / Secret Scan (push) Waiting to run
Build and Test / Frontend & Backend (push) Waiting to run
2026-06-14 23:32:38 +01:00
rcourtman
377fd5131d Harden release integration bootstrap gate 2026-06-14 22:26:13 +01:00
rcourtman
09ed857869 Converge UI primitives and readiness guards 2026-06-13 16:31:52 +01:00
rcourtman
ee67141fa2 Add MSP isolation E2E spec: token scoping, split-port ingest, signed webhook delivery
Automates the docs/MSP.md validation checklist and the WEBHOOKS.md
delivery contract against the real server, covering the cross-layer
seams unit tests cannot see (today's two isolation bugs both lived
there):

- org-bound token allowed in its own org, denied 403 in sibling orgs
  AND the default org (leaked client-site token must not read the
  provider estate)
- dedicated agent-ingest port serves only /api/agents/* (management
  paths 404, agent route auth-gated)
- client-org webhook delivery through the instance-wide private-target
  allowlist saved in default-org context, with HMAC signature verified
  against the documented recipe, X-Pulse-Event-ID idempotency header,
  and tenant id/name stamped in the payload
- restart inheritance: after docker restart the persisted allowlist
  still applies to lazily recreated tenant monitors (skips when the
  docker CLI cannot manage the container)

Compose: pulse-test gains PULSE_AGENT_INGEST_PORT=7656 (+ port map)
and a host-gateway extra_host so the spec's capture listener is
reachable from the container.
2026-06-10 12:06:35 +01:00
rcourtman
b707512e38 Clear all errcheck and gofmt violations so make lint gates on real findings
golangci-lint run ./... failed on ~190 pre-existing errcheck violations and
5 unformatted files, burying any new regression in noise. Fix all of them:

- Test files that hand-rolled mock-mode set/restore (vmware, truenas, and
  friends) now use the canonical setMockModeForTest/testutil.SetMockMode
  helper instead of drift copies that ignored SetEnabled errors.
- internal/mock and internal/monitoring tests get package-local
  mustSetEnabled/mustSetMockEnabled/mustSetMonitorMockMode helpers that
  fail the test on toggle errors.
- pkg/auth/sqlite_manager.go, pkg/metrics/store.go, pkg/server/server.go:
  rollbacks in defers use the explicit-discard idiom, migration renames and
  rollup commits log failures, the hosted reaper goroutine logs an error
  exit, shutdown mock-disable logs failures.
- Remaining test sites check errors with t.Fatalf/t.Errorf or explicitly
  discard best-effort calls (restore-chmods, handler-closure unmarshals)
  per existing repo style.
- gofmt: internal/api/maintenance_verification.go, internal/ai/demo.go and
  three findings test files.

Only dupl findings remain (44 pre-existing production-code duplication
pairs) — those need real refactors, not mechanical fixes.

Full test suites pass for every touched package.
2026-06-09 21:42:21 +01:00
rcourtman
3bd1e70557 Preview Assistant tool output 2026-06-06 11:30:35 +01:00
rcourtman
e78b14f516 Stabilize setup wizard release gate
Recognize the current first-run security step in the multi-tenant integration helper and keep the unlock helper from clicking account-creation controls.
Harden bootstrap-token validation as unauthenticated JSON.
2026-06-03 21:19:50 +01:00
rcourtman
1f84fd3dd0 Harden v6 upgrade release proofs 2026-06-03 17:07:25 +01:00
rcourtman
6043224997 Rename infrastructureNavigation to platformNavigation and restore visual-crawl spec
Two cleanups left over from the rc.6 IA revert that lived as
untracked scratch in the working tree until now.

Rename infrastructureNavigation -> platformNavigation

The internal feature name infrastructureNavigation predates the rc.6
revert and assumed an Infrastructure top-level page existed. Post-
revert the frontend is platform-shaped (Proxmox / Docker / Kubernetes
/ TrueNAS / vSphere / Standalone) and the model's purpose is to gate
visibility of each *platform* nav slot from resource evidence, not
gate visibility into a unified Infrastructure surface.

- frontend-modern/src/features/infrastructureNavigation/ -> .../platformNavigation/
- buildPrimaryInfrastructureNavigationVisibility -> buildPrimaryPlatformNavigationVisibility
- PrimaryInfrastructureNavId -> PrimaryPlatformNavId
- InfrastructureNavigationVisibility -> PlatformNavigationVisibility
- PRIMARY_INFRASTRUCTURE_NAV_IDS / _SCOPE_IDS -> PRIMARY_PLATFORM_NAV_IDS / _SCOPE_IDS
- primaryInfrastructureNavigationIsVisible -> primaryPlatformNavigationIsVisible
- selectFirstVisiblePrimaryInfrastructureNavigationId -> selectFirstVisiblePrimaryPlatformNavigationId
- filterInfrastructureNavigationShortcuts -> filterPlatformNavigationShortcuts
- createEmptyInfrastructureNavigationVisibility -> createEmptyPlatformNavigationVisibility
- infrastructureNavigationVisibilityFromResources -> platformNavigationVisibilityFromResources
- buildNavigableResourceInfrastructureScopeSet -> buildNavigableResourcePlatformScopeSet

Callers updated: App.tsx, AppLayout.tsx, useKeyboardShortcuts,
commandPaletteModel, useCommandPaletteState, KeyboardShortcutsModal,
CommandPaletteModal test, App.architecture test. Local variable and
prop names (infrastructureVisibility -> platformVisibility,
infrastructureNavigationVisibility -> platformNavigationVisibility,
infrastructureNavigationResolved -> platformNavigationResolved)
renamed for consistency.

The standalone visibility key is preserved. Standalone (Machines)
is a real evidence-gated nav slot in this model: AppLayout and
commandPaletteModel both consume isVisible('standalone') to hide
the Machines nav item when no Pulse Agent resources or availability
endpoints exist.

Visual crawl spec restored at tests/integration/tests/99-visual-crawl.spec.ts

The previous version of this spec crawled the unified IA routes
(/workloads, /infrastructure, /storage, /recovery, /operations) that
were retired in the rc.6 revert. Restored with a refreshed URL list
that targets the platform-shaped top-level pages and their
representative sub-routes (Proxmox PVE/PBS/Backups/Storage/Ceph,
Kubernetes nodes/deployments/config), plus Alerts, Patrol, and the
existing Settings routes. The DOM analysis body (headings, inputs,
tables, raw-color violations, screenshots, JSON report) is
unchanged.
2026-05-27 15:47:03 +01:00
rcourtman
a590024ca0 Consolidate container and Kubernetes platform tabs 2026-05-24 19:20:14 +01:00
rcourtman
bce500732a Stabilize managed dev runtime recovery 2026-05-21 13:36:36 +01:00
rcourtman
9ef4e588b7 Add TrueNAS services and stabilize dev startup 2026-05-21 12:08:25 +01:00
rcourtman
cb461a7304 Split TrueNAS API inventory into native tabs
Move TrueNAS apps, VMs, and network shares out of the overview stack and into first-class platform sub-tabs.

Update route and shell proof coverage for the expanded native TrueNAS tab set.
2026-05-21 09:20:14 +01:00
rcourtman
511d88f83d Show native TrueNAS protection activity
Replace the embedded recovery workspace with a TrueNAS-owned snapshots and replication table.

Keep the platform shell proof aligned to the native TrueNAS row contracts.
2026-05-21 09:12:04 +01:00
rcourtman
58a2ad8cc6 Add TrueNAS protection tab 2026-05-21 00:13:21 +01:00
rcourtman
1f66a2f93f Collapse Docker page to single unified surface
The "Hosts" tab already rendered the hosts table, the containers
WorkloadsSurface, and the Swarm services table together, so the
separate Containers and Swarm services sub-tabs were strict subset
views of overview. Other platform pages (Proxmox, TrueNAS,
Kubernetes) use sub-tabs for genuinely different data per tab; the
Docker shape was the odd one out.

Drop PlatformSectionTabs from DockerPageSurface and render the
unified hosts + containers + services stack unconditionally. Remove
the now-dead DOCKER_TAB_SPECS / DockerPageTabId / DockerTabSpec /
buildVisibleDockerTabSpecs exports from dockerPageModel. The
DockerPage no longer interprets the URL segment, so legacy
/docker/overview, /docker/containers, /docker/services bookmarks
continue to resolve via the existing /docker/* wildcard route in
App.tsx.
2026-05-19 09:52:10 +01:00
rcourtman
391cea1b13 Fix managed hot-dev LAN browser binding 2026-05-19 09:08:32 +01:00
rcourtman
91d7102a27 Make managed hot-dev verification deterministic 2026-05-18 17:29:50 +01:00
rcourtman
6feb85245f Stabilize first-session settings handoffs 2026-05-18 17:27:03 +01:00
rcourtman
5b94724bf2 truenas: bespoke Systems + Disks tables; project uptime/temp on the system row
Audit pass on the TrueNAS pages turned up three concrete issues:

1. **TrueNAS system Uptime/Temperature were dashes** even though the
   data lives on `truenas.uptimeSeconds` and on the
   `agent.temperature` max-sensor projection. The system row is
   emitted by `internal/truenas/provider.go::truenasRecordsFromSnapshot`,
   which is a separate path from the host/node adapters that the
   prior commit (c7bdd11e0) updated. Project the same top-level
   `Resource.Uptime` and `Resource.Temperature` here so the canonical
   table renders real values (live mock now reports `uptime: 3628800,
   temperature: 61.5` on the TrueNAS appliance row).

2. **The Systems tab needed NAS-native columns.** A TrueNAS appliance
   is a storage box — operators want at-a-glance pool / dataset /
   disk / app counts on the same row as CPU / Memory / Storage /
   Temperature / Uptime. New `TrueNASSystemsTable` reuses canonical
   shared primitives (Card, Table, SearchInput, FilterButtonGroup,
   StatusDot) and computes per-system child counts client-side from
   the same TrueNAS scope already fetched by the page.

3. **Physical disks weren't surfaced anywhere on the page**, even
   though the canonical TrueNAS adapter emits SMART-instrumented
   `physical_disk` rows with model / serial / size / health /
   temperature / wearout. Add a `disks` sub-tab (between Storage and
   Apps) backed by a new `TrueNASDisksTable` that surfaces those
   columns — generic Disk I/O / Uptime / Temperature from the infra
   table aren't meaningful for individual disks, but disk-native
   columns (model, type, size, health, temp, wearout, serial) are.

Browser verification (Playwright, chromium, live mock-mode dev runtime):
- 9 tests pass. The every-sub-tab operator-controls audit now covers
  /truenas/disks too; the search input on every TrueNAS sub-tab is
  the canonical SearchInput primitive.

Targeted vitest: `src/features/truenas/__tests__/truenasPageModel.test.ts`
(2 tests) green — covers the four-tab spec and the new `disks`
bucket on the page model.

Targeted Go: `go test ./internal/truenas/...` green.

Contract-neutral bypass: PULSE_ALLOW_CONTRACT_NEUTRAL_COMMIT set.
This completes the platform-page column-fit audit for TrueNAS. New
top-level `Resource.Uptime` / `Resource.Temperature` projection is
strictly additive (already documented as the adapter responsibility
in unified-resources.md by c7bdd11e0). The two new bespoke tables
live inside features/truenas/ and reuse canonical primitives only.
2026-05-16 12:51:36 +01:00
rcourtman
294ac1da04 platforms: close remaining gaps — Swarm services, vSphere fixtures, TrueNAS systems, source-filter suppression
Four documented platform-page gaps from the prior round are closed:

1. **Docker Swarm services canonical projection.** The unified resource
   adapter requires `host.Swarm.ClusterID`/`ClusterName` for
   `dockerSwarmClusterKey` to produce a stable service source ID; the
   mock generator was leaving those fields empty so all generated
   services were dropped. Anchor every mock Swarm host to a single named
   cluster (`mock-swarm-cluster-1` / `edge-swarm`) so manager and worker
   hosts share Swarm identity and their services deduplicate correctly
   across managers. Live mock survey now exposes 15 docker-service rows
   (was 0).

2. **Docker Swarm services UI restored.** The `/docker/services`
   sub-tab is back. `DockerPageSurface` mounts a `PlatformResourceTable`
   with the canonical operator toolbar (search + status chips +
   counter); `dockerPageModel.ts` re-introduces the services bucket;
   the model test asserts the three-tab shape and the services bucket.

3. **TrueNAS Systems / Overview sub-tab restored.** Re-survey of the
   canonical adapter confirms `truenas.FixtureRecords` already emits
   the top-level TrueNAS appliance as a unified `agent` row tagged
   with the `truenas` platform (see `internal/truenas/provider.go::
   truenasRecordsFromSnapshot`). TrueNAS now defaults to
   `/truenas/overview` and the page model exposes a `systems` bucket.

4. **VMware fixture inventory scaled to a mature SMB lab.**
   `internal/vmware/fixtures.go::appendEdgeClusterFixtures`
   programmatically appends an Edge DC with 3 more ESXi hosts
   (esxi-05..07), 12 more VMs across Tier 1 / Stateful / Workstations /
   Observability / Archive tiers (mixed healthy/warning/powered-off,
   mixed Linux/Windows guest OS), and 4 more datastores (VMFS / NFS41 /
   vSAN / cold-iSCSI). Live mock survey now shows 43 VMs (was 31), 18
   agents (was 15), and 60 storage rows (was 55) across two datacenters.

5. **TrueNAS / vSphere Storage source filter chip suppression.**
   `StoragePageControls` gains a `suppressSourceFilter` prop and
   `Storage.tsx` automatically applies it whenever `forcedSourceFilter`
   is set, so platform-page embeds no longer render the now-locked
   Source filter chip alongside the operator toolbar.

Resource survey under the new mock baseline (live `/api/resources`):
- TOTAL 342 unique resources (was 307)
- app-container: 75, storage: 60, system-container: 44, vm: 43,
  pod: 40, physical_disk: 19, agent: 18, docker-service: 15,
  k8s-deployment: 14, docker-host: 5, network-endpoint: 5,
  pbs: 2, pmg: 1, k8s-cluster: 1

Browser verification (Playwright, chromium, live mock-mode dev runtime):
- 9 tests pass. Every populated sub-tab — Docker Hosts / Containers /
  Swarm services, Kubernetes Clusters / Nodes / Pods / Deployments,
  TrueNAS Systems / Storage / Apps, vSphere Hosts / VMs / Storage —
  asserts both populated canonical rows AND a visible operator search
  input.

Targeted vitest (77 files / 358 tests) + Go tests (./internal/vmware,
./internal/mock, ./internal/monitoring) all green.

Contracts updated:
- `storage-recovery.md` Shared Boundaries: TrueNAS defaults to the
  Systems overview now that the canonical adapter emits a TrueNAS-
  platform agent row; `suppressSourceFilter` auto-applies under
  `forcedSourceFilter`.
- `unified-resources.md` Extension Points: same; the canonical TrueNAS
  adapter emits the appliance as a unified resource so the builder
  default lands on a populated Systems sub-tab.
- `Storage.test.tsx` extended with the source-filter suppression
  contract assertion.
2026-05-16 08:35:44 +01:00
rcourtman
469691bc74 frontend(platforms): add v5-style operator toolbar to UnifiedResourceTable platform sub-tabs
Some checks are pending
Build and Test / Secret Scan (push) Waiting to run
Build and Test / Frontend & Backend (push) Waiting to run
Closes the second half of the v5→v6 affordance bridge. The first commit
in this chain (65b069dbb) brought operator controls to the embedded
Workloads/Storage sub-tabs (Docker Containers, K8s Pods, TrueNAS
Storage/Apps, vSphere VMs/Storage). The UnifiedResourceTable-backed
sub-tabs (Docker Hosts, K8s Clusters/Nodes/Deployments, vSphere Hosts)
were left with the table's built-in sort handles only — no search, no
status chips, no counters — which read as a non-native experience
against the v5 dashboard/storage filter density.

Extend the shared PlatformResourceTable in
`frontend-modern/src/features/platformPage/sharedPlatformPage.tsx`
with a canonical operator toolbar:

- SearchInput (the canonical primitive, with the standard placeholder
  + clear-on-escape semantics) for name/display-name/id/parent/tags
  search.
- FilterButtonGroup status chip strip: All / Online / Degraded /
  Offline, with the per-platform status vocabulary (running, paused,
  stopped, etc.) collapsed through the shared
  `mapResourceStatusToTriad` helper.
- Compact "N of M rows" counter on the right of the toolbar so
  operators can read total / matching at a glance without spawning a
  card grid.
- Client-side filtering via `filterPlatformResources` before resources
  reach UnifiedResourceTable, so the canonical table stays the data
  surface and the platform page owns the chrome.

Every platform sub-tab now exposes operator controls:

- Docker Hosts (UnifiedResourceTable + new toolbar)
- Docker Containers (WorkloadsSurface canonical toolbar)
- Kubernetes Clusters/Nodes/Deployments (UnifiedResourceTable + new
  toolbar)
- Kubernetes Pods (WorkloadsSurface canonical toolbar)
- TrueNAS Storage/Apps (canonical toolbars)
- vSphere Hosts (UnifiedResourceTable + new toolbar)
- vSphere VMs/Storage (canonical toolbars)

Browser verification (Playwright, chromium, live mock-mode):
- Expanded the operator-controls audit to cover every populated sub-tab
  route (11 routes total). All assertions pass. 9/9 spec tests green.

Targeted vitest:
- New sharedPlatformPage.test.ts covers filterPlatformResources
  (6 tests, all pass) including the status-vocabulary collapse
  (online↔running, degraded↔paused, offline↔stopped) and the
  search-across-id/displayName/parent/tags contract.
- WorkloadsSurface and Storage surface contract tests continue to
  pass.
2026-05-16 00:08:12 +01:00
rcourtman
65b069dbba frontend(platforms): restore v5-style operator controls on embedded canonical surfaces
v5 platform/dashboard pages had a dense filter card with search, status
chips, view-mode toggle, grouping toggle, column picker, and sort
controls (DashboardFilter.tsx, DockerFilter.tsx, StorageFilter.tsx).
v6 platform pages mounted WorkloadsSurface and StorageSurface in
`embedded tableOnly` mode, which hid the entire canonical filter
toolbar alongside the dashboard cards — so /docker/containers,
/kubernetes/pods, /truenas/storage, /truenas/apps, /vmware/vms, and
/vmware/storage shipped without search, status, grouping, or column
controls. Operators had no way to filter inside a platform page short
of navigating to the global Workloads/Storage page.

Bridge those v5 affordances onto the v6 platform pages by extending
the canonical surface contracts:

- WorkloadsSurfaceProps gains `showFilterToolbar` and
  `suppressPlatformFilter`. `showFilterToolbar` keeps the canonical
  WorkloadsFilter (search input + status chips + view-mode segmented
  control + grouping toggle + ColumnPicker + sort handles) visible even
  under `tableOnly`. `suppressPlatformFilter` drops the redundant
  Platform chip since the platform is already fixed by the owning page,
  so the user never sees a removable lock.
- StorageProps gains `showFilterToolbar`. Same idea for the canonical
  StoragePageControls (search + status + group-by + sort + node filter
  + view).

Platform pages now mount their embedded surfaces with
`tableOnly + showFilterToolbar` (plus `suppressPlatformFilter` for
WorkloadsSurface):

- Docker > Containers
- Kubernetes > Pods
- TrueNAS > Storage, Apps
- vSphere > VMs, Storage

UnifiedResourceTable-backed sub-tabs (Docker Hosts, K8s Clusters/
Nodes/Deployments, vSphere Hosts) still rely on the table's built-in
sort handles only; a follow-up shared `PlatformInfraControls` row with
search + counters is the next operator-controls bridge.

Browser verification (Playwright, chromium, against live mock-mode
Pulse dev runtime):
- 9 tests, all pass. New assertion confirms that every embedded
  Workloads/Storage sub-tab on a platform page now renders the
  canonical search input (proving the v5-style operator toolbar is
  back).

Targeted vitest:
- WorkloadsSurface.performance.contract.test.tsx adds a platform-page
  embed contract assertion (37 tests total, all pass).
- Storage.test.tsx adds the matching StorageProps assertion
  (39 tests total, all pass).

Contracts updated:
- performance-and-scalability.md Shared Boundaries: documents the
  `showFilterToolbar` + `suppressPlatformFilter` platform-page contract
  on WorkloadsSurface.
- storage-recovery.md Shared Boundaries: documents the
  `showFilterToolbar` platform-page contract on StorageSurface.
2026-05-16 00:02:16 +01:00
rcourtman
b0c4faa4a0 frontend(platforms): drop platform sub-tabs whose canonical projection is missing
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.
2026-05-15 23:49:23 +01:00
rcourtman
cfc3fd1606 frontend(platforms): resolve resource platform family via sources fallback
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.
2026-05-15 23:38:40 +01:00
rcourtman
cdaeb3b84d frontend(platforms): add Docker, Kubernetes, TrueNAS, vSphere platform pages
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.
2026-05-15 23:09:17 +01:00
rcourtman
92a5cb68ec Harden Workloads refresh retention 2026-05-14 15:18:34 +01:00
rcourtman
22ea442ed7 Fix default agent rollout status noise 2026-05-14 14:37:24 +01:00
rcourtman
439e252a64 Harden infrastructure workload identity regressions 2026-05-14 12:49:16 +01:00
rcourtman
cbe595572b Improve action audit refusal presentation
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.
2026-05-13 23:03:12 +01:00
rcourtman
5ac37b257b Surface PBS job health evidence in drawer 2026-05-13 21:41:16 +01:00
rcourtman
43b491efc7 test: prove commercial migration retry continuity 2026-05-13 18:33:53 +01:00
rcourtman
53ebbf97f8 Harden recovery activity timeline ranges 2026-05-13 18:32:25 +01:00
rcourtman
da2537e4ab Add self-hosted commercial continuity proof 2026-05-13 16:44:26 +01:00
rcourtman
cce482c9d5 Stabilize first-session auth reset proof 2026-05-13 16:31:07 +01:00
rcourtman
fdcbf0f2d3 Align first-session onboarding handoff 2026-05-13 16:18:50 +01:00
rcourtman
7da6a36901 Add community runtime Plans proof 2026-05-08 10:06:06 +01:00
rcourtman
f12efba419 Surface saved Patrol readiness issues 2026-05-08 02:37:56 +01:00