From f8013331330fcc02dbda98ec5376059cc504b975 Mon Sep 17 00:00:00 2001 From: axiomlogicnexus Date: Wed, 24 Jun 2026 21:51:01 +0000 Subject: [PATCH] Refresh package proof and harden web auth continuity --- ...ated_family_package_validation_report.json | 184 ++++----- .../HyperTwist/DEVELOPMENT.md | 46 +++ ...run-hypertwist-remote-windows-file-pull.sh | 163 ++++++++ .../__tests__/DashboardOverviewPage.test.tsx | 2 + .../__tests__/download-center-page.test.tsx | 8 +- .../src/__tests__/package-validation.test.ts | 20 +- .../__tests__/protected-app-pages.test.tsx | 20 +- .../src/__tests__/public-auth-pages.test.tsx | 13 + .../__tests__/public-marketing-pages.test.tsx | 137 ++++++- website/src/__tests__/route-shells.test.tsx | 7 + website/src/components/layout/AppShell.tsx | 15 +- .../src/components/routes/ProtectedRoute.tsx | 22 +- .../ui/OperationalStatusCallout.tsx | 66 ++++ website/src/components/ui/Skeletons.tsx | 14 +- website/src/pages/app-pages.tsx | 272 ++++++++++--- website/src/pages/auth-pages.tsx | 199 +++++++++- website/src/pages/public-pages-commerce.tsx | 332 +++++++++++++++- website/src/pages/public-pages-marketing.tsx | 357 ++++++++++++------ .../windows-package-validation-summary.json | 2 +- website/src/shared/package-validation.ts | 2 +- website/src/site-data.ts | 10 + website/src/styles/global.css | 23 +- 22 files changed, 1580 insertions(+), 334 deletions(-) create mode 100644 scripts/run-hypertwist-remote-windows-file-pull.sh create mode 100644 website/src/components/ui/OperationalStatusCallout.tsx diff --git a/docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json b/docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json index 36aae3c..139f99e 100644 --- a/docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json +++ b/docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json @@ -1,93 +1,93 @@ { - "reportVersion": "ht-higher-dimensional-package-validation/v1", - "generatedAtUtc": "2026-06-23T10:27:31.6439999Z", - "projectRoot": "C:/HyperTwist_worktrees/phase10validate", - "archiveDirectory": "C:/HyperTwist_worktrees/phase10validate_packaged_phase6c_higherdim_refresh_20260623", - "configuration": "Development", - "cookMaps": [ - "/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining", - "/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining" - ], - "smokeMaps": [ - "/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining", - "/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining" - ], - "additionalCookerOptions": [ - "-DisablePlugins=MovieRenderPipeline", - "-SkipCookingEditorContent" - ], - "cleanArchive": true, - "skipBuild": true, - "skipLaunch": false, - "authoringManifest": { - "path": "C:\\HyperTwist_worktrees\\phase10validate\\docs\\generated\\higher_dimensional_training_maps\\phase6c_dedicated_family_map_manifest.json", - "manifestId": "phase6c/dedicated-family-training-map-authoring", - "manifestVersion": "2026.06.18", - "authoredThroughGameModeClassPath": "/Script/UnrealHyperTwist.HyperTwistCoachDashboardGameMode", - "validatedEntries": [ - { - "mapKind": "magic120cell", - "familyKey": "magic120cell", - "mapAssetPath": "/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining", - "mapFileRelativePath": "UnrealHyperTwist/Content/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining.umap", - "mapHashMd5": "9d9b9301f14cdad8c263d2c57b5f2c7f", - "activationProfileId": "magic120cell-cleanroom-runtime-activation", - "runtimeModeId": "magic120cell-full-color-runtime-v1", - "projectionProfileId": "magic120cell-4d-projection-distance-v1", - "primaryPersistenceBoundaryId": "magic120cell-persistence-boundary" - }, - { - "mapKind": "magiccube5d", - "familyKey": "magiccube5d", - "mapAssetPath": "/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining", - "mapFileRelativePath": "UnrealHyperTwist/Content/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining.umap", - "mapHashMd5": "15d2f7acfdce43402ad2fd291fc5c781", - "activationProfileId": "magiccube5d-cleanroom-runtime-activation", - "runtimeModeId": "magiccube5d-order3-runtime-v1", - "projectionProfileId": "magiccube5d-5d-projection-distance-v1", - "primaryPersistenceBoundaryId": "magiccube5d-persistence-boundary" - } - ] - }, - "result": "passed", - "packagedExecutablePath": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260623\\Windows\\UnrealHyperTwist.exe", - "smokeReports": [ - { - "reportVersion": "ht-higher-dimensional-package-smoke/v1", - "generatedAtUtc": "2026-06-23T10:28:44.7973129Z", - "packageRoot": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260623", - "executablePath": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260623\\Windows\\UnrealHyperTwist.exe", - "mapUrl": "/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining", - "smokeSeconds": 10, - "resolution": { - "width": 1600, - "height": 900 - }, - "keepRunning": false, - "result": "passed", - "processId": 20320, - "processStopped": true, - "exitCode": null, - "error": null - }, - { - "reportVersion": "ht-higher-dimensional-package-smoke/v1", - "generatedAtUtc": "2026-06-23T10:28:55.0662545Z", - "packageRoot": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260623", - "executablePath": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260623\\Windows\\UnrealHyperTwist.exe", - "mapUrl": "/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining", - "smokeSeconds": 10, - "resolution": { - "width": 1600, - "height": 900 - }, - "keepRunning": false, - "result": "passed", - "processId": 13584, - "processStopped": true, - "exitCode": null, - "error": null - } - ], - "error": null -} + "reportVersion": "ht-higher-dimensional-package-validation/v1", + "generatedAtUtc": "2026-06-24T12:53:32.7234772Z", + "projectRoot": "C:\\HyperTwist_worktrees\\phase10validate", + "archiveDirectory": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260624", + "configuration": "Development", + "cookMaps": [ + "/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining", + "/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining" + ], + "smokeMaps": [ + "/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining", + "/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining" + ], + "additionalCookerOptions": [ + "-DisablePlugins=MovieRenderPipeline", + "-SkipCookingEditorContent" + ], + "cleanArchive": true, + "skipBuild": true, + "skipLaunch": false, + "authoringManifest": { + "path": "C:\\HyperTwist_worktrees\\phase10validate\\docs\\generated\\higher_dimensional_training_maps\\phase6c_dedicated_family_map_manifest.json", + "manifestId": "phase6c/dedicated-family-training-map-authoring", + "manifestVersion": "2026.06.18", + "authoredThroughGameModeClassPath": "/Script/UnrealHyperTwist.HyperTwistCoachDashboardGameMode", + "validatedEntries": [ + { + "mapKind": "magic120cell", + "familyKey": "magic120cell", + "mapAssetPath": "/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining", + "mapFileRelativePath": "UnrealHyperTwist/Content/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining.umap", + "mapHashMd5": "9d9b9301f14cdad8c263d2c57b5f2c7f", + "activationProfileId": "magic120cell-cleanroom-runtime-activation", + "runtimeModeId": "magic120cell-full-color-runtime-v1", + "projectionProfileId": "magic120cell-4d-projection-distance-v1", + "primaryPersistenceBoundaryId": "magic120cell-persistence-boundary" + }, + { + "mapKind": "magiccube5d", + "familyKey": "magiccube5d", + "mapAssetPath": "/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining", + "mapFileRelativePath": "UnrealHyperTwist/Content/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining.umap", + "mapHashMd5": "15d2f7acfdce43402ad2fd291fc5c781", + "activationProfileId": "magiccube5d-cleanroom-runtime-activation", + "runtimeModeId": "magiccube5d-order3-runtime-v1", + "projectionProfileId": "magiccube5d-5d-projection-distance-v1", + "primaryPersistenceBoundaryId": "magiccube5d-persistence-boundary" + } + ] + }, + "result": "passed", + "packagedExecutablePath": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260624\\Windows\\UnrealHyperTwist.exe", + "smokeReports": [ + { + "reportVersion": "ht-higher-dimensional-package-smoke/v1", + "generatedAtUtc": "2026-06-24T12:54:48.8912848Z", + "packageRoot": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260624", + "executablePath": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260624\\Windows\\UnrealHyperTwist.exe", + "mapUrl": "/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining", + "smokeSeconds": 10, + "resolution": { + "width": 1600, + "height": 900 + }, + "keepRunning": false, + "result": "passed", + "processId": 34956, + "processStopped": true, + "exitCode": null, + "error": null + }, + { + "reportVersion": "ht-higher-dimensional-package-smoke/v1", + "generatedAtUtc": "2026-06-24T12:54:59.1871228Z", + "packageRoot": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260624", + "executablePath": "C:\\HyperTwist_worktrees\\phase10validate_packaged_phase6c_higherdim_refresh_20260624\\Windows\\UnrealHyperTwist.exe", + "mapUrl": "/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining", + "smokeSeconds": 10, + "resolution": { + "width": 1600, + "height": 900 + }, + "keepRunning": false, + "result": "passed", + "processId": 34432, + "processStopped": true, + "exitCode": null, + "error": null + } + ], + "error": null +} \ No newline at end of file diff --git a/docs/v6_5_deep_manual_pack/HyperTwist/DEVELOPMENT.md b/docs/v6_5_deep_manual_pack/HyperTwist/DEVELOPMENT.md index f857980..e275e04 100644 --- a/docs/v6_5_deep_manual_pack/HyperTwist/DEVELOPMENT.md +++ b/docs/v6_5_deep_manual_pack/HyperTwist/DEVELOPMENT.md @@ -118,6 +118,10 @@ Current packaged-proof bridge truth after the same `2026-06-23` continuation: - the `2026-06-24` centralized public-route-authority packet then kept the same umbrella gate green while moving navigation, footer links, router entries, and sitemap generation onto a shared route registry +- `scripts/run-hypertwist-remote-windows-file-pull.sh` now gives the lane a + bounded first-party way to pull Windows-side validation artifacts back into + the HyperTwist repo with explicit remote-to-local path mapping and SHA-256 + verification instead of relying on ad hoc manual copies Current bounded refactor-tool truth after the `2026-06-24` follow-up: @@ -242,6 +246,48 @@ Latest follow-up after that still on `2026-06-24`: - remaining structural work is now smaller-seam cleanup or broader product-quality hardening, not another big skill-validator extraction +Latest later higher-dimensional proof refresh still on `2026-06-24`: + +- the maintained Windows higher-dimensional package lane was rerun end to end + through: + - `Invoke-HyperTwistHigherDimensionalPackage.ps1` + - maintained validation root: + `C:\HyperTwist_worktrees\phase10validate` + - fresh archive root: + `C:\HyperTwist_worktrees\phase10validate_packaged_phase6c_higherdim_refresh_20260624` +- the refreshed authority report now records: + - `generatedAtUtc: 2026-06-24T12:53:32.7234772Z` + - `result: passed` + +Latest same-day browser/distribution continuity follow-up still on `2026-06-24`: + +- auth-entry, protected-route loading, dashboard auth health, and release-authority fallback states now share a more deliberate operator-facing recovery shape instead of scattering single-line warnings across public and protected surfaces +- the new shared callout posture explicitly separates: + - what still works + - what stays intentionally withheld + - recommended recovery order +- current widened surfaces include: + - login and register auth-runtime degradation guidance + - protected-route loading with preserved next-target sign-in and support escape hatches + - dashboard auth-health and release-authority fallback continuity + - public download and protected release-lane fallback continuity +- this hardening is still boundary-honest: + - degraded browser auth does not become a false production claim + - degraded release-manifest lookup does not unlock raw package delivery + - desktop-first simulator truth remains unchanged while browser/operator guidance improves + - packaged executable: + `C:\HyperTwist_worktrees\phase10validate_packaged_phase6c_higherdim_refresh_20260624\Windows\UnrealHyperTwist.exe` +- packaged smoke validation also passed for both dedicated-family maps: + - `/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining` + - `/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining` +- the new pull helper then brought the refreshed report back into: + - `docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json` +- `scripts/render-hypertwist-web-package-validation-summary.mjs` was rerun + immediately afterward, so + `website/src/shared/generated/windows-package-validation-summary.json` + now reflects the same fresh proof date instead of the earlier + `2026-06-23` report + ## Canonical development authorities Use these before widening implementation: diff --git a/scripts/run-hypertwist-remote-windows-file-pull.sh b/scripts/run-hypertwist-remote-windows-file-pull.sh new file mode 100644 index 0000000..73fb280 --- /dev/null +++ b/scripts/run-hypertwist-remote-windows-file-pull.sh @@ -0,0 +1,163 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: + HYPERTWIST_REMOTE_WINDOWS_PASSWORD=... \ + scripts/run-hypertwist-remote-windows-file-pull.sh \ + --map "C:\HyperTwist_worktrees\phase10validate\docs\generated\higher_dimensional_training_maps\phase6c_dedicated_family_package_validation_report.json::docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json" + +Options: + --map :: + Copy one remote Windows file back into the local repo. May be repeated. + + --dry-run + Print the pull plan without transferring files. + +Environment: + HYPERTWIST_REMOTE_WINDOWS_PASSWORD Required password for the reverse-SSH Windows user. + HYPERTWIST_REMOTE_TUNNEL_PORT Optional, defaults to 22022. + HYPERTWIST_REMOTE_WINDOWS_USER Optional, defaults to "anthracite ace". + HYPERTWIST_REMOTE_TUNNEL_HOST Optional, defaults to "localhost". +EOF +} + +if ! command -v python3 >/dev/null 2>&1; then + echo "python3 is required but was not found on PATH." >&2 + exit 1 +fi + +if ! command -v sha256sum >/dev/null 2>&1; then + echo "sha256sum is required but was not found on PATH." >&2 + exit 1 +fi + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +remote_ps_wrapper="${repo_root}/scripts/run-hypertwist-remote-windows-powershell.sh" + +if [[ ! -x "$remote_ps_wrapper" ]]; then + echo "Expected executable wrapper at $remote_ps_wrapper" >&2 + exit 1 +fi + +dry_run="false" +maps=() + +while [[ $# -gt 0 ]]; do + case "$1" in + --map) + maps+=("${2:-}") + shift 2 + ;; + --dry-run) + dry_run="true" + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + usage >&2 + exit 1 + ;; + esac +done + +if [[ ${#maps[@]} -eq 0 ]]; then + echo "Provide at least one --map." >&2 + exit 1 +fi + +ps_single_quote() { + printf "'%s'" "${1//\'/\'\'}" +} + +write_base64_to_file() { + local base64_payload="$1" + local destination_path="$2" + + python3 - <<'PY' "$base64_payload" "$destination_path" +import base64 +import pathlib +import sys + +payload = sys.argv[1] +destination = pathlib.Path(sys.argv[2]) +destination.parent.mkdir(parents=True, exist_ok=True) + +if payload: + destination.write_bytes(base64.b64decode(payload.encode("ascii"))) +else: + destination.write_bytes(b"") +PY +} + +for mapping in "${maps[@]}"; do + if [[ "$mapping" != *"::"* ]]; then + echo "Map must use ::: $mapping" >&2 + exit 1 + fi + + remote_path="${mapping%%::*}" + local_path="${mapping#*::}" + + if [[ -z "$remote_path" || -z "$local_path" ]]; then + echo "Map must include both remote and local paths: $mapping" >&2 + exit 1 + fi + + if [[ "$local_path" = /* ]]; then + local_destination="$local_path" + else + local_destination="${repo_root}/${local_path}" + fi + + if [[ "$dry_run" == "true" ]]; then + printf '%s -> %s\n' "$remote_path" "$local_destination" + continue + fi + + remote_payload="$( + cat <&2 + exit 1 + fi + + base64_payload="$( + printf '%s\n' "$remote_output" \ + | awk '/^REMOTE_BASE64_BEGIN$/{flag=1; next} /^REMOTE_BASE64_END$/{flag=0} flag' \ + | tr -d '\n' + )" + + write_base64_to_file "$base64_payload" "$local_destination" + + local_hash="$(sha256sum "$local_destination" | awk '{print tolower($1)}')" + if [[ "$local_hash" != "$remote_hash" ]]; then + echo "Hash mismatch for $remote_path" >&2 + echo " remote: $remote_hash" >&2 + echo " local : $local_hash" >&2 + exit 1 + fi + + printf 'Pulled %s -> %s (%s)\n' "$remote_path" "$local_destination" "$local_hash" +done diff --git a/website/src/__tests__/DashboardOverviewPage.test.tsx b/website/src/__tests__/DashboardOverviewPage.test.tsx index 5cfe755..a47b070 100644 --- a/website/src/__tests__/DashboardOverviewPage.test.tsx +++ b/website/src/__tests__/DashboardOverviewPage.test.tsx @@ -180,6 +180,8 @@ describe('DashboardOverviewPage', () => { expect(screen.getByText(/This session is currently using local fallback posture/i)).toBeTruthy() expect(screen.getByText(/Shared auth core is not fully ready right now/i)).toBeTruthy() + expect(screen.getByText('What stays intentionally bounded')).toBeTruthy() + expect(screen.getByText('Recommended recovery order')).toBeTruthy() expect(screen.getByText(/Public launch is not fully configured yet:/i)).toBeTruthy() expect(screen.getByText('Billing product-plan map: missing')).toBeTruthy() expect(screen.getByText('Billing price-plan map: missing')).toBeTruthy() diff --git a/website/src/__tests__/download-center-page.test.tsx b/website/src/__tests__/download-center-page.test.tsx index 9c101f3..0efa6d8 100644 --- a/website/src/__tests__/download-center-page.test.tsx +++ b/website/src/__tests__/download-center-page.test.tsx @@ -200,10 +200,12 @@ describe('DownloadCenterPage', () => { expect(screen.getByText('Release guide')).toBeTruthy() expect(screen.getByText('First launch follow-through')).toBeTruthy() expect(screen.getByText('Verify the current training lanes')).toBeTruthy() + expect(screen.getByText('Download and rollout escalation')).toBeTruthy() + expect(screen.getByText('Current product-surface map')).toBeTruthy() expect(await screen.findByText('Version: 1.0.0')).toBeTruthy() expect(screen.getByText('Build: win64-1000')).toBeTruthy() - expect(screen.getByText('Packaged validation passed')).toBeTruthy() - expect(screen.getByText(/MagicCube5D dedicated-family training map: passed/i)).toBeTruthy() + expect(screen.getAllByText('Packaged validation passed').length).toBeGreaterThan(0) + expect(screen.getAllByText(/MagicCube5D dedicated-family training map: passed/i).length).toBeGreaterThan(0) expect(document.title).toBe('HyperTwist downloads | HyperTwist') }) @@ -315,6 +317,8 @@ describe('DownloadCenterPage', () => { expect(await screen.findByText(/fallback release posture/i)).toBeTruthy() expect(screen.getByText(/your signed-in account still resolves to desktop access/i)).toBeTruthy() expect(screen.getAllByText('Live release authority temporarily unavailable').length).toBeGreaterThan(0) + expect(screen.getByText('What stays intentionally withheld')).toBeTruthy() + expect(screen.getByRole('link', { name: 'Open dashboard' }).getAttribute('href')).toBe('/app') expect(screen.queryByText(/account not entitled yet/i)).toBeNull() }) }) diff --git a/website/src/__tests__/package-validation.test.ts b/website/src/__tests__/package-validation.test.ts index 3f0a7c5..7bc7bab 100644 --- a/website/src/__tests__/package-validation.test.ts +++ b/website/src/__tests__/package-validation.test.ts @@ -1,27 +1,11 @@ import { describe, expect, it } from 'vitest' +import generatedWindowsValidationSummary from '../shared/generated/windows-package-validation-summary.json' import { getReleasePlatformValidationSummary } from '../shared/package-validation' describe('getReleasePlatformValidationSummary', () => { it('reads the current Windows packaged-validation truth from the generated higher-dimensional report summary', () => { - expect(getReleasePlatformValidationSummary('windows')).toMatchObject({ - lane: 'Windows Unreal packaged validation', - result: 'passed', - generated_at: '2026-06-23T10:27:31.6439999Z', - smoke_map_count: 2, - smoke_maps: [ - { - map_url: '/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining', - label: 'Magic120Cell dedicated-family training map', - result: 'passed', - }, - { - map_url: '/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining', - label: 'MagicCube5D dedicated-family training map', - result: 'passed', - }, - ], - }) + expect(getReleasePlatformValidationSummary('windows')).toEqual(generatedWindowsValidationSummary) }) it('keeps non-Windows release lanes free of fake packaged-validation summaries', () => { diff --git a/website/src/__tests__/protected-app-pages.test.tsx b/website/src/__tests__/protected-app-pages.test.tsx index 92942ea..8ecdea8 100644 --- a/website/src/__tests__/protected-app-pages.test.tsx +++ b/website/src/__tests__/protected-app-pages.test.tsx @@ -20,7 +20,7 @@ vi.mock('../auth/auth-api', () => ({ getReleaseManifest: (...args: unknown[]) => mockGetReleaseManifest(...args), })) -import { AccountPage, BrowserAccessPage, NoticesPage } from '../pages/app-pages' +import { AccountPage, BrowserAccessPage, DownloadCenterPage, NoticesPage } from '../pages/app-pages' function renderPage(page: React.ReactNode, initialEntry: string) { const queryClient = new QueryClient({ @@ -205,6 +205,22 @@ describe('protected app pages', () => { expect(screen.getByRole('link', { name: 'Open support' }).getAttribute('href')).toBe('/support?topic=operator-access') }) + it('keeps the protected download center aligned with packaged proof, notices, and escalation guidance', async () => { + renderPage(, '/app/downloads?platform=windows') + + expect(await screen.findByText('Release targets')).toBeTruthy() + expect(await screen.findByText('Version: 1.0.0')).toBeTruthy() + expect(screen.getAllByText('Requested target').length).toBeGreaterThan(0) + expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() + expect(screen.getAllByText('Packaged validation passed').length).toBeGreaterThan(0) + expect(screen.getByText('Download and rollout escalation')).toBeTruthy() + expect(screen.getByText('Current product-surface map')).toBeTruthy() + expect(screen.getByText('Protected browser dashboard')).toBeTruthy() + expect(screen.getByRole('link', { name: 'Protected notices' }).getAttribute('href')).toBe('/app/notices') + expect(screen.getByRole('link', { name: 'Public notices' }).getAttribute('href')).toBe('/open-source-notices') + expect(screen.getByRole('link', { name: 'Download Windows' }).getAttribute('href')).toBe('https://downloads.hypertwist.app/windows.exe') + }) + it('surfaces account release access and protected follow-through links', async () => { renderPage(, '/app/account') @@ -226,7 +242,7 @@ describe('protected app pages', () => { renderPage(, '/app/notices') expect(await screen.findByText('Distribution notices')).toBeTruthy() - expect(screen.getByText('Current packaged release proof')).toBeTruthy() + expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() expect(await screen.findAllByText(byExactTextContent('Configured release targets: 1/2', 'LI'))).toHaveLength(1) expect(screen.getByText(byExactTextContent('Public repository/notices URL: https://github.com/hypertwist/hypertwist', 'LI'))).toBeTruthy() diff --git a/website/src/__tests__/public-auth-pages.test.tsx b/website/src/__tests__/public-auth-pages.test.tsx index c392237..99aa0fc 100644 --- a/website/src/__tests__/public-auth-pages.test.tsx +++ b/website/src/__tests__/public-auth-pages.test.tsx @@ -206,6 +206,10 @@ describe('public auth and download pages', () => { const registerLink = screen.getByRole('link', { name: /create an account/i }) expect(registerLink.getAttribute('href')).toBe('/register?next=%2Fapp') + expect(screen.getByText('Protected operator dashboard')).toBeTruthy() + expect(screen.getAllByText(/After sign-in you will continue to the protected operator dashboard/i).length).toBeGreaterThan(0) + expect(screen.getByText('Protected browser dashboard')).toBeTruthy() + expect(screen.getByText('Native Unreal desktop runtime')).toBeTruthy() await userEvent.type(screen.getByLabelText('Email'), 'operator@hypertwist.app') await userEvent.type(screen.getByLabelText('Password'), 'password123') @@ -226,6 +230,10 @@ describe('public auth and download pages', () => { const loginLink = screen.getByRole('link', { name: 'Log in' }) expect(loginLink.getAttribute('href')).toBe('/login?next=%2Fapp%2Fdownloads%3Fplatform%3Dwindows') + expect(screen.getByText('Protected Windows release lane')).toBeTruthy() + expect(screen.getAllByText(/After sign-in you will continue to the protected Windows download center/i).length).toBeGreaterThan(0) + expect(screen.getByText('Protected browser dashboard')).toBeTruthy() + expect(screen.getByText('Native Unreal desktop runtime')).toBeTruthy() await userEvent.type(screen.getByLabelText('Name'), 'Operator') await userEvent.type(screen.getByLabelText('Email'), 'operator@hypertwist.app') @@ -278,8 +286,13 @@ describe('public auth and download pages', () => { renderAuthRoutes('/login') expect(screen.getByText(/Shared browser auth is not fully in production posture yet./i)).toBeTruthy() + expect(screen.getByText('What still works')).toBeTruthy() + expect(screen.getByText('What stays intentionally bounded')).toBeTruthy() + expect(screen.getByText('Recommended recovery order')).toBeTruthy() expect(screen.getByText('Missing auth env: VITE_SUPERTOKENS_API_DOMAIN')).toBeTruthy() expect(screen.getByText('VITE_AUTH_API_BASE_URL not configured; same-origin auth fallback remains active.')).toBeTruthy() + expect(screen.getByRole('link', { name: 'Open support' }).getAttribute('href')).toBe('/support?topic=operator-access') + expect(screen.getByText('Protected operator dashboard')).toBeTruthy() }) it('shows enabled OAuth buttons and routes provider clicks through the login handler', async () => { diff --git a/website/src/__tests__/public-marketing-pages.test.tsx b/website/src/__tests__/public-marketing-pages.test.tsx index 97e57dc..91f9778 100644 --- a/website/src/__tests__/public-marketing-pages.test.tsx +++ b/website/src/__tests__/public-marketing-pages.test.tsx @@ -241,19 +241,72 @@ describe('public marketing pages', () => { expect(screen.getByRole('link', { name: /sign in for windows access/i }).getAttribute('href')).toBe('/app/downloads?platform=windows') expect(screen.getAllByText('Preview posture').length).toBeGreaterThan(0) expect(screen.getByText('Operator checkout URL: missing')).toBeTruthy() + expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getByText('How the release lane works')).toBeTruthy() expect(screen.getByText('First launch and desktop setup')).toBeTruthy() + expect(screen.getByText('Digital delivery workflow')).toBeTruthy() + expect(screen.getByText('Protected entitlement handoff')).toBeTruthy() + expect(screen.getByText('Distribution doctrine')).toBeTruthy() + expect(screen.getByText('Public pages are distribution surfaces')).toBeTruthy() expect(screen.getByText('Pair desktop access to the browser account')).toBeTruthy() expect(await screen.findByText('Version: 1.0.0')).toBeTruthy() expect(screen.getByText('SHA-256: abc123')).toBeTruthy() - expect(screen.getByText('Packaged validation passed')).toBeTruthy() - expect(screen.getByText(/Magic120Cell dedicated-family training map: passed/i)).toBeTruthy() + expect(screen.getAllByText('Packaged validation passed').length).toBeGreaterThan(0) + expect(screen.getAllByText(/Magic120Cell dedicated-family training map: passed/i).length).toBeGreaterThan(0) expect(screen.getByText('Generates desktop-link tokens for safe browser-to-desktop handoff')).toBeTruthy() expect(screen.getByText('Owns the device/runtime integrations the public website does not claim')).toBeTruthy() expect(document.title).toBe('Download HyperTwist desktop | HyperTwist') expect(document.head.querySelector('meta[property="og:url"]')?.getAttribute('content')).toBe('https://hypertwist.app/download') }) + it('keeps public download fallback posture explicit when live release authority is unavailable', async () => { + mockGetAuthHealth.mockResolvedValue({ + ok: true, + service: 'hypertwist-auth-server', + supertokens: { + configured: true, + reachable: true, + ready: true, + apiVersion: '5.4', + error: null, + oauth: { + github: false, + google: false, + }, + }, + fallback: { + enabled: true, + active: false, + reason: null, + }, + billing: { + statePath: '/var/lib/hypertwist/auth/hypertwist-billing-state.json', + processedEventCount: 0, + pricePlanMapConfigured: false, + productPlanMapConfigured: false, + webhookSecretConfigured: false, + }, + runtime: { + mode: 'mixed', + public_origin_ready: true, + cookie_secure: true, + api_domain: 'https://hypertwist.app', + website_domain: 'https://hypertwist.app', + warnings: [], + errors: [], + }, + }) + mockGetReleaseManifest.mockRejectedValue(new Error('release manifest unavailable')) + + renderWithProviders() + + expect(await screen.findByText(/public release fallback/i)).toBeTruthy() + expect(screen.getByText(/direct package delivery stays intentionally withheld until that authority returns/i)).toBeTruthy() + expect(screen.getByText('What stays intentionally withheld')).toBeTruthy() + expect(screen.getByRole('link', { name: 'Sign in to inspect access' }).getAttribute('href')).toBe('/login') + expect(screen.getByRole('link', { name: 'Open support' }).getAttribute('href')).toBe('/support?topic=operator-access') + }) + it('surfaces homepage preview posture from live auth and release readiness', async () => { mockGetAuthHealth.mockResolvedValue({ ok: true, @@ -706,7 +759,44 @@ describe('public marketing pages', () => { role: null, accessStatus: null, }, - platforms: [], + platforms: [ + { + platform_key: 'windows', + platform: 'Windows', + subtitle: 'Primary shipping lane', + details: 'Current packaged validation is strongest on the Windows Unreal lane.', + configured: true, + channel: 'candidate', + version: '1.0.0', + build_id: 'win64-1000', + published_at: '2026-06-22T00:00:00.000Z', + file_name: 'HyperTwist-Windows.zip', + file_size_bytes: 1048576, + checksum_sha256: 'abc123', + download_url: null, + download_available: false, + validation_summary: { + lane: 'Windows Unreal packaged validation', + result: 'passed', + generated_at: '2026-06-22T01:43:08.7625247Z', + configuration: 'Development', + skip_build: true, + smoke_map_count: 2, + smoke_maps: [ + { + map_url: '/Game/HyperTwistTraining/Maps/L_HyperTwist_Magic120CellTraining', + label: 'Magic120Cell dedicated-family training map', + result: 'passed', + }, + { + map_url: '/Game/HyperTwistTraining/Maps/L_HyperTwist_MagicCube5DTraining', + label: 'MagicCube5D dedicated-family training map', + result: 'passed', + }, + ], + }, + }, + ], }, }) @@ -714,9 +804,14 @@ describe('public marketing pages', () => { expect(await screen.findByText('$19 / month')).toBeTruthy() expect(screen.getByText('$99 / month')).toBeTruthy() + expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() expect(screen.getAllByText('What happens after access is granted').length).toBeGreaterThan(0) expect(screen.getByText('Shows account, auth, billing, and release readiness posture')).toBeTruthy() expect(screen.getByText('Owns recognition, replay, coaching, and packaged training behavior')).toBeTruthy() + expect(screen.getByText('Commercial distribution doctrine')).toBeTruthy() + expect(screen.getByText('Public pages are distribution surfaces')).toBeTruthy() + expect(screen.getByText('Terms of access in practice')).toBeTruthy() + expect(screen.getByText('Access model')).toBeTruthy() const checkoutLinks = screen.getAllByRole('link', { name: /open paddle checkout/i }) expect(checkoutLinks).toHaveLength(2) expect(checkoutLinks[0].getAttribute('href')).toBe('https://buy.paddle.com/operator-live') @@ -790,6 +885,10 @@ describe('public marketing pages', () => { expect(screen.getByText('Browser and desktop responsibilities')).toBeTruthy() expect(screen.getByText('Shows account, auth, billing, and release readiness posture')).toBeTruthy() expect(screen.getByText('Support lanes')).toBeTruthy() + expect(screen.getByText('Digital delivery workflow')).toBeTruthy() + expect(screen.getByText('Post-install operator workflow')).toBeTruthy() + expect(screen.getByText('Privacy and compliance boundary')).toBeTruthy() + expect(screen.getByText('Browser identity and billing boundary')).toBeTruthy() expect(screen.getByText('Escalation map')).toBeTruthy() expect(screen.getByText('Runtime and training issues')).toBeTruthy() }) @@ -967,8 +1066,12 @@ describe('public marketing pages', () => { renderWithProviders(, ['/docs']) + expect(screen.getByText('Current shipped capability')).toBeTruthy() + expect(screen.getByText('Native training and coaching core')).toBeTruthy() expect(screen.getByText('Operator manual')).toBeTruthy() expect(screen.getAllByText('Current surface authority map').length).toBeGreaterThan(0) + expect(screen.getByText('When to use browser versus desktop')).toBeTruthy() + expect(screen.getAllByText('Protected browser dashboard').length).toBeGreaterThan(0) expect(screen.getAllByText('1. Start in the browser shell').length).toBeGreaterThan(0) expect(screen.getAllByText('Optional full-browser simulator branch').length).toBeGreaterThan(0) expect(screen.getByText('Simulator manual')).toBeTruthy() @@ -981,6 +1084,8 @@ describe('public marketing pages', () => { expect(screen.getAllByText(/latest persisted generated-mode selector posture is available for recall/i).length).toBeGreaterThan(0) expect(screen.getByText('Feature-registry-backed wording only')).toBeTruthy() expect(screen.getByText('Current packaged desktop proof')).toBeTruthy() + expect(screen.getByText('Common operator questions')).toBeTruthy() + expect(screen.getByText('If the desktop app is primary, why keep the web version?')).toBeTruthy() expect(screen.getByText('Packaged validation passed')).toBeTruthy() expect(await screen.findByRole('link', { name: /open public docs portal/i })).toBeTruthy() }) @@ -1195,17 +1300,31 @@ describe('public marketing pages', () => { expect(within(noticesView.container).getByText('Current packaged desktop proof')).toBeTruthy() expect(within(noticesView.container).getByText('Packaged validation passed')).toBeTruthy() - renderWithProviders(, ['/privacy']) - expect(screen.getByText('Practical privacy boundary')).toBeTruthy() - expect(screen.getByText('Browser identity and billing boundary')).toBeTruthy() + const privacyView = renderWithProviders(, ['/privacy']) + expect(within(privacyView.container).getByText('Practical privacy boundary')).toBeTruthy() + expect(within(privacyView.container).getByText('Browser identity and billing boundary')).toBeTruthy() + expect(within(privacyView.container).getByText('Browser and desktop responsibilities')).toBeTruthy() + expect(within(privacyView.container).getByText('Current surface authority map')).toBeTruthy() + expect(within(privacyView.container).getByText('Support-safe escalation boundary')).toBeTruthy() + expect(within(privacyView.container).getByText('Current packaged desktop proof')).toBeTruthy() + expect(within(privacyView.container).getByText('Packaged validation passed')).toBeTruthy() - renderWithProviders(, ['/terms']) - expect(screen.getByText('Terms in practice')).toBeTruthy() - expect(screen.getByText('Access model')).toBeTruthy() + const termsView = renderWithProviders(, ['/terms']) + expect(within(termsView.container).getByText('Terms in practice')).toBeTruthy() + expect(within(termsView.container).getByText('Access model')).toBeTruthy() + expect(within(termsView.container).getByText('Browser and desktop responsibilities')).toBeTruthy() + expect(within(termsView.container).getByText('Current surface authority map')).toBeTruthy() + expect(within(termsView.container).getByText('Release and redistribution checklist')).toBeTruthy() + expect(within(termsView.container).getByText('Current packaged desktop proof')).toBeTruthy() + expect(within(termsView.container).getByText('Packaged validation passed')).toBeTruthy() const shippingPaymentView = renderWithProviders(, ['/shipping-payment']) expect(within(shippingPaymentView.container).getByText('Digital delivery workflow')).toBeTruthy() expect(within(shippingPaymentView.container).getByText('Protected entitlement handoff')).toBeTruthy() + expect(within(shippingPaymentView.container).getByText('What happens after access is granted')).toBeTruthy() + expect(within(shippingPaymentView.container).getByText('Terms of access in practice')).toBeTruthy() + expect(within(shippingPaymentView.container).getByText('Distribution doctrine')).toBeTruthy() + expect(within(shippingPaymentView.container).getByText('Release and redistribution checklist')).toBeTruthy() expect(within(shippingPaymentView.container).getByText('Current packaged desktop proof')).toBeTruthy() expect(within(shippingPaymentView.container).getByText('Packaged validation passed')).toBeTruthy() }) diff --git a/website/src/__tests__/route-shells.test.tsx b/website/src/__tests__/route-shells.test.tsx index 15c9189..6b4bd60 100644 --- a/website/src/__tests__/route-shells.test.tsx +++ b/website/src/__tests__/route-shells.test.tsx @@ -159,6 +159,9 @@ describe('website route and shell behavior', () => { renderProtectedRoute('/app/account') expect(screen.getByText('Loading operator access...')).toBeTruthy() + expect(screen.getByText(/Checking your saved browser session, protected release posture, and browser-to-desktop continuity/i)).toBeTruthy() + expect(screen.getByRole('link', { name: 'Open sign-in' }).getAttribute('href')).toBe('/login?next=%2Fapp%2Faccount') + expect(screen.getByRole('link', { name: 'Open support' }).getAttribute('href')).toBe('/support?topic=operator-access') }) it('redirects unauthenticated protected routes to login with the full encoded next target', async () => { @@ -243,6 +246,10 @@ describe('website route and shell behavior', () => { expect(screen.getByText('Operator Prime')).toBeTruthy() expect(screen.getByText('studio plan')).toBeTruthy() expect(screen.getByText('Overview content')).toBeTruthy() + expect(screen.getByText('Desktop-first operator lane')).toBeTruthy() + expect(screen.getByRole('link', { name: 'Public download posture' }).getAttribute('href')).toBe('/download') + expect(screen.getByRole('link', { name: 'Public notices' }).getAttribute('href')).toBe('/open-source-notices') + expect(screen.getByRole('link', { name: 'Operator access support' }).getAttribute('href')).toBe('/support?topic=operator-access') await userEvent.click(screen.getByRole('button', { name: 'Switch to light mode' })) await userEvent.click(screen.getByRole('button', { name: 'Log out' })) diff --git a/website/src/components/layout/AppShell.tsx b/website/src/components/layout/AppShell.tsx index 4eae117..572745a 100644 --- a/website/src/components/layout/AppShell.tsx +++ b/website/src/components/layout/AppShell.tsx @@ -1,7 +1,8 @@ import { Gauge, KeyRound, MonitorSmartphone, PackageOpen, ShieldCheck } from 'lucide-react' -import { NavLink, Outlet } from 'react-router-dom' +import { Link, NavLink, Outlet } from 'react-router-dom' import { usePlatformAuth } from '../../auth/platform-auth' import { brandConfig } from '../../site-config' +import { buildSupportPath } from '../../site-routes' const appLinks = [ { to: '/app', label: 'Overview', icon: Gauge, end: true }, @@ -45,6 +46,18 @@ export function AppShell() { })}
+
+

Desktop-first operator lane

+

+ Use this protected shell for account, release, notices, and desktop-link pairing. + Use the native Unreal runtime for actual simulator execution. +

+
    +
  • Public download posture
  • +
  • Public notices
  • +
  • Operator access support
  • +
+
diff --git a/website/src/components/routes/ProtectedRoute.tsx b/website/src/components/routes/ProtectedRoute.tsx index 50fd836..f987b15 100644 --- a/website/src/components/routes/ProtectedRoute.tsx +++ b/website/src/components/routes/ProtectedRoute.tsx @@ -1,18 +1,34 @@ -import { Navigate, Outlet, useLocation } from 'react-router-dom' +import { Link, Navigate, Outlet, useLocation } from 'react-router-dom' import { usePlatformAuth } from '../../auth/platform-auth' import { buildLoginRedirectTarget } from '../../auth/route-guard' +import { buildSupportPath } from '../../site-routes' import { GeneralPageLoader } from '../ui/Skeletons' export function ProtectedRoute() { const { isAuthenticated, isLoading } = usePlatformAuth() const location = useLocation() + const loginRedirectTarget = buildLoginRedirectTarget(location) if (isLoading) { - return + return ( + +
+ + Open sign-in + + + Open support + +
+
+ ) } if (!isAuthenticated) { - return + return } return diff --git a/website/src/components/ui/OperationalStatusCallout.tsx b/website/src/components/ui/OperationalStatusCallout.tsx new file mode 100644 index 0000000..ed292f5 --- /dev/null +++ b/website/src/components/ui/OperationalStatusCallout.tsx @@ -0,0 +1,66 @@ +import { Link } from 'react-router-dom' +import { isExternalHref } from '../../site-routes' + +type OperationalStatusSection = { + title: string + items: readonly string[] +} + +type OperationalStatusAction = { + label: string + to: string +} + +export function OperationalStatusCallout({ + badge, + title, + summary, + sections = [], + actions = [], +}: { + badge: string + title: string + summary: string + sections?: readonly OperationalStatusSection[] + actions?: readonly OperationalStatusAction[] +}) { + const visibleSections = sections.filter((section) => section.items.length > 0) + + return ( +
+

{badge}

+

{title} {summary}

+ {visibleSections.map((section) => ( +
+

{section.title}

+
    + {section.items.map((item) => ( +
  • {item}
  • + ))} +
+
+ ))} + {actions.length > 0 ? ( +
+ {actions.map((action) => ( + isExternalHref(action.to) ? ( + + {action.label} + + ) : ( + + {action.label} + + ) + ))} +
+ ) : null} +
+ ) +} diff --git a/website/src/components/ui/Skeletons.tsx b/website/src/components/ui/Skeletons.tsx index 699d37c..8255024 100644 --- a/website/src/components/ui/Skeletons.tsx +++ b/website/src/components/ui/Skeletons.tsx @@ -1,7 +1,15 @@ -import { useEffect, useState } from 'react' +import { type ReactNode, useEffect, useState } from 'react' import { NamedAgentSpinner } from './agent-spinners' -export function GeneralPageLoader({ title = 'Loading' }: { title?: string }) { +export function GeneralPageLoader({ + title = 'Loading', + description, + children, +}: { + title?: string + description?: string + children?: ReactNode +}) { const [isCompleting, setIsCompleting] = useState(false) useEffect(() => { @@ -30,6 +38,8 @@ export function GeneralPageLoader({ title = 'Loading' }: { title?: string }) { className={`loading-spinner ${isCompleting ? 'is-completing' : ''}`} />

{title}

+ {description ?

{description}

: null} + {children ?
{children}
: null}
) diff --git a/website/src/pages/app-pages.tsx b/website/src/pages/app-pages.tsx index dd1d974..73a8b44 100644 --- a/website/src/pages/app-pages.tsx +++ b/website/src/pages/app-pages.tsx @@ -4,6 +4,7 @@ import { Link, useSearchParams } from 'react-router-dom' import { buildAuthApiBaseUrls, createDesktopLinkToken, getAuthHealth, getReleaseManifest } from '../auth/auth-api' import { usePlatformAuth, type PlatformUser } from '../auth/platform-auth' import { SiteMetadata } from '../components/seo/SiteMetadata' +import { OperationalStatusCallout } from '../components/ui/OperationalStatusCallout' import { ProductSurfaceMatrix } from '../components/ui/ProductSurfaceMatrix' import { ReleaseValidationSummary } from '../components/ui/ReleaseValidationSummary' import { resolvePublicLaunchStatusSummary } from '../public-launch' @@ -205,6 +206,56 @@ function findWindowsManifestTarget(releaseManifest: ReleaseManifestView) { return releaseManifest.platforms.find((platform) => platform.platform_key === 'windows') || null } +const protectedPackagedDesktopProofTitle = 'Current packaged desktop proof' + +function ProtectedReleaseAuthorityNotice({ + badge, + title, + summary, + stillWorks, + actionTo, + actionLabel, +}: { + badge: string + title: string + summary: string + stillWorks: readonly string[] + actionTo: string + actionLabel: string +}) { + return ( + + ) +} + function PackagedValidationPanel({ title, kicker, @@ -415,7 +466,35 @@ export function DashboardOverviewPage() { {healthQuery.isLoading ?

Checking auth server health...

: null} - {healthQuery.isError ?

Auth health probe failed. The local fallback can still keep the dashboard usable.

: null} + {healthQuery.isError ? ( + + ) : null} {healthQuery.data ? (
  • Service: {healthQuery.data.service}
  • @@ -432,9 +511,32 @@ export function DashboardOverviewPage() {
) : null} {healthQuery.data?.fallback.active ? ( -

- Shared auth core is not fully ready right now. Dashboard fallback posture remains available{healthQuery.data.fallback.reason ? ` (${healthQuery.data.fallback.reason})` : ''}. -

+ ) : null} {healthQuery.data && (healthQuery.data.runtime.errors.length > 0 || healthQuery.data.runtime.warnings.length > 0) ? (
@@ -507,9 +609,17 @@ export function DashboardOverviewPage() {

Refreshing release-manifest download readiness from the auth server.

) : null} {releaseManifestQuery.isError ? ( -

- Live release-manifest lookup failed. Download readiness is currently using local fallback metadata rather than current runtime release authority. -

+ ) : null} {launchReadinessIssues.length > 0 ? (

@@ -601,10 +711,17 @@ export function DownloadCenterPage() { {releaseManifestQuery.isError ? ( -

- The live release manifest could not be loaded from the auth server right now. - This panel is showing bounded fallback site metadata instead of current runtime release authority, and direct package delivery remains intentionally withheld until the auth server returns. -

+ ) : null} @@ -683,34 +800,42 @@ export function DownloadCenterPage() {
  • {step}
  • ))} - {(releaseManifest.public_docs_url || releaseManifest.release_notes_url || releaseManifest.corresponding_source_url) ? ( -
    - {releaseManifest.public_docs_url ? ( - - Public docs - - ) : null} - {releaseManifest.release_notes_url ? ( - - Release notes - - ) : null} - - {releaseManifest.corresponding_source_url ? 'Corresponding source' : 'Open source notices'} - -
    - ) : null} + + + + + + + +

    + The entitled download lane is only one part of the product. Keep the browser dashboard, + embedded browser shell, native runtime, and still-frozen browser branch separated so release actions do not drift into the wrong surface. +

    +
    + +
    +
    ) @@ -740,10 +865,27 @@ export function BrowserAccessPage() {
  • The public browser dashboard is for operator/account/release access, not a claim of full simulator parity.
  • {healthQuery.isLoading ?

    Checking current browser-shell auth posture...

    : null} - {healthQuery.isError ? ( -

    - Runtime auth-health could not be loaded. The page is still using the bounded dashboard posture rather than claiming browser-simulator parity. -

    + {healthQuery.isError ? ( + ) : null} {healthQuery.data ? (
      @@ -779,10 +921,18 @@ export function BrowserAccessPage() { description="This protected browser route keeps the simulator handoff honest by showing what the native runtime already owns today and where the later XR/controller completion packet still begins." /> - {releaseManifestQuery.isError ? ( -

      - Live release-manifest lookup failed. Browser-shell release context is currently using fallback metadata instead of current auth-server authority. -

      + {releaseManifestQuery.isError ? ( + ) : null}
      • Configured release targets: {configuredPlatformCount}/{releaseManifest.platforms.length}
      • @@ -792,7 +942,7 @@ export function BrowserAccessPage() { {releaseManifestQuery.isLoading ?

        Refreshing release-access posture from the live manifest...

        : null} - {releaseManifestQuery.isError ? ( -

        - Live release-manifest lookup failed. This account view is using bounded fallback metadata until auth-server release authority returns. -

        + {releaseManifestQuery.isError ? ( + ) : null}
        • Manifest viewer authenticated: {releaseManifest.viewer.authenticated ? 'yes' : 'no'}
        • @@ -896,7 +1054,7 @@ export function AccountPage() { ) : null} {releaseManifestQuery.isLoading ?

          Refreshing notices posture from the live release manifest...

          : null} {releaseManifestQuery.isError ? ( -

          - Live release-manifest lookup failed. This page is using bounded fallback notice metadata until auth-server release authority returns. -

          + ) : null}
          • Configured release targets: {configuredPlatforms.length}/{releaseManifest.platforms.length}
          • @@ -987,10 +1153,10 @@ export function NoticesPage() { ) : null} diff --git a/website/src/pages/auth-pages.tsx b/website/src/pages/auth-pages.tsx index a8f3ab2..cdee20d 100644 --- a/website/src/pages/auth-pages.tsx +++ b/website/src/pages/auth-pages.tsx @@ -9,6 +9,9 @@ import { isOrcidOAuthEnabled, } from '../auth/supertokens-client' import { SiteMetadata } from '../components/seo/SiteMetadata' +import { OperationalStatusCallout } from '../components/ui/OperationalStatusCallout' +import { deliverySurfaceCards, operatorManualTracks } from '../site-data' +import { buildSupportPath, getDownloadPlatformLabel, normalizeDownloadPlatform } from '../site-routes' function AuthShell({ title, @@ -39,33 +42,185 @@ function useNextPath() { return normalizeNextPath(searchParams.get('next')) } +type AuthNextStepDescriptor = { + title: string + description: string + bullets: readonly string[] +} + +function resolveAuthNextStep(nextPath: string): AuthNextStepDescriptor { + const [pathname, rawQuery = ''] = nextPath.split('?') + const searchParams = new URLSearchParams(rawQuery) + + if (pathname === '/app/downloads') { + const platform = normalizeDownloadPlatform(searchParams.get('platform')) + const platformLabel = platform ? getDownloadPlatformLabel(platform) : 'desktop' + + return { + title: `Protected ${platformLabel} release lane`, + description: + `After sign-in you will continue to the protected ${platformLabel} download center so entitlement, current package proof, and release-notice follow-through stay tied to your account instead of being exposed on an anonymous page.`, + bullets: [ + `Review the current ${platformLabel} target, package proof, and release notes before download.`, + 'Use the protected dashboard afterward if you need a desktop-link token for first launch.', + 'Return to protected or public notices if rollout or compliance posture changes.', + ], + } + } + + if (pathname === '/app/account') { + return { + title: 'Protected account lane', + description: + 'After sign-in you will continue to the protected account surface so session state, plan posture, and browser-to-desktop access continuity can be confirmed before any download or rollout step.', + bullets: [ + 'Confirm your plan, role, and current release access first.', + 'Use the protected download center once desktop entitlement is resolved.', + 'Use the dashboard and notices lanes if account or release posture changes later.', + ], + } + } + + if (pathname === '/app/notices') { + return { + title: 'Protected notices lane', + description: + 'After sign-in you will continue to the protected notices surface so distribution references, corresponding-source posture, and release-target notice truth remain attached to the signed-in operator lane.', + bullets: [ + 'Review notices before redistributing any covered downloadable build.', + 'Use the protected download center when you need the entitled package itself.', + 'Keep browser access, native package proof, and legal posture synchronized.', + ], + } + } + + return { + title: 'Protected operator dashboard', + description: + 'After sign-in you will continue to the protected operator dashboard so browser auth, billing, release posture, and desktop-link pairing are resolved before the native simulator lane takes over.', + bullets: [ + 'Confirm account, plan, and release readiness posture first.', + 'Open the protected download center when you need the entitled desktop build.', + 'Generate a desktop-link token there or from the dashboard before first native launch.', + ], + } +} + +function AuthNextStepNotice({ nextPath }: { nextPath: string }) { + const nextStep = resolveAuthNextStep(nextPath) + + return ( +
            +

            After sign-in

            +

            {nextStep.title}. {nextStep.description}

            +
              + {nextStep.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ) +} + +function AuthAccessGuide({ nextPath }: { nextPath: string }) { + const nextStep = resolveAuthNextStep(nextPath) + const dashboardCard = deliverySurfaceCards.find((card) => card.title === 'Protected browser dashboard') + const runtimeCard = deliverySurfaceCards.find((card) => card.title === 'Native Unreal desktop runtime') + const pairingTrack = operatorManualTracks.find((track) => track.title === '3. Pair the installed desktop runtime') + + return ( +
            +
            +

            {nextStep.title}

            +

            {nextStep.description}

            +
              + {nextStep.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + {dashboardCard ? ( +
            +

            {dashboardCard.title}

            +

            {dashboardCard.description}

            +
              + {dashboardCard.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ) : null} + {runtimeCard && pairingTrack ? ( +
            +

            {runtimeCard.title}

            +

            {pairingTrack.description}

            +
              + {pairingTrack.steps.map((step) => ( +
            • {step}
            • + ))} +
            +
            + ) : null} +
            + ) +} + function AuthRuntimeNotice() { const authRuntimeValidation = getSuperTokensAuthRuntimeValidation() if (authRuntimeValidation.ready && authRuntimeValidation.warnings.length === 0) { return null } + const diagnostics = [ + ...authRuntimeValidation.missing.map((item) => `Missing auth env: ${item}`), + ...authRuntimeValidation.warnings, + ] + return ( -
            -

            - Shared browser auth is not fully in production posture yet. - {!authRuntimeValidation.ready ? ' Local fallback mode may activate until the required auth env vars are configured.' : ''} -

            - {authRuntimeValidation.missing.length > 0 ? ( -
              - {authRuntimeValidation.missing.map((item) => ( -
            • Missing auth env: {item}
            • - ))} -
            - ) : null} - {authRuntimeValidation.warnings.length > 0 ? ( -
              - {authRuntimeValidation.warnings.map((item) => ( -
            • {item}
            • - ))} -
            - ) : null} -
            + ) } @@ -111,6 +266,7 @@ export function LoginPage() { footer={

            Need access? Create an account.

            } > +
            setEmail(event.target.value)} /> @@ -138,6 +294,7 @@ export function LoginPage() { ) : null} + ) @@ -186,6 +343,7 @@ export function RegisterPage() { footer={

            Already have access? Log in.

            } > + setName(event.target.value)} /> @@ -198,6 +356,7 @@ export function RegisterPage() { {isSubmitting ? 'Creating account...' : 'Create account'} + ) diff --git a/website/src/pages/public-pages-commerce.tsx b/website/src/pages/public-pages-commerce.tsx index b8b8e37..7feb78d 100644 --- a/website/src/pages/public-pages-commerce.tsx +++ b/website/src/pages/public-pages-commerce.tsx @@ -4,6 +4,8 @@ import { Link } from 'react-router-dom' import { getReleaseManifest } from '../auth/auth-api' import { MarketingShell } from '../components/layout/MarketingShell' import { SiteMetadata } from '../components/seo/SiteMetadata' +import { OperationalStatusCallout } from '../components/ui/OperationalStatusCallout' +import { ProductSurfaceMatrix } from '../components/ui/ProductSurfaceMatrix' import { PublicLaunchStatus } from '../components/ui/PublicLaunchStatus' import { ReleaseValidationSummary } from '../components/ui/ReleaseValidationSummary' import { paddleReadyDescription } from '../site-config' @@ -22,6 +24,9 @@ import { openSourceNotices, operatorManualTracks, privacyBoundaryCards, + productSurfaceMatrixRows, + releaseRolloutChecklist, + supportEscalationCards, termsBoundaryCards, } from '../site-data' import { @@ -43,10 +48,18 @@ export function PricingPage() { queryFn: getReleaseManifest, retry: false, }) + const releaseManifest = useMemo( + () => resolveReleaseManifestView(releaseManifestQuery.data?.manifest, buildPublicReleaseManifestFallback()), + [releaseManifestQuery.data?.manifest], + ) const releaseCommerce = useMemo( () => resolveReleaseCommerceView(releaseManifestQuery.data?.manifest, releaseCommerceFallback), [releaseManifestQuery.data?.manifest], ) + const windowsValidationPlatform = useMemo( + () => releaseManifest.platforms.find((platform) => platform.platform_key === 'windows') || null, + [releaseManifest.platforms], + ) const runtimePlanCatalog = useMemo(() => ([ explorerFallbackPlan, { @@ -97,6 +110,14 @@ export function PricingPage() { + +
            +
            +
            + {distributionDoctrineCards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            + +
            +
            + {termsBoundaryCards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            +

            @@ -147,6 +206,10 @@ export function DownloadPage() { () => resolveReleaseManifestView(releaseManifestQuery.data?.manifest, buildPublicReleaseManifestFallback()), [releaseManifestQuery.data?.manifest], ) + const windowsValidationPlatform = useMemo( + () => releaseManifest.platforms.find((platform) => platform.platform_key === 'windows') || null, + [releaseManifest.platforms], + ) return ( <> @@ -170,12 +233,38 @@ export function DownloadPage() { {releaseManifestQuery.isError ? (

            -
            -

            - The live release manifest could not be loaded from the auth server right now. - This page is showing bounded fallback site metadata instead of current runtime release authority, and direct package delivery stays intentionally withheld until that authority returns. -

            -
            +
            ) : null} @@ -247,6 +336,33 @@ export function DownloadPage() {
            + + +
            +
            + {digitalDeliveryCards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            +
            +
            +
            + {distributionDoctrineCards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            +
            {desktopReleaseSignals.map((signal) => ( @@ -421,12 +556,32 @@ export function OpenSourceNoticesPage() { ))}
            + +
            +
            + {releaseRolloutChecklist.map((card) => ( +
            +

            {card.title}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            ) } export function PrivacyPage() { + const { windowsValidationPlatform } = usePublicReleaseManifestView('public-privacy') + return ( <> + +
            + +
            + +
            + +
            + + + +
            +
            + {supportEscalationCards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            ) } export function TermsPage() { + const { windowsValidationPlatform } = usePublicReleaseManifestView('public-terms') + return ( <> + +
            + +
            + +
            + +
            + + + +
            +
            + {releaseRolloutChecklist.map((card) => ( +
            +

            {card.title}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            ) @@ -563,6 +801,32 @@ export function ShippingPaymentPage() { +
            +
            + {operatorManualTracks.slice(1, 4).map((track) => ( +
            +

            {track.title}

            +

            {track.description}

            +
              + {track.steps.map((step) => ( +
            • {step}
            • + ))} +
            +
            + ))} +
            +
            + +
            + +
            + + +
            +
            + {termsBoundaryCards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            + +
            +
            + {distributionDoctrineCards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            + +
            +
            + {releaseRolloutChecklist.map((card) => ( +
            +

            {card.title}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            ) diff --git a/website/src/pages/public-pages-marketing.tsx b/website/src/pages/public-pages-marketing.tsx index 3b594bb..9c37e9c 100644 --- a/website/src/pages/public-pages-marketing.tsx +++ b/website/src/pages/public-pages-marketing.tsx @@ -11,6 +11,8 @@ import { changelogEntries, companyNarrative, deploymentReadinessTracks, + digitalDeliveryCards, + featureAtlasCurrentTracks, heroMetrics, higherDimensionalRuntimeGuideCards, controlProfileRosterCards, @@ -25,6 +27,7 @@ import { roadmapHonestyCards, runtimeControlGuideCards, shippingNowCards, + privacyBoundaryCards, supportEscalationCards, simulatorManualCards, supportFaqs, @@ -37,6 +40,162 @@ import { usePublicReleaseManifestView, } from './public-page-helpers' +type PrincipleCard = { + title: string + description: string +} + +type BulletCard = { + title: string + description: string + bullets: readonly string[] +} + +type StepCard = { + title: string + description: string + steps: readonly string[] +} + +type StepOnlyCard = { + title: string + steps: readonly string[] +} + +type FaqCard = { + question: string + answer: string +} + +function PrincipleCardSection({ + title, + description, + cards, +}: { + title: string + description?: string + cards: readonly PrincipleCard[] +}) { + return ( +
            +
            + {cards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
            + ))} +
            +
            + ) +} + +function BulletCardSection({ + title, + description, + cards, +}: { + title: string + description?: string + cards: readonly BulletCard[] +}) { + return ( +
            +
            + {cards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            + ) +} + +function StepCardSection({ + title, + description, + cards, +}: { + title: string + description?: string + cards: readonly StepCard[] +}) { + return ( +
            +
            + {cards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.steps.map((step) => ( +
            • {step}
            • + ))} +
            +
            + ))} +
            +
            + ) +} + +function StepOnlyCardSection({ + title, + description, + cards, +}: { + title: string + description?: string + cards: readonly StepOnlyCard[] +}) { + return ( +
            +
            + {cards.map((card) => ( +
            +

            {card.title}

            +
              + {card.steps.map((step) => ( +
            • {step}
            • + ))} +
            +
            + ))} +
            +
            + ) +} + +function FaqCardSection({ + title, + description, + cards, +}: { + title: string + description?: string + cards: readonly FaqCard[] +}) { + return ( +
            +
            + {cards.map((card) => ( +
            +

            {card.question}

            +

            {card.answer}

            +
            + ))} +
            +
            + ) +} + export function HomeLanding() { const { windowsValidationPlatform } = usePublicReleaseManifestView('public-home') @@ -573,35 +732,19 @@ export function DocsPage() { title="HyperTwist documentation stays capability-accurate." lede="The public docs surface points users to product-safe truth: feature registry discipline, roadmap honesty, release notes, and distribution/legal guidance." > -
            -
            - {publicDocumentationPrinciples.map((principle) => ( -
            -

            {principle.title}

            -

            {principle.description}

            -
            - ))} -
            -
            + -
            + + -
            - {operatorManualTracks.map((track) => ( -
            -

            {track.title}

            -

            {track.description}

            -
              - {track.steps.map((step) => ( -
            • {step}
            • - ))} -
            -
            - ))} -
            -
            + cards={operatorManualTracks} + />
            + +
            + + -
            - {simulatorManualCards.map((card) => ( -
            -

            {card.title}

            -

            {card.description}

            -
              - {card.bullets.map((bullet) => ( -
            • {bullet}
            • - ))} -
            -
            - ))} -
            -
            + cards={simulatorManualCards} + /> -
            -
            - {higherDimensionalRuntimeGuideCards.map((card) => ( -
            -

            {card.title}

            -

            {card.description}

            -
              - {card.bullets.map((bullet) => ( -
            • {bullet}
            • - ))} -
            -
            - ))} -
            -
            + cards={higherDimensionalRuntimeGuideCards} + /> -
            -
            - {deploymentReadinessTracks.map((track) => ( -
            -

            {track.title}

            -
              - {track.steps.map((step) => ( -
            • {step}
            • - ))} -
            -
            - ))} -
            -
            + cards={deploymentReadinessTracks} + /> -
            -
            - {inputAndDevicePostureCards.map((card) => ( -
            -

            {card.title}

            -

            {card.description}

            -
              - {card.bullets.map((bullet) => ( -
            • {bullet}
            • - ))} -
            -
            - ))} -
            -
            + cards={inputAndDevicePostureCards} + /> -
            -
            - {controlProfileRosterCards.map((card) => ( -
            -

            {card.title}

            -

            {card.description}

            -
              - {card.bullets.map((bullet) => ( -
            • {bullet}
            • - ))} -
            -
            - ))} -
            -
            + cards={controlProfileRosterCards} + /> -
            -
            - {runtimeControlGuideCards.map((card) => ( -
            -

            {card.title}

            -

            {card.description}

            -
              - {card.bullets.map((bullet) => ( -
            • {bullet}
            • - ))} -
            -
            - ))} -
            -
            + cards={runtimeControlGuideCards} + /> + + {releaseManifest.public_docs_url ? (
            @@ -814,6 +893,44 @@ export function SupportPage() {
            +
            +
            + {digitalDeliveryCards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            + +
            +
            + {privacyBoundaryCards.map((card) => ( +
            +

            {card.title}

            +

            {card.description}

            +
              + {card.bullets.map((bullet) => ( +
            • {bullet}
            • + ))} +
            +
            + ))} +
            +
            +