Stages the doc-only subset of rc.6 packet prep work on top of
df7934936. Holds VERSION bump and the registry/contract governance
reconciliation back for a focused later pass since the IA revert
created broader subsystem-contract debt than the packet prep can
absorb.
- docs/releases/V6_RC6_OPERATOR_SUPPORT_PACK_DRAFT.md: new 300-line
operator support brief mirroring the rc.5 pack with rc.6 themes:
pre-release for testing framing, platform-shaped frontend revert
explanation, vSphere as a first-class platform, Machines surface,
TrueNAS native detail UX, FilterBar adoption, Patrol capacity-
forecast and PDM bridge, free-first self-hosted posture, install.sh
smoke gate. Carries the rc.5 free-first paid-continuity wording
through unchanged so the operator-support-pack policy test holds.
- docs/releases/RELEASE_NOTES_v6_RC6_DRAFT.md,
docs/releases/V6_CHANGELOG_RC6_DRAFT.md: fill in the SHA audit
numbers (v6.0.0-rc.5..df7934936, 616 commits, 1379 files / 139185
insertions / 67870 deletions). Add the licensing-continuity
paragraph carrying the rc.5 Pulse Mobile pairing for handoff
copy through unchanged so the discovered-packet policy test holds.
- docs/RELEASE_NOTES.md: link the rc.6 draft packet as current, push
rc.5 to historical.
- docs/UPGRADE_v6.md: round out the prerelease packet pointer block
with the rc.6 operator support pack path alongside the release
notes and changelog already pointed at in df7934936.
- docs/releases/V6_PRERELEASE_RUNBOOK.md: add 6.0.0-rc.6 to the
version-examples list and bump the RC_VERSION export shown in the
RC release steps to rc.6.
Out of scope for this commit and intentionally held back until
governance reconciliation can land coherently:
- VERSION bump to 6.0.0-rc.6 (triggers deployment-installability
shape-guard which cascades into registry/contract audits against
72 dead-file references left over from the rc.6 IA revert).
- docs/release-control/v6/internal/status.json,
docs/release-control/v6/internal/subsystems/registry.json, and the
10 subsystem contract .md files that need post-IA-revert cleanup.
- scripts/release_control test fixture refreshes.
- The rc-to-ga-promotion-readiness-blocked record regen (gated on
VERSION bump landing).
Working copies of the held-back files are preserved at
/tmp/rc6-prep-backup-2026-05-27/ with a MANIFEST.md describing each.
rc.1-rc.5 shipped a unified /infrastructure /workloads /storage
/recovery top-level layout; rc.6 reverts the frontend to platform-
shaped pages (Proxmox / Docker / Kubernetes / TrueNAS / vSphere /
Standalone) on the same unified resource backend.
Updates the shipped v6 release docs to match:
- RELEASE_NOTES_v6.md and V6_CHANGELOG.md rewritten to describe the
v6 layout as platform-shaped on a unified backend, with a paragraph
in each explaining the rc.6 revert and the operator feedback that
drove it.
- UPGRADE_v6.md prerelease packet pointer bumped from rc.5 to rc.6.
- MIGRATION_UNIFIED_NAV.md gets a top-of-file revert banner that
redirects bookmarks targeting the unified routes to their platform-
shaped equivalents; the original content is preserved below as a
Historical Context section so the 19 tracked references into that
doc still resolve.
Also adds the rc.6 draft packet:
- docs/releases/RELEASE_NOTES_v6_RC6_DRAFT.md
- docs/releases/V6_CHANGELOG_RC6_DRAFT.md
Validation SHAs in both drafts are left as <populate at packet
finalisation> markers; they fill in when the release-control packet
runs.
Closes the only API-coverage gap from the Docker / Kubernetes IA
maturity review: Roles, ClusterRoles, RoleBindings, and
ClusterRoleBindings now flow from the Kubernetes agent through the
canonical resource registry into the Kubernetes platform-page
Configuration tab.
Agent: pkg/agents/kubernetes/report.go gains four new report struct
types that carry summary counts plus subject-kind sets; individual
subject names and full PolicyRule contents are deliberately omitted
so Pulse stays a "what permissions exist where" surface, not an RBAC
enumeration tool. internal/kubernetesagent/agent.go gains four
collectors that call rbacv1.RoleList/ClusterRoleList/etc. through the
existing runKubernetesCallWithRetry wrapper, matching the
ServiceAccount collector's RBAC-forbidden retry pattern.
Canonical: internal/models mirrors with NormalizeCollections coverage;
convert* funcs in internal/monitoring/kubernetes_agents.go translate
agent report -> model; ResourceTypeK8sRole / K8sClusterRole /
K8sRoleBinding / K8sClusterRoleBinding join the canonical type set;
registry ingest* + adapter resourceFrom* functions emit one Resource
per RBAC object with ruleCount / roleKind / roleName / subjectCount /
subjectKinds / aggregationLabels on the K8s meta; search mapping in
internal/api/resources.go and the privacy allow-list in
internal/api/org_handlers.go pick up the four new type tokens; the
K8s privacy category in unifiedresources/policy_metadata.go classifies
them like the rest of K8s.
Frontend: ResourceType union + ResourceKubernetesMeta carry the new
kinds and RBAC summary fields; KubernetesPageSurface query asks for
them; the page model buckets them into the Configuration group;
KubernetesConfigTable renders Role / ClusterRole rule counts and the
aggregated flag, plus RoleBinding / ClusterRoleBinding role refs and
"N subjects · Kind1, Kind2 +overflow" subject summaries.
Curated demo seeds per-namespace Roles + RoleBindings plus an
aggregated ClusterRole + ClusterRoleBinding for pulse-demo-monitoring
in each cluster so the Configuration tab renders 18 RBAC rows across
the three demo clusters.
Contracts updated for the canonical-shape guard: monitoring,
api-contracts, unified-resources, frontend-primitives,
organization-settings (canonical) plus agent-lifecycle and
storage-recovery (dependent via Extension Points). Verification
proofs extended: kubernetes_registry_test.go, kubernetes_agents_test.go,
agent_inventory_test.go (new TestCollectRBACInventoryReportsSummaryCountsOnly
that pins the subject-name-omission contract), demo_scenarios_test.go,
adapter_coverage_test.go, contract_test.go, org_handlers_test.go,
resourceIdentity.test.ts, reportingResourceTypes.test.ts,
KubernetesConfigTable.test.tsx, and the
subsystem_lookup_test.py line-anchor bumps that the contract edits
shifted (api-contracts 246 -> 253, organization-settings 92 -> 93).
Verified:
- go build ./internal/... ./cmd/... clean
- go test ./internal/unifiedresources/..., ./internal/mock/...,
./internal/kubernetesagent/..., ./internal/api/...,
the K8s subset of ./internal/monitoring/... all clean (three
pre-existing unrelated monitoring failures noted earlier remain
unchanged by this commit)
- npm run type-check, lint:eslint, lint:theme,
lint:canonical-platforms clean
- vitest: 70 K8s frontend tests pass including the new RBAC render
coverage in KubernetesConfigTable.test.tsx
- browser proof on /kubernetes/configuration: 36 config rows
including 18 RBAC rows across three clusters; ClusterRole
"pulse-demo-monitoring" shows "12 rules · Aggregated";
ClusterRoleBinding shows "3 subjects · Group, ServiceAccount +1"
Per-cluster node profiles, kubelet versions, and degraded scenarios
replace the global rotation that made every demo cluster look like a
copy of the same one. Production EU keeps its prod-euw1-k8s-{01..05}
nodes and the NotReady worker on prod-euw1-k8s-03 (preserving the
existing host-posture test contract). Staging EU runs
stage-euw1-k8s-{01..05} and carries the payments-worker
CrashLoopBackOff. Development EU runs dev-euw1-{01..05} and carries
an ImagePullBackOff on cron-nightly-backfill (re-labelled from the
previous "Pending / PodInitializing" rotation so the curated
reconciler doesn't recover it). The unused Edge profile gets distinct
edge-pop-{lax,nrt,fra,iad,sin}-01 names + k3s version for when the
cluster count is bumped above three.
A new TestKubernetesDemoClustersTellDistinctStories test guards the
slice goal: each cluster's nodes use its own prefix, exactly one
cluster carries each degraded scenario, and every cluster has a
unique kubelet version. The monitoring subsystem contract is updated
to reflect the new three-cluster cast (Production EU + Staging EU +
Development EU) plus the per-cluster scenario distribution.
Side effect: with distinct node names per cluster, the K8s page
model's cluster-to-node matching now resolves all five nodes for
each cluster (previously two clusters showed "0 nodes" because every
cluster's nodes shared the same prod-euw1-* names, breaking
buildKubernetesClusterChildCounts' clusterId lookup).
Verified:
- go vet ./internal/mock/..., go test ./internal/mock/... clean
- browser proof on /kubernetes/overview: three clusters render with
distinct versions (v1.30.4 / v1.31.2 / v1.32.0-rc.1) and 5 nodes
each (vs the previous 5/0/0 split)
- /kubernetes/nodes: 15 rows across the three clusters with three
distinct name prefixes; one red NotReady dot on Production EU's
prod-euw1-k8s-03; fourteen green Ready dots elsewhere