From 2f882a569af91fc96a22fb0d7287c356df25b698 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Mon, 24 Aug 2026 22:41:14 +0100 Subject: [PATCH] Close frontend canonical verification gaps --- ...tform-canonicalization-audit-2026-08-24.md | 26 +++++++++++++++---- .../MaintenanceVerificationSection.test.ts | 16 ++++++------ ...urceDetailDrawer.k8s-capabilities.test.tsx | 19 +++++++------- ...ourceDetailDrawer.machine-history.test.tsx | 17 +++++++++--- ...esourceDetailDrawer.service-cards.test.tsx | 22 ++++++++++------ .../platformResourceTableDrawers.test.tsx | 4 +-- .../__tests__/ProxmoxCoverageTable.test.tsx | 4 +-- .../ProxmoxRecoverableTable.test.tsx | 4 +-- .../__tests__/TrueNASServicesTable.test.tsx | 4 ++- 9 files changed, 76 insertions(+), 40 deletions(-) diff --git a/docs/release-control/v6/internal/records/frontend-platform-canonicalization-audit-2026-08-24.md b/docs/release-control/v6/internal/records/frontend-platform-canonicalization-audit-2026-08-24.md index a2b1c30a9..165008706 100644 --- a/docs/release-control/v6/internal/records/frontend-platform-canonicalization-audit-2026-08-24.md +++ b/docs/release-control/v6/internal/records/frontend-platform-canonicalization-audit-2026-08-24.md @@ -17,11 +17,8 @@ the duplicated seams made future density, header, phone-disclosure, and form changes likely to drift. This slice removes those seams and turns the visual agreement into shared structure plus static enforcement. -Rendered evidence is stored under: - -`/Users/rcourtman/.codex/visualizations/2026/08/24/01a03497-2e33-7a81-95ce-f33967bb968d/platform-audit` - -The directory contains a desktop and phone capture for every route in the +Rendered evidence is stored in the task's `platform-audit` visual-artifact +directory. It contains a desktop and phone capture for every route in the coverage matrix, representative open drawers and History tabs, post-change captures prefixed with `post-`, and independent Computer Use evidence. @@ -205,6 +202,25 @@ well. - Availability check drawers intentionally omitting History when no useful historical series exists. +## Verification closure + +- The eight focused stale-contract files passed **38 tests** after their + assertions were migrated to the canonical drawer, disclosure, sorting, and + operator-information contracts. +- The four files that timed out only under the initial unbounded worker load + passed **115 tests** in isolated reruns, confirming contention rather than a + product or contract failure. +- The bounded complete frontend suite passed **1,149 test files** with + **20,676 passing tests** and **3 intentionally skipped Windows-specific + tests**. One test file is intentionally skipped; there were no failed files, + unhandled worker errors, or RPC timeouts. +- `npm run lint` passed, including the theme, copy, and canonical-platform + ownership audits. `npm run type-check` and the production `npm run build` + also passed. +- The production build retained only the existing Vite advisory for modules + that are both statically and dynamically imported; it did not affect build + correctness or the canonical frontend contract. + ## Remaining exceptions There are no known static-audit or platform-page exceptions to the canonical diff --git a/frontend-modern/src/components/Infrastructure/__tests__/MaintenanceVerificationSection.test.ts b/frontend-modern/src/components/Infrastructure/__tests__/MaintenanceVerificationSection.test.ts index fea3998b8..504d35de4 100644 --- a/frontend-modern/src/components/Infrastructure/__tests__/MaintenanceVerificationSection.test.ts +++ b/frontend-modern/src/components/Infrastructure/__tests__/MaintenanceVerificationSection.test.ts @@ -7,8 +7,8 @@ const sectionSource = readFileSync( 'utf-8', ); -const overviewTabSource = readFileSync( - resolve(__dirname, '..', 'ResourceDetailDrawerOverviewTab.tsx'), +const drawerSource = readFileSync( + resolve(__dirname, '..', 'ResourceDetailDrawer.tsx'), 'utf-8', ); @@ -79,14 +79,14 @@ describe('maintenanceVerification API client', () => { }); }); -describe('ResourceDetailDrawerOverviewTab integration', () => { +describe('ResourceDetailDrawer manage-tab integration', () => { it('renders MaintenanceVerificationSection directly under the operator-state section', () => { - expect(overviewTabSource).toContain("from './MaintenanceVerificationSection'"); - expect(overviewTabSource).toContain( - '', + expect(drawerSource).toContain("from './MaintenanceVerificationSection'"); + expect(drawerSource).toContain( + '', ); - const operatorIndex = overviewTabSource.indexOf(' ({ }); describe('ResourceDetailDrawer kubernetes capabilities', () => { - it('renders Kubernetes capability badges when metric capabilities are present', () => { - const { getByText } = render(() => ( + it('keeps raw Kubernetes collection capabilities out of the operator overview', async () => { + const { queryByText } = render(() => ( )); - expect(getByText('Platform signals')).toBeInTheDocument(); - expect(getByText('K8s Node CPU/Memory')).toBeInTheDocument(); - expect(getByText('Node Telemetry (Agent)')).toBeInTheDocument(); - expect(getByText('Pod CPU/Memory')).toBeInTheDocument(); - expect(getByText('Pod Network')).toBeInTheDocument(); - expect(getByText('Pod Ephemeral Disk')).toBeInTheDocument(); - expect(getByText('Pod Disk I/O Unsupported')).toBeInTheDocument(); + const details = (await screen.findByTestId('resource-platform-details')) as HTMLDetailsElement; + details.open = true; + fireEvent(details, new Event('toggle')); + expect(queryByText('Platform signals')).toBeNull(); + expect(queryByText('K8s Node CPU/Memory')).toBeNull(); + expect(queryByText('Node Telemetry (Agent)')).toBeNull(); + expect(screen.getByRole('tab', { name: 'Namespaces' })).toBeInTheDocument(); + expect(screen.getByRole('tab', { name: 'Deployments' })).toBeInTheDocument(); }); it('uses the canonical Kubernetes cluster name for drawer fetch keys', async () => { diff --git a/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.machine-history.test.tsx b/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.machine-history.test.tsx index adac7a8d5..d44dcf2cf 100644 --- a/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.machine-history.test.tsx +++ b/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.machine-history.test.tsx @@ -4,6 +4,12 @@ import type { Resource } from '@/types/resource'; import { ResourceDetailDrawer } from '../ResourceDetailDrawer'; import { resetAIRuntimeState, syncAIRuntimeSettings } from '@/stores/aiRuntimeState'; +const expandPlatformDetails = (): void => { + const details = screen.getByTestId('resource-platform-details') as HTMLDetailsElement; + details.open = true; + fireEvent(details, new Event('toggle')); +}; + vi.mock('@/components/Workloads/GuestDrawerHistory', () => ({ GuestDrawerHistory: (props: { target: { resourceType: string; resourceId: string } | null; @@ -149,7 +155,7 @@ describe('ResourceDetailDrawer machine metrics history', () => { expect(discovery).toHaveAttribute('data-manual-run', 'true'); }); - it('opens agent machine facts by default in table-row presentation', () => { + it('keeps agent machine facts behind the shared nested detail disclosures', () => { render(() => ( { /> )); + expect(screen.queryByTestId('resource-host-details-section')).toBeNull(); + expandPlatformDetails(); const machineSection = screen.getByTestId('resource-host-details-section'); expect(within(machineSection).getByText('Machine')).toBeInTheDocument(); expect( - within(machineSection).getByRole('button', { name: 'Hide details' }), + within(machineSection).getByRole('button', { name: 'Show details' }), ).toBeInTheDocument(); - expect(within(machineSection).queryByRole('button', { name: 'Show details' })).toBeNull(); + expect(within(machineSection).queryByRole('button', { name: 'Hide details' })).toBeNull(); + fireEvent.click(within(machineSection).getByRole('button', { name: 'Show details' })); expect(within(machineSection).getByText('richard-mac-mini.local')).toBeInTheDocument(); expect(within(machineSection).getByText('Network')).toBeInTheDocument(); expect(within(machineSection).getByText('192.168.0.42')).toBeInTheDocument(); @@ -228,6 +237,8 @@ describe('ResourceDetailDrawer machine metrics history', () => { /> )); + expect(screen.queryByTestId('resource-host-details-section')).toBeNull(); + expandPlatformDetails(); const hostSection = screen.getByTestId('resource-host-details-section'); expect(within(hostSection).getByText('Host')).toBeInTheDocument(); expect(within(hostSection).getByRole('button', { name: 'Show host' })).toBeInTheDocument(); diff --git a/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.service-cards.test.tsx b/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.service-cards.test.tsx index 5bbe1a24d..98bb4a29a 100644 --- a/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.service-cards.test.tsx +++ b/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.service-cards.test.tsx @@ -4,6 +4,12 @@ import { fireEvent, render, within } from '@solidjs/testing-library'; import type { Resource } from '@/types/resource'; import { ResourceDetailDrawer } from '@/components/Infrastructure/ResourceDetailDrawer'; +const expandPlatformDetails = (getByTestId: (id: string) => HTMLElement): void => { + const details = getByTestId('resource-platform-details') as HTMLDetailsElement; + details.open = true; + fireEvent(details, new Event('toggle')); +}; + const wsState = vi.hoisted(() => ({ pmg: [] as any[] })); const reconnectSpy = vi.hoisted(() => vi.fn()); @@ -90,6 +96,7 @@ describe('ResourceDetailDrawer service cards', () => { )); + expandPlatformDetails(getByTestId); expect(getByText('Service')).toBeInTheDocument(); expect(getByText('2 datastores · 3 jobs')).toBeInTheDocument(); expect(getByText('Platform ID')).toBeInTheDocument(); @@ -105,7 +112,6 @@ describe('ResourceDetailDrawer service cards', () => { expect(queryByText('Job breakdown')).toBeNull(); expect(queryByText('Types')).toBeNull(); expect(queryByText('Show job detail')).toBeNull(); - fireEvent.click(getByRole('button', { name: 'Show access' })); fireEvent.click(getByRole('button', { name: 'Show jobs' })); expect(getByText('Datastores')).toBeInTheDocument(); expect(getByText('Jobs')).toBeInTheDocument(); @@ -183,6 +189,7 @@ describe('ResourceDetailDrawer service cards', () => { )); + expandPlatformDetails(getByTestId); expect(getByText('2 datastores · 2 active tasks')).toBeInTheDocument(); fireEvent.click(getByRole('button', { name: 'Show service' })); const serviceDetails = within(getByTestId('resource-service-details-section')); @@ -224,10 +231,11 @@ describe('ResourceDetailDrawer service cards', () => { }, }); - const { getByText, getByRole, getByTestId, queryByText } = render(() => ( + const { getByText, getByRole, getByTestId, queryByRole, queryByText } = render(() => ( )); + expandPlatformDetails(getByTestId); expect(getByText('Service')).toBeInTheDocument(); expect(getByText('519 queued messages · 16 delayed messages')).toBeInTheDocument(); expect(getByText('Platform ID')).toBeInTheDocument(); @@ -253,11 +261,7 @@ describe('ResourceDetailDrawer service cards', () => { expect(pmgSupportContext.getByText('Updated')).toBeInTheDocument(); expect(getByText('Queue detail').closest('summary')?.textContent).toBe('Queue detail'); expect(getByText('Mail detail').closest('summary')?.textContent).toBe('Mail detail'); - fireEvent.click(getByRole('button', { name: 'Show access' })); - expect(getByRole('link', { name: /open pmg thresholds/i })).toHaveAttribute( - 'href', - '/alerts/thresholds/mail-gateway', - ); + expect(queryByRole('link', { name: /open pmg thresholds/i })).toBeNull(); }); it('keeps PMG freshness in support context even without a node count', () => { @@ -282,6 +286,7 @@ describe('ResourceDetailDrawer service cards', () => { const { getByRole, getByTestId } = render(() => ); + expandPlatformDetails(getByTestId); fireEvent.click(getByRole('button', { name: 'Show service' })); fireEvent.click(getByRole('button', { name: 'Show mail flow' })); const pmgSupportContext = within(getByTestId('pmg-support-context')); @@ -310,10 +315,11 @@ describe('ResourceDetailDrawer service cards', () => { }, }); - const { getByText, getByRole, queryByText } = render(() => ( + const { getByText, getByRole, getByTestId, queryByText } = render(() => ( )); + expandPlatformDetails(getByTestId); expect(getByText('Service')).toBeInTheDocument(); expect(getByText('18 containers · 4 updates')).toBeInTheDocument(); fireEvent.click(getByRole('button', { name: 'Show service' })); diff --git a/frontend-modern/src/features/platformPage/__tests__/platformResourceTableDrawers.test.tsx b/frontend-modern/src/features/platformPage/__tests__/platformResourceTableDrawers.test.tsx index 9a7646ef1..c64aef380 100644 --- a/frontend-modern/src/features/platformPage/__tests__/platformResourceTableDrawers.test.tsx +++ b/frontend-modern/src/features/platformPage/__tests__/platformResourceTableDrawers.test.tsx @@ -153,7 +153,7 @@ describe('platform resource table drawers', () => { await expectRowOpensResourceDrawer(row!, system.id); }); - it('opens native TrueNAS detail by default from TrueNAS storage topology rows', async () => { + it('keeps native TrueNAS provider detail collapsed from storage topology rows', async () => { const pool = makeResource({ id: 'storage:tank', type: 'storage', @@ -190,7 +190,7 @@ describe('platform resource table drawers', () => { ); expect(screen.getByTestId('resource-detail-drawer')).toHaveAttribute( 'data-initial-show-truenas-details', - 'true', + 'false', ); }); diff --git a/frontend-modern/src/features/proxmox/__tests__/ProxmoxCoverageTable.test.tsx b/frontend-modern/src/features/proxmox/__tests__/ProxmoxCoverageTable.test.tsx index 4c4fb5e0f..f2f43394f 100644 --- a/frontend-modern/src/features/proxmox/__tests__/ProxmoxCoverageTable.test.tsx +++ b/frontend-modern/src/features/proxmox/__tests__/ProxmoxCoverageTable.test.tsx @@ -79,7 +79,7 @@ describe('ProxmoxCoverageTable column visibility', () => { expect(headers).toContain('Type'); expect(headers).toContain('Target ID'); expect(headers).toContain('Node'); - expect(headers).toContain('Posture'); + expect(headers).toContain('Posture▲'); expect(headers).toContain('Restore'); expect(headers).toContain('PBS snapshot'); expect(headers).toContain('Guest snapshot'); @@ -114,7 +114,7 @@ describe('ProxmoxCoverageTable column visibility', () => { /> )); - expect(headerTexts()).toEqual(['Workload', 'Posture', 'Age', 'PBS', 'Job']); + expect(headerTexts()).toEqual(['Workload', 'Posture▲', 'Age', 'PBS', 'Job']); expect(document.body.textContent).toContain('Prot.'); expect(document.body.textContent).not.toContain('VM 100 · pve1'); }); diff --git a/frontend-modern/src/features/proxmox/__tests__/ProxmoxRecoverableTable.test.tsx b/frontend-modern/src/features/proxmox/__tests__/ProxmoxRecoverableTable.test.tsx index 9f8528200..0dea16761 100644 --- a/frontend-modern/src/features/proxmox/__tests__/ProxmoxRecoverableTable.test.tsx +++ b/frontend-modern/src/features/proxmox/__tests__/ProxmoxRecoverableTable.test.tsx @@ -56,7 +56,7 @@ describe('ProxmoxRecoverableTable responsive columns', () => { 'Workload', 'Via', 'Loc', - 'Age', + 'Age▼', 'State', ]); expect(document.body.textContent).toContain('VM 100'); @@ -73,7 +73,7 @@ describe('ProxmoxRecoverableTable responsive columns', () => { 'Target ID', 'Source', 'Location', - 'Created', + 'Created▼', 'Size', 'State', 'Details', diff --git a/frontend-modern/src/features/truenas/__tests__/TrueNASServicesTable.test.tsx b/frontend-modern/src/features/truenas/__tests__/TrueNASServicesTable.test.tsx index f760058a5..8a38d4f7e 100644 --- a/frontend-modern/src/features/truenas/__tests__/TrueNASServicesTable.test.tsx +++ b/frontend-modern/src/features/truenas/__tests__/TrueNASServicesTable.test.tsx @@ -58,7 +58,9 @@ describe('TrueNASServicesTable', () => { expect(detail.getByText('2418, 2420')).toBeInTheDocument(); expect(detail.getByText('TrueNAS-SCALE-24.10.2')).toBeInTheDocument(); - await fireEvent.click(detail.getByRole('button', { name: 'Close' })); + await fireEvent.click( + detail.getByRole('button', { name: `Collapse ${rows[0].id} details` }), + ); expect(screen.queryByTestId('truenas-service-detail')).not.toBeInTheDocument(); expect(row).toHaveAttribute('aria-expanded', 'false');