The guard judged substantive contract updates by diffing HEAD against
the index. In CI nothing is staged, the index equals HEAD, so every
contract file piped in via --files-from-stdin looked unchanged and the
guard blocked compliant pushes. Concretely, run 28944317805 blocked
7645965af even though its deployment-installability.md addition sits
inside the Current State section.
The guard now accepts --diff-base <ref> (requires --files-from-stdin),
resolves it to its merge base with HEAD so the comparison anchor
matches the three-dot changed-file list, and compares base vs HEAD
contract texts in that mode. Pre-commit keeps the index comparison.
The canonical-governance workflow passes the push or PR range base.
contract_patch_has_substantive_change walked git diff --unified=1000
output and tracked the last ## header seen in the patch, so an edit
more than 1000 lines below its section header (e.g. deep inside
unified-resources.md's Current State) lost its section and was wrongly
reported as not substantive, forcing a contract-neutral bypass on
74131e56e.
Replace the patch walk with full-file attribution: diff the HEAD blob
against the staged blob and map every changed line to its section via
a per-line section map built from the complete file. Covers new
contract files (empty HEAD blob) and keeps metadata-only edits
non-substantive. Adds regression tests for edits >1000 lines below
their section header in both directions.
Two silent-downgrade paths in the v5→v6 migration are now visible and
self-healing:
License load/decrypt failure (was: one log line, no UI state): when
license.enc exists but cannot be read, getTenantComponents now persists
a terminal commercial_migration state with reason
persisted_license_unreadable, so the licence panel and global banner
tell the customer to re-enter their v5 key instead of leaving them to
discover missing Pro features.
Failed startup exchange (was: once per process, Community until manual
restart): exchange failures classified as pending — license-server
blips, DNS failures, rate limits — now schedule a background retry loop
with backoff (30s → 30m cap) that re-attempts the exchange until it
succeeds, hits a terminal classification, or the org's service activates
through another path. The loop stops cleanly on manual activation and
StopAllBackgroundLoops.
Registers the new files in the subsystem registry (cloud-paid
commercial-migration verification policy + shared ownership) and pins
both behaviors in the cloud-paid and api-contracts contracts.
Primary nav moved to platform-first (Proxmox/Docker/K8s/TrueNAS/vSphere) and
the standalone Infrastructure/Workloads/Storage/Recovery/Ceph routes were no
longer reachable from the UI — they only persisted as deep-link fallbacks and
as cross-jump targets for command palette / shortcuts / drawer links.
Code:
- RuntimeHome and NotFound redirect to /proxmox/overview; kiosk-mode
redirect follows the same canonical home.
- App.tsx, routing/navigation.ts, routing/routePreload.ts, AppLayout.tsx
drop the legacy routes, preloaders, tab IDs, and tab-title entries.
- Old page wrappers (Infrastructure/Workloads/Storage/Recovery/Ceph) and
the orphan CephServiceIcon and workloadsLink helper are deleted; the
underlying feature surfaces (InfrastructurePageSurface, WorkloadsSurface,
StorageSurface, RecoverySurface, ProxmoxCephTable) stay embedded inside
platform pages.
- Command palette and keyboard shortcuts now expose the five platform
pages (g p/d/k/n/v) plus Patrol/Alerts/Settings; legacy g i/w/s/b are
retired.
- K8s Namespaces/Deployments drawer "view pods" buttons route to
/kubernetes/pods (the legacy ?context= + ?namespace= filter doesn't
carry forward yet — the new sub-tab doesn't consume those params).
- Workload-row node-name click, host-row workloads icon, resource
correlation/change drilldowns, and the PBS "Open Recovery Events" link
render as plain text or are dropped — platform pages already surface
the related data in adjacent sub-tabs.
Governance:
- Subsystem contracts updated to match: storage-recovery and
performance-and-scalability drop the retired page wrappers from their
Canonical Files lists; ai-runtime, cloud-paid, frontend-primitives, and
unified-resources gain Current-State notes describing the platform-first
redirect, palette/shortcut re-anchoring, and cross-link affordance
removal so future work doesn't resurrect the retired paths.
- status.json L8 (First-session & UX polish) evidence: the retired
pages/Infrastructure.tsx wrapper is replaced by pages/Proxmox.tsx as
the canonical post-redirect landing surface.
- registry.json: 18 retired-file entries removed from owned_files,
path-policy match_files, and exact_files across the route-shell-and-
operations, workload-presentation, storage-recovery, and unified-
resources subsystems. Surviving entries continue to cover the proof
set — the embedded feature surfaces remain canonical and the retired
page wrappers were thin shells with no remaining proof obligation.
- canonical_completion_guard_test.py and subsystem_lookup_test.py
retargeted: the recovery and storage product-surface fixtures now
exercise the canonical components/* surfaces instead of the retired
pages/* shells, matching the new registry shape.
Tests: typecheck clean. Vitest 5820 pass / 6 pre-existing fail
(PageControls.guardrails, useStoragePoolDetailModel, ApprovalSection x3,
frontendResourceTypeBoundaries:1018) — all failing on HEAD before this
change with clean porcelain on the offending source files. Python
canonical_completion_guard_test (141) and subsystem_lookup_test (183)
green.
Deletes files that no runtime path imports after the migration to
chip-based FilterBar:
Storage's three-layer filter indirection:
- StorageFilter.tsx (legacy filter shell)
- StorageControls.tsx (subtab + filter pass-through wrapper)
- useStorageFilterToolbarModel.ts (legacy active-filter / reset hook)
- useStoragePageControlsModel.ts (sortDisabled + groupBy gating)
- useStorageControlsModel.ts (subtab + node-filter wiring)
- their tests
Workloads filter state hook:
- useWorkloadsFilterState.ts (replaced by inline FilterBar wiring;
countActiveWorkloadsFilters / hasActiveWorkloadsFilters stay in
workloadsFilterModel.ts)
- its test
The StorageStatusFilter and StorageGroupByFilter type aliases that
StorageFilter.tsx exported fold into the existing canonical types in
storagePageState.ts (StorageStatusFilterValue) and storageModelCore.ts
(StorageGroupKey), keeping useStorageFilterState.ts alive without the
deleted shell.
PageControls.tsx and its companion FilterToolbar primitives stay in
the tree because the alert-history filter card and the Kubernetes
deployments drawer still consume them. The canonical claim shifts:
FilterBar is the chip-based shell for catalog-driven page filters
(Infrastructure, Workloads, Storage, Recovery Protected items, Recovery
events). PageControls remains for non-migrated surfaces.
Subsystem contracts and registry updated:
- frontend-primitives.md: adds FilterBar files to Canonical Files;
describes FilterBar as the canonical page-level filter shell for
catalog-driven resource lists; PageControls described as the legacy
fallback for non-migrated surfaces.
- performance-and-scalability.md: drops useWorkloadsFilterState
references; describes Workloads' FilterBar / viewOptionsTrailing
composition.
- storage-recovery.md: replaces "PageControls toolbar rail" prose with
FilterBar / viewOptionsTrailing for both Storage and Recovery events;
notes the legacy three-layer indirection retired.
- registry.json: drops deleted file paths from owned_files,
verification.exact_files, and verification.path_policies entries.
- canonical_completion_guard_test.py + subsystem_lookup_test.py: drop
deleted file paths from hard-coded fixtures so the governance helper
tests track the registry.
- SharedPrimitives.guardrails.test.ts: adds regression assertions that
StoragePageControls no longer imports the deleted shells.
Remove local upgrade-metrics API registration, settings payload wiring, startup store migration, and backend conversion recorder hooks from the normal product runtime.
Delete the retired conversion/funnel and metering packages from compiled licensing code, and extend diagnostics boundary audits and governance contracts so maintainer commercial analytics cannot return through Settings or diagnostics.
Refuse prerelease-shaped tags and explicit GitHub prerelease responses in the unattended stable updater before installer invocation.
Add installability tests and proof routing for the auto-update prerelease refusal guard.
Delete the stop-monitoring dialog plus the retired per-type settings
shells now that the unified ConnectionEditor replaces them: remove
PlatformConnectionsWorkspace / ProxmoxSettingsPanel /
ProxmoxDirectWorkspace / NodeModal et al and the accompanying tests.
Strip the lingering reporting-state hook from
useInfrastructureOperationsState and the guardrail test reinforces the
removal. Reconcile registry.json, frontend-primitives.md,
api-contracts.md, agent-lifecycle.md, status.json, and the
release-control guard/test fixtures so governance audits stay clean.
Summary cards now show degraded/alerting/failing counts rather than raw
online/offline splits, giving operators an at-a-glance health posture without
drilling into the full resource list.
- InfrastructureSummary/infrastructureSummaryModel: adds degraded and alerting
counts derived from resource statuses and active alerts
- StorageSummary/StoragePageSummary/useStoragePageSummary: adds poolsDegraded
and disksFailing indicators, shows "all healthy" when zero degradation
- WorkloadsSummary/useDashboardWorkloadDerivedState: adds alerting guest count
from activeAlerts accessor, included in summary header counts
- RecoverySummary: adds aggregate health-state summary row
- useDashboardState: threads alertsEnabled through workload derived state
- Fix monitored-system cap test helper to use TierEnterprise so limits are
honored (self-hosted tiers are now uncapped per the v6 product model)
- Update registry and governance test snapshots to include
useStoragePageSummary.test.ts in the storage-product-surface proof set
Introduce PULSE_ALLOW_CONTRACT_NEUTRAL_COMMIT as a narrow escape
hatch for the canonical-shape block in staged_commit_shape_guard
and canonical_completion_guard. A non-empty reason logs to stderr
for audit and suppresses only the canonical-shape requirements;
lane-progress, promotion-proof, sensitivity, gitleaks,
governance-stage, control-plane, status, registry, and contract
audits still run. Previously a behavioral bug fix on a canonical
runtime path demanded full contract + verification ceremony even
when no public-contract delta existed, forcing --no-verify.