Skip to content

fix(web): recover when the web app fails to start - #201

Merged
enaboapps merged 1 commit into
mainfrom
codex/web-start-recovery-200
Oct 9, 2026
Merged

enaboapps merged 1 commit into
mainfrom
codex/web-start-recovery-200

Conversation

@enaboapps

Copy link
Copy Markdown
Contributor

Closes #200

Summary

On a phone, the deployed web app stayed on the static loading spinner because its JavaScript never started. This makes sure nobody is left stuck there.

  • An inline watchdog script in src/app/+html.tsx (production exports only) shows "Switchify Remote didn't start" with a focused Reload button if the app hasn't started 10 seconds after the page loads.
  • Reload unregisters the service worker and deletes its caches before reloading, so a broken or stale copy cannot stick.
  • RootLayout calls markAppStarted() after its first render. That removes the message if a slow connection made it appear late. Native has a no-op.

The underlying failure on that phone is still unknown, because a fresh and a returning headless Chrome both start normally.

Validation

  • npm run validate: lint, typecheck, 692 Jest tests (including a new markAppStarted test) and 21/21 Expo Doctor checks pass.
  • Headless Chrome emulating a Pixel 7, against a production export:
    • On a normal load the message never appears.
    • With the app bundle blocked, the message appears after 10 seconds with Reload focused.
    • After unblocking, Reload brings the app up.

🤖 Generated with Claude Code

- If the app has not started 10 seconds after the page loads, an inline script in the
  root HTML shows "Switchify Remote didn't start" with a focused Reload button
- Reload unregisters the service worker and clears its caches first, so a broken or
  stale copy cannot leave anyone on the static loading spinner
- The root layout marks the app as started, removing the message if a slow connection
  made it appear; it only runs in production exports and native is unaffected

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
switchify-remote Ready Ready Preview Oct 9, 2026 2:44pm UTC

Request Review

@enaboapps
enaboapps marked this pull request as ready for review October 9, 2026 15:08
@enaboapps
enaboapps merged commit 2e4049e into main Oct 9, 2026
5 checks passed
@greptile-apps

greptile-apps Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 4/5

[Medium impact] Adds startup failure recovery to the web app.

Safe to merge with a non-blocking test-coverage concern; the current recovery behavior worked in the exercised browser scenario.

Findings

  1. P2 Recovery script remains untested ▶
Fix with agent prompt
### Issue 1
src/platform/installPlatform.web.test.ts:50-56
The new test replaces `__switchifyStarted` with a mock, so it never runs `startupWatchdog`. All five focused tests still passed when the entire watchdog was replaced with a no-op, even though that removed the recovery screen and Reload button. This is a non-blocking coverage gap: future changes could leave users stuck on the loading screen without failing these tests. Add tests that execute the inline script and cover the 10-second delay, early and late startup, and Reload after successful or failed cleanup.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

T-Rex evidence

Executable coverage and browser validation script

  • This executed script copies tracked sources into an isolated fixture, runs both Jest conditions, and captures Chromium behavior, making the coverage check reproducible.

Original watchdog source executed in Chromium

  • The harness extracted this exact script from the PR source and verified its presence in the production export, tying the baseline browser evidence to the candidate code.

Disabled watchdog source used for the controlled mutation

  • The harness substituted this no-op in the isolated source fixture and browser response, removing recovery behavior while the focused tests still passed.

Focused Jest output with the original watchdog

  • The original-source run passed all five tests and reported zero HTML statement coverage, establishing the baseline.

Focused Jest output with the watchdog disabled

  • The mutated-source run passed all five tests despite removing recovery behavior, demonstrating that the focused suite does not protect the watchdog.

▶ Original watchdog shows recovery and Reload

  • Chromium loaded the production HTML with the app bundle blocked, waited through the real deadline, and clicked Reload, showing that baseline recovery works.

Recovery screen after the original watchdog deadline

  • The screenshot captures the original watchdog after its timer fired, with DOM assertions confirming the recovery alert and focused Reload button.

▶ Disabled watchdog leaves recovery absent

  • Chromium repeated the blocked-startup scenario with only the watchdog disabled and waited past the same deadline, showing the behavior loss that Jest missed.

No recovery screen after the disabled watchdog deadline

  • The screenshot captures the controlled mutation after the deadline, with DOM assertions confirming that no recovery alert exists.

Combined executed validation output

  • The captured run records both Jest results, exact watchdog sources, Chromium observations, cache cleanup, and restoration assertions, with exit code 0.

Tracked source and fixture restoration check

  • The final command verified an empty tracked diff and equality between the restored fixture HTML and repository HTML, confirming no permanent tracked changes.

Evidence from the check

  • This executed script copies tracked sources into an isolated fixture, runs both Jest conditions, and captures Chromium behavior, making the coverage check reproducible.

Evidence from the check

  • The harness extracted this exact script from the PR source and verified its presence in the production export, tying the baseline browser evidence to the candidate code.

