-
Notifications
You must be signed in to change notification settings - Fork 7
fix: filter audit recursion from default search #277
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
110f436
316769b
1605ea5
70bdc7e
eb29a30
4a8c8ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -532,7 +532,8 @@ final class BrainDatabase: @unchecked Sendable { | |
| tag: String? = nil, | ||
| importanceMin: Double? = nil, | ||
| subscriberID: String? = nil, | ||
| unreadOnly: Bool = false | ||
| unreadOnly: Bool = false, | ||
| includeAudit: Bool = false | ||
| ) throws -> [[String: Any]] { | ||
| guard db != nil else { throw DBError.notOpen } | ||
| let trimmedQuery = query.trimmingCharacters(in: .whitespacesAndNewlines) | ||
|
|
@@ -551,7 +552,8 @@ final class BrainDatabase: @unchecked Sendable { | |
| project: project, | ||
| source: source, | ||
| tag: tag, | ||
| importanceMin: importanceMin | ||
| importanceMin: importanceMin, | ||
| includeAudit: includeAudit | ||
| ) { | ||
| return exact | ||
| } | ||
|
|
@@ -572,7 +574,8 @@ final class BrainDatabase: @unchecked Sendable { | |
| importanceMin: importanceMin, | ||
| subscribedTags: subscribedTags, | ||
| ackFloor: ackFloor, | ||
| unreadOnly: unreadOnly | ||
| unreadOnly: unreadOnly, | ||
| includeAudit: includeAudit | ||
| ) | ||
| maxRowID = max(maxRowID, searchResult.maxRowID) | ||
| appendDeduped(searchResult.rows, to: &results, seenChunkIDs: &seenChunkIDs, limit: limit) | ||
|
|
@@ -593,7 +596,8 @@ final class BrainDatabase: @unchecked Sendable { | |
| importanceMin: importanceMin, | ||
| subscribedTags: subscribedTags, | ||
| ackFloor: ackFloor, | ||
| unreadOnly: unreadOnly | ||
| unreadOnly: unreadOnly, | ||
| includeAudit: includeAudit | ||
| ) | ||
| maxRowID = max(maxRowID, searchResult.maxRowID) | ||
| appendDeduped(searchResult.rows, to: &results, seenChunkIDs: &seenChunkIDs, limit: limit) | ||
|
|
@@ -618,7 +622,8 @@ final class BrainDatabase: @unchecked Sendable { | |
| importanceMin: Double?, | ||
| subscribedTags: [String], | ||
| ackFloor: Int64, | ||
| unreadOnly: Bool | ||
| unreadOnly: Bool, | ||
| includeAudit: Bool | ||
| ) throws -> (rows: [[String: Any]], maxRowID: Int64) { | ||
| guard let db else { throw DBError.notOpen } | ||
| let allowedTables = ["chunks_fts", "chunks_fts_trigram"] | ||
|
|
@@ -636,6 +641,7 @@ final class BrainDatabase: @unchecked Sendable { | |
| let tagTerms = Array(repeating: "c.tags LIKE ?", count: subscribedTags.count).joined(separator: " OR ") | ||
| conditions.append("(\(tagTerms))") | ||
| } | ||
| if !includeAudit { conditions.append(Self.auditRecursionTagExclusionSQL(alias: "c")) } | ||
| if importanceMin != nil { conditions.append("c.importance >= ?") } | ||
| if unreadOnly { conditions.append("c.rowid > ?") } | ||
|
|
||
|
|
@@ -907,7 +913,8 @@ final class BrainDatabase: @unchecked Sendable { | |
| tag: String? = nil, | ||
| importanceMin: Double? = nil, | ||
| subscriberID: String? = nil, | ||
| unreadOnly: Bool = false | ||
| unreadOnly: Bool = false, | ||
| includeAudit: Bool = false | ||
| ) throws -> [SearchQueryCandidate] { | ||
| guard let db else { throw DBError.notOpen } | ||
| let sanitized = sanitizeFTS5Query(query) | ||
|
|
@@ -930,6 +937,7 @@ final class BrainDatabase: @unchecked Sendable { | |
| let tagTerms = Array(repeating: "c.tags LIKE ?", count: subscribedTags.count).joined(separator: " OR ") | ||
| conditions.append("(\(tagTerms))") | ||
| } | ||
| if !includeAudit { conditions.append(Self.auditRecursionTagExclusionSQL(alias: "c")) } | ||
| if importanceMin != nil { conditions.append("c.importance >= ?") } | ||
| if unreadOnly { conditions.append("c.rowid > ?") } | ||
|
|
||
|
|
@@ -1487,6 +1495,20 @@ final class BrainDatabase: @unchecked Sendable { | |
| """ | ||
| } | ||
|
|
||
| private static func auditRecursionTagExclusionSQL(alias: String) -> String { | ||
| let tagsJSON = "CASE WHEN json_valid(\(alias).tags) THEN \(alias).tags ELSE '[]' END" | ||
| let tagValue = "LOWER(CAST(audit_tags.value AS TEXT))" | ||
| return """ | ||
| NOT EXISTS ( | ||
| SELECT 1 | ||
| FROM json_each(\(tagsJSON)) audit_tags | ||
| WHERE \(tagValue) LIKE '%audit%' | ||
| OR \(tagValue) = 'agent=auditor' | ||
| OR \(tagValue) GLOB 'r0[0-9]' | ||
| ) | ||
| """ | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Swift audit filter missing r0x tag exclusionMedium Severity The Swift Reviewed by Cursor Bugbot for commit 4a8c8ee. Configure here. |
||
|
|
||
| private func databaseSizeBytes() -> Int64 { | ||
| let candidates = [path, "\(path)-wal", "\(path)-shm"] | ||
| return candidates.reduce(into: Int64(0)) { total, candidate in | ||
|
|
@@ -1813,7 +1835,8 @@ final class BrainDatabase: @unchecked Sendable { | |
| project: String?, | ||
| source: String?, | ||
| tag: String?, | ||
| importanceMin: Double? | ||
| importanceMin: Double?, | ||
| includeAudit: Bool | ||
| ) throws -> [[String: Any]]? { | ||
| guard let db else { throw DBError.notOpen } | ||
| guard limit > 0, !query.contains(where: { $0.isWhitespace }), query.contains("-") else { | ||
|
|
@@ -1825,6 +1848,7 @@ final class BrainDatabase: @unchecked Sendable { | |
| if project != nil { conditions.append("c.project = ?") } | ||
| if sourceFilter != nil { conditions.append("c.source = ?") } | ||
| if tag != nil { conditions.append("c.tags LIKE ?") } | ||
| if !includeAudit { conditions.append(Self.auditRecursionTagExclusionSQL(alias: "c")) } | ||
| if importanceMin != nil { conditions.append("c.importance >= ?") } | ||
|
|
||
| let sql = """ | ||
|
|
||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default BrainBar filter claims to exclude
r02/r0xaudit recursion tags, but this SQL only matchesGLOB 'r0[0-9]', so chunks tagged exactlyr0xstill leak into defaultbrain_searchresults wheninclude_auditis false. This creates an inconsistent contract versus the Python path (which does filterr0x) and allows the audit-recursion contamination this change is meant to prevent.Useful? React with 👍 / 👎.