Skip to content

Fix bottom-docked DevTools page shift - #1212

Merged
lawrencecchen merged 5 commits into
mainfrom
task-browser-page-pushed-up
Mar 12, 2026
Merged

lawrencecchen merged 5 commits into
mainfrom
task-browser-page-pushed-up

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Mar 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • add a regression test for the bottom-docked DevTools page-frame overflow
  • repair portal-hosted browser geometry so the page stays above a bottom-docked inspector

Testing

  • xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux-unit -configuration Debug -destination 'platform=macOS' -derivedDataPath /tmp/cmux-task-browser-page-pushed-up-tests -only-testing:cmuxTests/BrowserWindowPortalLifecycleTests/testPortalSyncRepairsBottomDockedInspectorOverflowedPageFrame test (fails on commit 94c5d621e, passes on this commit)
  • xcodebuild -project GhosttyTabs.xcodeproj -scheme cmux-unit -configuration Debug -destination 'platform=macOS' -derivedDataPath /tmp/cmux-task-browser-page-pushed-up-tests -only-testing:cmuxTests/BrowserWindowPortalLifecycleTests/testPortalResizePreservesSideDockedInspectorManagedWebViewFrame -only-testing:cmuxTests/BrowserWindowPortalLifecycleTests/testPortalSyncRepairsBottomDockedInspectorOverflowedPageFrame test

Issues

  • Related task: bottom-docked DevTools pushes the page upward until the site header is clipped

Summary by cubic

Fixes the bottom-docked DevTools bug that pushed the page upward and clipped headers. Also fixes geometry when replacing a visible local host so the inspector and page stay aligned.

  • Bug Fixes
    • Infers a bottom-docked WKInspector from visible subviews and repairs the WKWebView frame during portal sync to keep the page below the inspector and flush with the slot.
    • Preserves slot-local frames when reparenting into a visible local host, and triggers layout when sizes change so DevTools companion views move with the page.
    • Adds regression tests for bottom-docked overflow repair (portal sync) and visible local-host replacement.

Written for commit e35e1cd. Summary will update on new commits.

Summary by CodeRabbit

  • Bug Fixes

    • More reliable handling of web view and developer-inspector layouts when the inspector is docked at the bottom, with improved detection and automatic frame repair to prevent clipped or overflowed content.
    • Preserve local view positions when panels are relocated to maintain visual placement and avoid unintended resizing or layout shifts.
  • Tests

    • Added tests validating bottom-docked inspector synchronization, overflow repair, and replacement behavior to prevent regressions.

@vercel

vercel Bot commented Mar 12, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Mar 12, 2026 1:34am

@coderabbitai

coderabbitai Bot commented Mar 12, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Added helpers to detect and repair bottom-docked WKInspector layouts and updated portal synchronization to prefer a specialized bottom-docked page-frame repair before falling back to the previous outside-bounds fix; tests and WebView reparenting were adjusted to preserve slot-local frames during moves.

Changes

Cohort / File(s) Summary
Inspector Detection & Frame Repair
Sources/BrowserWindowPortal.swift
Added hasVisibleInspectorDescendant, inferredBottomDockedInspectorFrame, repairedBottomDockedPageFrame; portal sync now attempts bottom-docked repair first, logs DEBUG diagnostics, and appends webFrameBottomDock on success; retains fallback to original outside-bounds repair.
Test Coverage
cmuxTests/CmuxWebViewKeyEquivalentTests.swift
Added testPortalSyncRepairsBottomDockedInspectorOverflowedPageFrame() and testVisibleReplacementLocalHostNormalizesBottomDockedInspectorFrames(), plus helper findWindowBrowserSlotView(...) to validate bottom-docked inspector repair and viewport normalization.
WebView Reparenting / Slot-local Frames
Sources/Panels/BrowserPanelView.swift
Introduce preserveSlotLocalFrames flow: capture source slot bounds, preserve local frame origins for views moved from WindowBrowserSlotView, compute/assign target frame without unconditional coordinate conversion, and resize/layout container subviews if container size changed.

Sequence Diagram

