Skip to content

Commit 574d639

Browse files
radimsemclaude
andauthored
docs(search): include recency factor in ranking formula (#215)
## Summary - Fixes #203: `docs/temperature.md` and `docs/search.md` stated `score = relevance × (0.3 + 0.7 × temperature)`, but `pkg/query/rank.go` multiplies by a third `recency` factor (`1 / (1 + hours_since_last_access / 24)`, `1.0` for never-accessed nodes). Docs now reflect the real three-factor formula. - Scope extended beyond the two files the issue named to also cover `skills/remind/SKILL.md` (the agent-facing mental model) and `.claude/skills/tune-temperature-policy/SKILL.md` — `CLAUDE.md`'s "Tread carefully — Temperature policy" section explicitly flags those as silent-drift surfaces that must stay in sync. - Docs-only. No code change. ## Test plan - [x] `make check-skills` — PASS (`skills/remind/SKILL.md` still under 180-line budget) - [x] Negative grep: no remaining `(0.3 + 0.7 × temperature)` occurrence lacks a trailing `× recency` (or is the standalone `temperature_score = …` breakdown). - [x] Manual read-through of both `docs/*.md` paragraphs for tone consistency. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 53c4851 commit 574d639

4 files changed

Lines changed: 5 additions & 5 deletions

File tree

.claude/skills/tune-temperature-policy/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ If the numbers or the workflow drift from the code, agents will reason from stal
2020
|---|---|---|
2121
| `DecayRate` | `0.05` | `decayFactor = exp(-rate × elapsed_hours)` — applied each tick to every node |
2222
| `AccessBoost` | `0.15` | Added to a node's temperature on read; capped at `1.0` by SQL `min(1.0, …)` |
23-
| `ColdThreshold` | `0.1` | Below this, nodes are "cold" — used by `GetColdNodes` and the search relevance floor (`Score = relevance × (0.3 + 0.7 × temperature)`) |
23+
| `ColdThreshold` | `0.1` | Below this, nodes are "cold" — used by `GetColdNodes` and the search relevance floor (`score = relevance × (0.3 + 0.7 × temperature) × recency`) |
2424
| `NotifyThreshold` | `0.1` | Below this, the server pushes an MCP notification (`level: "warning"`, `logger: "remindb.temperature"`) — gated by per-node hysteresis dedup |
2525
| `TickInterval` | `5 * time.Minute` | How often `Tracker.Run` decays + queries cold nodes |
2626

@@ -59,7 +59,7 @@ The two public skills carry different surfaces of the policy. Walk both:
5959

6060
- **Frontmatter description** — mentions "warning-level cold-node notifications"
6161
- **Mental model → Nodes** — quotes `+0.15`, `exp(-0.05 × elapsed_hours)`, `~5% per hour`, the two thresholds, and `0.1` defaults
62-
- **Mental model → Ranking**`score = relevance × (0.3 + 0.7 × temperature)`
62+
- **Mental model → Ranking**`score = relevance × (0.3 + 0.7 × temperature) × recency`
6363
- **Mental model → Notifications** — quotes the message string, hysteresis behavior, payload shape
6464
- **Anti-patterns** — the dedup-and-rearm note, the `ColdThreshold` vs `NotifyThreshold` distinction
6565

docs/search.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ When an agent doesn't have a memory layer, "find where I wrote about rate limiti
1616

1717
Search runs on SQLite's **FTS5** virtual table, built at write time with a porter tokenizer over labels, content, and types. `MemorySearch` returns ranked anchors in milliseconds — no file rescan, no regex, no timeout. Ask for 500 tokens of matches and you get exactly 500: the engine fills up to the budget and stops, which is cheaper than returning everything and hoping the client truncates.
1818

19-
Ranking folds in [temperature](./temperature.md): `score = relevance × (0.3 + 0.7 × temperature)`, where relevance is FTS5's BM25-like rank. A cold node with a strong match still surfaces; a warm node with a weak one does too. The budget trims from the bottom *after* ranking.
19+
Ranking composes three factors: `score = relevance × temperature_score × recency`, where `relevance` is FTS5's BM25-like rank, `temperature_score = 0.3 + 0.7 × [temperature](./temperature.md)` (the `0.3` floor keeps cold-but-relevant matches visible), and `recency = 1 / (1 + hours_since_last_access / 24)` (`1.0` for never-accessed nodes, `0.5` at 24h since last access). A cold node with a strong match still surfaces; a warm node with a weak one does too. The budget trims from the bottom *after* ranking.
2020

2121
## The one thing you must know: the OR rewrite
2222

docs/temperature.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Every node carries a **temperature** in `[0.0, 1.0]`. A fresh compile starts eve
2323

2424
The spread you see in a [tree dump](./node-tree.md) is the history of how the memory was actually used. *Architecture* sits at `0.88` because the agent keeps coming back. *Observability* has decayed to `0.08` because nobody has.
2525

26-
Temperature feeds [search ranking](./search.md): `score = relevance × (0.3 + 0.7 × temperature)`. A cold node with a great keyword match still surfaces — it just stops crowding the top when its match is weak. Cold never means gone.
26+
Temperature feeds [search ranking](./search.md), which composes three factors: `score = relevance × temperature_score × recency`, with `temperature_score = 0.3 + 0.7 × temperature`. The `0.3` floor keeps a cold node with a great keyword match visible — it just stops crowding the top when its match is weak. Cold never means gone. (The `recency` multiplier is documented under [search](./search.md).)
2727

2828
Two thresholds gate what happens next, independent so an operator can run a tighter alert band than the cold-set query:
2929

skills/remind/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ Smallest unit = **node**:
4646

4747
### Ranking
4848

49-
`score = relevance × (0.3 + 0.7 × temperature)`. Relevance = FTS5 BM25-like rank. Cold node + great match still surfaces; warm node + weak match too. Budget trims bottom after ranking.
49+
`score = relevance × (0.3 + 0.7 × temperature) × recency`, where `recency = 1 / (1 + hours_since_last_access / 24)` (`1.0` if never accessed, `0.5` at 24h). Relevance = FTS5 BM25-like rank. Cold node + great match still surfaces; warm node + weak match too. Budget trims bottom after ranking.
5050

5151
### Notifications
5252

0 commit comments

Comments
 (0)