Skip to content

Fix mobile PWA reflow and avoid redundant session refresh#3976

Open
ksj5131513-ops wants to merge 1 commit into
nesquena:masterfrom
ksj5131513-ops:fix/mobile-pwa-reflow-refresh
Open

Fix mobile PWA reflow and avoid redundant session refresh#3976
ksj5131513-ops wants to merge 1 commit into
nesquena:masterfrom
ksj5131513-ops:fix/mobile-pwa-reflow-refresh

Conversation

@ksj5131513-ops

Copy link
Copy Markdown

Summary

  • avoid an unnecessary same-session force reload when idle reconciliation runs after a stream settles
  • add a small mobile viewport reflow guard for PWA visualViewport changes
  • tighten mobile safe-area and horizontal overflow protection in the main layout

Why

On mobile PWA installs, the active conversation could visibly flash at end-of-turn when idle reconciliation immediately force-reloaded the same session. In the same environment, viewport/compositor changes could also leave the layout slightly clipped on the left until a manual scroll or repaint corrected it.

Changes

  • in static/sessions.js, prefer
    efreshActiveSessionIfExternallyUpdated('idle-reconcile') before falling back to a same-session force reload
  • in static/boot.js, add a mobile-only viewport reflow helper and trigger it on window resize and �isualViewport resize/scroll changes
  • in static/style.css, add horizontal overflow protection on .layout and apply mobile safe-area-aware padding to the topbar, messages container, and composer shell

Notes

  • this PR intentionally does not change static/manifest.json
  • the local manifest orientation adjustment was useful for device-specific testing but is left out here because it is a product-policy choice rather than a general bug fix

@greptile-apps

greptile-apps Bot commented Jun 11, 2026

Copy link
Copy Markdown

Greptile Summary

This PR addresses two mobile PWA regressions: an end-of-turn visible flash caused by an unconditional forced session reload during idle reconciliation, and a layout-clipping issue triggered by visualViewport compositor changes. The approach is to probe server metadata first and only force a full reload when data has actually changed, while adding a CSS-driven reflow nudge and safe-area padding for the affected UI regions.

  • sessions.js: Extracts a new _probeActiveSessionServerFreshness helper that compares local vs. remote message_count/last_message_at before deciding whether to call loadSession; refreshActiveSessionIfExternallyUpdated becomes a thin wrapper preserving its original external-session-only guard.
  • boot.js: Adds _forceMobileViewportReflow (GPU-promoted repaint via translateZ(0) class toggle + offsetWidth flush), debounced on visualViewport events and synchronously on window.resize when visualViewport is absent.
  • style.css: Applies overflow-x:hidden and transform:translateZ(0) reflow class to .layout, and env(safe-area-inset-*) padding to topbar, messages container, and composer, all scoped to @media(max-width:640px).

Confidence Score: 4/5

Safe to merge with one logic fix: loadSession failures inside the probe incorrectly trigger a second loadSession call in the idle-reconcile path.

The catch in _probeActiveSessionServerFreshness wraps both the metadata api() call and the inner loadSession call. A loadSession throw returns 'failed', which causes _scheduleActiveSessionIdleReload to fire loadSession a second time — an unintended retry loop absent in the original code. The mobile CSS and reflow changes are well-scoped and low-risk.

static/sessions.js — specifically the single try/catch in _probeActiveSessionServerFreshness that conflates fetch errors with reload errors.

Important Files Changed

Filename Overview
static/sessions.js Refactors idle-reconcile path to probe server metadata before forcing a reload; introduces _probeActiveSessionServerFreshness but its catch block conflates API errors with loadSession errors, which can cause a double reload.
static/boot.js Adds _forceMobileViewportReflow helper, wires it to visualViewport resize/scroll (debounced) and window.resize (synchronous when no visualViewport); debouncing asymmetry on old browsers is a pre-existing thread concern.
static/style.css Adds GPU-promoted reflow class, overflow-x guard, and safe-area-aware padding for mobile PWA; all changes are scoped to @media(max-width:640px).

Sequence Diagram

sequenceDiagram
    participant Stream as Streaming "done" event
    participant FinalizeStream as _finalizeStreamingSession
    participant IdleReload as _scheduleActiveSessionIdleReload
    participant Probe as _probeActiveSessionServerFreshness
    participant API as /api/session (metadata)
    participant LoadSession as loadSession

    Stream->>FinalizeStream: "sets _streamJustFinished=true"
    FinalizeStream->>IdleReload: setTimeout(0)
    IdleReload->>Probe: allowNative:true, ignoreStreamJustFinished:true
    Probe->>API: fetch message_count / last_message_at
    alt API error (network/timeout)
        API-->>Probe: throws
        Probe-->>IdleReload: 'failed'
        IdleReload->>LoadSession: force reload (fallback)
        note over LoadSession: if loadSession also throws,<br/>it was already counted as 'failed'<br/>double-call risk
    else remote newer than local
        API-->>Probe: newer data
        Probe->>LoadSession: force reload inside probe
        Probe-->>IdleReload: 'reloaded'
    else local is current
        API-->>Probe: same counts
        Probe-->>IdleReload: 'unchanged'
        note over IdleReload: no reload - flash avoided
    end
Loading

Reviews (3): Last reviewed commit: "Rebase mobile PWA refresh fix onto curre..." | Re-trigger Greptile

Comment thread static/sessions.js Outdated
Comment thread static/sessions.js Outdated
Comment thread static/boot.js
Comment thread static/style.css Outdated
@nesquena-hermes

Copy link
Copy Markdown
Collaborator

Thanks for this — the mobile PWA end-of-turn flash is a real annoyance and the visualViewport reflow approach is reasonable. Two things need sorting before it can be reviewed for merge:

1. Rebase needed — it overlaps code that just shipped. refreshActiveSessionIfExternallyUpdated was changed on master in v0.51.417 (#4195): it now early-returns for non-external sessions (if(!_isExternalSession(S.session)) return;) and the signature is (reason). Your PR changes the same function to (reason, opts={}) with an ignoreStreamJustFinished bypass and routes the idle-reconcile through it. After rebasing onto current master, please make sure the two changes compose correctly: your idle-reconcile path calls refreshActiveSessionIfExternallyUpdated('idle-reconcile', {ignoreStreamJustFinished:true}), which will now ALSO hit the new _isExternalSession guard — confirm that's the behavior you want (today your reconcile is meant to run for the just-finished turn regardless of source; the new guard would skip it for WebUI-native sessions). If you need it to run for native sessions too, the guard and the bypass need to be reconciled explicitly.

2. Settle-cooldown invariant + mobile evidence. This touches the post-stream cooldown (window._streamJustFinished) that exists specifically to avoid clobbering S.toolCalls/Activity right after a turn ends. Please confirm the ignoreStreamJustFinished:true path doesn't reintroduce that — and since this is a mobile-PWA visual fix, include before/after capture on a phone-width viewport (the flash is the thing to show gone).

Once it's rebased with the #4195 interaction resolved and has mobile before/after evidence, I'll run the full gate. Appreciate the contribution @ksj5131513-ops.

@nesquena-hermes nesquena-hermes added the changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address label Jun 14, 2026
@ksj5131513-ops ksj5131513-ops force-pushed the fix/mobile-pwa-reflow-refresh branch from 4a2378e to c32b80e Compare June 15, 2026 05:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changes-requested Maintainer left detailed feedback requesting changes; PR is waiting on author to address

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants