fix(menu): re-measure merged-menu rows when a tab swap changes card height - #3616
Conversation
…eight AppKit's table-backed menu keeps a reused row's measured height. The merged menu's cached tab swap exchanges card payloads inside the attached row, so a card of a different height at the same position (Overview's Codex row becoming the Claude card, for example) kept the previous height: empty space under shorter cards and clipped taller ones, until the next rebuild (steipete#3549). The in-place payload swap now applies only when the row's height is unchanged; otherwise the incoming item replaces the live one, which AppKit measures. Same- height swaps keep the flash-free path. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
Opt-in signed native proof that opens the production merged menu with six synthetic providers of deliberately different card heights, switches tabs while the menu tracks (Overview also scrolls), records menu, table and row geometry with item identity, and asserts no row keeps a stale height. Fails on the reproduced 735pt table / 341pt row without the fix. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
Codex review: needs maintainer review before merge. Reviewed September 13, 2026, 11:36 AM ET / 15:36 UTC (Revision 7). ClawSweeper reviewWhat this changesReplace cached menu cards when their measured heights differ, preserve equal-height row reuse, simplify reconciliation, and add regression tests, native diagnostics, and a release note. Merge readiness✅ Ready for maintainer review This remains a useful, well-supported fix: current main and v0.60.1 retain the affected swap behavior. Native before/after evidence supports the repair, the previous diagnostic finding is resolved, and no actionable patch defects remain. Priority: P2 Review scores
Verification
How this fits togetherCodexBar’s merged menu displays cached usage cards when users switch provider tabs. Its reconciliation layer decides whether to reuse attached AppKit rows or insert replacement rows, affecting card sizing and access to menu actions. flowchart TD
A[Provider tab selection] --> B[Cached usage cards]
B --> C[Compare row compatibility and height]
C -->|Matching heights| D[Reuse attached row]
C -->|Different heights| E[Insert replacement row]
D --> F[Content-sized menu and actions]
E --> F
Before mergeNone. Agent review detailsSecurityNone. Review metrics
Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Technical reviewBest possible solution: Keep content-sized provider tabs by replacing differently sized cached rows while preserving equal-height reuse and the existing menu cache. Do we have a high-confidence way to reproduce the issue? Yes: switching between unequal-height cached cards has a concrete native reproduction and negative control in the supplied evidence, supported by current-main source. This reviewer did not execute AppKit. Is this the best way to solve the issue? Yes: the guard uses existing measured sizes and replacement behavior, preserving equal-height reuse and avoiding the previously rejected uniform-height padding. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against 62a7fa1c409c. LabelsLabel justifications:
EvidenceWhat I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (6 earlier review cycles)
|
CODEXBAR_MENU_SWAP_SHORT enabled only Codex and Claude while the swap script still selected Copilot, z.ai and Cursor, so a short run could never satisfy the phase count. The proof now always enables every provider the script selects. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012T91QRonsX591fKr6UuN5R
Keep the measured-height fix, simplify tail and metadata swaps, and require attached geometry and the intended selection in native proof. Preserve contributor credit in the release note.
|
Landed as caad1ca. Thanks @zenibako for the root-cause isolation, fix, and native fixture. The final head passed 182 focused tests ( The matching Developer ID-signed macOS 26.6.2 diagnostic passed all 11 transitions in 38.25 seconds. Disabling only the height check reproduced the original table/menu mismatch (735/516 points) and card row/content mismatch (341/122 points), failing the diagnostic in 44.28 seconds. The inspected before/after screenshots in the PR contain only synthetic fixture data. Production changes are net -2 lines, and the Unreleased changelog credits the contributor. |
Fixes #3549.
Switching merged-menu tabs could leave a large gap around a short card or clip content and actions. The cached swap preserved an attached AppKit row while replacing its payload with a differently sized card; AppKit retained the row's old measurement.
The in-place swap now requires matching measured card heights. Different-height cards use the existing insert-before-remove path, so AppKit measures the incoming row. Equal-height swaps retain their attached views. Nearby tail, highlight, and metadata reconciliation is simplified; the complete PR is net -2 production lines.
Thanks @zenibako (Chandler Anderson) for isolating the cause, implementing the fix, and supplying the native diagnostic. The diagnostic now requires materialized card geometry, validates the intended tab selection, and compares row height against both the view frame and independently measured intrinsic height. Offscreen virtualized rows remain valid.
Native before/after proof
Same six-provider synthetic fixture on macOS 26.6.2, opened through the production status-item menu with cost sections and a scrollable Overview. Both test bundles were signed with the matching Developer ID. The before control disables only the height check; the final source was restored and rebuilt afterward. No real accounts or provider credentials were used.
Validation
Reviewed head:
5af73dc90f6c655927f1a41b8781f6a061cf4f69.make test-fast FILTER='StatusMenuTests|MenuRowContainerSizingTests': 182 tests in two suites passed.make check: zero violations in 2,276 files. Independent review and isolated Codex review completed; no accepted actionable findings remain.make testwas attempted locally: 47 groups passed before an unrelatedCostUsageStoreScaleProofTests180-second timeout stopped the run. This is not a full local-suite pass.