Skip to content

fix: prevent stale personalized cache and preserve page edits#436

Draft
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-74e6
Draft

fix: prevent stale personalized cache and preserve page edits#436
cursor[bot] wants to merge 1 commit into
mainfrom
cursor/critical-bug-investigation-74e6

Conversation

@cursor

@cursor cursor Bot commented Jun 13, 2026

Copy link
Copy Markdown

Summary

  • Prevent the service worker from caching /, /auth, private/no-store/no-cache responses, or Set-Cookie responses; bump the SW cache version to evict previously cached personalized home HTML.
  • Render moderation page-fixer thumbnails against the saved edited PDF baseline with only the pending reorder/rotation delta applied.
  • Include saved pageEdits in course paper list data and pass them into split-view PDF rendering/markdown extraction.

Bug and impact

  • A signed-in user's personalized home HTML could be cached by the service worker and shown after sign-out or account switch, leaking stale user identity.
  • Page-fixer thumbnails for papers with saved reorder/rotation fixes could show the wrong page or double-rotated page, leading moderators to save corrupt page metadata.
  • Split-view PDF rendering omitted saved page fixes, so users could see and extract markdown from the unfixed paper layout.

Root cause

  • The service worker cached credentialed navigation/prefetch responses without honoring route or response cacheability.
  • Thumbnail rendering used source page indices/absolute rotations even though the active PDF buffer already had saved page edits applied.
  • Course paper list rows did not carry pageEdits into the split-view item.

Validation

  • pnpm exec tsx -e ... targeted page-edit render mapping regression check passed.
  • node -e ... targeted service-worker cache guard check passed.
  • pnpm exec tsc --noEmit --pretty false passed.
  • pnpm build passed with local placeholder env and PostgreSQL service.
Open in Web View Automation 

Co-authored-by: theg1239 <theg1239@users.noreply.github.com>
@vercel

vercel Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
examcooker-dev Error Error Jun 13, 2026 11:14am

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes three related bugs: stale personalized HTML being served by the service worker after sign-out, incorrect thumbnails in the moderation page-fixer when saved page edits exist, and split-view PDF rendering ignoring saved page fixes.

  • Service worker hardening: adds isCacheableResponse to block responses with Cache-Control: private/no-store/no-cache or Set-Cookie headers from being written to the page cache; excludes / and /auth exactly via NO_CACHE_PATH_EXACT; bumps the cache version to v4 to evict previously cached personalized HTML.
  • Thumbnail rendering fix: introduces getPdfPageRenderEntry in lib/pdf/page-edits.ts to compute the correct page index and incremental rotation delta against the already-processed (baseline-edited) PDF buffer, preventing double-rotation and wrong-page thumbnails in the moderator UI.
  • Split-view data flow: threads pageEdits from the DB query through CoursePaperListItemPaperSplitItemPDFViewerClient, with a Redis cache key bump (course-paper-rows-v2) to invalidate entries missing the new field.

Confidence Score: 4/5

Safe to merge — all three bugs are addressed by well-scoped, targeted changes with no regressions in the data flow or rendering paths.

The service worker changes correctly guard all write sites except one: the background-refresh branch inside cacheFirst's cache-hit path still uses the old response.ok && !opaque check. For static assets this is benign in practice, but it leaves a small gap in the consistency of the new isCacheableResponse contract. The PDF page-edit and split-view changes look correct and the Redis cache key bump ensures old entries are evicted.

public/sw.js — the cacheFirst background-refresh write at line 185 was not updated to use isCacheableResponse.

Important Files Changed

Filename Overview
public/sw.js Adds isCacheableResponse to block private/no-store/set-cookie responses from the page cache; adds NO_CACHE_PATH_EXACT for / and /auth; bumps CACHE_VERSION to v4. The cacheFirst background-refresh path (hit branch, line 185) still uses the old ok+!opaque guard instead of isCacheableResponse — minor inconsistency for static assets.
lib/pdf/page-edits.ts Adds getPdfPageRenderEntry and toPdfPageRotation helpers to compute the correct page index and rotation delta against a baseline-edited PDF buffer. Logic correctly handles negative deltas via modular normalization and falls back safely when baselineEntry is not found.
app/components/moderation/past-paper-page-editor.tsx Threads baselinePageEdits down to PageEntryCard and uses getPdfPageRenderEntry to derive the correct pageIndex/rotation for PdfPageThumbnail against the already-processed PDF buffer. Change is well-scoped and memoized correctly.
lib/data/course-papers.ts Adds pageEdits to the DB select projection and CoursePaperListItem type; bumps Redis cache key to course-paper-rows-v2 to invalidate entries missing the new field. Clean and correct.
app/components/past_papers/paper-split-view.tsx Adds pageEdits to PaperSplitItem and forwards it to PDFViewerClient, completing the data flow from the DB through to split-view rendering. Straightforward type and prop addition.
app/components/past_papers/course-paper-grid.tsx Passes paper.pageEdits into the PaperSplitItem mapping. One-line addition that correctly connects the data layer field to the split-view consumer.
app/components/past_papers/course-paper-card.tsx Adds pageEdits to the Paper prop type to match the updated CoursePaperListItem. Type-only change, no logic impact.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["SW fetch event (navigate/HTML)"] --> B{isUncacheable?}
    B -- "/ or /auth or /api/..." --> C[Pass through — no cache]
    B -- No --> D[staleWhileRevalidate]
    D --> E[Fetch network response]
    E --> F{isCacheableResponse?}
    F -- "private/no-store/no-cache/set-cookie" --> G[Discard — not cached]
    F -- Yes --> H[Write to PAGE_CACHE]
Loading

Comments Outside Diff (1)

  1. public/sw.js, line 183-191 (link)

    P2 Inconsistent cache guard in cacheFirst background-refresh path

    The cacheFirst hit path still uses the old response.ok && response.type !== "opaque" guard on its background-refresh write (line 185), while all other write sites in this PR were updated to use isCacheableResponse. If a static asset somehow starts returning a private or set-cookie response, this path would cache it. The two miss-path writes (staleWhileRevalidate and the miss branch of cacheFirst) were correctly updated, but this hit-path branch was overlooked.

    Fix in Codex Fix in Claude Code Fix in Cursor

Fix All in Codex Fix All in Claude Code Fix All in Cursor

Reviews (1): Last reviewed commit: "fix: prevent stale personalized cache an..." | Re-trigger Greptile

Comment thread public/sw.js
@@ -1,4 +1,4 @@
const CACHE_VERSION = "v3";
const CACHE_VERSION = "v4";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Commit message style

The PR title reads well as a conventional commit, but individual commit messages in this branch would benefit from being more descriptive — stating why each change was made, not just what changed (e.g., "bump SW cache version to v4 to evict stale user-personalized page cache" rather than just a generic description). This makes bisecting and blame much easier for the team.

Context Used: Encourage people to write better commit messages (source)

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!

Fix in Codex Fix in Claude Code Fix in Cursor

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.

1 participant