Restore the TrueNAS pool topology discriminator

599c8e634 changed the TrueNAS pool projection to publish the ZFS data vdev
layout ("mirror", "raidz2", "stripe") as Storage.Topology. Topology is the
closed discriminator vocabulary every storage consumer keys on, and TrueNAS
pools travel as ResourceTypeStorage, so the frontend identifies them solely
by storage.topology === 'pool'. On any appliance whose pools report data
vdevs, every pool therefore fell out of the TrueNAS page, its datasets
orphaned, and per-system pool counts read zero.

Nothing caught it because internal/truenas/fixtures.go carries no VDevs, so
the projection still returned "pool" for every fixture while the producer
side pinned the new "mirror" value. Both suites stayed green and disagreed
with each other.

Pools now publish Topology "pool" again, with the layout in the new
Storage.VDevLayout field. poolVDevLayout returns an empty string when the
native report carries no data vdevs so callers fall back rather than
inventing a layout, and the presentation surfaces that previously read the
layout out of topology now prefer vdevLayout and fall back to topology.

Alert typing was unaffected (unified_eval.go already routes non-dataset
storage to truenas-pool through its default arm); incident metadata carried
the layout string and now carries the discriminator again.

Regression coverage pins the boundary from both sides, driving real vdev
layouts rather than the vdev-less fixtures:
- TestPoolTopologyStaysDiscriminatorAcrossVDevLayouts (producer, five layouts)
- TestStorageTopologyAndVDevLayoutAreDistinctIdentityFields (clone and wire)
- pool identity boundary cases in truenasPageModel.test.ts (consumer)
- topology label cases in storageAdapters.test.ts and the TrueNAS drawer model
This commit is contained in:
rcourtman
2026-07-24 22:11:51 +01:00
parent d8962fc9a4
commit 6c6deb8e2b
14 changed files with 337 additions and 16 deletions
@@ -2415,6 +2415,17 @@ verification.
rather than verified results. Safe auto-fix and Autopilot remain visibly
`not_assessed` until their governed canaries exist.
42. Frontend consumers identify a storage resource by
`storage.topology`, never by a ZFS vdev layout. TrueNAS pools arrive
as `type: 'storage'`, so `topology === 'pool'` is the only pool
discriminator available to the page model, and layout strings belong
in `storage.vdevLayout`. Regression coverage: the `pool identity
boundary` cases in
`frontend-modern/src/features/truenas/__tests__/truenasPageModel.test.ts`
and `shows the vdev layout as the storage kind while topology stays
the pool discriminator` in
`frontend-modern/src/components/Infrastructure/__tests__/resourceDetailDrawerTrueNASModel.test.ts`.
## Current State
### System member rows are source-type aware
@@ -712,6 +712,16 @@ remains.
paths added to the adapter must keep that persistence step; ephemeral
snapshot-bridge adapters stay read-only.
11. The TrueNAS provider projects pools with `Storage.Topology` fixed to
`pool` and the ZFS data vdev layout in `Storage.VDevLayout`. The
layout summary (`poolVDevLayout`) returns an empty string when the
native report carries no data vdevs so callers fall back instead of
inventing a layout. Publishing the layout as the topology drops every
pool out of the TrueNAS page, and package fixtures carry no vdevs, so
layout-bearing pools must be exercised explicitly. Regression
coverage: `TestPoolTopologyStaysDiscriminatorAcrossVDevLayouts` in
`internal/truenas/provider_pool_health_contract_test.go`.
## Current State
### PBS health is one completed-poll outcome
@@ -1958,6 +1958,15 @@ pressure to assess context selection, but it must not read live backup records,
invoke recovery APIs, mutate storage, or treat a synthetic pass as evidence
that Safe auto-fix or Autopilot remediation is verified.
26. Storage row presentation resolves its topology label from
`storage.vdevLayout` first and falls back to `storage.topology`, so a
pool reads as its concrete layout ("Mirror", "Raidz2") without the
discriminator ever carrying presentation detail. Regression coverage:
`labels a TrueNAS pool by its vdev layout while keeping the pool
discriminator` and `falls back to the topology discriminator when no
vdev layout is reported` in
`frontend-modern/src/features/storageBackups/__tests__/storageAdapters.test.ts`.
## Current State
### Proxmox runtime continuity is not protection evidence
@@ -1633,6 +1633,16 @@ AI-only summary payloads, or page-local heuristics.
`TestIngestRecordsSkipRecordDeclaredSuccessionForLiveOldID` in
`internal/unifiedresources/canonical_id_succession_test.go`.
28. `StorageMeta.Topology` is a closed discriminator vocabulary shared by
every storage provider (`pool`, `dataset`, `array`, `datastore`).
Consumers key resource identity off it, so a provider must never
publish presentation detail there. ZFS data vdev layout is
presentation and belongs in `StorageMeta.VDevLayout`, which is absent
rather than invented when the native report carries no data vdevs.
Regression coverage:
`TestStorageTopologyAndVDevLayoutAreDistinctIdentityFields` in
`internal/unifiedresources/canonical_identity_test.go`.
## Current State
### Host views expose the integration-source discriminator