Skip to content

Keep rich Overview rows but move hover to AppKit#1676

Open
hhh2210 wants to merge 2 commits into
steipete:mainfrom
hhh2210:codex/overview-rich-row
Open

Keep rich Overview rows but move hover to AppKit#1676
hhh2210 wants to merge 2 commits into
steipete:mainfrom
hhh2210:codex/overview-rich-row

Conversation

@hhh2210

@hhh2210 hhh2210 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Refs #1674.

Summary

  • Add an Overview-only AppKit hosting wrapper for rich provider rows.
  • Keep the current rich row content: header, usage section, storage text, submenu indicator, provider click behavior, and provider detail submenus.
  • Move row hover highlight to a cheap CALayer on the AppKit boundary instead of propagating menuItemHighlighted through the full SwiftUI row tree.
  • Preserve menuCardRefreshMonitor injection for live refresh subtitles.
  • Follow-up after ClawBot: add a lifecycle regression test proving recycled Overview row hosting views are reused and stale AppKit highlight state is cleared before reuse.

Behavior change

Overview rows no longer use the standard menu highlight. Because the AppKit host no longer injects menuItemHighlighted or the container-level foregroundStyle, hovered Overview rows show a faint translucent CALayer background with non-inverted text, instead of the system solid-blue-with-white-text selection used elsewhere in the menu. This is intentional (it is what removes the per-hover SwiftUI re-render) but it is a visible change and worth a maintainer's explicit sign-off.

Why this direction

The scroll sample in #1674 suggests every scroll event can trigger expensive menu row layout/reconciliation work. This branch keeps the existing detailed Overview UI, but removes the most suspicious per-hover SwiftUI state propagation from Overview rows and makes hit testing/highlighting local to the AppKit host view.

This is an alternative to the lite-row PR; they are not meant to merge together.

Tests

  • swift test --filter "overview row"
  • swift test --filter "highlight"
  • swift build
  • make check
  • git diff --check

Follow-up validation

Verified locally on macOS 27.0 (26A5353q), Swift 6.4 / arm64:

  • swift test --filter "overview row" passed: 11 tests / 3 suites.
  • swift build passed.
  • make check passed.
  • CODEXBAR_SIGNING=adhoc ./Scripts/package_app.sh debug passed and produced CodexBar.app.
  • codesign --verify --deep --strict --verbose=2 CodexBar.app passed.

What this proves locally:

  • Overview row content still renders through the rich SwiftUI row path.
  • Overview rows keep provider selection and provider-detail submenu behavior.
  • Scroll navigation still targets only Overview rows.
  • Row hover/hit-test is handled at the AppKit container boundary.
  • Overview row hosting views are recycled and clear stale AppKit highlight state before reuse.

Runtime scroll sample

