feat(intelligence): add Knowledge Freshness#2932
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR introduces a memory freshness feature: a deterministic scoring engine that computes fact recall probabilities via exponential decay, classifies facts into fresh/fading/stale bands, and orders a reconfirmation queue. The implementation spans a scoring library, API facade, React presentational and container components, Intelligence page tab integration, and English i18n strings. ChangesMemory Freshness Feature
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
app/src/lib/memory/memoryFreshness.test.ts (1)
6-28: 💤 Low valueConsider sharing the
GraphRelationtest factory.
rel()/NOW/DAYare duplicated here and inmemoryFreshnessApi.test.ts(with a divergingrelsignature). A small shared factory underapp/src/test/would keep them in sync as the relation shape evolves.As per coding guidelines: "use helpers from
app/src/test/before adding new harness code".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/src/lib/memory/memoryFreshness.test.ts` around lines 6 - 28, Tests duplicate the GraphRelation test factory (NOW, DAY and rel) across memoryFreshness.test.ts and memoryFreshnessApi.test.ts; extract a shared factory module under app/src/test/ (e.g., export NOW, DAY and a unified rel(subject, object, agoDays, evidenceCount?, predicate?) that returns GraphRelation) and update both tests to import those helpers, reconcile the diverging rel signatures so both tests use the same parameter order and defaults, and export any needed types (GraphRelation) from the shared helper so callers stay type-safe.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src/components/intelligence/MemoryFreshnessTab.tsx`:
- Around line 23-33: The load function can be overwritten by slower earlier
requests; add a request-tracking token (e.g., a numeric latestLoadId in a React
ref) and increment it at the start of load(ns), capture the current id in the
async closure, then after await loadFreshness(...) but before calling
setReport/setError/setLoading, verify the captured id === latestLoadId.current
and only update state when they match; reference the load function,
loadFreshness, and state setters setReport/setError/setLoading when making this
change.
---
Nitpick comments:
In `@app/src/lib/memory/memoryFreshness.test.ts`:
- Around line 6-28: Tests duplicate the GraphRelation test factory (NOW, DAY and
rel) across memoryFreshness.test.ts and memoryFreshnessApi.test.ts; extract a
shared factory module under app/src/test/ (e.g., export NOW, DAY and a unified
rel(subject, object, agoDays, evidenceCount?, predicate?) that returns
GraphRelation) and update both tests to import those helpers, reconcile the
diverging rel signatures so both tests use the same parameter order and
defaults, and export any needed types (GraphRelation) from the shared helper so
callers stay type-safe.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: e918d157-0eed-4e3d-a449-ea79862a1e52
📒 Files selected for processing (23)
app/src/components/intelligence/MemoryFreshnessPanel.test.tsxapp/src/components/intelligence/MemoryFreshnessPanel.tsxapp/src/components/intelligence/MemoryFreshnessTab.test.tsxapp/src/components/intelligence/MemoryFreshnessTab.tsxapp/src/lib/i18n/chunks/ar-1.tsapp/src/lib/i18n/chunks/bn-1.tsapp/src/lib/i18n/chunks/de-1.tsapp/src/lib/i18n/chunks/en-1.tsapp/src/lib/i18n/chunks/es-1.tsapp/src/lib/i18n/chunks/fr-1.tsapp/src/lib/i18n/chunks/hi-1.tsapp/src/lib/i18n/chunks/id-1.tsapp/src/lib/i18n/chunks/it-1.tsapp/src/lib/i18n/chunks/ko-1.tsapp/src/lib/i18n/chunks/pt-1.tsapp/src/lib/i18n/chunks/ru-1.tsapp/src/lib/i18n/chunks/zh-CN-1.tsapp/src/lib/i18n/en.tsapp/src/lib/memory/memoryFreshness.test.tsapp/src/lib/memory/memoryFreshness.tsapp/src/pages/Intelligence.tsxapp/src/services/api/memoryFreshnessApi.test.tsapp/src/services/api/memoryFreshnessApi.ts
graycyrus
left a comment
There was a problem hiding this comment.
@aashir-athar hey, the code looks clean to me — well-structured feature. CI is still pending so I'll hold off on the approval until those pass, but I spotted a couple of things while reviewing:
Design looks solid. Pure engine with injected clock, container/presentational split, 26 tests covering decay math / edge cases / error paths, debug logging via the debug package — all matches project patterns. Zero new core surface, fully read-only.
i18n completeness — the PR description says "i18n across all 13 locales" but all 12 non-English locale files (ar, bn, de, es, fr, hi, id, it, ko, pt, ru, zh-CN) have English strings verbatim. Not a blocker if translations are deferred by convention here, but worth confirming — users in Arabic, Bengali, Hindi etc. will see English UI copy for this entire tab.
Re-confirm queue truncation — MAX_QUEUE_ROWS = 50 silently caps the queue. There's no "showing 50 of N" label or pagination, so a user with 51+ stale facts has no way of knowing the list is incomplete. A simple truncation note would fix it.
Once CI is green I'll come back and approve this.
- MemoryFreshnessTab guards against out-of-order load responses with a monotonic request token (CodeRabbit), so a slow earlier query can't overwrite a newer namespace result. - The re-confirm queue now shows a "Showing N of M — address these first." note when it is truncated past the 50-row cap (graycyrus), so a user with more stale facts isn't misled into thinking the list is complete. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Thanks @coderabbitai and @graycyrus — both addressed in 59d2016:
Appreciate the kind words on the structure, @graycyrus. Local suite green: 27 freshness tests, |
|
Tip For best results, initiate chat on the files or code changes.
Thanks for the thorough follow-through. 🎉 (∧ ﻌ ∧)♡ If you found this review helpful, would you consider giving us a shout-out on X? Thank you for using CodeRabbit! |
graycyrus
left a comment
There was a problem hiding this comment.
@aashir-athar the fix commit addressed both open items from the first pass:
- Race condition (CodeRabbit): the request-id token is in place, stale responses are properly dropped.
- Truncation note (mine): the "Showing {shown} of {total}" note is rendered and has test coverage for the 50-of-60 case.
Code is clean. One E2E check (Windows/Appium Chromium) is still pending — once that goes green, this is good to merge.
- MemoryFreshnessTab guards against out-of-order load responses with a monotonic request token (CodeRabbit), so a slow earlier query can't overwrite a newer namespace result. - The re-confirm queue now shows a "Showing N of M — address these first." note when it is truncated past the 50-row cap (graycyrus), so a user with more stale facts isn't misled into thinking the list is complete. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
59d2016 to
fac7825
Compare
|
CI note: the Rust Core Coverage lane went red after the rebase, but this PR is TypeScript-only (Rust core unchanged from main) and the job failed at the infra level (no test output). Re-triggered via an empty commit; a maintainer re-run would also clear it. |
- MemoryFreshnessTab guards against out-of-order load responses with a monotonic request token (CodeRabbit), so a slow earlier query can't overwrite a newer namespace result. - The re-confirm queue now shows a "Showing N of M — address these first." note when it is truncated past the 50-row cap (graycyrus), so a user with more stale facts isn't misled into thinking the list is complete. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
78dca83 to
62ed0f4
Compare
62ed0f4 to
f5117dc
Compare
A new read-only "Freshness" tab on the Intelligence page that scores how current each remembered fact is, using a forgetting-curve decay model — so facts the assistant hasn't reconfirmed lately surface for re-checking instead of being treated as still-certain. - Pure deterministic engine (lib/memory/memoryFreshness.ts): recall = 2^(-ageDays / halfLifeDays), where halfLifeDays scales with evidenceCount via 1 + log2(evidence) (more corroboration decays slower, with diminishing returns). The engine never reads the clock — `nowSeconds` is injected — so it is fully deterministic and unit-tested. Facts are banded fresh / fading / stale and the non-fresh ones form a "re-confirm queue". - Zero new core surface: reuses the already-shipped memoryGraphQuery and memoryListNamespaces RPC wrappers. Read-only — recomputed from the live graph. - Container/presentational split; namespace selector; status tiles + average recall + the re-confirm queue with per-fact recall bars and age. i18n across all 13 locales. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- MemoryFreshnessTab guards against out-of-order load responses with a monotonic request token (CodeRabbit), so a slow earlier query can't overwrite a newer namespace result. - The re-confirm queue now shows a "Showing N of M — address these first." note when it is truncated past the 50-row cap (graycyrus), so a user with more stale facts isn't misled into thinking the list is complete. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
f5117dc to
59a88a3
Compare
en.ts carried the 21 memory.tab.freshness / memoryFreshness.* keys but the other 13 locale files did not, breaking the i18n:check key-parity gate after the rebase. Add the keys (English placeholders per the repo convention — translators fill in later) so every locale is at parity.
@coderabbitai on memoryFreshness.test.ts) CodeRabbit flagged rel()/NOW/DAY duplicated across memoryFreshness.test.ts and memoryFreshnessApi.test.ts with a diverging rel signature. Move them to app/src/test/memoryRelationFactory.ts with a unified signature so both suites stay in sync as GraphRelation evolves, per the 'use helpers from app/src/test/' guideline.
Summary
Adds a new read-only "Freshness" tab on the Intelligence page that scores how current each remembered fact is, using a forgetting-curve decay model. Facts the assistant hasn't reconfirmed lately surface in a re-confirm queue instead of being treated as still-certain.
The assistant accumulates facts over time but treats a thing it learned a year ago the same as something confirmed yesterday. This lens applies the psychology of memory decay to the assistant's own stored facts — a question no mainstream assistant surfaces.
What it computes (pure deterministic engine)
recall = 2^(-ageDays / halfLifeDays)— 1.0 the moment a fact is recorded, halving every half-life as it ages un-reinforced.halfLifeDays = 30 · (1 + log2(max(1, evidenceCount)))— a fact corroborated by more evidence decays more slowly, with diminishing returns.Design
lib/memory/memoryFreshness.ts): the reference timenowSecondsis injected by the caller (minted in an event handler, never during render), so the engine is fully deterministic and every branch is unit-tested. Known decay values (recall halving at each half-life, evidence scaling, status banding, future-timestamp clamp, duplicate-triple collapse) are asserted.memoryGraphQueryandmemoryListNamespacesRPC wrappers. Read-only — recomputed from the live graph on mount, never persisted.Test plan
vitest— 26 tests (engine decay/banding/evidence/dedup/edge cases; api facade; presentational panel; container load/selector/error)tsc --noEmit— cleaneslint— 0 errorsprettier --check— cleanmemoryFreshness.*keys🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes