From 98c528b38cf3e78920eb4b152190f46807715506 Mon Sep 17 00:00:00 2001 From: Lior Cohen Date: Fri, 10 Apr 2026 16:35:57 +0300 Subject: [PATCH] KS78: Add recency tie-breaker to fix score equality (#13) - Add microsecond-precision recency epsilon (step 7c7) after inflation cap so newer memories win ties when final_score values are identical - Fix test matcher for google_result to exclude the Meta memory content (both memories contain "Google", causing ambiguous match) Co-Authored-By: Claude Opus 4.6 (1M context) --- crates/shrimpk-memory/src/echo.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/shrimpk-memory/src/echo.rs b/crates/shrimpk-memory/src/echo.rs index 9905c66..6d431e5 100644 --- a/crates/shrimpk-memory/src/echo.rs +++ b/crates/shrimpk-memory/src/echo.rs @@ -1627,6 +1627,17 @@ impl EchoEngine { } } + // 7c7. KS78: Recency tie-breaker (#13) — after all boosts and caps, add a + // negligible epsilon derived from created_at so newer memories win ties. + // NOTE: This intentionally follows the inflation cap and may exceed it + // by up to ~3e-5. The epsilon only breaks ties, never meaningful score differences. + for result in &mut results { + if let Some(entry) = store.get(&result.memory_id) { + let recency_epsilon = (entry.created_at.timestamp_micros() as f64) * 1e-18; + result.final_score += recency_epsilon; + } + } + // 7d. Re-sort by final_score (similarity + hebbian boost) results.sort_by(|a, b| { b.final_score @@ -3621,7 +3632,9 @@ mod tests { // Find both memories in results let meta_result = results.iter().find(|r| r.content.contains("Meta")); - let google_result = results.iter().find(|r| r.content.contains("Google")); + let google_result = results + .iter() + .find(|r| r.content.contains("Google") && !r.content.contains("Meta")); assert!(meta_result.is_some(), "Meta memory should surface"); assert!(google_result.is_some(), "Google memory should surface");