sequenceDiagram
    participant Portal as BrowserWindowPortal
    participant Container as ContainerView/Slot
    participant WebView as WKWebView
    participant Inspector as WKInspector

    Portal->>Portal: portalDidSync()
    Portal->>Inspector: hasVisibleInspectorDescendant(in: container)?
    Inspector-->>Portal: visible (yes/no)
    alt inspector visible
        Portal->>Portal: inferredBottomDockedInspectorFrame(in: container, primaryWebView)
        Portal-->>Portal: bottom-docked rect?
        alt bottom-docked detected
            Portal->>Portal: repairedBottomDockedPageFrame(...)
            Portal-->>Portal: corrected page frame
            Portal->>WebView: apply repaired frame
            Portal->>Portal: DEBUG log old/new frames & inspector metrics
            Portal->>Portal: append "webFrameBottomDock" to refreshReasons
        else not detected
            Portal->>Portal: fall back to frameExtendsOutsideBounds repair
            Portal->>WebView: apply original repair frame
        end
    else inspector not visible
        Portal->>WebView: no inspector repair needed
    end
    Portal->>Container: ensure layout/reflow
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • manaflow-ai/cmux-dev-artifacts#72 — touches WebView relocation/reparenting and could be linked to the preserve-slot-frame changes that affect redock behavior.
  • manaflow-ai/cmux-dev-artifacts#76 — directly relates to BrowserPanelView reparenting logic (preserveSlotLocalFrames) and failing redock UI test coverage.

Possibly related PRs

Poem

I nibble at frames with careful paws, 🐇
I hunt the dock where the inspector draws,
Two-step fixes, snug and slight,
WebView restored — no overflow in sight,
Portal hums softly through the night.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: fixing a bug where bottom-docked DevTools pushes the page upward.
Description check ✅ Passed The description covers the key sections from the template: Summary (what changed and why), Testing (with specific xcodebuild commands), and addresses the related bug.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch task-browser-page-pushed-up

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

@greptile-apps

greptile-apps Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes the bottom-docked DevTools panel causing the page viewport to overflow the portal slot by adding a dedicated geometry-repair path in WindowBrowserPortal. When synchronizeWebViewForAnchor detects that the web view's frame extends outside the container bounds and a visually-present WebKit inspector panel is anchored at the container bottom, it now computes a corrected frame (y = inspectorPanel.maxY, height = container.height − inspectorPanel.height) rather than blindly clamping to containerBounds. A regression test is added that constructs the exact overflow state and asserts the three key frame invariants (minY, height, maxY) are repaired correctly.

Key changes:

  • hasVisibleInspectorDescendant — DFS traversal that detects a live WKInspector* descendant using the same string-matching convention as the existing isInspectorView helper.
  • inferredBottomDockedInspectorFrame — Scans the container's direct children for a bottom-anchored sibling that has a wide enough horizontal overlap with the web view and a visible inspector descendant; returns the tallest match.
  • repairedBottomDockedPageFrame — Gates on frameExtendsOutsideBounds + a found inspector, then returns the adjusted NSRect.
  • The call site now tries the new repair branch first and falls through to the generic normalization (containerBounds) only when no inspector is detected.

Confidence Score: 4/5

  • This PR is safe to merge — the fix is well-scoped, guarded by multiple geometry predicates, consistent with existing patterns, and backed by a targeted regression test.
  • The repair logic correctly computes the adjusted frame and falls through to the pre-existing normalization when no inspector is found, so there is no regression risk for non-inspector cases. The one point deducted is for the inherent fragility of string-based WebKit internal class-name detection (contains("WKInspector")), which is already an established pattern in this codebase and is the only practical approach given the absence of a public API, but could silently break if Apple renames the internal class.
  • No files require special attention.

Important Files Changed

Filename Overview
Sources/BrowserWindowPortal.swift Adds three new private helpers (hasVisibleInspectorDescendant, inferredBottomDockedInspectorFrame, repairedBottomDockedPageFrame) and wires the repair path into the sync logic before falling back to the existing generic bounds-normalization, correctly preventing the full-container override when a bottom-docked DevTools panel is present.
cmuxTests/CmuxWebViewKeyEquivalentTests.swift Adds testPortalSyncRepairsBottomDockedInspectorOverflowedPageFrame — a targeted regression test that constructs the precise overflow scenario (webView.height == slot.bounds.height starting at y == inspectorHeight) and asserts that the portal sync repairs minY, height, and maxY to the expected values.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[synchronizeWebViewForAnchor] --> B{containerOwnsWebView?}
    B -- No --> Z[Skip web-frame repair]
    B -- Yes --> C[repairedBottomDockedPageFrame]
    C --> D{frameExtendsOutsideBounds?}
    D -- No --> E[return nil]
    D -- Yes --> F[inferredBottomDockedInspectorFrame]
    F --> G{Any subview with\nhasVisibleInspectorDescendant\nat container bottom?}
    G -- No --> E
    G -- Yes --> H[Pick tallest candidate]
    H --> I[Compute NSRect\nx=containerBounds.minX\ny=inspectorFrame.maxY\nw=containerBounds.width\nh=containerBounds.maxY−inspectorFrame.maxY]
    I --> J[Apply repairedBottomDockFrame\nvia CATransaction\nappend 'webFrameBottomDock']
    E --> K{frameExtendsOutsideBounds\nfallback check}
    K -- Yes --> L[Clamp webView to containerBounds\nappend 'webFrame']
    K -- No --> Z
Loading

Last reviewed commit: fbd04ca

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fbd04ca09e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2235 to +2238
if current !== root {
let className = String(describing: type(of: current))
if className.contains("WKInspector"),
!current.isHidden,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Treat direct inspector siblings as bottom-dock candidates

The new bottom-dock repair can miss real inspector layouts because hasVisibleInspectorDescendant skips checking the root view itself (current !== root). If WebKit exposes the inspector as a direct sibling of the page view (a pattern already handled elsewhere via isInspectorView), this helper returns false when that inspector view has no WKInspector-named descendants, so repairedBottomDockedPageFrame never runs and sync falls back to full-frame normalization that reintroduces the page shift.

Useful? React with 👍 / 👎.

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Sources/BrowserWindowPortal.swift">

<violation number="1" location="Sources/BrowserWindowPortal.swift:2234">
P2: The traversal loop unconditionally enters `current.subviews` even for hidden nodes, and bypasses the `isHidden` check for the `root` node. Because AppKit child views report `isHidden == false` even when their parent is hidden, this causes closed but cached DevTools containers to falsely report as visible and trigger unnecessary geometry repairs.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment on lines +2234 to +2246
while let current = stack.popLast() {
if current !== root {
let className = String(describing: type(of: current))
if className.contains("WKInspector"),
!current.isHidden,
current.alphaValue > 0,
current.frame.width > 1,
current.frame.height > 1 {
return true
}
}
stack.append(contentsOf: current.subviews)
}

@cubic-dev-ai cubic-dev-ai Bot Mar 12, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The traversal loop unconditionally enters current.subviews even for hidden nodes, and bypasses the isHidden check for the root node. Because AppKit child views report isHidden == false even when their parent is hidden, this causes closed but cached DevTools containers to falsely report as visible and trigger unnecessary geometry repairs.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Sources/BrowserWindowPortal.swift, line 2234:

<comment>The traversal loop unconditionally enters `current.subviews` even for hidden nodes, and bypasses the `isHidden` check for the `root` node. Because AppKit child views report `isHidden == false` even when their parent is hidden, this causes closed but cached DevTools containers to falsely report as visible and trigger unnecessary geometry repairs.</comment>

<file context>
@@ -2229,6 +2229,71 @@ final class WindowBrowserPortal: NSObject {
 
+    private static func hasVisibleInspectorDescendant(in root: NSView) -> Bool {
+        var stack: [NSView] = [root]
+        while let current = stack.popLast() {
+            if current !== root {
+                let className = String(describing: type(of: current))
</file context>
Suggested change
while let current = stack.popLast() {
if current !== root {
let className = String(describing: type(of: current))
if className.contains("WKInspector"),
!current.isHidden,
current.alphaValue > 0,
current.frame.width > 1,
current.frame.height > 1 {
return true
}
}
stack.append(contentsOf: current.subviews)
}
while let current = stack.popLast() {\n if current.isHidden || current.alphaValue <= 0 { continue }\n if current !== root {\n let className = String(describing: type(of: current))\n if className.contains("WKInspector"),\n current.frame.width > 1,\n current.frame.height > 1 {\n return true\n }\n }\n stack.append(contentsOf: current.subviews)\n }
Fix with Cubic

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
cmuxTests/CmuxWebViewKeyEquivalentTests.swift (1)

2496-2506: Consider extracting a generic recursive view lookup helper.

This duplicates the DFS pattern already used by findHostContainerView(in:), so a small generic findSubview<T: NSView>(ofType:in:) helper would keep future test helpers from drifting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmuxTests/CmuxWebViewKeyEquivalentTests.swift` around lines 2496 - 2506,
Extract the duplicated DFS into a generic helper like findSubview<T:
NSView>(ofType: T.Type, in root: NSView) -> T? and replace both
findWindowBrowserSlotView(in:) and the existing findHostContainerView(in:) call
sites to use it: implement the helper to check if root is T then recurse through
root.subviews, and update callers to call findSubview(ofType:
WindowBrowserSlotView.self, in: root) and findSubview(ofType:
HostContainerView.self, in: root) so the recursive logic is centralized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@cmuxTests/CmuxWebViewKeyEquivalentTests.swift`:
- Around line 2496-2506: Extract the duplicated DFS into a generic helper like
findSubview<T: NSView>(ofType: T.Type, in root: NSView) -> T? and replace both
findWindowBrowserSlotView(in:) and the existing findHostContainerView(in:) call
sites to use it: implement the helper to check if root is T then recurse through
root.subviews, and update callers to call findSubview(ofType:
WindowBrowserSlotView.self, in: root) and findSubview(ofType:
HostContainerView.self, in: root) so the recursive logic is centralized.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 50d18cda-28e7-4433-9a8d-9ddf68f6a582

📥 Commits

Reviewing files that changed from the base of the PR and between fbd04ca and 5d82a29.

📒 Files selected for processing (2)
  • Sources/Panels/BrowserPanelView.swift
  • cmuxTests/CmuxWebViewKeyEquivalentTests.swift

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5d82a29f45

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2237 to +2241
if className.contains("WKInspector"),
!current.isHidden,
current.alphaValue > 0,
current.frame.width > 1,
current.frame.height > 1 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Propagate ancestor hidden state in inspector visibility scan

hasVisibleInspectorDescendant only checks isHidden/alphaValue on the current node, so a hidden inspector container can still be treated as visible when its WKInspector child views are not individually hidden. In that case inferredBottomDockedInspectorFrame can keep selecting an actually invisible bottom-dock candidate and webFrameBottomDock repair continues to reserve inspector space, leaving the page permanently shrunk after DevTools is hidden via wrapper visibility changes.

Useful? React with 👍 / 👎.

…hed-up

# Conflicts:
#	cmuxTests/CmuxWebViewKeyEquivalentTests.swift

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/BrowserWindowPortal.swift`:
- Around line 2262-2291: The detector currently skips the root view in
hasVisibleInspectorDescendant(in:) so a bottom-docked inspector that is a direct
sibling/subview (i.e. the candidate itself) is missed; update the logic so the
candidate root is also examined for the WKInspector* class and visibility checks
(or add an explicit check for the candidate before calling
hasVisibleInspectorDescendant) so
inferredBottomDockedInspectorFrame(in:containerView:primaryWebView:epsilon:) can
detect and return a repaired bottom-docked inspector frame instead of falling
back to the generic reset; reference the functions hasVisibleInspectorDescendant
and inferredBottomDockedInspectorFrame (and the candidate guard currently
filtering out primaryWebView) when making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 20a1b152-fc27-40c5-adaf-d240ea75bf0e

📥 Commits

Reviewing files that changed from the base of the PR and between 5d82a29 and e35e1cd.

📒 Files selected for processing (2)
  • Sources/BrowserWindowPortal.swift
  • cmuxTests/CmuxWebViewKeyEquivalentTests.swift

Comment on lines +2262 to +2291
private static func hasVisibleInspectorDescendant(in root: NSView) -> Bool {
var stack: [NSView] = [root]
while let current = stack.popLast() {
if current !== root {
let className = String(describing: type(of: current))
if className.contains("WKInspector"),
!current.isHidden,
current.alphaValue > 0,
current.frame.width > 1,
current.frame.height > 1 {
return true
}
}
stack.append(contentsOf: current.subviews)
}
return false
}

private static func inferredBottomDockedInspectorFrame(
in containerView: NSView,
primaryWebView: WKWebView,
epsilon: CGFloat = 1
) -> NSRect? {
let pageFrame = primaryWebView.frame
let containerBounds = containerView.bounds

let candidates = containerView.subviews.compactMap { candidate -> NSRect? in
guard candidate !== primaryWebView else { return nil }
guard hasVisibleInspectorDescendant(in: candidate) else { return nil }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Handle direct WKInspector* siblings in the detector.

Line 2265 skips root itself, so a bottom-docked inspector that is reparented as a direct companion subview never matches this path. In that case repairedBottomDockedPageFrame(...) stays nil and we fall back to the generic full-bounds reset instead of parking the page above the inspector.

Suggested fix
 private static func hasVisibleInspectorDescendant(in root: NSView) -> Bool {
     var stack: [NSView] = [root]
     while let current = stack.popLast() {
-        if current !== root {
-            let className = String(describing: type(of: current))
-            if className.contains("WKInspector"),
-               !current.isHidden,
-               current.alphaValue > 0,
-               current.frame.width > 1,
-               current.frame.height > 1 {
-                return true
-            }
-        }
+        let className = String(describing: type(of: current))
+        if className.contains("WKInspector"),
+           !current.isHidden,
+           current.alphaValue > 0,
+           current.frame.width > 1,
+           current.frame.height > 1 {
+            return true
+        }
         stack.append(contentsOf: current.subviews)
     }
     return false
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/BrowserWindowPortal.swift` around lines 2262 - 2291, The detector
currently skips the root view in hasVisibleInspectorDescendant(in:) so a
bottom-docked inspector that is a direct sibling/subview (i.e. the candidate
itself) is missed; update the logic so the candidate root is also examined for
the WKInspector* class and visibility checks (or add an explicit check for the
candidate before calling hasVisibleInspectorDescendant) so
inferredBottomDockedInspectorFrame(in:containerView:primaryWebView:epsilon:) can
detect and return a repaired bottom-docked inspector frame instead of falling
back to the generic reset; reference the functions hasVisibleInspectorDescendant
and inferredBottomDockedInspectorFrame (and the candidate guard currently
filtering out primaryWebView) when making the change.

@lawrencecchen
lawrencecchen merged commit 320451e into main Mar 12, 2026
14 checks passed
@lawrencecchen
lawrencecchen deleted the task-browser-page-pushed-up branch March 12, 2026 01:36

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e35e1cd94c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2296 to +2297
guard frame.minY <= containerBounds.minY + epsilon else { return nil }
guard frame.maxY <= pageFrame.minY + epsilon else { return nil }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Exclude offscreen inspector frames from bottom-dock repair

The bottom-dock inference currently accepts candidates solely by minY <= container minY and maxY <= page minY, which also matches inspector containers that are entirely below the slot (for example, during hide/transition states where a WKInspector view is still visible but has a negative y). In that case repairedBottomDockedPageFrame uses a negative inspectorFrame.maxY, producing another out-of-bounds page frame and repeatedly applying the wrong repair. Add a bounds-intersection check (or at least require frame.maxY >= containerBounds.minY) before selecting a candidate.

Useful? React with 👍 / 👎.

bn-l pushed a commit to bn-l/cmux that referenced this pull request Apr 3, 2026
…e-pushed-up

Fix bottom-docked DevTools page shift

This branch was successfully deployed

1 active deployment
Preview — e35e1cd9 Deployed Mar 12, 2026 by vercel[bot]
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