Captured an after-fix interactive sample while the freshly packaged PR app was running and the Overview menu was being scrolled:

  • Branch/head: codex/overview-rich-row at 963ed4cf9941.
  • App: debug/ad-hoc package from this worktree, CodexBar.app, com.steipete.codexbar.debug.
  • Runtime: macOS 27.0 (26A5353q), Swift 6.4 / arm64.
  • Command: sample 2921 8 1 -file ~/Desktop/codexbar-rich-row-after-scroll-sample.txt.
  • Sample header: Version: 0.37.1 (91), Path: /Users/USER/*/CodexBar.app/Contents/MacOS/CodexBar, Physical footprint: 174.2M, peak 187.3M.
  • Main thread sample count: 3641.

Relevant before/after sample summary, comparing the v0.37.0 baseline sample attached in #1674 with this PR sample:

Symbol / stack marker v0.37.0 baseline PR #1676 after-fix sample
@objc NSHostingView.hitTest(_:) 12 below sample's >=5 summary threshold
NSHostingView.hitTest(_:) 12 below sample's >=5 summary threshold
NSHostingView.hitTestingResponder() 9 below sample's >=5 summary threshold
-[NSView _hitTestForContext:point:preferPointOverContext:] 54 below sample's >=5 summary threshold
protocol witness ... LazyVGridLayout.lengthAndSpacing 9 5
ViewGraphRootValueUpdater.render(...) 23 30
-[NSView scrollWheel:] 6 6
-[NSContextMenuImpl _performOptimalSizePassUsingQueuesWithTitles:keyEquivalents:customViews:] below summary threshold 9
-[NSContextMenuImpl _recalculateOptimalSize] below summary threshold 5

The after-fix call graph also shows the PR-specific wrapper path in the sampled runtime:

  • StatusItemController.makeOverviewMenuRowItem<A>(_:id:configuration:) at StatusItemController+MenuCardItems.swift:143.
  • OverviewMenuRowHostingView.measuredHeight(width:) at StatusItemController+MenuPresentation.swift:276.
  • OverviewMenuRowHostingView.layout() at StatusItemController+MenuPresentation.swift:259.

Still not covered

  • I still do not have a visual recording proving hover, provider click, and provider-detail submenu behavior under the same provider-heavy setup. The sample above is runtime scroll proof, not a complete UX recording.
  • Maintainers still need to choose between this rich-row direction and Lighten Overview menu rows #1675, since the two PRs are alternatives.

@clawsweeper

clawsweeper Bot commented Jun 20, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed June 21, 2026, 3:46 AM ET / 07:46 UTC.

Summary
The PR adds an Overview-specific AppKit hosting wrapper for rich provider rows, moves hover highlighting to a CALayer-backed NSView, preserves row content wiring, and adds recycling/highlight lifecycle tests.

Reproducibility: no. high-confidence local runtime reproduction was run in this read-only review. The linked issue supplies macOS 27 sample-backed steps, and the patch's embedded-control regression is source-reproducible from the new hitTest override and current CopyIconButton path.

Review metrics: 2 noteworthy metrics.

  • Diff surface: 5 files changed, +303/-15. The branch crosses menu construction, AppKit presentation, row rendering, and tests, so runtime menu behavior matters beyond compile-time checks.
  • Competing fix candidates: 2 open PRs. Maintainers need to choose between preserving rich Overview rows with an AppKit boundary and replacing them with compact rows.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #1674
Summary: This PR is one candidate fix for the open Overview scroll-stutter issue, with a sibling PR exploring a mutually exclusive compact-row direction.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦐 gold shrimp
Patch quality: 🧂 unranked krab
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Fix OverviewMenuRowHostingView hit testing so embedded SwiftUI controls and row click/submenu behavior can coexist.
  • [P1] Add redacted real-menu proof showing scroll responsiveness plus hover, provider click, provider-detail submenu, and error-copy behavior.
  • Get maintainer sign-off choosing this rich-row direction over Lighten Overview menu rows #1675.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body includes copied live sample output for the scroll path, but it does not show the changed hover, provider-click, submenu, or error-copy behavior; redacted visual or diagnostic proof is still needed. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Mantis proof suggestion
A visible desktop proof would materially help verify the changed menu scroll, hover, click, submenu, and error-copy behavior in a real CodexBar menu. A maintainer can ask Mantis to capture proof by posting this exact PR comment:

@openclaw-mantis visual task: on macOS 27, verify CodexBar Overview scrolling with multiple providers is responsive and row hover, provider click, provider-detail submenu, and error copy button still work.

Risk before merge

  • [P1] The new AppKit wrapper can swallow clicks for the SwiftUI CopyIconButton shown in rich Overview error rows, breaking an existing error-copy affordance.
  • [P1] The copied sample output supports the scroll-performance hypothesis, but it does not show hover, provider click, provider-detail submenu, or error-copy behavior after the patch.
  • [P1] This PR and Lighten Overview menu rows #1675 are explicit alternatives for the same open performance report, so maintainers need to choose one UI/performance direction.
  • [P1] Overview rows intentionally stop using the standard selected-menu highlight, so the visible hover behavior needs maintainer UX sign-off.

Maintainer options:

  1. Fix Rich-Row Hit Testing First (recommended)
    Before merge, adjust the AppKit wrapper so embedded SwiftUI controls like the error copy button still receive clicks while row hover remains cheap.
  2. Profile And Choose One Direction
    Maintainers should compare this rich-row AppKit boundary with Lighten Overview menu rows #1675 on the reported provider-heavy macOS 27 setup and pick one shipping path.
  3. Pause The Stale Alternative
    If maintainers prefer the compact-row approach or do not want the hover-style change, this branch should pause or close rather than remain a parallel landing candidate.

Next step before merge

  • [P1] The remaining blockers are contributor proof, a concrete interaction regression, and maintainer choice between two mutually exclusive UI/performance directions.

Security
Cleared: The diff only touches local AppKit/SwiftUI menu code and focused tests; no dependency, workflow, secret, or build-system risk was found.

Review findings

  • [P1] Preserve SwiftUI control hit testing in Overview rows — Sources/CodexBar/StatusItemController+MenuPresentation.swift:254-256
  • [P3] Refresh the selection layer color on appearance changes — Sources/CodexBar/StatusItemController+MenuPresentation.swift:291-293
Review details

Best possible solution:

Land one profiled fix for #1674 after preserving rich-row embedded controls and choosing either this AppKit-boundary approach or the compact-row alternative.

Do we have a high-confidence way to reproduce the issue?

No high-confidence local runtime reproduction was run in this read-only review. The linked issue supplies macOS 27 sample-backed steps, and the patch's embedded-control regression is source-reproducible from the new hitTest override and current CopyIconButton path.

Is this the best way to solve the issue?

No. The AppKit-boundary approach is plausible, but the current patch blocks embedded SwiftUI control hit testing and still needs maintainer direction against the compact-row alternative.

Full review comments:

  • [P1] Preserve SwiftUI control hit testing in Overview rows — Sources/CodexBar/StatusItemController+MenuPresentation.swift:254-256
    OverviewMenuRowHostingView.hitTest(_:) now returns the wrapper for every in-bounds point. Rich Overview rows still include UsageMenuCardHeaderSectionView, which shows a SwiftUI CopyIconButton for error subtitles, so clicking that affordance can no longer reach the button and will instead be handled by the row wrapper. Let hit testing reach the hosting view for embedded controls, or remove/replace the interactive affordance in this row type.
    Confidence: 0.91
  • [P3] Refresh the selection layer color on appearance changes — Sources/CodexBar/StatusItemController+MenuPresentation.swift:291-293
    selectedContentBackgroundColor is dynamic, but converting it to cgColor once freezes the current appearance. If the menu row is reused or the effective appearance changes while the menu is open, the custom hover layer can keep the old palette; update the layer color when the effective appearance changes or before showing the highlight.
    Confidence: 0.76

Overall correctness: patch is incorrect
Overall confidence: 0.88

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 9e7a70a42dd2.

Label changes

Label changes:

  • add merge-risk: 🚨 compatibility: The PR can break an existing embedded copy control in rich Overview error rows and intentionally changes visible hover behavior.

Label justifications:

  • P2: This is a normal-priority performance/UI fix candidate for a primary menu path with limited blast radius but visible UX impact.
  • merge-risk: 🚨 compatibility: The PR can break an existing embedded copy control in rich Overview error rows and intentionally changes visible hover behavior.
  • merge-risk: 🚨 availability: The PR changes row hosting, hit testing, highlighting, height measurement, and recycling in the NSMenu surface already reported to stall during scrolling.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦐 gold shrimp and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body includes copied live sample output for the scroll path, but it does not show the changed hover, provider-click, submenu, or error-copy behavior; redacted visual or diagnostic proof is still needed. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

What I checked:

Likely related people:

  • steipete: Current blame for Overview row assembly, rich row rendering, and header behavior points to the v0.37.0 release tree, and current main is only a few menu-adjacent commits beyond that release. (role: recent area contributor and release integrator; confidence: high; commits: 33a5f4362eab, 9e7a70a42dd2; files: Sources/CodexBar/StatusItemController+Menu.swift, Sources/CodexBar/StatusItemController+MenuTypes.swift, Sources/CodexBar/MenuCardView.swift)
  • elijahfriedman: Recent merged menu/highlight work touched StatusItemController menu files and the embedded-control behavior this PR risks regressing. (role: recent adjacent menu contributor; confidence: high; commits: cbf406032104, 0260a9a70706, 8d7f1e53bbd4; files: Sources/CodexBar/StatusItemController+Menu.swift, Sources/CodexBar/StatusItemController+MenuCardItems.swift, Sources/CodexBar/StatusItemController+MenuPresentation.swift)
  • bcssewl: Merged work introduced the menu-card hosting-view recycling and in-place reconciliation surface that this PR extends with an Overview-specific host view. (role: menu-card recycling contributor; confidence: high; commits: f927e8ad90ae; files: Sources/CodexBar/StatusItemController+Menu.swift, Sources/CodexBar/StatusItemController+MenuCardItems.swift, Sources/CodexBar/StatusItemController+MenuPresentation.swift)
  • hhh2210: Beyond authoring this PR, prior merged history shows work on menu-card refresh feedback and height caching in the same custom menu-card surface. (role: prior menu-card contributor and current proposer; confidence: medium; commits: d1c96c3ac4a6, 65e39f4dcb3a; files: Sources/CodexBar/StatusItemController+MenuCardItems.swift, Sources/CodexBar/StatusItemController+MenuPresentation.swift)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. labels Jun 20, 2026
@hhh2210

hhh2210 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up after ClawBot review:

  • Re-reviewed the AppKit boundary: SwiftUI still owns row content/model rendering, while AppKit owns only row hit-testing, hover background, measurement, recycling, and click glue.
  • Added focused lifecycle coverage: recycled overview row keeps hosting view and clears appkit highlight state proves reuse keeps the same hosting view and clears stale AppKit hover state.
  • Verified locally on macOS 27.0 (26A5353q), Swift 6.4: swift test --filter "overview row", swift build, make check, CODEXBAR_SIGNING=adhoc ./Scripts/package_app.sh debug, and codesign --verify --deep --strict --verbose=2 CodexBar.app.

I did not fabricate an interactive scroll profile: the remaining proof gap is still a controlled NSMenuTrackingSession scroll sample/recording on a provider-heavy setup. This PR is the rich-row direction; #1675 is the lite-row alternative.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 20, 2026

Copy link
Copy Markdown

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@hhh2210 hhh2210 marked this pull request as ready for review June 20, 2026 09:44
Copilot AI review requested due to automatic review settings June 20, 2026 09:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR targets the scroll/hover performance issues in the Overview tab by keeping the existing “rich” SwiftUI row content but moving hover highlighting and hit-testing decisions to a lightweight AppKit boundary (NSView + CALayer) to avoid per-hover SwiftUI highlight propagation.

Changes:

  • Introduces an Overview-specific AppKit hosting wrapper (OverviewMenuRowHostingView) that owns hover highlight rendering via a CALayer and consumes hit testing at the AppKit level.
  • Adds a dedicated builder path (makeOverviewMenuRowItem + OverviewMenuRowItemConfiguration) for Overview rows, preserving height caching and view recycling.
  • Updates/extends unit tests to cover Overview row highlighting, hit testing, and recycling behavior (including clearing stale highlight state).

Reviewed changes

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

Show a summary per file
File Description
Tests/CodexBarTests/MenuCardViewRecyclingTests.swift Adds tests asserting Overview row AppKit-boundary hit testing/highlighting and recycling clears highlight state.
Sources/CodexBar/StatusItemController+MenuTypes.swift Removes dependency on menuItemHighlighted for Overview row styling and adds an in-row submenu chevron indicator.
Sources/CodexBar/StatusItemController+MenuPresentation.swift Adds OverviewMenuRowHostingView (AppKit wrapper + CALayer hover highlight) and an Overview-only SwiftUI environment wrapper.
Sources/CodexBar/StatusItemController+MenuCardItems.swift Introduces OverviewMenuRowItemConfiguration and makeOverviewMenuRowItem for recycled, height-cached Overview rows.
Sources/CodexBar/StatusItemController+Menu.swift Switches Overview row construction to the new Overview-specific item builder and wiring.

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

Comment on lines +254 to +256
override func hitTest(_ point: NSPoint) -> NSView? {
self.bounds.contains(point) ? self : nil
}
Comment on lines +286 to +301
private func configureView() {
self.wantsLayer = true
self.layer?.masksToBounds = false
self.selectionLayer.cornerRadius = 6
self.selectionLayer.cornerCurve = .continuous
self.selectionLayer.backgroundColor = NSColor.selectedContentBackgroundColor
.withAlphaComponent(0.16)
.cgColor
self.selectionLayer.isHidden = true
self.layer?.addSublayer(self.selectionLayer)

self.hostingView.translatesAutoresizingMaskIntoConstraints = true
self.hostingView.autoresizingMask = [.width, .height]
self.hostingView.frame = self.bounds
self.addSubview(self.hostingView)
}
@hhh2210

hhh2210 commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Added the after-fix runtime scroll proof to the PR body.

The new section documents an interactive sample 2921 8 1 capture from the freshly packaged codex/overview-rich-row app at 963ed4cf9941 on macOS 27.0 (26A5353q). It compares the v0.37.0 baseline sample from #1674 with the PR sample and calls out the PR-specific OverviewMenuRowHostingView path observed in the runtime stack.

Scope note: this is scroll-runtime proof, not a visual recording. The remaining manual proof gap is hover/provider-click/submenu visual behavior, plus maintainer choice between this rich-row PR and #1675.

@clawsweeper re-review

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. label Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 availability 🚨 Merging this PR could cause crashes, hangs, restart loops, stalls, or process outages. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants