Skip to content

Fix stale Chromium composer page during pane holds - #28002

Merged
teamleaderleo merged 10 commits into
feat-cmux-nextfrom
lane/composer-native-ghost
Oct 30, 2026
Merged

teamleaderleo merged 10 commits into
feat-cmux-nextfrom
lane/composer-native-ghost

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Leo (2026-10-29): “Dude, I hate how the fing composer acts like this... Number one: the fing rendering is stupid as hell.”

The stale second composer came from a native Chromium page window surviving a paint hold. PanePaintHold hid the app view with alphaValue, but Chromium renders in a separate child window and AppKit does not propagate ancestor alpha to that window. The old page therefore stayed composited over the live chat. Launch images also remained valid across a pane resize even though their captured width was stale.

This PR synchronizes Chromium visibility with ancestor alpha during paint holds, release, and page attach/hide/unhide; queues host visibility when a CEF tab is concealed; and clears launch images when the pane content size changes or the live page paints. Focused regressions cover Chromium visibility, CEF conceal ordering, and launch-image resize invalidation.

Validation

  • python3 scripts/cmux-next/prepush-gate.py --base origin/feat-cmux-next --head HEAD — no new violations (existing warnings only).
  • Linux Swift package checks passed for portable packages; CmuxNext is macOS-only.
  • Focused CmuxNext suites are dispatched through the fleet route: PageWebViewChromiumTests, CEFDeferredTabShowTests, and LaunchFirstFrameRevealTests.

Proof

Before: the native hold made the app view transparent while its separate Chromium child window stayed visible, allowing an idle stale chat to cover the live composer.

After: hold transitions explicitly hide the Chromium page window, release re-shows only the incoming page, conceal queues the host hide, and a resize drops the old-size launch snapshot.

No capture: the native Chromium child-window lifecycle requires a fleet macOS build; the focused fleet tests provide the regression evidence.

Agent session: agent session

Agent session: agent session

@github-actions github-actions Bot added the risk:normal Risk tier (docs/ci/risk-tiers.md) label Oct 30, 2026
@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

cmux status (one comment, edited in place; each line is updated by the job that owns it)

Review 3740ab4: HQ feed card · gallery before/after runs · checks

App of this head (app.zip, kept 1 day)

gh workflow run reload-build.yml -R manaflow-ai/cmux --ref feat-cmux-next -f tag=pr28002 -f ref=lane/composer-native-ghost -f platform=macos -f backend_mode=local

web and size checks: green

@blacksmith-sh

blacksmith-sh Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Found 2 test failures on Blacksmith runners:

Failures

Test View Logs
test_every_listed_hook_is_one_glaeda_released_with_the_check (main.SigningHooksInSt
epWithGlaedaTests.test_every_listed_hook_is_one_glaeda_released_with_the_check)/
test_every_listed_hook_is_one_glaeda_released_with_the_check (main.SigningHooksInSt
epWithGlaedaTests.test_every_listed_hook_is_one_glaeda_released_with_the_check)
View Logs
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)/
test_the_repository_highlights_validate (main.DigestTests.test_the_repository_highl
ights_validate)
View Logs

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

@teamleaderleo
teamleaderleo force-pushed the lane/composer-native-ghost branch from 429d734 to 164084e Compare October 30, 2026 06:52
@cursor

cursor Bot commented Oct 30, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@cursor

cursor Bot commented Oct 30, 2026

Copy link
Copy Markdown

Bugbot needs on-demand usage enabled

Bugbot uses usage-based billing for this team and requires on-demand usage to be enabled.

A team admin can enable on-demand usage in the Cursor dashboard.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Review (codex gpt-6-astra high, next-review): BLOCK at 799d1e3

  • Packages/macOS/CmuxNext/Sources/CmuxNextPages/PageWebView+Chromium.swift:16-19 — Chromium visibility is sampled when setChromiumVisibility is called, but the agent loading flow changes PageWebView.alphaValue from 0 to 1 without calling it. If Chromium attaches while the loading cover is active, it receives setVisible(false) and can remain hidden after the page is revealed; a fresh pane has no paint-hold callback to restore it.

  • Packages/macOS/CmuxNext/Sources/CmuxNextApp/AgentTabContent.swift:84-87 — PageWebView.whenPainted fires on the generic document paint probe before the agent’s pane.painted handshake/chat-ready signal. This clears the saved launch image while the agent page is still intentionally transparent, and the clear callback re-enables the loading state, causing a visible loading/blank gap during slow attach.

@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

SHIP: independent Astra review at exact head d1df487. Reviewed Chromium visibility during paint holds, CEF conceal ordering, launch reveal/resize lifecycle, and regression coverage; prior P1s fixed in this head.

PageWebViewChromiumTests' new alpha-visibility test builds an NSWindow; the
file imported only Foundation, so the CmuxNextPages test target failed to compile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo and others added 2 commits October 30, 2026 06:19
Exercise window-owned PanePaintHold, loading-state reveal, move covers and handoff through FakeChromiumPage visibility. Fleet red/green verification follows on the pushed commits; no tests run on this host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-35aad81d5881fa12f16a
Exercise window-owned PanePaintHold, loading-state reveal and move covers through FakeChromiumPage visibility. Fleet red/green verification follows on the pushed commits; no tests run on this host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-35aad81d5881fa12f16a
The shared PageWebView subtree sync now serves PanePaintHold begin, end, released outgoing and handoff, plus loading and move-cover alpha transitions. PaneContentView uses the shared traversal. Add a handoff detach/reuse regression.

Alpha audit of CmuxNextAgentPane and CmuxNextApp: loading/page and move-cover transitions and PanePaintHold are covered. NewTabSpareParking sets alpha zero before children exist; page attach/start derives visibility from that ancestor. Loading cover, toolbar/titlebar glass, labels and drag ghost views contain no PageWebView. Popup/window alpha is separate; WindowCloseMotion already propagates it to child windows.

Static Swift syntax and prepush-gate passed. No builds or tests on this host; focused fleet verification follows at the pushed SHA.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-35aad81d5881fa12f16a
Fleet job cbe2ca3ee493a09cef3072dc found AgentTabContent reading internal AgentPaneView.page, introduced before the alpha repair. Keep the page private to its target and provide a package-scoped paint callback with the same behavior so the focused suite can compile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-35aad81d5881fa12f16a
…cument paint

whenPagePainted forwarded to the page document probe, which fires before the
chat is read, so the launch image went while the page was still clear and the
empty loading state showed. It now waits on AgentPaneModel.whenPainted, the
gate the page is revealed on. The Chromium visibility window test keeps its
window (isReleasedWhenClosed = false), as other window tests do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teamleaderleo
teamleaderleo merged commit aeb3a6d into feat-cmux-next Oct 30, 2026
147 of 151 checks passed
@teamleaderleo
teamleaderleo deleted the lane/composer-native-ghost branch October 30, 2026 16:54
@teamleaderleo

Copy link
Copy Markdown
Collaborator Author

Before/after stills of the agent pane (the agent-pane tour; the composer scene fails to seed its agent turn both before and after this PR). Settled frames match, one composer each: the doubled composer only appeared during a pane or window hold, which the new AgentPaneChromiumVisibilityTests and PageWebViewChromiumTests cover.

After aeb3a6de053c

Light Dark
light dark

Before aead767cca64

Light Dark
light dark

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

teamleaderleo added a commit that referenced this pull request Oct 30, 2026
… frame (#28461)

* fix(pages): keep a Chromium page drawing while its pane waits for its frame

#28002 hid the Chromium page whenever any view up to it, itself included,
was transparent. The agent pane clears the page itself while it waits for
the first frame (loading state) or the next one (move cover), and a hidden
Chromium page draws no frame, so a new chat showed the loading spinner until
the 8-12 s give-up instead of its composer. Only ancestors alpha (pane and
window paint holds, the ghost-composer case) now hides the page.

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

* fix(pages): skip the page itself without an optional sequence start

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 31, 2026
…e paints) (#28980)

* test(new-tab): a parked Chromium spare keeps drawing in its off-screen parking

Red on base: the parking's alpha hides the Chromium page (#28002), so the
spare never paints before Cmd-T adopts it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-d750cf10922c785efa64

* perf(new-tab): let a parked Chromium spare paint before Cmd-T adopts it

#28002 hides a Chromium page whenever an ancestor is transparent. The New
Tab spare's parking view is transparent (and 100000 pt off screen) only to
stay out of sight, so a Chromium spare never painted while parked. Cmd-T
then adopted an unpainted page, the pane's paint hold hid it again, and the
New Tab page showed only at the hold's 500 ms limit. The parking now opts
out of that rule (PageChromiumOffscreenParking); paint holds still hide.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-d750cf10922c785efa64

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Nov 5, 2026
… drawing while it is held off screen (#32448)

* test(agent pane): a hidden adopted page still reports its paint (fails: it waits for a frame)

The page's pane.painted report moves to paintReport.ts unchanged (one frame,
then a task). paint-report.test.ts fails on it: a hidden document runs no
animation frames, so the report never comes (HQ#5914).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-14c3a892e82255726cbb

* cmux NEXT: an adopted spare page reports its paint while hidden, and existing chats take the spare again

The parked spare can be hidden (Chromium marks the page hidden), and a hidden
document runs no animation frames. The page's pane.painted waited for one, and
the host keeps an adopted page away and covered until that report: reopens held
the cover for the ~15 s give-up (HQ#5914; diag bench at 7d8c57e:
visibilityState hidden, last frame before the report was asked). A hidden page
now reports on a task, at once or when it goes hidden while it waits.

The chat-open trace counts an adopted page as drawn once its pane painted: its
first frame (page_painted) came before the trace, as New Tab, so every adopted
open read page_empty.

Turns adoption back on (#31486 switched it off).

paint-report.test.ts: red on the previous commit (2 fail), green here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-14c3a892e82255726cbb

* test(agent pane): an adopted page opens an unlisted chat with no list read beside its attach (fails)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-14c3a892e82255726cbb

* cmux NEXT: the adopted page reads the chat list again only when its attach fails

adoptSession read the whole list beside the attach, on the same socket; a busy
acpmux paces that list for seconds, and adopted reopens drew later than a cold
page (HQ#5914 bench). The list now decides only a failed attach, and only a list
that was read says the chat is missing (#31033's review follow-up).

spare-session-adopt.test.ts: 1 fail on the previous commit, 7 pass here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-14c3a892e82255726cbb

* test(agent pane): an adopted page held outside the window keeps drawing under the pane's paint hold (fails)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-23bb1f8ee2895ef522be

* cmux NEXT: an adopted page held outside the window keeps drawing under the pane's paint hold

The pane's paint hold makes its incoming view transparent, and a transparent
ancestor hides a Chromium page (#28002). An adopted New Tab spare waits
100 000 pt outside the window until it drew the chat (adoptSession), so the
hold hid a page nobody could see: Chromium throttled it, and it drew the chat
only once the hold gave up at 500 ms. A page laid out wholly outside its
window's content now stays visible to Chromium whatever its ancestors' alpha;
in place, a hold still hides it.

Drops #31619's hidden-page paint report (on a task, without a frame): with the
held page drawing, the report waits for a real frame again, and a report with
no frame drawn showed the page's previous frame when the host revealed it.

AgentPaneChromiumVisibilityTests.anAdoptedPageHeldAwayKeepsDrawingUnderAPaintHold:
red on the previous commit, green here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-23bb1f8ee2895ef522be

* test: cover selection after a failed spare adoption

Agent-Session: https://cmux.com/deeplink/agent?id=aid-81082f85640c1fa29ca9

* fix: retain a newer selection after spare adoption fails

Agent-Session: https://cmux.com/deeplink/agent?id=aid-81082f85640c1fa29ca9

* Agent pane: an adopted spare turns its cover on before its loading state begins

The chat-open bench counted a flash on 7-10 of 10 adopted opens: its trace
recorded the chat's saved frame ("image"), then the empty cover, then the
chat. No such frame was drawn. beginLoadingState binds the trace and
samples the surface at once, while the New Tab page's cover was still
hidden; adoptSession turned the cover on only after that, in the same main
turn, so the first sample read a state no frame showed. The cover now goes
on first, so the pane is in its loading state from the first sample.

Diagnosed on the fleet with a probe build that recorded every cover change
after the adoption; it found none, which left the trace's own first sample.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-758f5f82cc10b26ecf3c

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch was previously deployed

1 inactive deployment
ci-routing-agent — 3740ab4c Deployed Oct 30, 2026 by teamleaderleo via namespace autofix #8118
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:normal Risk tier (docs/ci/risk-tiers.md)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant