Skip to content

PWA bugs #696

Open
Open

Description

@ngoiyaeric

Heads up, core.queue.cx is broken on iOS. Tapping on questions from home page immediately reloads or for “How do I use the computer” responds with instructions to use a computer.

Activity

  1. ngoiyaeric commented on Jun 27, 2026

    @ngoiyaeric
    CollaboratorAuthor
  2. coderabbitai commented on Jun 27, 2026

    @coderabbitai
    Contributor

    Coding Plan

    Summary

    • Treat the ticket as two independent bugs: an iOS PWA reload and an AI misinterpretation.
    • For the reload, detect standalone PWA mode (reusing existing detection) and suppress the router.refresh()/history side effects that iOS escalates into full reloads, with optional service-worker hardening as secondary defense.
    • For the wrong answer, enrich the default system prompt in researcher.tsx so "the computer" is understood as QCX-Terra and answered as app-usage guidance, extending the existing pre-configured-response pattern.
    • Preserve all existing non-PWA behavior and per-user custom prompts.
    Design Choices
    Design Choice 1: Where should the iOS PWA reload be prevented?

    Options Considered:

    1. Detect iOS/standalone PWA mode and skip/replace the disruptive router.refresh() (and review replaceState) only in that environment.
    2. Remove router.refresh() entirely for all platforms.
    3. Rework the service worker caching/takeover strategy as the primary fix.

    Chosen Option: 1

    Rationale: Option 1 — surgically guarding the refresh for standalone PWA mode preserves desktop/browser behavior while eliminating the reload, reusing the existing standalone-detection pattern; SW hardening is applied only as secondary defense.

    Design Choice 2: How should the app-specific question be answered correctly?

    Options Considered:

    1. Augment the default system prompt so the AI understands "the computer" refers to QCX-Terra / the planet computer (and extend the existing "Pre-configured Responses" guidance).
    2. Add the exact string to the hardcoded bypass filter in app/actions.tsx for a canned response.
    3. Reword the preset question in components/empty-screen.tsx to be unambiguous.

    Chosen Option: 1

    Rationale: Option 1 — strengthening the system prompt fixes the class of app-related/ambiguous "computer" phrasings (not just one exact string), aligns with the existing pre-configured-response pattern, and keeps responses AI-generated rather than brittle canned text.

    💡 User Tips

    Regenerate the plan with different choices with @coderabbitai <feedback>.

    Implementation Steps

    Phase 1: Eliminate the iOS PWA Reload on Question Tap

    This phase removes the full-page reload that occurs when a home page suggestion is tapped while running as an iOS standalone PWA. The objective is to keep the chat interaction fully client-side in PWA mode by suppressing the navigation/refresh side effects that iOS Safari escalates into hard reloads, while leaving normal browser behavior intact. Secondary hardening of the service worker reduces the chance of SW-driven reloads during the same session.

    Task 1: Task 1.1: Detect standalone PWA mode in the chat flow

    Provide a reliable signal for whether the app is running as an installed PWA so the reload-inducing effects can be conditionally disabled.

    • Reuse the existing standalone-detection approach from components/install-prompt.tsx (window.matchMedia('(display-mode: standalone)'), plus the iOS navigator.standalone check).
    • Expose this as a small shared helper/hook (place a hook under lib/hooks/ or a utility in lib/utils/) so components/chat.tsx can consume it without duplicating detection logic.
    Task 2: Task 1.2: Guard the post-response refresh and URL rewrite in `components/chat.tsx`

    Stop the side effects that iOS PWA escalates into full reloads.

    • In components/chat.tsx, gate the debounced router.refresh() effect (lines ~80–89) so it does not run when in standalone PWA mode; in that mode rely on the existing in-memory setMessages updates rather than a server refresh.
    • Review the window.history.replaceState effect (lines ~73–76) that rewrites the URL to /search/{id}; ensure this URL update does not, in standalone mode, cause the SW navigation handler to re-fetch and reload. If it contributes to the reload, defer or guard it for standalone mode while preserving deep-link/shareable URL behavior in the browser.
    • Keep all non-PWA (desktop/browser) behavior unchanged.
    Task 3: Task 1.3: Harden service worker takeover behavior (secondary defense)

    Reduce the chance that service-worker activation reloads an active iOS session mid-interaction.

    • In app/sw.ts, reconsider skipWaiting/clientsClaim so a new SW does not forcibly claim and disrupt an open PWA session, and review navigationPreload: true given inconsistent iOS Safari support.
    • Confirm components/sw-update-notification.tsx only reloads on an explicit user-driven update action (not implicitly during a chat session).
    • Treat these as defensive adjustments; the primary fix remains Task 1.2.
    🤖 Prompt for AI agents
    This phase eliminates the full-page reload that occurs when a home page
    suggestion is tapped in an iOS standalone PWA, while preserving all existing
    non-PWA behavior.
    
    **Task 1.1 — Create a shared standalone PWA detection hook/utility:**
    - Create a small shared hook or utility (e.g., `lib/hooks/useIsStandalone.ts` or
    `lib/utils/isStandalone.ts`) that detects standalone PWA mode.
    - Mirror the existing detection logic from `components/install-prompt.tsx`:
    check `window.matchMedia('(display-mode: standalone)')` and the iOS-specific
    `navigator.standalone` property.
    - Export this so `components/chat.tsx` (and others) can consume it without
    duplicating logic.
    
    **Task 1.2 — Guard reload-inducing side effects in `components/chat.tsx`:**
    - Import and use the standalone detection helper/hook created in Task 1.1.
    - Gate the debounced `router.refresh()` effect (around lines 80–89) so it does
    **not** execute when running in standalone PWA mode; in that mode, rely solely
    on the existing in-memory `setMessages` updates.
    - Review the `window.history.replaceState` effect (around lines 73–76) that
    rewrites the URL to `/search/{id}`; if this triggers the service worker
    navigation handler to re-fetch and reload in standalone mode, defer or guard it
    for standalone mode while keeping deep-link/shareable URL behavior intact in the
    browser.
    - Ensure all non-PWA (desktop/browser) behavior remains unchanged.
    
    **Task 1.3 — Harden service worker takeover behavior in `app/sw.ts` (secondary
    defense):**
    - In `app/sw.ts`, review and reconsider `skipWaiting`/`clientsClaim` settings so
    a newly activated service worker does not forcibly claim and disrupt an open PWA
    session.
    - Review `navigationPreload: true` given inconsistent iOS Safari support —
    consider disabling or conditionally applying it.
    - In `components/sw-update-notification.tsx`, confirm that any reload triggered
    by a SW update only fires on an explicit user-driven action, not implicitly
    during an active chat session.
    - These are defensive adjustments; the primary fix is in Task 1.2.
    

    Phase 2: Correct AI Interpretation of App-Specific Questions

    This phase ensures that questions phrased about "the computer" are understood as questions about QCX-Terra (the "planet computer") rather than a generic desktop machine. The objective is to give the AI enough product context to respond with app-usage guidance for the preset question and similar phrasings.

    Task 1: Task 2.1: Strengthen the default system prompt with product context

    Make the model treat "the computer"/"the planet computer" as QCX-Terra and respond with app-usage guidance.

    • In lib/agents/researcher.tsx, extend getDefaultSystemPrompt so it explicitly states that within this app "the computer" / "planet computer" refers to QCX-Terra, and that questions like "How do I use the computer?" should be answered as guidance on using QCX-Terra rather than a generic computer.
    • Extend the existing "Pre-configured Responses" section to cover the "How do I use the computer?" intent so the model produces an app-onboarding style answer.
    • Ensure this applies only to the default prompt path; per-user custom prompts (dynamicSystemPrompt) continue to take precedence.
    Task 2: Task 2.2: Verify the home page preset routes through the corrected path

    Confirm the preset suggestion reaches the updated prompt logic without being mishandled.

    • Confirm in components/empty-screen.tsx and app/actions.tsx that the "How do I use the computer?" preset flows through submit() → researcher() and now benefits from the strengthened prompt (no change needed if behavior is correct after Task 2.1).
    • Optionally, if exact-match certainty is desired, mirror the existing hardcoded bypass pattern in app/actions.tsx (lines ~272–325) for this specific phrasing — only as a fallback, with the system-prompt fix as the primary mechanism.
    🤖 Prompt for AI agents
    This phase corrects the AI's interpretation of app-specific questions so that
    "the computer" / "planet computer" is understood as QCX-Terra rather than a
    generic desktop machine.
    
    **Task 2.1 — Strengthen the default system prompt in
    `lib/agents/researcher.tsx`:**
    - Locate the `getDefaultSystemPrompt` function in `lib/agents/researcher.tsx`.
    - Add explicit product context stating that within this app, "the computer" and
    "planet computer" refer to QCX-Terra.
    - Specify that questions like "How do I use the computer?" must be answered as
    app-usage/onboarding guidance for QCX-Terra, not as a generic computer question.
    - Extend the existing "Pre-configured Responses" section of the prompt to cover
    the "How do I use the computer?" intent, so the model produces an app-onboarding
    style answer.
    - Ensure these additions only affect the default prompt path — per-user custom
    prompts (`dynamicSystemPrompt`) must continue to take precedence and remain
    unchanged.
    
    **Task 2.2 — Verify the preset question routes through the corrected path:**
    - Trace the "How do I use the computer?" preset from
    `components/empty-screen.tsx` through `submit()` in `app/actions.tsx` to
    `researcher()` in `lib/agents/researcher.tsx`.
    - Confirm no existing logic (e.g., an exact-match bypass) intercepts or
    short-circuits this query before it reaches the updated system prompt.
    - If no code changes are needed after Task 2.1 (i.e., the flow is already
    correct), document the confirmation.
    - Optionally, if additional certainty is desired, add the exact phrasing to the
    existing hardcoded bypass pattern in `app/actions.tsx` (around lines 272–325) as
    a fallback only — the system-prompt fix from Task 2.1 remains the primary
    mechanism.
    
    Research

    This is a Next.js App Router PWA. app/page.tsx renders <Chat> (components/chat.tsx), which conditionally shows EmptyScreen (preset suggestion buttons) and orchestrates submission. Tapping a suggestion fills the input and triggers the form in components/chat-panel.tsx, which calls the submit() server action in app/actions.tsx. That action extracts the raw query and passes it to researcher() (lib/agents/researcher.tsx), which selects a system prompt (per-user DB prompt or a built-in geospatial/tool-routing default). PWA behavior is configured via app/sw.ts (Serwist), app/manifest.ts, and Apple metadata in app/layout.tsx. components/install-prompt.tsx already detects standalone (PWA) display mode.


    🚀 Next Steps

    🤖 All AI agent prompts combined
    Task: 1
    
    This phase eliminates the full-page reload that occurs when a home page
    suggestion is tapped in an iOS standalone PWA, while preserving all existing
    non-PWA behavior.
    
    **Task 1.1 — Create a shared standalone PWA detection hook/utility:**
    - Create a small shared hook or utility (e.g., `lib/hooks/useIsStandalone.ts` or
    `lib/utils/isStandalone.ts`) that detects standalone PWA mode.
    - Mirror the existing detection logic from `components/install-prompt.tsx`:
    check `window.matchMedia('(display-mode: standalone)')` and the iOS-specific
    `navigator.standalone` property.
    - Export this so `components/chat.tsx` (and others) can consume it without
    duplicating logic.
    
    **Task 1.2 — Guard reload-inducing side effects in `components/chat.tsx`:**
    - Import and use the standalone detection helper/hook created in Task 1.1.
    - Gate the debounced `router.refresh()` effect (around lines 80–89) so it does
    **not** execute when running in standalone PWA mode; in that mode, rely solely
    on the existing in-memory `setMessages` updates.
    - Review the `window.history.replaceState` effect (around lines 73–76) that
    rewrites the URL to `/search/{id}`; if this triggers the service worker
    navigation handler to re-fetch and reload in standalone mode, defer or guard it
    for standalone mode while keeping deep-link/shareable URL behavior intact in the
    browser.
    - Ensure all non-PWA (desktop/browser) behavior remains unchanged.
    
    **Task 1.3 — Harden service worker takeover behavior in `app/sw.ts` (secondary
    defense):**
    - In `app/sw.ts`, review and reconsider `skipWaiting`/`clientsClaim` settings so
    a newly activated service worker does not forcibly claim and disrupt an open PWA
    session.
    - Review `navigationPreload: true` given inconsistent iOS Safari support —
    consider disabling or conditionally applying it.
    - In `components/sw-update-notification.tsx`, confirm that any reload triggered
    by a SW update only fires on an explicit user-driven action, not implicitly
    during an active chat session.
    - These are defensive adjustments; the primary fix is in Task 1.2.
    ===============================================================================
    
    Task: 2
    
    This phase corrects the AI's interpretation of app-specific questions so that
    "the computer" / "planet computer" is understood as QCX-Terra rather than a
    generic desktop machine.
    
    **Task 2.1 — Strengthen the default system prompt in
    `lib/agents/researcher.tsx`:**
    - Locate the `getDefaultSystemPrompt` function in `lib/agents/researcher.tsx`.
    - Add explicit product context stating that within this app, "the computer" and
    "planet computer" refer to QCX-Terra.
    - Specify that questions like "How do I use the computer?" must be answered as
    app-usage/onboarding guidance for QCX-Terra, not as a generic computer question.
    - Extend the existing "Pre-configured Responses" section of the prompt to cover
    the "How do I use the computer?" intent, so the model produces an app-onboarding
    style answer.
    - Ensure these additions only affect the default prompt path — per-user custom
    prompts (`dynamicSystemPrompt`) must continue to take precedence and remain
    unchanged.
    
    **Task 2.2 — Verify the preset question routes through the corrected path:**
    - Trace the "How do I use the computer?" preset from
    `components/empty-screen.tsx` through `submit()` in `app/actions.tsx` to
    `researcher()` in `lib/agents/researcher.tsx`.
    - Confirm no existing logic (e.g., an exact-match bypass) intercepts or
    short-circuits this query before it reaches the updated system prompt.
    - If no code changes are needed after Task 2.1 (i.e., the flow is already
    correct), document the confirmation.
    - Optionally, if additional certainty is desired, add the exact phrasing to the
    existing hardcoded bypass pattern in `app/actions.tsx` (around lines 272–325) as
    a fallback only — the system-prompt fix from Task 2.1 remains the primary
    mechanism.
    
    💡 Iterate on the plan with: `@coderabbitai` <feedback>
    Example Feedback
    - `@coderabbitai` You can skip phase 3. Add a simple unit test case for phase 2.
    - `@coderabbitai` For design choice 1 go ahead with option 3 and replan.
    

    💬 Have feedback or questions? Drop into our discord!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions