feat(brainbar): humanize injections tab (item F-2)#336
Conversation
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.
📝 WalkthroughWalkthroughThis PR enriches injection events with detailed chunk data throughout the stack: DB loads chunk rows into events; the model adds chunk/kind/filter types; presentation adds type filtering and chunk previews; the feed UI renders kind-based glyphs, previews, and persisted filters; and components/tests were updated accordingly. ChangesInjection Event Chunk Enrichment
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ee8bb71314
ℹ️ 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 trimmed = needle.trimmingCharacters(in: .whitespacesAndNewlines) | ||
| guard !trimmed.isEmpty else { return events } | ||
| let typedEvents = events.filter { event in | ||
| typeFilter.contains(event.primaryKind) |
There was a problem hiding this comment.
Match type filter against all retrieved chunk kinds
The new type filter only checks event.primaryKind, which is derived from the first chunk, so mixed-source retrievals are filtered incorrectly. If an event includes a selected type in any non-first chunk (for example a Video hit after a Stored hit), selecting that chip will hide the event even though it contains matching retrieved chunks. This makes the filter semantics inconsistent with the per-chunk UI and can mislead operators about what sources were actually injected.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 6b3207d: InjectionEvent now exposes allKinds/matches(typeFilter:), and InjectionPresentation filters with event.matches(typeFilter:) so non-first retrieved chunks are included. Added testSnapshotTypeFilterMatchesAnyRetrievedChunkKind.
| ] | ||
| if let event = try? InjectionEvent(row: row) { | ||
| if var event = try? InjectionEvent(row: row) { | ||
| let details = try injectionChunkDetails(ids: event.chunkIDs) |
There was a problem hiding this comment.
Prevent one bad chunk lookup from failing entire feed
Inside listInjectionEvents, chunk metadata loading is now a throwing call in the main row loop; if injectionChunkDetails fails for any single event (for example due malformed/oversized chunk_ids input), the whole query throws and the Injections feed degrades instead of returning the other valid events. This is a regression in read-path resilience introduced by metadata enrichment and can blank the tab for an otherwise recoverable per-event problem.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 6b3207d: listInjectionEvents now wraps injectionChunkDetails in try? and falls back to [] for that event, preserving the rest of the feed if one metadata lookup fails.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@brain-bar/Sources/BrainBar/InjectionFeedView.swift`:
- Around line 610-613: The color(for:) function uses kind.rawValue.hashValue
which is unstable across launches; replace that with a deterministic mapping
from InjectionKind.rawValue to an index into accentPalette (e.g., if rawValue is
an Int use Int(rawValue) % accentPalette.count, or if it’s a String compute a
stable numeric value such as summing unicodeScalars (unicodeScalars.map {
Int($0.value) }.reduce(0,+)) and then take abs(...) % accentPalette.count) so
that color(for:) always returns the same palette index for a given InjectionKind
across runs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 64292945-d66e-4427-8232-f25f9dd24eca
📒 Files selected for processing (7)
brain-bar/Sources/BrainBar/BrainDatabase.swiftbrain-bar/Sources/BrainBar/InjectionEvent.swiftbrain-bar/Sources/BrainBar/InjectionFeedView.swiftbrain-bar/Sources/BrainBar/InjectionPresentation.swiftbrain-bar/Sources/BrainBar/Views/Components/ChunkConversationSheet.swiftbrain-bar/Tests/BrainBarTests/DatabaseTests.swiftbrain-bar/Tests/BrainBarTests/InjectionEventTests.swift
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: test (3.13)
- GitHub Check: test (3.11)
- GitHub Check: test (3.12)
- GitHub Check: Macroscope - Correctness Check
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-03-18T00:12:08.774Z
Learnt from: EtanHey
Repo: EtanHey/brainlayer PR: 87
File: brain-bar/Sources/BrainBar/BrainBarServer.swift:118-129
Timestamp: 2026-03-18T00:12:08.774Z
Learning: In Swift files under brain-bar/Sources/BrainBar, enforce that when a critical dependency like the database is nil due to startup ordering (socket before DB), any tool handler that accesses the database must throw an explicit error (e.g., ToolError.noDatabase) instead of returning a default/empty value. Do not allow silent defaults (e.g., guard let db else { return ... }). Flag patterns that silently return defaults when db is nil, as this masks startup timing issues. This guidance applies broadly to similar Swift files in the BrainBar module, not just this one location.
Applied to files:
brain-bar/Sources/BrainBar/Views/Components/ChunkConversationSheet.swiftbrain-bar/Sources/BrainBar/BrainDatabase.swiftbrain-bar/Sources/BrainBar/InjectionPresentation.swiftbrain-bar/Sources/BrainBar/InjectionFeedView.swiftbrain-bar/Sources/BrainBar/InjectionEvent.swift
📚 Learning: 2026-03-29T18:45:40.988Z
Learnt from: EtanHey
Repo: EtanHey/brainlayer PR: 133
File: brain-bar/Sources/BrainBar/BrainDatabase.swift:0-0
Timestamp: 2026-03-29T18:45:40.988Z
Learning: In the BrainBar module’s Swift database layer (notably BrainDatabase.swift), ensure that the `search()` function’s `unreadOnly=true` path orders results by the delivery frontier cursor so the watermark `maxRowID` stays contiguous. Specifically, when `unreadOnly` is enabled, the query must include `ORDER BY c.rowid ASC` (e.g., via `let orderByClause = unreadOnly ? "c.rowid ASC" : "f.rank"`). Do not replace the unread-only ordering with relevance-based sorting (e.g., `f.rank`) unconditionally or for the unread-only path, as it can introduce gaps in the watermark and incorrectly mark unseen rows as delivered. Flag any future change to the `ORDER BY` clause in this function that makes relevance sorting apply to the unread-only case.
Applied to files:
brain-bar/Sources/BrainBar/BrainDatabase.swiftbrain-bar/Sources/BrainBar/InjectionPresentation.swiftbrain-bar/Sources/BrainBar/InjectionFeedView.swiftbrain-bar/Sources/BrainBar/InjectionEvent.swift
🔇 Additional comments (7)
brain-bar/Tests/BrainBarTests/DatabaseTests.swift (1)
654-685: LGTM!brain-bar/Tests/BrainBarTests/InjectionEventTests.swift (1)
37-63: LGTM!Also applies to: 65-73, 75-126
brain-bar/Sources/BrainBar/InjectionEvent.swift (1)
3-289: LGTM!brain-bar/Sources/BrainBar/BrainDatabase.swift (1)
4551-4561: LGTM!Also applies to: 4568-4604
brain-bar/Sources/BrainBar/InjectionPresentation.swift (1)
98-105: LGTM!Also applies to: 173-190, 334-335
brain-bar/Sources/BrainBar/InjectionFeedView.swift (1)
69-114: LGTM!Also applies to: 130-590, 721-747
brain-bar/Sources/BrainBar/Views/Components/ChunkConversationSheet.swift (1)
5-16: LGTM!Also applies to: 23-23, 99-110, 119-119
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\n@cursor @BugBot re-review\n@coderabbitai review\n\nUpdated PR branch at 6b3207d with fixes for prior review comments: type filtering now matches all retrieved chunk kinds, chunk detail lookup failure falls back per event, and kind colors use deterministic declaration-order palette indices. Please re-review current head. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Get the PR diff and key file contents
gh pr view 336 --repo EtanHey/brainlayer --json title,state,headRefName,baseRefName,commits
echo "=== Recent commits ==="
gh pr view 336 --repo EtanHey/brainlayer --json commits --jq '.commits[-5:]'
echo "=== PR files changed ==="
gh pr diff 336 --repo EtanHey/brainlayer --name-onlyLength of output: 2810 🏁 Script executed: #!/bin/bash
echo "=== InjectionEvent.swift ==="
cat brain-bar/Sources/BrainBar/InjectionEvent.swift
echo ""
echo "=== InjectionPresentation.swift ==="
cat brain-bar/Sources/BrainBar/InjectionPresentation.swift
echo ""
echo "=== BrainDatabase.swift (injection section) ==="
grep -n -A 60 "listInjectionEvents\|injectionChunkDetails" brain-bar/Sources/BrainBar/BrainDatabase.swift | head -200
echo ""
echo "=== InjectionFeedView.swift ==="
cat brain-bar/Sources/BrainBar/InjectionFeedView.swift
echo ""
echo "=== ChunkConversationSheet.swift ==="
cat brain-bar/Sources/BrainBar/Views/Components/ChunkConversationSheet.swiftLength of output: 65526 🏁 Script executed: #!/bin/bash
echo "=== InjectionEventTests.swift ==="
cat brain-bar/Tests/BrainBarTests/InjectionEventTests.swift
echo ""
echo "=== DatabaseTests.swift ==="
cat brain-bar/Tests/BrainBarTests/DatabaseTests.swiftLength of output: 58052
✅ Verified fixes
🔍 Remaining observations1. SQL variable limit in The // Chunk injectionChunkDetails into batches of, say, 500
private static let maxChunkQueryBatch = 500
private func injectionChunkDetails(ids: [String]) throws -> [InjectionChunk] {
guard let db else { throw DBError.notOpen }
let orderedIDs = ids.filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty }
guard !orderedIDs.isEmpty else { return [] }
var detailsByID: [String: InjectionChunk] = [:]
for batch in stride(from: 0, to: orderedIDs.count, by: Self.maxChunkQueryBatch).map({
Array(orderedIDs[$0..<min($0 + Self.maxChunkQueryBatch, orderedIDs.count)])
}) {
// existing prepare/step logic per batch...
}
return orderedIDs.compactMap { detailsByID[$0] }
}2. If a row's 3. Palette color collisions in the legend (cosmetic) With 10
Since the legend shows a colored dot per kind with a text label, users can still distinguish them by label; but the dots alone are ambiguous. Not a blocking issue — just consider expanding 4. Events whose chunk metadata couldn't be loaded ( OverallThe PR is well-structured and the injection humanization works correctly end-to-end. Issues 1 and 2 are worth a follow-up, but none are blocking for merge. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6b3207d8c7
ℹ️ 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".
|
|
||
| private static func topicOrSource(for event: InjectionEvent) -> String { | ||
| let trimmed = event.query.trimmingCharacters(in: .whitespacesAndNewlines) | ||
| let trimmed = event.displayTitle.trimmingCharacters(in: .whitespacesAndNewlines) |
There was a problem hiding this comment.
Keep burst grouping keyed on trigger query
Using event.displayTitle as topicOrSource makes burst grouping depend on the first retrieved chunk’s summary/content instead of the triggering query. In practice, repeated injections from the same session and prompt often return different top chunks, so the same retrieval flow gets split into multiple bursts, inflating burstCount and fragmenting the feed. This regresses the burst semantics validated elsewhere in InjectionPresentationTests (group-by session + topic) and should continue grouping by the trigger text while using display titles only for presentation.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 03ed083. The burst topic/source path is keyed from the trigger query again instead of displayTitle, preserving burst aggregation across multiple chunks with distinct content summaries. Added InjectionPresentationTests/testBurstAggregationUsesTriggerQueryWhenChunkSummariesDiffer; it failed before the change with two groups, then passed after.
|
@cursor @BugBot re-review\n@codex review\n@coderabbitai review\n\nUpdated current head 6f9ec2f for Cursor Bugbot findings: row Open title now uses the actually opened chunk or generic fallback, burst preview chunks are de-duplicated before ForEach, and typed filters keep events with chunk IDs visible when metadata failed to load. Local gates: focused regressions passed, affected Injection* tests passed, full BrainBar Swift suite passed (483 tests), pre-push BrainLayer gate passed. |
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.
|
You need to increase your spend limit or enable usage-based billing to run background agents. Go to Cursor |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== InjectionFeedView.swift ==="
cat brain-bar/Sources/BrainBar/InjectionFeedView.swift
echo ""
echo "=== InjectionPresentation.swift ==="
cat brain-bar/Sources/BrainBar/InjectionPresentation.swift
echo ""
echo "=== InjectionEvent.swift (filter/kind section) ==="
grep -n "matches\|typeFilter\|allKinds\|chunkIDs\|id = 0\|paletteIndex\|other\|other\b" brain-bar/Sources/BrainBar/InjectionEvent.swift | head -80
echo ""
echo "=== BrainDatabase.swift (injectionChunkDetails) ==="
grep -n -A 50 "injectionChunkDetails" brain-bar/Sources/BrainBar/BrainDatabase.swift | head -120
echo ""
echo "=== Recent commits at new head ==="
gh pr view 336 --repo EtanHey/brainlayer --json commits --jq '.commits[-5:] | .[] | {oid: .oid[0:8], message: .messageHeadline}'Length of output: 50990
✅ Fix verification
Bonus: Fix 3 also resolves the prior observation about 📌 Still-open latent items (non-blocking)The two low-risk observations from the previous round remain:
Would you like me to open GitHub issues for these two so they don't get lost? |
|
Codex Review: Didn't find any major issues. Already looking forward to the next diff. ℹ️ 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". |
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.
|
@coderabbitai review |
|
@codex 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.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 2c05eb3. Configure here.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2c05eb3800
ℹ️ 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".
| if normalizedSource == "mcp" || normalizedSource == "brain_store" { | ||
| return .storedMemory | ||
| } |
There was a problem hiding this comment.
Include manual source in stored-memory classification
InjectionKind.classify only maps mcp and brain_store to .storedMemory, but stored memories in this repo are also written with source="manual" (see brain_store tests and ingestion paths). With the current mapping, those chunks fall into .other, so they get the wrong glyph/label and are excluded by the new Stored type filter, which makes the injections view misclassify a major class of retrieved memories.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in a803a30. InjectionKind.classify now maps source="manual" to .storedMemory, so manually stored brain_store chunks get the Stored Memory glyph/label and remain visible under the Stored type filter. Added InjectionEventTests/testManualSourceClassifiesAsStoredMemory; it failed before the classifier change and passes after. Also addressed a local pre-commit review finding by resetting the conversation title on overlay close with InjectionConversationSelectionTests/testCloseClearsConversationAndResetsTitle.
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.
|
@coderabbitai review |
|
@codex 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: 03ed083d8c
ℹ️ 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".
| if ["cursor", "codex_cli", "codex"].contains(normalizedSource) { | ||
| return .toolSession |
There was a problem hiding this comment.
Include cursor_cli and gemini_cli in tool-session mapping
InjectionKind.classify only treats cursor, codex_cli, and codex as tool sessions, so chunks from the canonical CLI sources cursor_cli and gemini_cli fall through to .other. In practice this makes Tool-filtered views miss/mislabel real tool-origin injections (these source names are already first-class in src/brainlayer/pipeline/enrichment_tiers.py), which undermines the new type chips and modal labeling for common data.
Useful? React with 👍 / 👎.
| VStack(alignment: .leading, spacing: 8) { | ||
| ForEach(event.chunkIDs, id: \.self) { chunkID in | ||
| Button { | ||
| selectedConversationTitle = chunk(for: chunkID, event: event)?.kind.modalTitle ?? event.modalTitle |
There was a problem hiding this comment.
Use unknown-title fallback for chunk list modal opens
When a chunk in the expanded hit list has no loaded metadata, this path falls back to event.modalTitle instead of the generic unknown fallback used elsewhere (openingModalTitle(... ) returns "Conversation"). That means selecting an unmapped chunk can display an incorrect contextual title (for example, "Other" or another chunk’s kind) even though the selected chunk type is unknown.
Useful? React with 👍 / 👎.
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 |
|
@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: a803a30946
ℹ️ 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".
| if normalizedSource == "whatsapp" { | ||
| return .chat | ||
| } | ||
| if ["cursor", "codex_cli", "codex"].contains(normalizedSource) { | ||
| return .toolSession |
There was a problem hiding this comment.
Map known source values to the intended injection kinds
InjectionKind.classify currently recognizes chat only for whatsapp and tool sessions only for cursor/codex_cli/codex, so chunks from other known first-class sources (for example telegram, cursor_cli, gemini_cli) will be classified as .other. That causes the new type chips and labels to silently mis-filter/mislabel real events whenever those sources appear in chunk.source, even though the broader codebase already treats them as explicit source categories.
Useful? React with 👍 / 👎.
a803a30 to
dca7b71
Compare
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.
|
@coderabbitai review |
|
@codex review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dca7b71b2d
ℹ️ 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".
| ] | ||
| if let event = try? InjectionEvent(row: row) { | ||
| if var event = try? InjectionEvent(row: row) { | ||
| let details = (try? injectionChunkDetails(ids: event.chunkIDs)) ?? [] |
There was a problem hiding this comment.
Batch chunk detail reads instead of querying per injection event
listInjectionEvents now calls injectionChunkDetails inside the row loop, which turns one feed refresh into N+1 SQL statements (1 + event_count). In this repo, InjectionStore polls every 250ms with a default limit of 50 events, so this path can execute ~51 queries per refresh and significantly increase read-path cost and lock pressure on the shared DB during normal UI use. Fetching all needed chunk IDs in one batched query would avoid this regression.
Useful? React with 👍 / 👎.
| if ["cursor", "codex_cli", "codex"].contains(normalizedSource) { | ||
| return .toolSession |
There was a problem hiding this comment.
Map cursor_cli and gemini_cli sources to tool sessions
Tool-session classification only matches cursor, codex_cli, and codex, so chunks with source cursor_cli or gemini_cli are classified as .other and won't appear under the Tool filter despite being agent/tool sources in this codebase (see src/brainlayer/pipeline/enrichment_tiers.py). This causes incorrect type chips, legends, and modal titles for those injections.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
brain-bar/Sources/BrainBar/InjectionEvent.swift (1)
286-293:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
id = 0fallback risks duplicateIdentifiableids in SwiftUI.When row id parsing fails, multiple events will share
id = 0, violatingIdentifiableuniqueness. SwiftUIForEachmay exhibit undefined behavior (missing/duplicated rows, incorrect animations).Consider throwing an error or generating a unique sentinel (e.g., negative random id) instead.
🐛 Proposed fix using a unique sentinel
init(row: [String: Any]) throws { if let intID = row["id"] as? Int { id = Int64(intID) } else if let intID = row["id"] as? Int64 { id = intID } else { - id = 0 + id = Int64.random(in: Int64.min..<0) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@brain-bar/Sources/BrainBar/InjectionEvent.swift` around lines 286 - 293, The init(row:) currently falls back to id = 0 which creates duplicate Identifiable ids; update the InjectionEvent initializer to avoid using 0 as a fallback by either throwing a parsing error (propagate by making init(row:) throw a descriptive error when id is missing/invalid) or assign a unique sentinel (e.g., generate a negative random/hashed Int64 or derive from UUID/timestamp) to the id property; modify the init(row:) branch that now sets id = 0 to implement one of these two options and ensure any callers handle the thrown error or that the sentinel generation uses Int64 and is deterministic enough to avoid collisions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@brain-bar/Sources/BrainBar/BrainDatabase.swift`:
- Around line 4568-4604: injectionChunkDetails currently builds one IN(...)
statement which will fail silently for large id arrays due to SQLite's
SQLITE_MAX_VARIABLE_NUMBER limit; modify injectionChunkDetails to batch
orderedIDs into smaller chunks (e.g., 500 IDs per batch) and for each batch
build the placeholders, call sqlite3_prepare_v2, bindText for that batch, step
through rows to populate detailsByID, finalize the statement, then continue with
the next batch; after all batches are processed, return orderedIDs.compactMap {
detailsByID[$0] } so order is preserved and no metadata is dropped when the
variable limit is reached.
---
Outside diff comments:
In `@brain-bar/Sources/BrainBar/InjectionEvent.swift`:
- Around line 286-293: The init(row:) currently falls back to id = 0 which
creates duplicate Identifiable ids; update the InjectionEvent initializer to
avoid using 0 as a fallback by either throwing a parsing error (propagate by
making init(row:) throw a descriptive error when id is missing/invalid) or
assign a unique sentinel (e.g., generate a negative random/hashed Int64 or
derive from UUID/timestamp) to the id property; modify the init(row:) branch
that now sets id = 0 to implement one of these two options and ensure any
callers handle the thrown error or that the sentinel generation uses Int64 and
is deterministic enough to avoid collisions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 8b3f104d-ec36-4a95-840d-ce6ec6085bd8
📒 Files selected for processing (9)
brain-bar/Sources/BrainBar/BrainDatabase.swiftbrain-bar/Sources/BrainBar/InjectionEvent.swiftbrain-bar/Sources/BrainBar/InjectionFeedView.swiftbrain-bar/Sources/BrainBar/InjectionPresentation.swiftbrain-bar/Sources/BrainBar/Views/Components/ChunkConversationSheet.swiftbrain-bar/Tests/BrainBarTests/DatabaseTests.swiftbrain-bar/Tests/BrainBarTests/InjectionConversationSelectionTests.swiftbrain-bar/Tests/BrainBarTests/InjectionEventTests.swiftbrain-bar/Tests/BrainBarTests/InjectionPresentationTests.swift
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test (3.12)
- GitHub Check: test (3.13)
- GitHub Check: test (3.11)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-03-18T00:12:08.774Z
Learnt from: EtanHey
Repo: EtanHey/brainlayer PR: 87
File: brain-bar/Sources/BrainBar/BrainBarServer.swift:118-129
Timestamp: 2026-03-18T00:12:08.774Z
Learning: In Swift files under brain-bar/Sources/BrainBar, enforce that when a critical dependency like the database is nil due to startup ordering (socket before DB), any tool handler that accesses the database must throw an explicit error (e.g., ToolError.noDatabase) instead of returning a default/empty value. Do not allow silent defaults (e.g., guard let db else { return ... }). Flag patterns that silently return defaults when db is nil, as this masks startup timing issues. This guidance applies broadly to similar Swift files in the BrainBar module, not just this one location.
Applied to files:
brain-bar/Sources/BrainBar/BrainDatabase.swiftbrain-bar/Sources/BrainBar/Views/Components/ChunkConversationSheet.swiftbrain-bar/Sources/BrainBar/InjectionEvent.swiftbrain-bar/Sources/BrainBar/InjectionFeedView.swiftbrain-bar/Sources/BrainBar/InjectionPresentation.swift
📚 Learning: 2026-03-29T18:45:40.988Z
Learnt from: EtanHey
Repo: EtanHey/brainlayer PR: 133
File: brain-bar/Sources/BrainBar/BrainDatabase.swift:0-0
Timestamp: 2026-03-29T18:45:40.988Z
Learning: In the BrainBar module’s Swift database layer (notably BrainDatabase.swift), ensure that the `search()` function’s `unreadOnly=true` path orders results by the delivery frontier cursor so the watermark `maxRowID` stays contiguous. Specifically, when `unreadOnly` is enabled, the query must include `ORDER BY c.rowid ASC` (e.g., via `let orderByClause = unreadOnly ? "c.rowid ASC" : "f.rank"`). Do not replace the unread-only ordering with relevance-based sorting (e.g., `f.rank`) unconditionally or for the unread-only path, as it can introduce gaps in the watermark and incorrectly mark unseen rows as delivered. Flag any future change to the `ORDER BY` clause in this function that makes relevance sorting apply to the unread-only case.
Applied to files:
brain-bar/Sources/BrainBar/BrainDatabase.swiftbrain-bar/Sources/BrainBar/InjectionEvent.swiftbrain-bar/Sources/BrainBar/InjectionFeedView.swiftbrain-bar/Sources/BrainBar/InjectionPresentation.swift
🪛 SwiftLint (0.63.2)
brain-bar/Tests/BrainBarTests/InjectionConversationSelectionTests.swift
[Warning] 4-4: Classes should have an explicit deinit method
(required_deinit)
🔇 Additional comments (15)
brain-bar/Sources/BrainBar/Views/Components/ChunkConversationSheet.swift (2)
5-5: LGTM!Also applies to: 9-17, 23-23
99-99: LGTM!Also applies to: 102-110, 119-119
brain-bar/Sources/BrainBar/InjectionPresentation.swift (1)
98-105: LGTM!Also applies to: 140-151, 186-203
brain-bar/Sources/BrainBar/InjectionFeedView.swift (1)
68-70: LGTM!Also applies to: 109-114, 153-177, 258-279, 319-343, 378-397, 419-424, 441-467, 481-493, 617-619, 732-754, 757-771
brain-bar/Sources/BrainBar/InjectionEvent.swift (6)
3-49: LGTM!
51-72: LGTM!
74-166: LGTM!
168-211: LGTM!
299-307: Graceful handling of malformedchunk_idsJSON.Using
try?to silently fall back to an empty array on JSON decode failure is appropriate here—per PR objectives, malformed JSON no longer throws.
309-313: LGTM!brain-bar/Sources/BrainBar/BrainDatabase.swift (1)
4551-4563: Event enrichment with graceful fallback on chunk lookup failure.The
try?pattern correctly ensures events are still returned (with emptychunks) when chunk metadata lookup fails, matching the PR's robustness objective.brain-bar/Tests/BrainBarTests/DatabaseTests.swift (1)
654-685: LGTM!brain-bar/Tests/BrainBarTests/InjectionConversationSelectionTests.swift (1)
1-26: LGTM!brain-bar/Tests/BrainBarTests/InjectionEventTests.swift (1)
37-261: LGTM!brain-bar/Tests/BrainBarTests/InjectionPresentationTests.swift (1)
116-145: LGTM!Also applies to: 261-293, 300-323
| private func injectionChunkDetails(ids: [String]) throws -> [InjectionChunk] { | ||
| guard let db else { throw DBError.notOpen } | ||
| let orderedIDs = ids.filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty } | ||
| guard !orderedIDs.isEmpty else { return [] } | ||
|
|
||
| let placeholders = Array(repeating: "?", count: orderedIDs.count).joined(separator: ",") | ||
| let sql = """ | ||
| SELECT id, content, summary, source, source_file, tags, content_type | ||
| FROM chunks | ||
| WHERE id IN (\(placeholders)) | ||
| """ | ||
| var stmt: OpaquePointer? | ||
| guard sqlite3_prepare_v2(db, sql, -1, &stmt, nil) == SQLITE_OK else { | ||
| throw DBError.prepare(sqlite3_errcode(db)) | ||
| } | ||
| defer { sqlite3_finalize(stmt) } | ||
|
|
||
| for (offset, id) in orderedIDs.enumerated() { | ||
| bindText(id, to: stmt, index: Int32(offset + 1)) | ||
| } | ||
|
|
||
| var detailsByID: [String: InjectionChunk] = [:] | ||
| while sqlite3_step(stmt) == SQLITE_ROW { | ||
| let row: [String: Any] = [ | ||
| "id": columnText(stmt, 0) as Any, | ||
| "content": columnText(stmt, 1) as Any, | ||
| "summary": columnText(stmt, 2) as Any, | ||
| "source": columnText(stmt, 3) as Any, | ||
| "source_file": columnText(stmt, 4) as Any, | ||
| "tags": columnText(stmt, 5) as Any, | ||
| "content_type": columnText(stmt, 6) as Any, | ||
| ] | ||
| let detail = InjectionChunk(row: row) | ||
| detailsByID[detail.id] = detail | ||
| } | ||
| return orderedIDs.compactMap { detailsByID[$0] } | ||
| } |
There was a problem hiding this comment.
SQL variable limit could silently drop chunk metadata for high-cardinality events.
SQLite's default SQLITE_MAX_VARIABLE_NUMBER is 999. For events with ≥999 chunkIDs, sqlite3_prepare_v2 will fail and the caller's try? fallback returns empty chunks—silently degrading the event.
Consider batching queries (e.g., 500 IDs per batch) to avoid hitting the limit.
♻️ Suggested batching approach
private func injectionChunkDetails(ids: [String]) throws -> [InjectionChunk] {
guard let db else { throw DBError.notOpen }
let orderedIDs = ids.filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty }
guard !orderedIDs.isEmpty else { return [] }
+ let batchSize = 500
+ var detailsByID: [String: InjectionChunk] = [:]
+
+ for batchStart in stride(from: 0, to: orderedIDs.count, by: batchSize) {
+ let batchEnd = min(batchStart + batchSize, orderedIDs.count)
+ let batch = Array(orderedIDs[batchStart..<batchEnd])
+ let placeholders = Array(repeating: "?", count: batch.count).joined(separator: ",")
+ let sql = """
+ SELECT id, content, summary, source, source_file, tags, content_type
+ FROM chunks
+ WHERE id IN (\(placeholders))
+ """
+ var stmt: OpaquePointer?
+ guard sqlite3_prepare_v2(db, sql, -1, &stmt, nil) == SQLITE_OK else {
+ throw DBError.prepare(sqlite3_errcode(db))
+ }
+ defer { sqlite3_finalize(stmt) }
+
+ for (offset, id) in batch.enumerated() {
+ bindText(id, to: stmt, index: Int32(offset + 1))
+ }
+
+ while sqlite3_step(stmt) == SQLITE_ROW {
+ let row: [String: Any] = [
+ "id": columnText(stmt, 0) as Any,
+ "content": columnText(stmt, 1) as Any,
+ "summary": columnText(stmt, 2) as Any,
+ "source": columnText(stmt, 3) as Any,
+ "source_file": columnText(stmt, 4) as Any,
+ "tags": columnText(stmt, 5) as Any,
+ "content_type": columnText(stmt, 6) as Any,
+ ]
+ let detail = InjectionChunk(row: row)
+ detailsByID[detail.id] = detail
+ }
+ }
+
+ return orderedIDs.compactMap { detailsByID[$0] }
- let placeholders = Array(repeating: "?", count: orderedIDs.count).joined(separator: ",")
- // ... rest of current implementation
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@brain-bar/Sources/BrainBar/BrainDatabase.swift` around lines 4568 - 4604,
injectionChunkDetails currently builds one IN(...) statement which will fail
silently for large id arrays due to SQLite's SQLITE_MAX_VARIABLE_NUMBER limit;
modify injectionChunkDetails to batch orderedIDs into smaller chunks (e.g., 500
IDs per batch) and for each batch build the placeholders, call
sqlite3_prepare_v2, bindText for that batch, step through rows to populate
detailsByID, finalize the statement, then continue with the next batch; after
all batches are processed, return orderedIDs.compactMap { detailsByID[$0] } so
order is preserved and no metadata is dropped when the variable limit is
reached.

Summary
Implements Item F Fix 2 from
/tmp/codex-mandate-item-F.md: humanize the BrainBar Injections tab so retrieval cards are based on retrieved chunk content instead of source-prompt plumbing.Changes
InjectionEventobjects with chunk metadata fromchunksduringlistInjectionEvents.summary/content, with query text demoted toTriggered by:subtitle.Tests
swift test --package-path brain-bar --filter 'InjectionEventTests|DatabaseTests/testListInjectionEventsLoadsChunkDisplayMetadata'swift test --package-path brain-bar --filter 'InjectionPresentationTests|InjectionStoreTests|InjectionEventTests|DatabaseTests/testListInjectionEventsLoadsChunkDisplayMetadata'swift test --package-path brain-bar— 478 tests, 0 failuresgit diff --checkcr review --plain --type uncommitted— no findingstest_fts5_determinism.sh: passVisual Gate
Per Etan addendum, this PR still requires post-merge rebuild + relaunch + Computer Use screenshots of Dashboard, Injections, and Graph before
TASK_DONE_FIX_2.Note
Medium Risk
Each injection list now runs an extra chunks query per event (read-path cost), and classification/filter behavior affects what users see in a core BrainBar surface; changes are localized to UI/read models with broad test coverage.
Overview
Humanizes the BrainBar Injections tab by loading retrieved chunk rows when listing injection events and driving cards from summary/content instead of raw query text, with the query shown as a “Triggered by:” line.
Adds
InjectionChunk,InjectionKind(glyphs, labels, source-based classification), andInjectionTypeFilterwith persisted filter chips (All, Memory, Stored, Realtime, etc.).InjectionPresentation.snapshotapplies the type filter and extends text search to display titles and chunk sources; burst previews can show deduplicated chunk previews with kind glyphs.InjectionFeedViewupdates burst/event rows, hit-bar colors by kind (not chunk-ID hash), legends/tooltips, andInjectionConversationSelectionsoChunkConversationSheet/ overlay use chunk-type modal titles instead of a fixed “Conversation”.InjectionEventrow parsing no longer throws on malformedchunk_idsJSON—it falls back to an empty array. Events with chunk IDs but missing loaded metadata still pass non-Alltype filters so rows are not hidden incorrectly.Reviewed by Cursor Bugbot for commit dca7b71. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Note
Add semantic kind classification and type filtering to the BrainBar injections tab
InjectionKind(with glyphs, labels, and palette indices) andInjectionTypeFilterto classify injection events by source type (memory, stored, realtime, checkpoint, video, chat, tool)InjectionEventandInjectionChunknow carry chunk metadata (content, summary, source, tags) fetched from the database, enabling display-ready titles and kind classification in the UIInjectionFeedViewis reworked to show kind glyphs, display titles, 'Triggered by' query lines, and a persistent type-filter chip row; chunk ribbon colors are now stable per kind rather than hashed per chunk IDInjectionPresentation.snapshotandfilteraccept atypeFilterto narrow results by type and match against display titles and chunk sourceschunk_idsJSON inInjectionEventrow initializer no longer throws — it silently falls back to an empty arrayMacroscope summarized dca7b71.