Keep rich Overview rows but move hover to AppKit#1676
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed June 21, 2026, 3:46 AM ET / 07:46 UTC. Summary 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.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Mantis proof suggestion Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest 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:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 9e7a70a42dd2. Label changesLabel changes:
Label justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
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
|
|
Follow-up after ClawBot review:
I did not fabricate an interactive scroll profile: the remaining proof gap is still a controlled @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
There was a problem hiding this comment.
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 aCALayerand 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.
| override func hitTest(_ point: NSPoint) -> NSView? { | ||
| self.bounds.contains(point) ? self : nil | ||
| } |
| 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) | ||
| } |
|
Added the after-fix runtime scroll proof to the PR body. The new section documents an interactive 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 |
Refs #1674.
Summary
CALayeron the AppKit boundary instead of propagatingmenuItemHighlightedthrough the full SwiftUI row tree.menuCardRefreshMonitorinjection for live refresh subtitles.Behavior change
Overview rows no longer use the standard menu highlight. Because the AppKit host no longer injects
menuItemHighlightedor the container-levelforegroundStyle, hovered Overview rows show a faint translucentCALayerbackground 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 buildmake checkgit diff --checkFollow-up validation
Verified locally on macOS 27.0 (26A5353q), Swift 6.4 / arm64:
swift test --filter "overview row"passed: 11 tests / 3 suites.swift buildpassed.make checkpassed.CODEXBAR_SIGNING=adhoc ./Scripts/package_app.sh debugpassed and producedCodexBar.app.codesign --verify --deep --strict --verbose=2 CodexBar.apppassed.What this proves locally:
Runtime scroll sample
Captured an after-fix interactive
samplewhile the freshly packaged PR app was running and the Overview menu was being scrolled:codex/overview-rich-rowat963ed4cf9941.CodexBar.app,com.steipete.codexbar.debug.sample 2921 8 1 -file ~/Desktop/codexbar-rich-row-after-scroll-sample.txt.Version: 0.37.1 (91),Path: /Users/USER/*/CodexBar.app/Contents/MacOS/CodexBar,Physical footprint: 174.2M, peak187.3M.Relevant before/after sample summary, comparing the v0.37.0 baseline sample attached in #1674 with this PR sample:
@objc NSHostingView.hitTest(_:)NSHostingView.hitTest(_:)NSHostingView.hitTestingResponder()-[NSView _hitTestForContext:point:preferPointOverContext:]protocol witness ... LazyVGridLayout.lengthAndSpacingViewGraphRootValueUpdater.render(...)-[NSView scrollWheel:]-[NSContextMenuImpl _performOptimalSizePassUsingQueuesWithTitles:keyEquivalents:customViews:]-[NSContextMenuImpl _recalculateOptimalSize]The after-fix call graph also shows the PR-specific wrapper path in the sampled runtime:
StatusItemController.makeOverviewMenuRowItem<A>(_:id:configuration:)atStatusItemController+MenuCardItems.swift:143.OverviewMenuRowHostingView.measuredHeight(width:)atStatusItemController+MenuPresentation.swift:276.OverviewMenuRowHostingView.layout()atStatusItemController+MenuPresentation.swift:259.Still not covered