From 28ffc76834fb6926189ad303bc35f617a2169bb9 Mon Sep 17 00:00:00 2001 From: coe0718 Date: Tue, 31 Mar 2026 16:47:37 -0400 Subject: [PATCH] Polish ranking readability --- src/memory/__tests__/ranking.test.ts | 16 ++++++++++++++++ src/memory/ranking.ts | 14 ++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/memory/__tests__/ranking.test.ts b/src/memory/__tests__/ranking.test.ts index 126d586..84f6da9 100644 --- a/src/memory/__tests__/ranking.test.ts +++ b/src/memory/__tests__/ranking.test.ts @@ -75,4 +75,20 @@ describe("memory ranking", () => { expect(shouldIncludeEpisodeInContext(staleWeak)).toBe(false); expect(shouldIncludeEpisodeInContext(durableRepeat)).toBe(true); }); + + test("invalid timestamps degrade gracefully", () => { + const score = calculateEpisodeRecallScore( + 0.5, + { + importance: 0.6, + accessCount: 2, + startedAt: "not-a-date", + lastAccessedAt: "still-not-a-date", + decayRate: 1, + }, + "metadata", + ); + + expect(score).toBeFinite(); + }); }); diff --git a/src/memory/ranking.ts b/src/memory/ranking.ts index 9b02c26..55f779b 100644 --- a/src/memory/ranking.ts +++ b/src/memory/ranking.ts @@ -43,7 +43,7 @@ export function calculateEpisodeContextScore(episode: Episode): number { decayRate: episode.decay_rate, }); - return weightedAverage(signals.durability, signals.recency, 0, 0.6, 0.4, 0); + return weightedAverage2(signals.durability, signals.recency, 0.6, 0.4); } export function shouldIncludeEpisodeInContext(episode: Episode): boolean { @@ -75,6 +75,10 @@ function weightedAverage(a: number, b: number, c: number, aWeight: number, bWeig return a * aWeight + b * bWeight + c * cWeight; } +function weightedAverage2(a: number, b: number, aWeight: number, bWeight: number): number { + return a * aWeight + b * bWeight; +} + function exponentialDecay(ageHours: number, halfLifeHours: number, decayRate: number): number { if (!Number.isFinite(ageHours) || ageHours < 0) return 1; return Math.exp(-((ageHours / halfLifeHours) * decayRate)); @@ -83,13 +87,7 @@ function exponentialDecay(ageHours: number, halfLifeHours: number, decayRate: nu function hoursSince(value?: number | string): number { if (value == null) return Number.POSITIVE_INFINITY; - const timestamp = - typeof value === "number" - ? value - : (() => { - const parsed = Date.parse(value); - return Number.isNaN(parsed) ? Number.NaN : parsed; - })(); + const timestamp = typeof value === "number" ? value : Date.parse(value); if (!Number.isFinite(timestamp)) return Number.POSITIVE_INFINITY;