Skip to content

fix(queue): stop rich merge-queue row from freezing the page#535

Merged
mergify[bot] merged 2 commits into
mainfrom
devs/fix-rich-row-freeze-loop
Jun 9, 2026
Merged

fix(queue): stop rich merge-queue row from freezing the page#535
mergify[bot] merged 2 commits into
mainfrom
devs/fix-rich-row-freeze-loop

Conversation

@kozlek

@kozlek kozlek commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Problem

On PRs with an engine merge-queue payload comment (e.g. queued PRs like monorepo#34031), the page froze: clicking anything in the Mergify row — Remove from merge queue, Refresh, Rebase, Update, the Mergify brand — did nothing, as if the click never registered.

Root cause

updateAllMergifyRows() runs on every tryInject tick, which fires from the body MutationObserver. The rich-row path in updateMergifyRow called row.replaceChildren(...) unconditionally. That swap is itself a tree mutation in the observed subtree, so it re-triggered the observer in a self-sustaining requestAnimationFrame loop:

MutationObserver → tryInject → updateAllMergifyRows → replaceChildren → (mutation) → MutationObserver → …

The loop pegged the main thread and rebuilt the row's buttons ~60×/sec, so a click could never survive mousedown → mouseup on the same node.

Why only "some PRs": the legacy row path is already idempotent, and the context panel + stack-nav pill both dedup via data-mergify-hash. The rich row (added in #522) was the one surface missing that guard.

Fix

Give the rich row the same data-mergify-hash dedup used elsewhere in the codebase. updateMergifyRow now skips the children swap when the payload-derived fingerprint is unchanged. Live ETA text is intentionally excluded from the hash, since the ETA ticker already refreshes it on a 1s cadence by touching only [data-mergify-eta].

Tests

  • New regression test reproduces the bug via MutationObserver.takeRecords(): a no-op rich-row update emitted 2 mutation records before the fix, 0 after.
  • A companion test confirms a real state change (checking → frozen) still rebuilds, so the guard isn't over-aggressive.
  • Full suite: 244/244 pass; Biome lint clean; esbuild bundle compiles.

🤖 Generated with Claude Code

On PRs with an engine merge-queue payload comment, the page froze and
every button in the Mergify row (Remove from merge queue, Refresh,
Rebase, Update, brand link) stopped responding to clicks.

Root cause: updateAllMergifyRows() runs on every tryInject tick, which
fires from the body MutationObserver. The rich-row path in
updateMergifyRow called row.replaceChildren(...) unconditionally — and
that swap is itself a tree mutation in the observed subtree, so it
re-triggered the observer in a self-sustaining requestAnimationFrame
loop. The loop pegged the main thread and rebuilt the row's buttons
~60x/sec, so clicks never survived mousedown -> mouseup on the same node.

Only "some PRs" were affected because the legacy row path is already
idempotent and the context panel / stack-nav pill both dedup via
data-mergify-hash; the rich row (added in #522) was the one surface
missing that guard.

Fix: give the rich row the same data-mergify-hash dedup. updateMergifyRow
now skips the children swap when the payload-derived fingerprint is
unchanged. Live ETA text is excluded from the hash since the ETA ticker
already owns it on a 1s cadence.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: Ic45d555b676693cf784cad6b526500272c6f419d
Copilot AI review requested due to automatic review settings June 9, 2026 07:56
@mergify mergify Bot had a problem deploying to Mergify Merge Protections June 9, 2026 07:56 Failure
@mergify

mergify Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

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,})

@mergify mergify Bot requested a review from a team June 9, 2026 07:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Prevents the “rich” merge-queue row from continuously rebuilding itself (and thereby freezing the page / eating clicks) by making rich-row updates idempotent when the underlying payload hasn’t changed.

Changes:

  • Add a data-mergify-hash fingerprint to rich rows and skip replaceChildren(...) when the fingerprint matches.
  • Introduce _richRowHash(...) to compute a stable payload-derived hash (excluding live ETA text).
  • Add regression tests asserting that no-op rich-row updates produce zero DOM mutations while real state changes still rebuild.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/queue.js Adds rich-row hash + idempotency guard to avoid self-triggered MutationObserver loops.
src/tests/queue.test.js Adds regression coverage for the rich-row freeze/idempotency behavior.

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

Comment thread src/queue.js
The queue/logs links and the merged-message easter egg are all keyed on
the PR number, but _richRowHash() omitted it. Two same-state queued PRs
in one org/repo hashed identically, so a rich row reused across an SPA
navigation (resetForNavigation doesn't remove the merge-box row) would
skip the swap and keep the previous PR's links/message.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Change-Id: I3f097c5f46b1e505a41cc434d04dfa2126e1f990
@mergify mergify Bot deployed to Mergify Merge Protections June 9, 2026 08:07 Active
@jd jd requested a review from a team June 9, 2026 08:58
@mergify

mergify Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

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

Required conditions to merge

mergify Bot added a commit that referenced this pull request Jun 9, 2026
@mergify mergify Bot added the queued label Jun 9, 2026
@mergify mergify Bot merged commit 0612bb6 into main Jun 9, 2026
4 checks passed
@mergify mergify Bot deleted the devs/fix-rich-row-freeze-loop branch June 9, 2026 09:27
@mergify mergify Bot removed the queued label Jun 9, 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