feat: overhaul BrainBar dashboard UX#246
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (24)
📝 WalkthroughWalkthroughThis PR introduces enrichment pipeline tracking to the dashboard with new metrics and UI components, extends BrainDatabase with typed conversation structures and enrichment statistics, refactors InjectionStore to use Darwin notifications and polling, updates knowledge graph sidebar for conversation browsing, improves popover sizing behavior, and adds comprehensive test coverage. Changes
Sequence Diagram(s)sequenceDiagram
participant Dashboard as Dashboard UI
participant Collector as StatsCollector
participant DB as BrainDatabase
participant Daemon as DaemonHealthMonitor
Dashboard->>Collector: observe `@Published` stats
Collector->>Daemon: getDaemonHealth()
Daemon-->>Collector: DaemonHealthSnapshot
Collector->>DB: dashboardStats()
DB->>DB: compute enrichmentRatePerMinute<br/>compute recentEnrichmentBuckets
DB-->>Collector: DashboardStats
Collector->>Collector: `@Published` stats updated
Dashboard->>Dashboard: derive PipelineIndicators<br/>derive PipelineActivityTracks
Dashboard->>Dashboard: render pipeline badges<br/>render activity rows
sequenceDiagram
participant User as User Interaction
participant InjectionFeed as InjectionFeedView
participant Store as InjectionStore
participant DB as BrainDatabase
participant Sheet as ChunkConversationSheet
User->>InjectionFeed: tap expand button
InjectionFeed->>InjectionFeed: toggle expandedEventIDs
User->>InjectionFeed: tap chunk Open button
InjectionFeed->>Store: expandedConversation(chunkID:)
Store->>DB: expandedConversation(id:)
DB->>DB: query before_context + target + after_context
DB-->>Store: ExpandedConversation typed result
Store-->>InjectionFeed: ExpandedConversation
InjectionFeed->>InjectionFeed: set selectedConversation
InjectionFeed->>Sheet: present ChunkConversationSheet
Sheet->>Sheet: render conversation entries<br/>with role/timestamp/summary
sequenceDiagram
participant System as Darwin Notification
participant Store as InjectionStore
participant PollingTask as Polling Task
participant DB as BrainDatabase
PollingTask->>Store: start(sessionID:)
Store->>Store: install Darwin observer<br/>launch repeating pollTask
loop Every 250ms
PollingTask->>DB: dataVersion()
DB-->>PollingTask: version
alt Version changed
PollingTask->>DB: listInjectionEvents()
DB-->>PollingTask: [InjectionEvent]
PollingTask->>Store: update `@Published` events
end
end
System->>Store: Darwin notification fired
Store->>Store: dispatch refresh(force: false)
Store->>DB: dataVersion() & listInjectionEvents()
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
|
@codex review |
|
You need to increase your spend limit or enable usage-based billing to run background agents. Go to Cursor |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: caa7e9e726
ℹ️ 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".
|
@codex review |
|
@coderabbitai review |
|
You need to increase your spend limit or enable usage-based billing to run background agents. Go to Cursor |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 638671e523
ℹ️ 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".
|
Codex Review: Didn't find any major issues. Bravo. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
…ddresses cursor thread)
…addresses macroscopeapp thread)
…r I/O (addresses cursor thread)
|
Follow-up fixes pushed for the recovered review items on head 24521cc. @codex review @cursor @BugBot re-review @coderabbitai review |
|
🧠 Learnings used✅ Actions performedReview triggered.
|
|
|
||
| private func readMCPMessage(fd: Int32, timeout: TimeInterval = 5.0) throws -> [String: Any] { | ||
| var buffer = Data() | ||
| var buffer = bufferedMessagesByFD[fd] ?? Data() |
There was a problem hiding this comment.
🟡 Medium BrainBarTests/SocketIntegrationTests.swift:703
In readMCPMessage, when EOF or a non-recoverable read error occurs, the code removes fd from bufferedMessagesByFD (lines 719-720, 721-723) but then unconditionally re-stores bufferedMessagesByFD[fd] = buffer at line 728 before throwing. This preserves stale buffer data for a closed connection. Since the OS can reuse file descriptor numbers after close(), a subsequent connectClient() call may receive the same fd and inherit the stale buffered data from the previous connection, causing incorrect parsing or test failures. Consider skipping the re-store when the connection is dead (after the break statements at lines 720 or 723).
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file brain-bar/Tests/BrainBarTests/SocketIntegrationTests.swift around line 703:
In `readMCPMessage`, when EOF or a non-recoverable read error occurs, the code removes `fd` from `bufferedMessagesByFD` (lines 719-720, 721-723) but then unconditionally re-stores `bufferedMessagesByFD[fd] = buffer` at line 728 before throwing. This preserves stale buffer data for a closed connection. Since the OS can reuse file descriptor numbers after `close()`, a subsequent `connectClient()` call may receive the same `fd` and inherit the stale buffered data from the previous connection, causing incorrect parsing or test failures. Consider skipping the re-store when the connection is dead (after the `break` statements at lines 720 or 723).
Evidence trail:
brain-bar/Tests/BrainBarTests/SocketIntegrationTests.swift lines 703-729 at REVIEWED_COMMIT: readMCPMessage function shows the removal at lines 719-720 (EOF case) and 721-723 (error case) followed by unconditional re-store at line 728.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 24521cc63f
ℹ️ 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".
| let currentDataVersion = try database.dataVersion() | ||
| if force || currentDataVersion != lastDataVersion { | ||
| events = try database.listInjectionEvents( | ||
| sessionID: currentSessionID, | ||
| limit: currentLimit | ||
| ) |
There was a problem hiding this comment.
Move injection refresh DB reads off the main actor
InjectionStore is @MainActor, and refresh(force:) performs synchronous SQLite calls (dataVersion and listInjectionEvents) directly on that actor. Because this code path is triggered by both the 250ms poll loop and Darwin notifications, any DB lock contention can block the UI thread (the database connection is configured with a long busy timeout), which can freeze the popover/menubar app during enrichment lock windows. This regression was introduced by replacing GRDB observation with direct reads on the main actor.
Useful? React with 👍 / 👎.
| private func flushPendingWrites(fd: Int32) -> Bool { | ||
| guard var state = clients[fd] else { return false } | ||
| state.hasScheduledWriteRetry = false | ||
| clients[fd] = state |
There was a problem hiding this comment.
Keep retry guard set while a stalled write is still pending
flushPendingWrites clears hasScheduledWriteRetry before attempting to write, even when the socket is still backpressured. If more responses are enqueued before the previously scheduled retry fires, each enqueue path resets the flag and schedules another asyncAfter, producing a growing queue of redundant retry tasks for the same fd. Under sustained backpressure this adds avoidable queue churn and can degrade responsiveness for other clients.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 99a0d6d. Configure here.
|
|
||
| func openConversation(chunkID: String) { | ||
| selectedConversation = try? database.expandedConversation(id: chunkID) | ||
| } |
There was a problem hiding this comment.
Silent error swallowing hides conversation load failures
Medium Severity
KGViewModel.openConversation uses try? to silently discard database errors, so when a user clicks "Open" on a linked chunk in the knowledge-graph sidebar and the query fails (chunk not found, database locked, etc.), nothing happens — no sheet, no error message. The parallel code path in InjectionFeedView properly catches errors and shows an alert via conversationErrorMessage. This inconsistency means KG users get zero feedback on failure.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 99a0d6d. Configure here.
| track: activityTracks.enriching, | ||
| detailRateText: DashboardMetricFormatter.rateDetailString( | ||
| ratePerMinute: enrichmentDisplayRatePerMinute | ||
| ) |
There was a problem hiding this comment.
Render recomputes rates already derived by PipelineActivityTracks
Low Severity
render() manually computes enrichmentDisplayRatePerMinute and indexingRatePerMinute using PipelineActivityTracks.displayedRatePerMinute and recentRatePerMinute, then a few lines later calls PipelineActivityTracks.derive() which internally recomputes exactly the same rates with the same inputs and defaults. These duplicated calculations diverge silently if the default parameters ever change in one place but not the other. Exposing the rates from PipelineActivityTrack or PipelineActivityTracks would remove the duplication.
Reviewed by Cursor Bugbot for commit 99a0d6d. Configure here.


Summary
InjectionStore, real popover-size regression coverage, andbuild-app.shsocket verification only when the LaunchAgent is actually installedTest plan
swift test --package-path brain-bar --filter 'BrainBarUXLogicTests|InjectionStoreTests|PopoverTabTests|StabilityFixTests'bash brain-bar/build-app.shVerification notes
638671e5.swift test --package-path brain-baris still red on this branch because of pre-existing knowledge-graph test failures/crashes outside this UX slice (KGDatabaseTestsassertions and aKGViewModelTestsindex-out-of-range crash).Note
Overhaul BrainBar dashboard UX with pipeline indicators, activity tracks, and conversation drill-down
PipelineIndicatorBadgeView), a Speed metric tile, and two activity rows (PipelineActivityRowView) showing per-track sparklines and rate/detail strings; removes the old inline sparkline and Refresh button.DashboardMetricFormatterandPipelineStatemodels (PipelineIndicators,PipelineActivityTracks) to compute and format indexing/enriching rates, statuses, and bucket-based sparkline data.BrainDatabasewith enrichment rate and bucket queries, a typedExpandedConversationmodel, and a Darwin notification posted on injection insert;InjectionStoreis rewritten to use polling + Darwin notifications instead of GRDB ValueObservation.ChunkConversationSheetdisplaying role, timestamp, and content for a chunk's conversation history.build-app.shto deterministically stop the LaunchAgent, wait for process exit, clean up the socket, and verify connectivity after bootstrapping.recentEnrichmentBucketsinstead ofrecentActivityBuckets.Macroscope summarized 99a0d6d.
Note
Medium Risk
Touches multiple runtime-critical paths (SQLite stats queries, injection event persistence/ordering, and socket write/backpressure handling) plus a sizable dashboard UI refactor, so regressions could affect live status rendering and client connectivity.
Overview
Dashboard UX overhaul: the popover is redesigned into a stable 560×520 utility panel with new pipeline indicator badges and separate Indexing/Enriching activity rows (each with its own sparkline), plus a new
Speedmetric and digit-stable formatting viaDashboardMetricFormatter.New enrichment telemetry:
BrainDatabase.DashboardStatsnow includesrecentEnrichmentBucketsandenrichmentRatePerMinute, with new SQL helpers to bucket byenriched_atand compute a short-window completion rate; the menu-bar sparkline is switched to render enrichment activity.Conversation thread viewing: adds typed
ExpandedConversation/ConversationChunkmodels andexpandedConversation(...), introducesChunkConversationSheet, and wires injection events and KG sidebar chunk links to open the surrounding thread for a selected chunk.Data + reliability fixes:
InjectionStoreis rewritten to useBrainDatabase+ Darwin notifications/data-version polling (removing GRDB observation), injection events use deterministic ordering (timestamp DESC, id DESC) and only post change notifications on successful insert, popover resizing is guarded to prevent drift, socket backpressure tests are expanded/cleaned up, andbuild-app.shnow safely stops the LaunchAgent and verifies socket recreation only when the agent is installed.Reviewed by Cursor Bugbot for commit 99a0d6d. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
Bug Fixes
Improvements