# Toby incident fix-shipper · ship result

- **Run id:** `b3400d87-0830-4f89-bb70-4c3907c085f1`
- **Incident doc:** `toby/incidents/2026-05-11-blank-extension-page.md`
- **Source ticket:** TOBY-14
- **Validator verdict (input):** `validated` · confidence `high`
- **Outcome:** **shipped**
- **PR:** https://github.com/axiomzen/toby-mono-repo/pull/12
- **Branch:** `warroom/2026-05-11-blank-extension-page-toby-14`
- **Commit:** `06baf0f8a`
- **Base:** `origin/main` (was at `75a09e34d`)

## Files touched

| Path | Change |
|---|---|
| `apps/extension/app/state/accessors/user.tsx` | Layer 1 — 5s fail-open timeout around `getUser()` in the `useEffect` block. `.finally(clearTimeout)` on happy path; `.catch` + cancelled-flag for race-safety. |
| `apps/extension/app/hooks/useOnboarding2Draft.ts` | Layer 1 — same shape applied to `isReady`. Try/catch/finally around the load with the timeout cleared in both finally branches. |
| `apps/extension/app/containers/Toby.tsx` | Layer 2 — `showStuckEscapeHatch` flips true at 8s when the AuthWrapper gate is still false; the `return null` branch now returns `<StuckRecoveryScreen onRetry={reload} />` once that's true. Layer 3 — `trackEvent('NewTabHangShown', …)` fires once at the show site (guarded by `useRef`). |
| `apps/extension/app/components/StuckRecoveryScreen.tsx` | New component. Copy: "Your tabs are safe. Tap to recover." |

## What was deliberately NOT included

Per orders + the incident doc's "Follow-ups" section, this PR ships only the three validated layers. The following items are queued separately and are **out of scope**:

- Layer-1 shape for `isInitializing` (the `useIsRestoring()` IDB-backed path).
- SW hardening trio (background.ts:14 `.catch` chain; contextMenus.ts AbortController; unified `chromeStorageGet` helper).
- Layer-1 telemetry beacon (`NewTabHydrationTimeout`).

## Process notes

- Worked entirely in ephemeral worktree at `/tmp/toby-warroom-blank-extension-page-toby-14-242fba43`, rooted at `origin/main`. User's primary checkout at `/Users/guilhermegiacchetto/az/toby-mono-repo` was untouched.
- No husky/lint-staged hooks at repo root, so no `--no-verify` decisions needed.
- No `node_modules` in the worktree, so no local typecheck/lint executed — relying on CI. The diff is minimal and additive; no API surface changed.
- Worktree removed via `git worktree remove --force` after the PR was opened.
