Skip to content

Gallery: keep the previous preview through frame swaps - #18345

Merged
teamleaderleo merged 24 commits into
feat-cmux-nextfrom
fix/next-gallery-white-flash
Oct 10, 2026
Merged

teamleaderleo merged 24 commits into
feat-cmux-nextfrom
fix/next-gallery-white-flash

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 7, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Keep the last painted gallery preview visible while a new variant, theme, or control state loads. The incoming frame stays hidden until the stage reports ready, and the neutral frame background follows the shell theme.

Changelog

  • Fixed: gallery previews no longer flash white between frame swaps.

Proof

Validation

  • git diff --check
  • Hosted web checks on the exact pushed head

View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Keeps the previous gallery preview visible until the new frame reports ready, so the preview no longer flashes white when switching variant, theme, or control state.

  • The incoming frame loads hidden and only replaces the visible one after the stage signals ready or error.
  • Stale ready messages are discarded by matching the frame's query and run; frame refs stay stable across swaps.
  • The single-variant stage keeps a stable key so it is not remounted between variant changes.
  • The frame background now follows the shell theme instead of white.
  • Scroll position is restored when the new frame takes over the stage.
  • Component frames keep natural bounds; only page frames inherit the scaled window.
  • The gallery matrix now also renders narrow responsive widthsholistically and shards the render stages.

Written for commit 347d3de. Summary will update on new commits.

View guided diff Turn on auto-fix


Note

Medium Risk
Changes PR merge gates (Swift canary, cmux-tui tree fallback, rustfmt) and Mac runner placement; gallery and pre-commit edits are lower risk.

Overview
Gallery previews no longer flash white when variant, theme, or controls change: Stage loads the next frame.html in a hidden iframe and swaps only after cmux-gallery-stage reports ready/error (matched by query and run), with a stable stage key in variant view and a themed frame background.

Gallery PR CI shards each render stage four ways, adds compact and normal pane widths to the matrix (deduping identical narrow/normal pixels), and merges shard results.json before compare.

cmux-tui formatting adds cmux-tui-fmt-changed.py plus unit tests and a rustfmt job in cmux-tui-spec.yml that runs cargo fmt --check only on packages touched by the diff (or all packages when rustfmt/toolchain changes). The pre-commit hook now formats staged webview files with vp fmt and staged cmux-tui Rust with rustfmt, skips formatters during merges, and documents the behavior in CONTRIBUTING.md.

cmux-next CI introduces a Swift canary job (debug swift build --target for small package-only Swift diffs) as the PR gate while Release compile stays advisory on that class; routing adds swift_canary outputs. PRs that do not touch cmux-tui/ or ghostty-next can use CMUX_TUI_TREE_BASE_FALLBACK so daemon/scheme jobs fetch the newest published tree instead of failing on an unpublished merge tree. Mac jobs keep side-lane placement through bot attempt 3; attempt 4 drops to Blacksmith. Published manifest verification retries remote binary digest checks with cache-busted URLs. Nightly publish bounds the release-notes step with its own timeout.

Reviewed by Cursor Bugbot for commit 347d3de. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: fa216596-932f-4988-bc11-b46c6f78e3bc

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Passes: CI passes on 347d3dead8.

CI passes on 347d3dead8 (run 38017541452 attempt 1).

Written by scripts/ci/classify_failures.py (ci-failure-attribution.yml); signatures are its SIGNATURES table. A machine verdict is the runner's fault, not this PR's; yours means the failing file is one this PR changes, also red on main that main's latest full suite fails the same way, seen on other PRs that it failed on another pull request's run lately.

@cursor cursor Bot 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.

Stale Bugbot comment from a previous run.

Comment thread webviews/src/gallery/shell/Stage.tsx Outdated
Comment thread webviews/src/gallery/shell/Stage.tsx
Comment thread webviews/src/gallery/shell/Stage.tsx Outdated
@blacksmith-sh

This comment has been minimized.

@cursor cursor Bot 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.

Stale Bugbot comment from a previous run.

? current
: requested,
);
}, [display.query, display.run, frameHeight, frameWidth, query, run, scale]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale play report after swap

Low Severity

Variant view now reuses Stage across swaps, but report is never cleared when query or run change. After a new frame is promoted, the previous variant's play metrics can stay visible, especially when the incoming variant has no play and never posts a replacement.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 402a9fe. Configure here.

@blacksmith-sh

This comment has been minimized.

@cursor cursor Bot 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.

Stale Bugbot comment from a previous run.

