Skip to content

0.12.1 — the tail is findable and relevance outranks the calendar

Choose a tag to compare

@spranab spranab released this 05 Aug 02:49
· 147 commits to main since this release

Four engine changes, every one measured on a 4,297-record production corpus with a paraphrase-labeled query set before shipping, and dogfooded on a production memory server before this tag.

Ranking: relevance outranks the calendar (10× measured)

  • The recency wall is gone. The composite's additive 0.2·decay + 0.3·recency handed every fresh record up to +0.5 free — an old record needed an impossible >1.0 similarity advantage to outrank fresh noise, so every default install served this week's records regardless of the question. Freshness now multiplies relevance, bounded to +12.5% at default weights: a tie-breaker that can never build a wall. Engine MRR on the production corpus: 0.054 → 0.298.
  • Graph expansion is off by default. Entity-linked candidates scored 0.3·proximity into the relevance core, letting entity-name-sharing noise outrank genuinely similar records (measured −0.24 MRR; neutral even on the connected corpus built to favor it). Opt in per call for curated, dense graphs.
  • MMR diversity softened (λ 0.7 → 0.9): keeps the duplicate-flood defense at 40% of the relevance cost.
  • Net: MRR 0.054 → 0.541 — 96% of the embedding ceiling; rank-1 2% → 48%.

Chunked embeddings: the tail of a long record is findable (schema v40)

A record longer than the embedder's input window used to be stored intact but embedded only from its head — content in the tail was unretrievable (measured: an end-of-record cue found its parent 8% of the time). The engine now embeds overlapping windows on write, indexes each under the parent, and collapses windows to records at search — plus detect_embedder_window() to probe any embedder's true window and rechunk_long_records() to backfill an existing corpus in one idempotent pass.

Also: writes that overflow the window are counted (embedder_truncated_writes vs embedder_chunked_writes in stats()) — silent truncation is silent retrieval loss.

Schema migrates 39 → 40 lazily and in place; existing databases, packs, and replicas are unaffected until they opt into new behavior.

⚠️ For consumers holding absolute score thresholds

Removing the additive freshness terms changes absolute score magnitudes by roughly 2× (a typical top-1 composite drops from ~1.2 to ~0.6). Ranking quality improves — one downstream consumer measured MRR 0.928 → 0.946 on their own corpus — but any absolute threshold tuned against a pre-0.12.1 score scale now means something else: a "minimum score" cutoff will reject answers it used to accept, and a "gap detector" comparing scores to a constant will fire on questions the memory answers at rank 1.

If you gate on score magnitude anywhere (min-score floors, gap thresholds, pack retrieval settings measured pre-0.12.1): re-measure and recalibrate against 0.12.1 — and note the adjustment may not be uniform across thresholds, so measure each one rather than scaling all by the same factor. Relative comparisons (ranking, ratios between candidates in one result set) are unaffected.

A calibration tuned against an engine's score scale expires silently when the scale changes — behaviour tests never catch it, only re-measurement does. (Credit: the yantrikdb-hermes-plugin team, who caught and measured this within a day.)