fix(mcp): 9 quality improvements for search, save, and pipeline#43
fix(mcp): 9 quality improvements for search, save, and pipeline#43kckylechen1 wants to merge 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces several enhancements to the memory system, including updating the feedback mechanism to return a boolean status, clamping rating and importance values, and improving the robustness of code fence stripping in LLM responses. It also extends the memory extraction prompt and logic to support entities and persons, and updates the synchronization process to merge known revisions from project-specific databases. Additionally, a cross-DB score normalization step was added to the search logic to ensure results from global and project scopes are comparable. A review comment suggests optimizing the normalization logic by leveraging the existing sort order to find maximum scores more efficiently.
| let global_max = combined_results | ||
| .iter() | ||
| .filter(|(_, s)| matches!(s, DbScope::Global)) | ||
| .map(|(r, _)| r.score.final_score) | ||
| .fold(0.0_f64, f64::max); | ||
| let project_max = combined_results | ||
| .iter() | ||
| .filter(|(_, s)| matches!(s, DbScope::Project)) | ||
| .map(|(r, _)| r.score.final_score) | ||
| .fold(0.0_f64, f64::max); |
There was a problem hiding this comment.
Since combined_results is already sorted by final_score in descending order (lines 241-246), calculating global_max and project_max using fold and f64::max is inefficient as it iterates through the entire list. You can simply find the first occurrence for each scope to get the maximum score.
| let global_max = combined_results | |
| .iter() | |
| .filter(|(_, s)| matches!(s, DbScope::Global)) | |
| .map(|(r, _)| r.score.final_score) | |
| .fold(0.0_f64, f64::max); | |
| let project_max = combined_results | |
| .iter() | |
| .filter(|(_, s)| matches!(s, DbScope::Project)) | |
| .map(|(r, _)| r.score.final_score) | |
| .fold(0.0_f64, f64::max); | |
| let global_max = combined_results | |
| .iter() | |
| .find(|(_, s)| matches!(s, DbScope::Global)) | |
| .map(|(r, _)| r.score.final_score) | |
| .unwrap_or(0.0); | |
| let project_max = combined_results | |
| .iter() | |
| .find(|(_, s)| matches!(s, DbScope::Project)) | |
| .map(|(r, _)| r.score.final_score) | |
| .unwrap_or(0.0); |
There was a problem hiding this comment.
Removed the per-store re-normalization block instead of micro-optimizing it. That keeps the merged ranking on the raw final scores and avoids flattening relevance gaps between global and project hits.
This carries forward the PR #43 fixes while dropping the extra cross-DB score rescaling step that could flatten real relevance gaps between global and project search hits. Keeping the merged order on raw final scores preserves the branch intent without leaving the Gemini review concern in place. Constraint: Current workspace has unrelated local changes, so the PR was rebuilt and fixed in an isolated worktree Rejected: Per-scope max renormalization | it can promote weak project hits to parity with stronger global hits Rejected: Keep the block and micro-optimize max lookup | preserves disputed ranking behavior Confidence: medium Scope-risk: narrow Reversibility: clean Directive: Do not add per-store score rescaling back without proving the merged ranking semantics with tests Tested: cargo check -p memory-server Tested: cargo test -p memory-server -- --nocapture Not-tested: Dedicated regression test for cross-store ranking semantics Related: PR #43
581cb9a to
59bf72a
Compare
Summary
Reapplies fixes from #42 onto the restructured codebase (db split into modules, hub_ops split into subdirectory, tool_params became a directory).
Of the original 13 fixes, 4 were already applied on main (auto_link scope, enrichment concurrency, search skip response, generate_summary fallback). The remaining 9 are applied here.
Changes
save_memorynow clamps importance to[0.0, 1.0]entities/persons;fact_to_entryparses them from LLM outputhub_record_feedbackreturnsbool; handler returnsrecorded: falsefor non-existent IDs; rating clamped[0.0, 5.0]rfind("```")for last closing fence (handles nested)[3..5]sliceTest plan
cargo check— zero warningscargo test -p memory-core— 39 tests pass