Comment thread webviews/src/gallery/shell/Stage.tsx
stages.map((stage) => (
<Stage
key={stage.key}
key={search.view === "variant" ? "stage" : stage.key}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Play report persists across variants

Low Severity

The variant-view Stage now keeps a stable key, but report is never cleared when query changes. The previous variant’s play metrics stay in the caption, and they remain indefinitely when the next variant has no play and never sends a replacement report.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 1e46b26. Configure here.

teamleaderleo and others added 11 commits October 8, 2026 14:07
* ci: format staged files in the trusted pre-commit hook

* ci: guard formatter scope for staged files

* ci: scope Rust formatter guard to its package

* ci: use direct rustfmt and skip merge formatting

* ci: pass the cmux-tui Rust edition to rustfmt
* test(ci): red test, PRs check rustfmt on the cmux-tui packages they touch

PR CI never runs cmux-tui.yml (dispatch only), so #18706 landed
unformatted Rust and broke base cargo fmt --check. These tests pin a
helper that runs cargo fmt --check once per touched package, checks
every package when a rustfmt config changes or there is no base, and
names each unformatted package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci: check rustfmt on the cmux-tui packages a PR touches

PR CI never runs cmux-tui.yml (dispatch only), so #18706 landed
unformatted Rust and broke base cargo fmt --check. cmux-tui-spec.yml
already runs on every PR and push touching cmux-tui/** on hosted Linux;
its new rustfmt job runs cmux-tui-fmt-changed.py, which maps each changed
.rs file or Cargo.toml to its nearest tracked package and runs cargo fmt
--check on it with the pinned toolchain. No build and no dependency
download. A rustfmt config or toolchain change, or no base, checks every
package; vendored crates and deleted packages are skipped. A PR compares
with its merge commit's first parent, a push with the commit before it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* style(cmux-tui): rustfmt acpmux's draft tests and the relay circuit

The new rustfmt job's full run found two base packages that fail
cargo fmt --check: acpmux, from #18706's draft tests and their module
order, and the Cloudflare relay's circuit.rs. Formatting only, exactly
the hosted rustfmt diff.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* style(cmux-tui): leave the relay circuit to its own repair

Touching the Cloudflare relay runs its lane, whose npm audit is red on
base (sharp and undici advisories through wrangler, fixed only by a
wrangler bump outside the stated range). That is the relay's own repair,
so this PR keeps acpmux's formatting only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* ci: add mini-first Swift canary for cmux-next

* ci: remove unit tests from Swift canary change
…e cmux-tui (#18698)

* test(cmux-next): red: a PR that changes no cmux-tui fails same-tree on an unpublished merge tree

#16614, #17551 and #18605 change no cmux-tui or ghostty-next path, yet
same-tree cmux-tui failed them because the base tip's tree was never published
(its artifacts run was cancelled). Such a PR should reuse the newest published
tree in its history (tree_fetch_key, fetched through CMUX_TUI_TREE_KEY), or skip
the tree jobs when none is published, never fail.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(cmux-next): same-tree cmux-tui is a hard check only for PRs that change cmux-tui

Path routing records whether the pull request's own diff touches cmux-tui/ or
ghostty-next. For one that does not, a merge tree that is not ready no longer
fails: the probe (CMUX_TUI_TREE_BASE_FALLBACK=1) resolves the newest published
tree in the merge's history and reports ready with tree_fetch_key, which the
daemon tests and the Debug scheme compile fetch through CMUX_TUI_TREE_KEY; with
none published it reports skipped. Pushes, dispatches and PRs that change
cmux-tui keep the hard check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cmux-next): the newest-published search deepens only this commit's history

A bare `git fetch --deepen=50 origin` deepens every branch of origin: on this
PR's first run it took path routing past its 5-minute limit (job 113609407061)
before the probe's base fallback, which then resolved in under a second.
Deepening only HEAD takes about 30 s on a depth-2 clone of feat-cmux-next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* docs(cmux-next): map UI parity reference sources

* docs(cmux-next): add media preview reference source

* docs(cmux-next): define reference freshness checks
* test(nightly): the notes step cannot spend the publish budget before the upload (red)

Run 37611677848 spent 29 of publish-nightly's 30 minutes on release notes and
was cancelled mid-upload, leaving partial release assets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(nightly): bound the publish notes step at 10 minutes

The notes take seconds since 0115b26. A regression now fails the step
before any asset upload, instead of spending publish-nightly's 30 minutes and
being cancelled mid-upload with partial assets left on the release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…self (#17622)

* test(cmux-next): the cmux-tui gate pins and dispatches an unpublished tree itself

Publisher run 37505519359 failed transiently and its retry was replaced by a
newer feat-cmux-next push, so the tree was never published and lanes pushed
cmux-tui-pin-* branches by hand to unblock their gates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(cmux-next): the tree gate watches the base and may pin the tree

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(cmux-next): the cmux-tui gate pins and dispatches an unpublished tree

When two run checks find no artifacts run that will publish the tree, the
gate creates cmux-tui-pin-<key12> at the publisher commit and dispatches the
artifacts workflow there, once, then keeps waiting. A pull request now
watches its base commit (the merge's first parent) instead of no publisher,
so it neither waits 45 minutes for a tree nobody builds nor needs a lane to
push a pin branch by hand. A superseded push still skips; forks keep a
read-only token and no autopin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(cmux-tui): a transient wrong binary read must not fail publication

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cmux-tui): read a mismatched published binary again before failing

R2 objects are write-once, so a digest mismatch on a binary the run just
uploaded is a bad read. Fetch it again from a cache-busting URL up to
three times, and name the response headers when it still differs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(cmux-next): a pull request gate pins a tree its base never builds

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(cmux-next): a pull request gate pins a tree its base never builds

A pull request that changes cmux-tui has a merge tree no push builds,
and the artifacts workflow's pull_request_target trigger has never
started a run, so its gate waited 45 minutes with the run check off.
With CMUX_TUI_TREE_AUTOPIN the gate now pins its own checkout at once
and watches that run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci(cmux-next): retain base tree dispatch tests

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* ci(gallery): capture narrow responsive states

* test(gallery): cover workflow matrix changes

* fix(gallery): dedupe equal responsive widths

* ci: shard gallery matrix renders

* ci: retrigger sharded gallery validation
Stage.tsx: kept useRef for the frame swap alongside base's useEffect
(useRoom now an effect).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@cursor cursor Bot 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 347d3de. Configure here.

contents: read
timeout-minutes: 20
env:
CMUX_NEXT_RUNNER: ${{ needs.macos-placement.outputs.runner || github.repository_owner != 'manaflow-ai' && 'macos-26' || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository && 'blacksmith-6vcpu-macos-26' || vars.CI_PR_POOL_OWNED == '1' && contains(fromJSON('["pull_request","push","workflow_dispatch"]'), github.event_name) && (github.run_attempt <= 2 || github.triggering_actor != 'github-actions[bot]') && vars.CI_SIDE_LANE_RUNNER || vars.MACOS_RUNNER_26 || 'blacksmith-6vcpu-macos-26') }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Canary skips overflow runner fallback

Medium Severity

swift-canary still uses the old runs-on / CMUX_NEXT_RUNNER expression, so a bot re-run keeps macos-placement's mini label on attempts 4 and later. The other Mac jobs now drop that label after attempt 3. A mini refusal can leave the canary queued instead of moving to Blacksmith.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 347d3de. Configure here.

@teamleaderleo
teamleaderleo merged commit 55b55dd into feat-cmux-next Oct 10, 2026
84 of 88 checks passed
@teamleaderleo
teamleaderleo deleted the fix/next-gallery-white-flash branch October 10, 2026 02:56
@github-actions

Copy link
Copy Markdown
Contributor

Gallery

Review in feed

No state changed · 3766 removed states · 14 broken states · 16 play checks failed

Diff page and renders (the run's gallery-pr artifact)

Play checks failed (0 px anchor movement, 0 layout shift, no frame over 33 ms unless the entry gives a reason):

  • agent-pane.chat-gallery/renders (Apple System Colors Light, chromium): step 3 click button "Renders 2": layout shift 0.1338 (limit 0.1)
  • agent-pane.chat-gallery/renders (Apple System Colors, chromium): step 3 click button "Renders 2": layout shift 0.1338 (limit 0.1)
  • agent-pane.composer/image-attached (Apple System Colors Light, chromium): step 1 hover .acpmux-attachment-image: layout shift 0.0902 (limit 0)
  • agent-pane.composer/image-attached (Apple System Colors Light, chromium): step 1 hover .acpmux-attachment-image: layout shift 0.0498 (limit 0)
  • agent-pane.composer/image-attached (Apple System Colors, chromium): step 1 hover .acpmux-attachment-image: layout shift 0.0902 (limit 0)
  • agent-pane.composer/image-attached (Apple System Colors, chromium): step 1 hover .acpmux-attachment-image: layout shift 0.0498 (limit 0)
  • 75 more on the diff page

0 unchanged · base d808aa1 · head 347d3de

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