Add search text matcher boundary#13
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 701307a35d
ℹ️ 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".
| <!-- session:019e1a49-efbb-7911-936e-90e6dfd8b17e rollout:/Users/aki/.codex/sessions/2026/05/11/rollout-2026-05-11T22-45-13-019e1a49-efbb-7911-936e-90e6dfd8b17e.jsonl --> | ||
| - User asked: Implement the next AkFit cleanup-only PR. |
There was a problem hiding this comment.
Drop committed local session log from repository
Remove this .memsearch memory file from the commit: it contains local machine paths and session metadata that are unrelated to app behavior, and committing it leaks developer-environment details while adding persistent noise to version control. These generated artifacts should be excluded (for example via ignore rules) rather than tracked.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR refactors shared search normalization/matching/scoring into a new pure helper (SearchTextMatcher) and updates both Supabase-backed search and SearchView type-ahead to delegate to it, with new unit tests to preserve behavior.
Changes:
- Added
SearchTextMatcherwith normalization, aliasing, stemming, scoring, and suggestion-matching helpers. - Updated
SupabaseFoodSearchServiceandSearchViewto delegate search behavior to the helper. - Added
SearchTextMatcherTeststo lock in expected normalization and suggestion ranking behavior.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| AkFit/AkFit/Search/SearchTextMatcher.swift | Introduces centralized pure search-text normalization/matching/scoring/suggestions logic. |
| AkFit/AkFit/Search/SupabaseFoodSearchService.swift | Delegates query normalization, filtering, and scoring to SearchTextMatcher. |
| AkFit/AkFit/Views/Search/SearchView.swift | Delegates type-ahead suggestion matching to SearchTextMatcher. |
| AkFit/AkFitTests/SearchTextMatcherTests.swift | Adds unit tests for normalization, stemming, and suggestion ranking behavior. |
| .memsearch/memory/2026-05-11.md | Adds a local session log file (appears unrelated to app code). |
| .memsearch/.index.pid | Adds a transient PID artifact (appears unrelated to app code). |
Comments suppressed due to low confidence (1)
.memsearch/.index.pid:2
.index.pidlooks like a transient runtime artifact (PID) that will change between machines/runs and cause needless churn/merge conflicts. Suggest removing it from the PR and ignoring it (e.g. via.gitignorefor.memsearch/).
55537
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ## Session 22:45 | ||
|
|
||
| ### 22:45 | ||
| <!-- session:019e1a49-fa43-7912-b11c-9fd8c96a3034 rollout: --> | ||
| - Codex: {"title":"Add search helper tests"} | ||
|
|
||
| ### 22:52 | ||
| <!-- session:019e1a49-efbb-7911-936e-90e6dfd8b17e rollout:/Users/aki/.codex/sessions/2026/05/11/rollout-2026-05-11T22-45-13-019e1a49-efbb-7911-936e-90e6dfd8b17e.jsonl --> | ||
| - User asked: Implement the next AkFit cleanup-only PR. | ||
| - Codex: Implemented the cleanup-only search boundary. No commit made. | ||
|
|
||
| **Files Changed** | ||
| - [SearchTextMatcher.swift](/Users/aki/Documents/AkTalkToEM/AkCodeForEm/Project%20Workspace/AkPerso/AkFit/AkFit/AkFit/Search/SearchTextMatcher.swift) new pure helper | ||
| - [SupabaseFoodSearchService.swift](/Users/aki/Documents/AkTalkToEM/AkCodeForEm/Project%20Workspace/AkPerso/AkFit/AkFit/AkFit/Search/SupabaseFoodSearchService.swift) now delegates normalization/filtering/scoring | ||
| - [SearchView.swift](/Users/aki/Documents/AkTalkToEM/AkCodeForEm/Project%20Workspace/AkPerso/AkFit/AkFit/AkFit/Views/Search/SearchView.swift) type-ahead matching now delegates to helper | ||
| - [SearchTextMatcherTests.swift](/Users/aki/Documents/AkTalkToEM/AkCodeForEm/Project%20Workspace/AkPerso/AkFit/AkFit/AkFitTests/SearchTextMatcherTests.swif... |
| /// Returns true when every normalized query word matches the term either | ||
| /// directly or through the rough plural stem. | ||
| static func matchesAllQueryWords(term: String, normalizedQuery: String) -> Bool { | ||
| guard !normalizedQuery.isEmpty else { return false } | ||
| let words = normalizedQuery.split(separator: " ").map(String.init) | ||
| let stemmedWords = words.map { stemWord($0) } | ||
| let normalizedTerm = normalizeForSearch(term) | ||
| let stemmedTerm = stemmedForm(normalizedTerm) | ||
| return words.allSatisfy { normalizedTerm.contains($0) } || | ||
| stemmedWords.allSatisfy { stemmedTerm.contains($0) } | ||
| } | ||
|
|
| rows = candidates.filter { row in | ||
| let n = Self.normalizeForSearch(row.foodName) | ||
| let nStemmed = Self.stemmedForm(n) | ||
| return words.allSatisfy { w in n.contains(w) } || | ||
| stemmedWords.allSatisfy { sw in nStemmed.contains(sw) } | ||
| SearchTextMatcher.matchesAllQueryWords( | ||
| term: row.foodName, | ||
| normalizedQuery: normalized | ||
| ) | ||
| } |
|
Patched the review comments. Changes:
Verification:
|
|
No further changes needed on my side—latest commits |
|
Claude finished @BigAkins's task in 2m 10s —— View job Code Review
The refactor is well-executed. The 1. Implicit safety assumption in
|
| Gap | Why it matters |
|---|---|
editDistance |
Directly tests the O(n*m) routine in isolation |
| Fuzzy fallback path (< 3 exact matches, query ≥ 3 chars, single-char typo) | The fallback branch in suggestions is never exercised by existing tests |
matchScore for all score bands (0–4) |
Verifies the scoring tiers explicitly rather than relying on end-to-end suggestion order |
Overall
Solid PR. The QueryMatch struct is the right design, the two-overload pattern (String + QueryMatch) makes the parity tests clean, and the delegation in SearchView is a meaningful simplification. Items 1 and 2 above are quick fixes; the rest are minor quality notes that could reasonably go in a follow-up.
| Branch: Ak/search-quality-boundary
Summary
This cleanup adds a small pure helper boundary for AkFit search text behavior.
It moves current search normalization, alias handling, simple plural stemming, edit distance, match scoring, dessert/processed penalty behavior, and type-ahead suggestion matching into
SearchTextMatcher.What changed
Added
AkFit/AkFit/Search/SearchTextMatcher.swiftAkFit/AkFitTests/SearchTextMatcherTests.swiftUpdated
SupabaseFoodSearchServicenow delegates normalization/filtering/scoring behavior toSearchTextMatcherSearchViewnow delegates type-ahead matching toSearchTextMatcherWhy
Search behavior was becoming dense across
SupabaseFoodSearchServiceandSearchView.This PR creates a small testable boundary before future search/ranking work, reducing the chance that future feature work duplicates or changes search behavior accidentally.
Behavior
Search behavior is intended to be preserved exactly.
This PR does not:
What is still not solved
This does not yet:
Those should be handled in future feature-specific branches.
Verification
Verified with the PR-safe AkFit test plan.
Result: