Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ jobs:
run: pnpm --filter @workspace/occu-med-map test:sidebar-workspace-hardening
- name: General UI
run: pnpm --filter @workspace/occu-med-map test:general-ui-hardening
- name: Startup resilience
run: pnpm --filter @workspace/occu-med-map test:startup-hardening
- name: Runtime ownership
run: pnpm --filter @workspace/occu-med-map test:runtime-ownership
- name: Request pipeline
Expand Down
1 change: 1 addition & 0 deletions occu-med-map/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"test:map-synchronization-hardening": "tsx scripts/map-synchronization-hardening-smoke.ts",
"test:sidebar-workspace-hardening": "tsx scripts/sidebar-workspace-hardening-smoke.ts",
"test:general-ui-hardening": "tsx scripts/general-ui-hardening-smoke.ts",
"test:startup-hardening": "tsx scripts/startup-hardening-smoke.ts",
"test:runtime-ownership": "tsx scripts/runtime-ownership-smoke.ts",
"test:network-request-hardening": "tsx scripts/network-request-hardening-smoke.ts",
"test:ui-production": "node scripts/production-ui-smoke.mjs && node scripts/production-pdf-ui-smoke.mjs",
Expand Down
7 changes: 5 additions & 2 deletions occu-med-map/scripts/phase-two-map-smoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ assert.match(main, /import\("\.\/phaseTwoMapBridge"\)/);
assert.match(main, /import\("\.\/phase-two-controls\.css"\)/);
assert.match(main, /import\("\.\/PhaseTwoShell"\)/);
assert.doesNotMatch(main, /phaseTwoLegacyLayerBridge/);
assert.match(main, /root\.render\(<App \/>\)/);
assert.match(main, /function renderStandardApplication\(\): void/);
assert.match(main, /<AppErrorBoundary>\s*<App \/>\s*<\/AppErrorBoundary>/);
assert.match(main, /<AppErrorBoundary>\s*<PhaseTwoShell><App \/><\/PhaseTwoShell>\s*<\/AppErrorBoundary>/);
assert.match(main, /catch \(error\) \{[\s\S]*recordBootFailure\("phase-two-preview"[\s\S]*renderStandardApplication\(\);/);

const app = readFileSync(resolve(here, '../src/App.tsx'), 'utf8');
assert.match(app, /from ['"]\.\/providerLayerRequestRuntime['"]/);
Expand All @@ -141,4 +144,4 @@ const diagnosticsGate = readFileSync(resolve(here, '../src/usDiagnosticsGate.ts'
assert.match(diagnosticsGate, /scheduleDiagnosticsSync/);
assert.match(diagnosticsGate, /clearTimeout\(syncTimer\)/);

console.log('P2 preview uses the unified provider route, avoids global runtime patches, and keeps loading and pagination stable');
console.log('P2 preview uses the unified provider route, avoids global runtime patches, preserves startup recovery, and keeps loading and pagination stable');
46 changes: 46 additions & 0 deletions occu-med-map/scripts/startup-hardening-smoke.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import path from "node:path";

const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
const projectRoot = path.resolve(scriptDirectory, "..");

function source(relativePath: string): string {
return readFileSync(path.join(projectRoot, relativePath), "utf8");
}

const main = source("src/main.tsx");
const diagnostics = source("src/startupDiagnostics.ts");
const boundary = source("src/AppErrorBoundary.tsx");
const css = source("src/startup-hardening.css");

assert.match(main, /AppErrorBoundary/, "the application must render inside an error boundary");
assert.match(main, /ApplicationFailureScreen/, "asynchronous boot failures must render a recovery screen");
assert.match(main, /installGlobalBootDiagnostics\(\)/, "startup diagnostics must install before rendering");
assert.match(main, /aria-busy/, "the root must expose startup busy state");
assert.match(main, /requestIdleCallback/, "optional runtimes must defer until idle time");
assert.match(main, /timeout: 1600/, "idle loading must include a bounded fallback");
assert.match(main, /boot\(\)\.catch/, "asynchronous boot failures must be handled");
assert.match(main, /markApplicationInteractive/, "the first interactive frame must be recorded");
assert.match(main, /markOptionalRuntimesComplete/, "optional runtime completion must be recorded");
assert.match(main, /import "\.\/startup-hardening\.css";/, "recovery styles must load");
assert.doesNotMatch(main, /import\("\.\/dualMapTransitionRuntime"\)/, "startup resilience must not restore the renderer-blocking transition runtime");

assert.match(diagnostics, /__NETWORK_MAP_BOOT__/, "boot diagnostics must be externally inspectable");
assert.match(diagnostics, /runtimeRecords/, "optional runtime timing and state must be recorded");
assert.match(diagnostics, /unhandledrejection/, "unhandled promise rejections must be captured");
assert.match(diagnostics, /window-error/, "global runtime errors must be captured");
assert.match(diagnostics, /duplicate/, "repeated identical failures must be deduplicated");
assert.doesNotMatch(diagnostics, /setInterval\s*\(/, "startup diagnostics must not poll");

assert.match(boundary, /componentDidCatch/, "React render failures must be recorded");
assert.match(boundary, /role="alert"/, "the recovery screen must be announced to assistive technology");
assert.match(boundary, /Reload application/, "the recovery screen must provide a deterministic reload action");
assert.match(boundary, /Copy diagnostics/, "diagnostics must be easy to capture");

assert.match(css, /min-height: 100vh/, "the recovery screen must fill the desktop viewport");
assert.match(css, /max-height: calc\(100vh - 64px\)/, "recovery content must remain viewport constrained");
assert.match(css, /@media \(forced-colors: active\)/, "recovery controls must support forced-colors mode");

console.log("Startup hardening smoke test passed.");
80 changes: 80 additions & 0 deletions occu-med-map/src/AppErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from "react";
import { recordBootFailure } from "./startupDiagnostics";

type FailureScreenProps = {
title: string;
message: string;
onRetry?: () => void;
};

type AppErrorBoundaryProps = {
children?: React.ReactNode;
};

export function ApplicationFailureScreen({ title, message, onRetry }: FailureScreenProps) {
const copyDiagnostics = async (): Promise<void> => {
const diagnostics = window.__NETWORK_MAP_BOOT__?.snapshot();
const payload = JSON.stringify(diagnostics || { message }, null, 2);
try {
await navigator.clipboard.writeText(payload);
} catch {
// Clipboard access is optional; technical details remain visible below.
}
};

return (
<main className="app-fatal-state" role="alert" aria-live="assertive">
<section className="app-fatal-card">
<p className="app-fatal-kicker">Network Map recovery</p>
<h1>{title}</h1>
<p>{message}</p>
<div className="app-fatal-actions">
{onRetry ? <button type="button" onClick={onRetry}>Try again</button> : null}
<button type="button" onClick={() => window.location.reload()}>Reload application</button>
<button type="button" className="secondary" onClick={() => void copyDiagnostics()}>Copy diagnostics</button>
</div>
<details>
<summary>Technical details</summary>
<pre>{JSON.stringify(window.__NETWORK_MAP_BOOT__?.snapshot() || { message }, null, 2)}</pre>
</details>
</section>
</main>
);
}

type ErrorBoundaryState = {
error: Error | null;
};

export default class AppErrorBoundary extends React.Component<AppErrorBoundaryProps, ErrorBoundaryState> {
state: ErrorBoundaryState = { error: null };

static getDerivedStateFromError(error: Error): ErrorBoundaryState {
return { error };
}

componentDidCatch(error: Error, info: React.ErrorInfo): void {
recordBootFailure(
"react-render",
`${error.message}${info.componentStack ? `\n${info.componentStack}` : ""}`,
true,
);
}

private retry = (): void => {
this.setState({ error: null });
};

render(): React.ReactNode {
if (this.state.error) {
return (
<ApplicationFailureScreen
title="The map interface could not finish loading"
message="The application entered recovery mode instead of leaving a frozen or blank screen."
onRetry={this.retry}
/>
);
}
return this.props.children;
}
}
71 changes: 58 additions & 13 deletions occu-med-map/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ import "./dualMapEngineRuntime";
import "./providerExplorerStabilityRuntime";
import "./mapOverlaySynchronizationControllerRuntime";
import App from "./App";
import AppErrorBoundary, { ApplicationFailureScreen } from "./AppErrorBoundary";
import {
installGlobalBootDiagnostics,
loadOptionalRuntime,
markApplicationInteractive,
markOptionalRuntimesComplete,
recordBootFailure,
setBootPhase,
} from "./startupDiagnostics";
import "./dual-map-engines.css";
import "./dual-map-transition-opaque.css";
import "./map-engine-final-fixes.css";
Expand All @@ -41,18 +50,16 @@ import "./sidebarWorkspaceControllerRuntime";
import "./sidebar-workspace-final-fixes.css";
import "./sidebarWorkspacePanelGuardRuntime";
import "./ui-system.css";
import "./startup-hardening.css";
import "./dialogControllerRuntime";
import "./generalUiIntegrityRuntime";

async function safeLoad(name: string, loader: () => Promise<unknown>): Promise<void> {
try {
await loader();
} catch (error) {
console.error(`Network Map optional runtime failed: ${name}`, error);
}
await loadOptionalRuntime(name, loader);
}

async function loadOptionalRuntimes(): Promise<void> {
setBootPhase("optional-runtimes");
await safeLoad("Mapbox load hardening", () => import("./mapboxGlobeLoadHardeningRuntime"));
await safeLoad("map engine cleanup", () => import("./mapEngineFinalFixRuntime"));

Expand All @@ -75,6 +82,7 @@ async function loadOptionalRuntimes(): Promise<void> {
safeLoad("U.S. diagnostics", () => import("./usDiagnosticsGate")),
safeLoad("drive time", () => import("./features/driveTime/nativeDriveTimeRuntime")),
]);
markOptionalRuntimesComplete();
}

function installDirectMapModeSwitching(): void {
Expand Down Expand Up @@ -127,16 +135,38 @@ function scheduleOptionalRuntimes(): void {
}

installDirectMapModeSwitching();
installGlobalBootDiagnostics();

const rootElement = document.getElementById("root");
if (!rootElement) throw new Error("Network Map root element is missing");
const rootHost = document.getElementById("root");
if (!rootHost) {
recordBootFailure("application-root", new Error("Network Map root element is missing"), true);
throw new Error("Network Map root element is missing");
}
const rootElement: HTMLElement = rootHost;
rootElement.setAttribute("aria-busy", "true");
const root = createRoot(rootElement);
Comment on lines +140 to 147

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Render recovery UI when #root is absent.

This branch records the failure and throws before boot().catch() at Line 193. The application therefore leaves a blank page for the exact root-validation failure that this startup hardening adds.

Create a temporary recovery host in the document and render ApplicationFailureScreen into it instead of throwing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@occu-med-map/src/main.tsx` around lines 140 - 147, Update the missing-root
branch in the bootstrap flow to create a temporary recovery host, render
ApplicationFailureScreen into it, and return without throwing. Preserve
recordBootFailure("application-root", ...) and ensure the recovery UI is
displayed when `#root` is absent rather than relying on boot().catch().

const phaseTwoPreview = new URLSearchParams(window.location.search).get("p2-preview") === "1";

function renderStandardApplication(): void {
root.render(
<AppErrorBoundary>
<App />
</AppErrorBoundary>,
);
}

function markInitialRenderComplete(): void {
window.requestAnimationFrame(() => {
markApplicationInteractive(rootElement);
scheduleOptionalRuntimes();
});
}

async function boot(): Promise<void> {
setBootPhase("rendering");
if (!phaseTwoPreview) {
root.render(<App />);
scheduleOptionalRuntimes();
renderStandardApplication();
markInitialRenderComplete();
return;
}

Expand All @@ -147,12 +177,27 @@ async function boot(): Promise<void> {
import("./phase-two-controls.css"),
]);
const { default: PhaseTwoShell } = await import("./PhaseTwoShell");
root.render(<PhaseTwoShell><App /></PhaseTwoShell>);
root.render(
<AppErrorBoundary>
<PhaseTwoShell><App /></PhaseTwoShell>
</AppErrorBoundary>,
);
} catch (error) {
recordBootFailure("phase-two-preview", error, false);
console.error("Phase Two preview failed; loading standard map", error);
root.render(<App />);
renderStandardApplication();
}
scheduleOptionalRuntimes();
markInitialRenderComplete();
}

void boot();
void boot().catch((error) => {
recordBootFailure("application-boot", error, true);
setBootPhase("failed");
rootElement.setAttribute("aria-busy", "false");
root.render(
<ApplicationFailureScreen
title="Network Map could not start"
message="The application stopped safely before entering a frozen state. Reload to retry the startup sequence."
/>,
);
});
Loading
Loading