diff --git a/__tests__/route-error-retry.test.tsx b/__tests__/route-error-retry.test.tsx
new file mode 100644
index 0000000..73ce8a6
--- /dev/null
+++ b/__tests__/route-error-retry.test.tsx
@@ -0,0 +1,38 @@
+import { act, createElement } from 'react';
+import { createRoot } from 'react-dom/client';
+import { afterEach, expect, it, vi } from 'vitest';
+import RootError from '@/app/error';
+import GlobalError from '@/app/global-error';
+import DashboardError from '@/app/dashboard/error';
+import EditorError from '@/app/editor/[id]/error';
+import TailorError from '@/app/tailor/[jobId]/error';
+import CoverLetterError from '@/app/cover-letter/[jobId]/error';
+import InterviewError from '@/app/interview-prep/[jobId]/error';
+
+vi.mock('@/lib/foundry-monitoring', () => ({ captureError: vi.fn() }));
+afterEach(() => vi.restoreAllMocks());
+for (const [name, Boundary] of [
+ ['root', RootError],
+ ['global', GlobalError],
+ ['dashboard', DashboardError],
+ ['editor', EditorError],
+ ['tailor', TailorError],
+ ['cover letter', CoverLetterError],
+ ['interview', InterviewError],
+] as const) {
+ it(`${name} retries the failed server segment instead of merely clearing its cached error`, async () => {
+ vi.spyOn(console, 'error').mockImplementation(() => {});
+ const retry = vi.fn();
+ const reset = vi.fn();
+ const node = document.createElement('div');
+ document.body.append(node);
+ const root = createRoot(node);
+ const props = { error: new Error('Synthetic read failure'), retry, reset };
+ await act(async () => root.render(createElement(Boundary, props)));
+ await act(async () => node.querySelector('button')!.click());
+ expect(retry).toHaveBeenCalledOnce();
+ expect(reset).not.toHaveBeenCalled();
+ await act(async () => root.unmount());
+ node.remove();
+ });
+}
diff --git a/e2e/editor-toolbar.spec.ts b/e2e/editor-toolbar.spec.ts
new file mode 100644
index 0000000..6dbd32a
--- /dev/null
+++ b/e2e/editor-toolbar.spec.ts
@@ -0,0 +1,104 @@
+import { expect, test } from '@playwright/test';
+
+for (const width of [390, 768, 1440]) {
+ test(`initial editor toolbar hit targets and keyboard access at ${width}`, async ({
+ context,
+ page,
+ }, testInfo) => {
+ test.setTimeout(90_000);
+ await page.setViewportSize({ width, height: 900 });
+ await context.route('**/*', (route) => {
+ const url = new URL(route.request().url());
+ if (url.origin !== new URL(testInfo.project.use.baseURL!).origin) return route.abort();
+ if (url.pathname === '/api/auth/get-session') return route.fulfill({ json: null });
+ return route.continue();
+ });
+ await page.goto('/resume-builder');
+ await expect(page.getByRole('button', { name: '+ New Resume', exact: true })).toBeEnabled({
+ timeout: 30_000,
+ });
+ await page.evaluate(() =>
+ localStorage.setItem(
+ 'rt-resumes',
+ JSON.stringify([
+ {
+ id: 'synthetic-toolbar',
+ name: 'Synthetic Resume',
+ source: '# Ada Example\n\n## Experience\n- Built accessible TypeScript screens.\n',
+ created_at: 1767225600,
+ updated_at: 1767225600,
+ },
+ ])
+ )
+ );
+ await page.goto('/editor/synthetic-toolbar');
+ await expect(page.locator('.cm-editor')).toBeVisible({ timeout: 30_000 });
+ await page.evaluate(() => document.fonts.ready);
+ const toolbar = page.locator('.product-editor-toolbar');
+ const targets = [
+ toolbar.getByTitle('Back to Resume Builder'),
+ toolbar.getByTitle('Click to rename'),
+ toolbar.getByTitle('Format settings'),
+ toolbar.locator('summary').filter({ hasText: 'Export resume' }),
+ toolbar.getByRole('button', { name: 'Save', exact: true }),
+ ];
+ const initialScroll = await toolbar.evaluate((element) => {
+ const pane = element.parentElement!;
+ return { document: window.scrollX, pane: pane.scrollLeft };
+ });
+ // No locator.click(), focus() or scrollIntoView() before these initial hit tests.
+ for (const target of targets) {
+ expect(
+ await target.evaluate((element) => {
+ const box = element.getBoundingClientRect();
+ const first = document.elementsFromPoint(
+ box.x + box.width / 2,
+ box.y + box.height / 2
+ )[0];
+ return (
+ box.width > 0 &&
+ box.height > 0 &&
+ box.x >= 0 &&
+ box.right <= innerWidth &&
+ first != null &&
+ (first === element || element.contains(first))
+ );
+ })
+ ).toBe(true);
+ }
+ expect(
+ await toolbar.evaluate((element) => ({
+ document: window.scrollX,
+ pane: element.parentElement!.scrollLeft,
+ }))
+ ).toEqual(initialScroll);
+ expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(
+ true
+ );
+ await expect(page.locator('.resume-page').first()).toHaveCSS('width', '816px');
+ await page.screenshot({ path: testInfo.outputPath('initial.png'), fullPage: true });
+ const reached = new Set