From 1289728ded4ade630948425f137d85163fb12037 Mon Sep 17 00:00:00 2001 From: rcourtman <8825017+rcourtman@users.noreply.github.com> Date: Thu, 8 Oct 2026 09:56:53 +0100 Subject: [PATCH] Point dev:verify at the Proxmox backups layout spec The managed proof pack behind `npm run dev:verify` still named tests/17-recovery-layout.spec.ts, which 1c38d79937 replaced with tests/17-proxmox-backups-layout.spec.ts in July. The registered proof for scripts/hot-dev-bg.sh pinned the stale path, so nothing flagged it. The stale path did not fail the pack. Playwright treats each spec path as a filter, so `test --list` with main's arguments reports 10 tests in 2 files and exits 0: the Proxmox backups layout guard had silently dropped out of dev:verify. The replacement spec reads the mock-mode estate, while dev:verify attaches to the managed runtime in whatever mode it was left in. Under the managed runtime it now skips with a `npm run mock:on` hint when mock mode is off, instead of flipping modes in place: Monitor.SetMockMode clears the runtime's active alerts and in-memory history on every switch. The Core E2E harness runs mock mode and is unaffected. test-hot-dev-bg.sh now pins the new spec and checks that every spec the default verify command names exists under tests/integration; against main's hot-dev-bg.sh that check fails on the retired path. The integration README and its pin, the deployment-installability contract clause, and two unused RECOVERY_PRODUCT_SURFACE_EXACT_FILES lists naming deleted files are brought in line. --- .../subsystems/deployment-installability.md | 18 ++++++++--- scripts/hot-dev-bg.sh | 2 +- .../canonical_completion_guard_test.py | 7 ---- .../release_control/subsystem_lookup_test.py | 6 ---- scripts/tests/test-hot-dev-bg.sh | 23 +++++++++++-- tests/integration/README.md | 10 +++--- .../tests/17-proxmox-backups-layout.spec.ts | 32 ++++++++++++++++++- 7 files changed, 72 insertions(+), 26 deletions(-) diff --git a/docs/release-control/v6/internal/subsystems/deployment-installability.md b/docs/release-control/v6/internal/subsystems/deployment-installability.md index 14ef915a65..9fb3efcbd3 100644 --- a/docs/release-control/v6/internal/subsystems/deployment-installability.md +++ b/docs/release-control/v6/internal/subsystems/deployment-installability.md @@ -5192,10 +5192,20 @@ browser runtime, cover both stream-only reconnect degradation and full backend loss, bounce the real backend through the launcher contract when needed, and prove that the shell degrades and recovers through the proxy instead of relying on backend-only API checks that miss browser/runtime drift. -That same managed browser proof pack must also keep the desktop Recovery page -layout guard on the canonical entrypoint, so `dev:verify` catches right-edge -history-table overflow regressions introduced by more human-readable subject -labels instead of leaving that check as a hidden one-off Playwright command. +That same managed browser proof pack must also keep the desktop Proxmox Backups +layout guard, `tests/integration/tests/17-proxmox-backups-layout.spec.ts`, on +the canonical entrypoint instead of leaving that check as a hidden one-off +Playwright command. It checks that selecting an activity day keeps the +operator on `/proxmox/backups` with an `N of M backups` count, and that a +one-year activity range keeps the page inside the horizontal viewport with the +PBS servers table's trailing column inside its wrapper. The guard reads the +mock-mode estate, so against a real-mode managed runtime it skips with a +`npm run mock:on` hint rather than switching modes in place, which would clear +the runtime's active alerts. Every spec the default proof command names must +exist under `tests/integration/`: Playwright treats each path as a filter and +runs whatever still matches, so a retired spec would drop out of `dev:verify` +without failing it. `scripts/tests/test-hot-dev-bg.sh` pins the spec name +and that existence check. That same proof pack must also keep the Patrol blocked-runtime page contract on the canonical entrypoint, so `dev:verify` catches stale healthy-summary regressions where the real `/ai` route would otherwise look healthy even after diff --git a/scripts/hot-dev-bg.sh b/scripts/hot-dev-bg.sh index 1c52fb2a7d..10bab1e769 100755 --- a/scripts/hot-dev-bg.sh +++ b/scripts/hot-dev-bg.sh @@ -986,7 +986,7 @@ run_verify_proof_command() { HOT_DEV_VERIFY_LOCK_FILE="${HOT_DEV_VERIFY_LOCK}" \ node ./scripts/run-playwright.mjs \ tests/16-dev-runtime-recovery.spec.ts \ - tests/17-recovery-layout.spec.ts \ + tests/17-proxmox-backups-layout.spec.ts \ tests/18-patrol-runtime-state.spec.ts \ --project=chromium ) diff --git a/scripts/release_control/canonical_completion_guard_test.py b/scripts/release_control/canonical_completion_guard_test.py index b5a72494e0..2c633671ff 100644 --- a/scripts/release_control/canonical_completion_guard_test.py +++ b/scripts/release_control/canonical_completion_guard_test.py @@ -157,13 +157,6 @@ def first_matching_policy_id(rule: dict, rel: str) -> str: return "DEFAULT" -RECOVERY_PRODUCT_SURFACE_EXACT_FILES = [ - "frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx", - "frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts", - "tests/integration/tests/17-recovery-layout.spec.ts", -] - - class CanonicalCompletionGuardTest(unittest.TestCase): def test_registry_exists_and_contains_required_subsystems(self): self.assertTrue(SUBSYSTEM_REGISTRY.exists()) diff --git a/scripts/release_control/subsystem_lookup_test.py b/scripts/release_control/subsystem_lookup_test.py index b2b903baa8..5c33bfaae8 100644 --- a/scripts/release_control/subsystem_lookup_test.py +++ b/scripts/release_control/subsystem_lookup_test.py @@ -10,12 +10,6 @@ from repo_file_io import canonical_workspace_repos_root, strip_local_git_env from subsystem_lookup import lookup_paths, normalize_input_path, parse_args, render_pretty -RECOVERY_PRODUCT_SURFACE_EXACT_FILES = [ - "frontend-modern/src/components/Recovery/__tests__/Recovery.test.tsx", - "frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts", - "tests/integration/tests/17-recovery-layout.spec.ts", -] - PATROL_PAGE_AND_STATE_EXACT_FILES = [ "frontend-modern/src/api/__tests__/patrolAttention.test.ts", "frontend-modern/src/components/Brand/__tests__/PulsePatrolLogo.test.tsx", diff --git a/scripts/tests/test-hot-dev-bg.sh b/scripts/tests/test-hot-dev-bg.sh index 9b1b5fbb68..e7eb6c3e9a 100755 --- a/scripts/tests/test-hot-dev-bg.sh +++ b/scripts/tests/test-hot-dev-bg.sh @@ -205,9 +205,27 @@ EOF assert_contains "default verify proof runs from integration harness" "${output}" "cwd=${ROOT_DIR}/tests/integration" assert_contains "default verify proof runs through the dedicated Playwright harness" "${output}" "args=./scripts/run-playwright.mjs" assert_contains "default verify proof includes dev runtime recovery spec" "${output}" "tests/16-dev-runtime-recovery.spec.ts" - assert_contains "default verify proof includes recovery layout spec" "${output}" "tests/17-recovery-layout.spec.ts" + assert_contains "default verify proof includes Proxmox backups layout spec" "${output}" "tests/17-proxmox-backups-layout.spec.ts" assert_contains "default verify proof includes patrol runtime-state spec" "${output}" "tests/18-patrol-runtime-state.spec.ts" assert_contains "default verify proof keeps chromium project pin" "${output}" "--project=chromium" + + # Playwright treats each spec path as a filter and runs whatever still + # matches, so a retired spec drops out of dev:verify without failing it. + local verify_cwd verify_args arg checked_specs=0 missing_specs="" + verify_cwd="$(printf '%s\n' "${output}" | sed -n 's/^cwd=//p')" + verify_args="$(printf '%s\n' "${output}" | sed -n 's/^args=//p')" + for arg in ${verify_args}; do + [[ "${arg}" == *.spec.ts ]] || continue + checked_specs=$((checked_specs + 1)) + [[ -f "${verify_cwd}/${arg}" ]] || missing_specs+=" ${arg}" + done + if (( checked_specs > 0 )) && [[ -z "${missing_specs}" ]]; then + echo "[PASS] default verify proof names only specs that exist" + else + echo "[FAIL] default verify proof names only specs that exist" >&2 + echo "Missing under ${verify_cwd}:${missing_specs:- no spec arguments found}" >&2 + ((failures++)) + fi } test_managed_wrapper_defaults_to_local_only_runtime() { @@ -1156,7 +1174,8 @@ test_integration_readme_uses_managed_backend_restart_wrapper() { assert_contains "integration readme documents managed backend restart wrapper" "${output}" "npm run dev:backend-restart" assert_contains "integration readme documents owner-process recovery proof" "${output}" "kills the supervised" assert_contains "integration readme names the owner process" "${output}" "owner process" - assert_contains "integration readme documents recovery layout proof" "${output}" "tests/17-recovery-layout.spec.ts" + assert_contains "integration readme documents Proxmox backups layout proof" "${output}" "tests/17-proxmox-backups-layout.spec.ts" + assert_not_contains "integration readme drops the retired recovery layout spec" "${output}" "tests/17-recovery-layout.spec.ts" assert_contains "integration readme documents patrol runtime-state proof" "${output}" "tests/18-patrol-runtime-state.spec.ts" assert_contains "integration readme documents explicit browser override precedence" "${output}" "PLAYWRIGHT_BASE_URL" assert_contains "integration readme documents backend base split" "${output}" "backend-oriented base" diff --git a/tests/integration/README.md b/tests/integration/README.md index f80f76ba66..0d3599a68c 100644 --- a/tests/integration/README.md +++ b/tests/integration/README.md @@ -44,10 +44,10 @@ End-to-end Playwright tests that validate critical user flows against a running - `tests/16-dev-runtime-recovery.spec.ts` — managed browser runtime proof: - Attaches Playwright to the canonical `5173` browser entrypoint - Restarts the managed backend and proves the browser shell recovers through the proxy -- `tests/17-recovery-layout.spec.ts` — desktop Recovery layout regression guard: - - Mocks a realistic Recovery dataset with human-readable subject labels - - Proves the focused history table fits the desktop wrapper without horizontal overflow - - Proves the `Outcome` column stays visible at the right edge +- `tests/17-proxmox-backups-layout.spec.ts` — desktop Proxmox Backups layout guard: + - Needs the mock-mode dataset and skips against a real-mode runtime (`npm run mock:on` first) + - Proves picking an activity day keeps `/proxmox/backups` and shows an `N of M backups` count + - Proves a one-year range keeps the page inside the horizontal viewport and the PBS servers table's trailing column inside its wrapper - `tests/18-patrol-runtime-state.spec.ts` — Patrol runtime-state browser guard: - Mocks a blocked Patrol runtime with stale healthy summary payloads - Proves the real `/ai` route shows Patrol as paused and suppresses stale healthy summary copy @@ -181,7 +181,7 @@ Equivalent direct proof command from the integration harness: cd tests/integration PULSE_E2E_USE_HOT_DEV=1 \ PULSE_E2E_SKIP_PLAYWRIGHT_INSTALL=1 \ -npm test -- tests/16-dev-runtime-recovery.spec.ts tests/17-recovery-layout.spec.ts tests/18-patrol-runtime-state.spec.ts --project=chromium +npm test -- tests/16-dev-runtime-recovery.spec.ts tests/17-proxmox-backups-layout.spec.ts tests/18-patrol-runtime-state.spec.ts --project=chromium ``` This mode attaches Playwright to the canonical dev browser entrypoint on `http://127.0.0.1:5173`, uses the repo-root managed runtime wrappers as the control surface, and writes browser runtime connection state for Playwright instead of targeting the backend port directly. Those wrappers are backed by `scripts/hot-dev-bg.sh`, but the wrapper surface is the canonical operator contract. diff --git a/tests/integration/tests/17-proxmox-backups-layout.spec.ts b/tests/integration/tests/17-proxmox-backups-layout.spec.ts index 9759a5e617..236777b261 100644 --- a/tests/integration/tests/17-proxmox-backups-layout.spec.ts +++ b/tests/integration/tests/17-proxmox-backups-layout.spec.ts @@ -1,8 +1,36 @@ import { expect, test, type Page } from "@playwright/test"; -import { ensureAuthenticated, primaryNavigationLink } from "./helpers"; +import { + ensureAuthenticated, + getMockMode, + primaryNavigationLink, +} from "./helpers"; const DESKTOP_VIEWPORT = { width: 1440, height: 900 }; +const truthy = (value: string | undefined) => + ["1", "true", "yes", "on"].includes( + String(value || "") + .trim() + .toLowerCase(), + ); + +// The guards read the mock-mode estate: PBS servers and a populated backup +// calendar. The Core E2E harness runs mock mode, but `npm run dev:verify` +// attaches to the managed hot-dev runtime in whatever mode it was left in. +// There a real-mode runtime skips the guards instead of switching modes in +// place, because Monitor.SetMockMode clears the runtime's active alerts and +// in-memory history on every switch. +async function skipUnlessManagedRuntimeIsMock(page: Page) { + if (!truthy(process.env.PULSE_E2E_USE_HOT_DEV)) { + return; + } + const { enabled } = await getMockMode(page); + test.skip( + !enabled, + "Needs the mock-mode dataset; run `npm run mock:on` before `npm run dev:verify`", + ); +} + async function openProxmoxBackups(page: Page) { const proxmoxTab = primaryNavigationLink(page, "Proxmox"); await expect(proxmoxTab).toBeVisible({ timeout: 30_000 }); @@ -41,6 +69,7 @@ test.describe("Proxmox backups layout guards", () => { await page.setViewportSize(DESKTOP_VIEWPORT); await ensureAuthenticated(page); + await skipUnlessManagedRuntimeIsMock(page); await openProxmoxBackups(page); // The Backups section now opens the date view directly. @@ -69,6 +98,7 @@ test.describe("Proxmox backups layout guards", () => { await page.setViewportSize(DESKTOP_VIEWPORT); await ensureAuthenticated(page); + await skipUnlessManagedRuntimeIsMock(page); await openProxmoxBackups(page); await page