Evidence from the check

  • The harness substituted this no-op in the isolated source fixture and browser response, removing recovery behavior while the focused tests still passed.

Command output from the check

  • The original-source run passed all five tests and reported zero HTML statement coverage, establishing the baseline.

Command output from the check

  • The mutated-source run passed all five tests despite removing recovery behavior, demonstrating that the focused suite does not protect the watchdog.

▶ Recording of the check

  • Chromium loaded the production HTML with the app bundle blocked, waited through the real deadline, and clicked Reload, showing that baseline recovery works.

Recovery screen after the original watchdog deadline

  • The screenshot captures the original watchdog after its timer fired, with DOM assertions confirming the recovery alert and focused Reload button.

▶ Recording of the check

  • Chromium repeated the blocked-startup scenario with only the watchdog disabled and waited past the same deadline, showing the behavior loss that Jest missed.

No recovery screen after the disabled watchdog deadline

  • The screenshot captures the controlled mutation after the deadline, with DOM assertions confirming that no recovery alert exists.

Command output from the check

  • The captured run records both Jest results, exact watchdog sources, Chromium observations, cache cleanup, and restoration assertions, with exit code 0.

Command output from the check

  • The final command verified an empty tracked diff and equality between the restored fixture HTML and repository HTML, confirming no permanent tracked changes.

View artifacts

Summary

Adds a production-only recovery screen when the web app has not started after 10 seconds.

  • A stalled web page offers a reload that clears old cached copies.

Reviews (1) · Last reviewed commit: "fix(web): recover when the web app fails..." · Reviewed by Greptile

Comment on lines +50 to +56
it('tells the startup watchdog the app has started', () => {
const started = jest.fn();
(window as Window & { __switchifyStarted?: () => void }).__switchifyStarted = started;
markAppStarted();
expect(started).toHaveBeenCalledTimes(1);
delete (window as Window & { __switchifyStarted?: () => void }).__switchifyStarted;
expect(() => markAppStarted()).not.toThrow();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Recovery script remains untested

The new test replaces __switchifyStarted with a mock, so it never runs startupWatchdog. All five focused tests still passed when the entire watchdog was replaced with a no-op, even though that removed the recovery screen and Reload button. This is a non-blocking coverage gap: future changes could leave users stuck on the loading screen without failing these tests. Add tests that execute the inline script and cover the 10-second delay, early and late startup, and Reload after successful or failed cleanup.

Artifacts

Executable coverage and browser validation script

  • This executed script copies tracked sources into an isolated fixture, runs both Jest conditions, and captures Chromium behavior, making the coverage check reproducible.

Original watchdog source executed in Chromium

  • The harness extracted this exact script from the PR source and verified its presence in the production export, tying the baseline browser evidence to the candidate code.

Disabled watchdog source used for the controlled mutation

  • The harness substituted this no-op in the isolated source fixture and browser response, removing recovery behavior while the focused tests still passed.

Focused Jest output with the original watchdog

  • The original-source run passed all five tests and reported zero HTML statement coverage, establishing the baseline.

Focused Jest output with the watchdog disabled

  • The mutated-source run passed all five tests despite removing recovery behavior, demonstrating that the focused suite does not protect the watchdog.

▶ Original watchdog shows recovery and Reload

  • Chromium loaded the production HTML with the app bundle blocked, waited through the real deadline, and clicked Reload, showing that baseline recovery works.

Recovery screen after the original watchdog deadline

  • The screenshot captures the original watchdog after its timer fired, with DOM assertions confirming the recovery alert and focused Reload button.

▶ Disabled watchdog leaves recovery absent

  • Chromium repeated the blocked-startup scenario with only the watchdog disabled and waited past the same deadline, showing the behavior loss that Jest missed.

No recovery screen after the disabled watchdog deadline

  • The screenshot captures the controlled mutation after the deadline, with DOM assertions confirming that no recovery alert exists.

Combined executed validation output

  • The captured run records both Jest results, exact watchdog sources, Chromium observations, cache cleanup, and restoration assertions, with exit code 0.

Tracked source and fixture restoration check

  • The final command verified an empty tracked diff and equality between the restored fixture HTML and repository HTML, confirming no permanent tracked changes.

View artifacts

T-Rex Ran code and verified through T-Rex

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/platform/installPlatform.web.test.ts
Line: 50-56

Comment:
**Recovery script remains untested**

The new test replaces `__switchifyStarted` with a mock, so it never runs `startupWatchdog`. All five focused tests still passed when the entire watchdog was replaced with a no-op, even though that removed the recovery screen and Reload button. This is a non-blocking coverage gap: future changes could leave users stuck on the loading screen without failing these tests. Add tests that execute the inline script and cover the 10-second delay, early and late startup, and Reload after successful or failed cleanup.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

This branch was successfully deployed

1 active deployment
Preview — 47245616 Deployed Oct 9, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Recover when the web app fails to start

2 participants