Skip to content

perf(extension): render stack surfaces from localStorage cache before network#479

Merged
mergify[bot] merged 1 commit into
mainfrom
devs/jd/feat/stack-context-cache/render-stack-surfaces-localstorage-cache-network--02898eca
May 22, 2026
Merged

perf(extension): render stack surfaces from localStorage cache before network#479
mergify[bot] merged 1 commit into
mainfrom
devs/jd/feat/stack-context-cache/render-stack-surfaces-localstorage-cache-network--02898eca

Conversation

@jd
Copy link
Copy Markdown
Member

@jd jd commented May 20, 2026

Mirror the merge-box queue-row speedup for the stack context panel and the
floating stack-nav pill. Previously both surfaces only appeared after
renderMergifyContext finished its full network walk:

  1. Find Mergify comment IDs (DOM scan or fetch the ~500KB Conversation HTML
    on the Files tab).
  2. Fetch each comment body (4 parallel workers).
  3. Parse stack + revision markers.

The in-memory caches (_commentBodyCache, _remoteCommentIdsCache) only
help within a single SPA session — they're lost on every hard reload, so
each cold load re-paid the full network walk before either surface drew
anything.

Add a localStorage-backed StackContextCache (1h TTL, keyed by
org/repo/PR) that stores the parsed stackData and revisionData
both already plain JSON-serializable objects produced by
parseStackMarker / parseRevisionMarker. renderMergifyContext now:

  • Reads the cache synchronously and, on hit, builds + injects the panel
    and nav immediately. The surfaces are on screen before the comment
    fetches even start.
  • Continues the existing network refresh path. injectContextPanel
    and injectStackNav already dedupe via data-mergify-hash, so when
    the fresh data matches the cached render the second injection is a
    no-op. When it differs, the surfaces are swapped in place.
  • Invalidates the cache when the fresh fetch reports no Mergify
    comments or no panel content, so a stale entry doesn't keep showing
    after the stack is dismantled upstream.

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

Copilot AI review requested due to automatic review settings May 20, 2026 13:21
@mergify mergify Bot had a problem deploying to Mergify Merge Protections May 20, 2026 13:21 Failure
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 20, 2026

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟢 Required Reviews

Wonderful, this rule succeeded.
  • any of:
    • #approved-reviews-by >= 2
    • author = dependabot[bot]

🟢 Enforce conventional commit

Wonderful, this rule succeeded.

Make sure that we follow https://www.conventionalcommits.org/en/v1.0.0/

  • title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert|ui)(?:\(.+\))?:

🟢 🔎 Reviews

Wonderful, this rule succeeded.
  • #changes-requested-reviews-by = 0
  • #review-requested = 0
  • #review-threads-unresolved = 0

🟢 📕 PR description

Wonderful, this rule succeeded.
  • body ~= (?ms:.{48,})

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a localStorage-backed cache to render the Mergify stack context panel and floating stack navigation pill immediately on cold loads, then refreshes from the network and updates the cache.

Changes:

  • Introduce StackContextCache (localStorage, 1h TTL) to persist parsed stack + revision data by org/repo/PR.
  • Update renderMergifyContext to render from cache synchronously before starting the network comment walk, then refresh and update/invalidate the cache.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/stacks.js Uses StackContextCache for cache-first rendering and cache update/invalidation during renderMergifyContext.
src/cache.js Adds StackContextCache implementation backed by localStorage with TTL and remove/update helpers.
Comments suppressed due to low confidence (2)

src/stacks.js:758

  • Cache invalidation on !panel is potentially too aggressive: parseStackMarker can return null for transient reasons (e.g., it explicitly rejects markers that don't match the current PR when stale DOM IDs are fetched during SPA navigation). In that case, removing the localStorage entry discards the last-known-good cache and defeats the cache-first speedup on the next tick. Consider only removing the cache when you have a strong signal the stack is gone (e.g., bodies.length === 0 or none of the fetched bodies contain either marker prefix), and otherwise keep the cached entry while still removing surfaces for this tick.
    const stackData = parseStackMarker(bodies, currentPull.number);
    const revisionData = parseRevisionMarker(bodies, currentPull.number);
    const panel = buildContextPanel(stackData, revisionData, currentPull);
    if (!panel) {
        _stackContextCache.remove(
            currentPull.org,
            currentPull.repo,
            currentPull.number,
        );
        removeContextSurfaces(currentPull);

src/cache.js:132

  • get() treats entries with a missing/invalid timestamp as non-expiring because Date.now() - data.timestamp becomes NaN and the TTL check never triggers. It would be safer to validate timestamp is a finite number and treat anything else as expired (removing the key) to avoid sticky stale cache entries.
        try {
            const raw = localStorage.getItem(k);
            if (!raw) return null;
            const data = JSON.parse(raw);
            if (Date.now() - data.timestamp > this.expirationMs) {
                localStorage.removeItem(k);
                return null;
            }
            return {
                stackData: data.stackData ?? null,
                revisionData: data.revisionData ?? null,
            };

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/stacks.js Outdated
Comment thread src/cache.js
Comment thread src/cache.js
… network

Mirror the merge-box queue-row speedup for the stack context panel and the
floating stack-nav pill. Previously both surfaces only appeared after
`renderMergifyContext` finished its full network walk:

  1. Find Mergify comment IDs (DOM scan or fetch the ~500KB Conversation HTML
     on the Files tab).
  2. Fetch each comment body (4 parallel workers).
  3. Parse stack + revision markers.

The in-memory caches (`_commentBodyCache`, `_remoteCommentIdsCache`) only
help within a single SPA session — they're lost on every hard reload, so
each cold load re-paid the full network walk before either surface drew
anything.

Add a localStorage-backed `StackContextCache` (1h TTL, keyed by
org/repo/PR) that stores the parsed `stackData` and `revisionData` —
both already plain JSON-serializable objects produced by
`parseStackMarker` / `parseRevisionMarker`. `renderMergifyContext` now:

  - Reads the cache synchronously and, on hit, builds + injects the panel
    and nav immediately. The surfaces are on screen before the comment
    fetches even start.
  - Continues the existing network refresh path. `injectContextPanel`
    and `injectStackNav` already dedupe via `data-mergify-hash`, so when
    the fresh data matches the cached render the second injection is a
    no-op. When it differs, the surfaces are swapped in place.
  - Invalidates the cache when the fresh fetch reports no Mergify
    comments or no panel content, so a stale entry doesn't keep showing
    after the stack is dismantled upstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Change-Id: I02898eca47b9dfb1f7f19f8045120ba02d7eb64a
@jd jd force-pushed the devs/jd/feat/stack-context-cache/render-stack-surfaces-localstorage-cache-network--02898eca branch from ff77f7c to 6fe7f18 Compare May 20, 2026 13:58
@jd
Copy link
Copy Markdown
Member Author

jd commented May 20, 2026

Revision history

# Type Changes Reason Date
1 initial ff77f7c 2026-05-20 13:58 UTC
2 content ff77f7c → 6fe7f18 (raw) address review #479: wrap cache-first render in try/catch and discard the entry on shape mismatch (Copilot gc6Dfqot); export StackContextCache and add 7 unit tests mirroring PrStatusCache coverage (C… 2026-05-20 13:58 UTC

@mergify mergify Bot deployed to Mergify Merge Protections May 20, 2026 13:58 Active
@jd jd marked this pull request as ready for review May 20, 2026 14:41
@mergify mergify Bot requested a review from a team May 20, 2026 14:43
@jd jd requested a review from a team May 22, 2026 14:11
@mergify
Copy link
Copy Markdown
Contributor

mergify Bot commented May 22, 2026

Merge Queue Status

This pull request spent 2 minutes 18 seconds in the queue, including 1 minute 30 seconds running CI.

Required conditions to merge

mergify Bot added a commit that referenced this pull request May 22, 2026
@mergify mergify Bot added the queued label May 22, 2026
@mergify mergify Bot merged commit 210b558 into main May 22, 2026
4 of 6 checks passed
@mergify mergify Bot deleted the devs/jd/feat/stack-context-cache/render-stack-surfaces-localstorage-cache-network--02898eca branch May 22, 2026 15:07
@mergify mergify Bot removed the queued label May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants