Skip to content

feat: show in-flight feedback on manual refresh - #1458

Merged
steipete merged 3 commits into
steipete:mainfrom
hhh2210:feat/refresh-in-flight-feedback
Jun 12, 2026
Merged

feat: show in-flight feedback on manual refresh#1458
steipete merged 3 commits into
steipete:mainfrom
hhh2210:feat/refresh-in-flight-feedback

Conversation

@hhh2210

@hhh2210 hhh2210 commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Problem

Clicking Refresh while the menu is open gives no immediate feedback. The visible provider cards keep their old subtitles and the persistent Refresh row looks idle until the network round-trip completes. Because tracked root menus intentionally defer rebuilds, the existing refreshing state was not reaching already-hosted views.

That ambiguity also encourages repeated clicks, which could start overlapping manual refresh work.

Fix

Surface one explicit manual-refresh lifecycle in place, without rebuilding the tracked menu:

  • inject a narrow observable MenuCardRefreshMonitor into hosted provider cards
  • update eligible card subtitles to Refreshing…, then surface fresh success or failure subtitles when the request finishes
  • preserve measured error-card geometry and copy affordance while the menu remains open
  • let provider override cards retain their own subtitle behavior
  • swap the persistent Refresh icon for a spinner in the same fixed slot, including high-contrast highlighted appearance
  • coalesce repeated clicks behind one owned task
  • cancel and drain UI state during controller shutdown

The updates mutate existing SwiftUI/AppKit views only; tracked NSMenu geometry remains stable.

Tests

StatusMenuPersistentRefreshTests now covers 13 cases, including:

  • fixed row metrics while the spinner toggles
  • in-place store refresh-state propagation
  • success and failure subtitle transitions
  • canonical error filtering and stable error-card height
  • override-card isolation
  • repeated-click coalescing
  • shutdown suppression and failed-refresh cleanup

Verification

  • swift test --filter StatusMenuPersistentRefreshTests (13/13)
  • make check
  • ./Scripts/compile_and_run.sh
  • live Peekaboo exercise: open menu, trigger and repeat Refresh; cards show Refreshing…, one fixed-slot spinner remains, geometry stays stable
  • Codex autoreview: clean (0.86 confidence)

Proof

Manual refresh feedback

Copilot AI review requested due to automatic review settings June 12, 2026 05:30
@clawsweeper

clawsweeper Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codex review: needs maintainer review before merge. Reviewed June 12, 2026, 3:51 AM ET / 07:51 UTC.

Summary
The PR adds immediate in-place manual-refresh subtitles and a fixed-slot spinner, coalesces repeated clicks into one task, clears UI state on shutdown, and adds focused tests and UI documentation.

Reproducibility: yes. Current main defers rebuilding an open tracked menu, so already-hosted cards and the persistent Refresh row remain visually stale during manual refresh; the exact-head live proof demonstrates the corrected success and failure paths.

Review metrics: 3 noteworthy metrics.

  • Changed surface: 14 files, +472/-25. The implementation spans the connected SwiftUI, AppKit, controller lifecycle, test, documentation, and release-note surfaces.
  • Focused scenarios: 13 covered cases. The suite exercises geometry, observation, success and failure transitions, error preservation, provider overrides, shutdown, and duplicate-click behavior.
  • Exact-head live paths: 2 lifecycles proven. The owner verified both success and failure behavior in a freshly built exact-head app bundle.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

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

Next step before merge

  • [P2] No repair task is needed; the exact head has no identified blocking defect and can proceed through ordinary maintainer merge handling.

Security
Cleared: The patch changes local UI and task lifecycle only, with no new dependency, permission, credential, download, workflow, or supply-chain execution surface.

Review details

Best possible solution:

Merge the exact head through ordinary maintainer handling, retaining the in-place hosted-view updates, canonical subtitle resolution, fixed spinner geometry, single-task coalescing, shutdown cleanup, and focused lifecycle coverage.

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

Yes. Current main defers rebuilding an open tracked menu, so already-hosted cards and the persistent Refresh row remain visually stale during manual refresh; the exact-head live proof demonstrates the corrected success and failure paths.

Is this the best way to solve the issue?

Yes. Updating the existing SwiftUI-hosted subtitle and fixed-size AppKit action row in place is the narrowest maintainable approach because it preserves the no-rebuild-during-tracking boundary and reuses canonical provider subtitle and error resolution.

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P3: This is a limited-blast-radius menu feedback and ergonomics improvement with strong validation.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): Exact-head owner proof shows a freshly built app with immediate success and failure feedback, stable menu geometry, repeated-click coalescing, and a successful live provider refresh.
  • proof: sufficient: Contributor real behavior proof is sufficient. Exact-head owner proof shows a freshly built app with immediate success and failure feedback, stable menu geometry, repeated-click coalescing, and a successful live provider refresh.
Evidence reviewed

What I checked:

  • Tracked-menu-safe implementation: The exact head updates an already-hosted observable card subtitle rather than rebuilding the tracked NSMenu, preserving the established menu-tracking boundary. (Sources/CodexBar/MenuCardView.swift:11, 2ced0e620ff6)
  • Owned refresh lifecycle: Manual refresh now rejects shutdown, duplicate manual work, and an already-refreshing store; defer-based cleanup restores the task, live subtitle state, and persistent row state on all exits. (Sources/CodexBar/StatusItemController+Actions.swift:51, 2ced0e620ff6)
  • Fixed geometry and highlight handling: The persistent Refresh row swaps its icon for an NSProgressIndicator in the same fixed slot and updates spinner appearance for highlighted and unhighlighted states. (Sources/CodexBar/StatusItemController+MenuPresentation.swift:195, 2ced0e620ff6)
  • Focused regression coverage: The exact head adds coverage for fixed row metrics, observation updates, success and failure subtitles, error-card geometry, override isolation, click coalescing, shutdown suppression, and cleanup. (Tests/CodexBarTests/StatusMenuPersistentRefreshTests.swift:191, 2ced0e620ff6)
  • Exact-head real behavior proof: The repository owner reports running a bundle identified as 2ced0e6 and observing success and failure feedback, unchanged 310x304 geometry, one request for repeated-click bursts, live provider refresh, and passing focused and broad validation. (2ced0e620ff6)
  • Patch scope: The exact branch changes 14 files with 472 additions and 25 deletions, limited to menu refresh UI/lifecycle code, tests, and documentation. (2ced0e620ff6)

Likely related people:

  • steipete: Authored the exact-head hardening and controller-refactor commits, resolved review concerns, rebased the branch, and supplied exact-head native-app proof. (role: recent area contributor and reviewer; confidence: high; commits: 87e6e26270b2, 2ced0e620ff6; files: Sources/CodexBar/StatusItemController+Actions.swift, Sources/CodexBar/StatusItemController+MenuPresentation.swift, Tests/CodexBarTests/StatusMenuPersistentRefreshTests.swift)
  • hhh2210: Introduced the in-place manual-refresh feedback design and initial implementation; the owner’s later commits preserve the contributor’s central approach. (role: feature introducer; confidence: high; commits: d1c96c3ac4a6; files: Sources/CodexBar/MenuCardView.swift, Sources/CodexBar/StatusItemController+Actions.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.

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

Note

Copilot was unable to run its full agentic suite in this review.

Adds in-place “refresh in progress” UI updates (spinner + “Refreshing…” subtitle) while the status menu stays open, avoiding NSMenu rebuilds during tracking.

Changes:

  • Track live persistent “Refresh” rows and toggle a spinner immediately on click, then sync to store.isRefreshing.
  • Inject a refresh-state monitor into SwiftUI menu card views via EnvironmentValues to update subtitles in place.
  • Add tests covering fixed row metrics, row/store sync behavior, and refresh-indicator gating.

Reviewed changes

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

Show a summary per file
File Description
Tests/CodexBarTests/StatusMenuPersistentRefreshTests.swift Adds tests for persistent refresh spinner metrics and store-sync behavior.
Sources/CodexBar/StatusItemController.swift Introduces refresh monitor + weak tracking of persistent refresh rows; sync on store observation.
Sources/CodexBar/StatusItemController+PersistentMenuActions.swift Adds APIs to force/sync spinner state across tracked refresh rows.
Sources/CodexBar/StatusItemController+MenuPresentation.swift Adds spinner overlay to persistent action row; injects refresh monitor into SwiftUI environment.
Sources/CodexBar/StatusItemController+MenuCardItems.swift Passes refresh monitor into menu card container view.
Sources/CodexBar/StatusItemController+Menu.swift Registers refresh rows and initializes spinner state during menu build.
Sources/CodexBar/StatusItemController+Actions.swift Forces spinner on immediately when refresh is triggered.
Sources/CodexBar/MenuHighlightStyle.swift Adds menuCardRefreshMonitor environment entry.
Sources/CodexBar/MenuCardView.swift Adds MenuCardRefreshMonitor and live subtitle override based on refresh state.

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

Comment thread Sources/CodexBar/MenuCardView.swift
Comment thread Tests/CodexBarTests/StatusMenuPersistentRefreshTests.swift
Comment thread Sources/CodexBar/StatusItemController+PersistentMenuActions.swift Outdated
Comment thread Sources/CodexBar/MenuCardView.swift Outdated
Comment thread Sources/CodexBar/StatusItemController+MenuPresentation.swift
@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. labels Jun 12, 2026
hhh2210 and others added 3 commits June 12, 2026 07:56
Clicking the persistent Refresh row (⌘R) gave no immediate feedback while
the menu stayed open: the provider card kept showing "Updated …" and only
changed after switching cards or reopening the menu, prompting repeat clicks.

Add two in-place updates that work during NSMenu tracking without rebuilding
the open menu (preserving the deferred parent-rebuild policy from steipete#1001/steipete#1196/
steipete#1325):

- Live card subtitle: a narrowly-scoped MenuCardRefreshMonitor wraps the
  @observable UsageStore and is injected via the environment. The header
  subtitle reads shouldShowRefreshingMenuCardIndicator(for:) so SwiftUI
  re-renders the single-line subtitle in place to "Refreshing…" while a
  refresh is in flight, converging to the next rebuild's state. The gate
  requires error == nil, so the multi-line error layout is never swapped and
  row height stays fixed.

- Refresh row spinner: PersistentMenuActionItemView swaps its arrow.clockwise
  icon for a spinner occupying the same fixed 18pt slot (icon faded, not
  hidden, to avoid stack collapse). Forced on at click for instant feedback
  and reverted via the store observation on completion/failure.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@steipete
steipete force-pushed the feat/refresh-in-flight-feedback branch from 74ff56c to fec70d6 Compare June 12, 2026 07:09
@clawsweeper clawsweeper Bot added rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. and removed proof: sufficient Contributor real behavior proof is sufficient. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 12, 2026
@steipete
steipete force-pushed the feat/refresh-in-flight-feedback branch from fec70d6 to 2ced0e6 Compare June 12, 2026 07:31
@steipete

Copy link
Copy Markdown
Owner

Exact-head maintainer proof for 2ced0e62:

  • Rebased onto current main (f759e119) and preserved @hhh2210's authored commit and credit.
  • Built and ran the exact macOS app bundle. Info.plist reports CodexGitCommit=2ced0e62; executable SHA-256 is e3fe6fd0691b3f0fd61f72c8b50acd4d6bb9e0052ac1c725b326a828674fb69c.
  • Authenticated live refresh against an available local provider/account succeeded and updated live account data. No credentials, account payloads, or private labels were captured.
  • Exact built-app success lifecycle: the open menu changed immediately to Refreshing... plus spinner, retained 310x304 geometry, then returned to the idle refresh glyph with Updated just now.
  • Exact built-app failure lifecycle: the same immediate in-flight state and 310x304 geometry, then the idle refresh glyph plus the inline error/copy affordance.
  • Repeated-click coalescing: each burst of three physical Refresh clicks during an active success or failure request produced exactly one backend request.
  • Focused regression suite: 13/13 passed.
  • Full coverage: 3,802 tests passed in the full run; the two current-main suite-order hang cases each passed independently, covering all 3,804 tests.
  • make check, release build, strict ad-hoc codesign verification, and branch-mode autoreview all passed.
  • Public Model Identifier Gate: PASS. Exact diff and sanitized proof had zero candidates; exact candidate/base app bundles each had 45 pre-existing candidates and zero novel strings.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 12, 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.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels Jun 12, 2026
@steipete
steipete merged commit 915a9da into steipete:main Jun 12, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P3 Low-risk cleanup, docs, polish, ergonomics, or speculative feature. proof: sufficient Contributor real behavior proof is sufficient. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants