Skip to content

Commit d4a6936

Browse files
committed
merge: phase 14 — bench harness scoped/unscoped pass + v0.3.0a4
Wave 1 (14-A): LongMemEval haystack ingestion + isolated bench collection + v0.1.5 baseline re-capture Wave 2 (14-B): dual-pass scoped runner at runner.py:428 + sibling-key envelope in report.py Wave 2 (14-C): bundled scoped-smoke fixture + suite_loader dispatch Wave 3 (14-D): ADR-0001 + CHANGELOG v0.3.0a4 + llms.txt + READMEs ×5 + version bump Verifier: 677 passed / 4 skipped, ruff clean, uv build + twine clean. Outstanding: GitHub-render checkpoint (D5) + tag/publish v0.3.0a4.
2 parents ab0a0d5 + dc84ba3 commit d4a6936

30 files changed

Lines changed: 3761 additions & 92 deletions

CHANGELOG.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,78 @@
22

33
All notable changes to `supamem` will be documented in this file.
44

5+
## [0.3.0a4] — 2026-05-04 — Bench harness where-filter pass (Phase 14)
6+
7+
### Added
8+
9+
- **Scoped/unscoped bench passes.** `supamem eval --suite longmemeval_s`
10+
now emits BOTH an unscoped and a scoped retrieval pass per question at
11+
the single `runner.py:428` call site (`_run_longmemeval` per-record
12+
loop). The scoped pass derives a per-question `where` filter from
13+
LongMemEval haystack session ids (`{"session_id": [list]}`),
14+
exercising Phase 7 / 9 / 11 / 14 indexer-side filter payloads end-to-end.
15+
Smoke vs full continues to be gated by the existing `smoke_ids` filter
16+
inside the same loop — no second physical call site.
17+
- **Bench-only LongMemEval ingestion.** New module
18+
`supamem.eval.longmemeval_ingest` builds an isolated
19+
`supamem_eval_longmemeval_s` collection, attaches `payload.session_id`
20+
to each haystack chunk, and creates a `session_id` keyword payload
21+
index at first ingestion (idempotent). Production indexer paths
22+
(markdown, transcript) are unchanged. The `session_id` payload field
23+
is **bench-only**`supamem index` does NOT set it.
24+
- **Bundled smoke fixture.** New static fixture at
25+
`src/supamem/eval/datasets/longmemeval_scoped_smoke.json` (≤5 questions,
26+
≤200 KB, self-contained — does not trigger the ~3 GB lazy fetch). New
27+
suite name `longmemeval_scoped_smoke` for the CI fast-path; `suite_loader`
28+
dispatches to the bundled fixture for that suite.
29+
- **ADR-0001**`docs/adr/0001-scoped-only-bench-gate.md` records the
30+
methodology, the v0.1.5 corpus mismatch disclosure (D-GATE-05), and
31+
the strict isolation from FUTURE-24 (rerank composition rework) per
32+
D-FUT24-01..03. New `docs/adr/` directory established with a
33+
convention note (`docs/adr/README.md`).
34+
35+
### Changed
36+
37+
- **Result JSON shape.** `scores` and `by_axis` now carry `unscoped` +
38+
`scoped` sibling sub-dicts. `_compute_main_score` for the
39+
`longmemeval_s` suite reads `scores.scoped.tokens_per_correct_answer`
40+
for the Phase 13 gate decision. Unscoped is reported in the same
41+
envelope for transparency only — it never gates. Legacy callers
42+
(goldens etc.) continue to see the flat shape (sibling-key envelope
43+
contract pinned by `tests/test_build_report.py`).
44+
- **Gate decision is scoped-only.** The Phase 13 publication gate
45+
(`baseline_delta.tokens_per_correct_answer ≤ -0.30`) now reads
46+
`scores.scoped.tokens_per_correct_answer` against v0.1.5. Unscoped
47+
numbers ship in the same envelope but never gate. See ADR-0001.
48+
49+
### Migration
50+
51+
- **v0.1.5 baseline re-captured.** `eval/baselines/v0.1.5.json` carries
52+
both `unscoped` and `scoped` sibling keys plus a legacy mirror at
53+
top-level for migration safety. The original devdocs-collection
54+
number (`1374.59`) is preserved as `legacy_devdocs_unscoped_tpca` but
55+
does NOT gate; v0.1.5 was re-captured against the new haystack
56+
collection. **Absolute pre-Phase-14 numbers are not directly
57+
comparable to post-Phase-14 numbers — the corpus changed.** See
58+
ADR-0001 for the disclosure.
59+
60+
### Cross-references
61+
62+
- **FUTURE-24** (rerank composition rework) — Phase 14's scoped pass
63+
runs with rerank-OFF so the measured scoped-vs-unscoped delta
64+
attributes cleanly to scoping. FUTURE-24 is a SIBLING unblocker
65+
tracked separately. Public claims about scoping gains do NOT
66+
extrapolate to assume FUTURE-24 will further close the gap (D-FUT24-03).
67+
68+
### Locks preserved
69+
70+
- `runner.py:157` (`_run_goldens_legacy`, v0.1.x regression infra) is
71+
**byte-identical** (D-VEND-04 lock). Plan B touched only
72+
`runner.py:428`.
73+
- `retrieval/filters.py` is **byte-identical**. `session_id` flows
74+
through Phase 11's existing pass-through path (key-name =
75+
payload-key-name); not a magic key. Zero new branches.
76+
577
## [0.3.0a3] — 2026-05-03 — Filtered retrieval backend (FILT-01) + anti-identity-tier lock (FILT-02)
678

779
### Added

README.es.md

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
**Idiomas:** [English](README.md) · [简体中文](README.zh-CN.md) · [Español](README.es.md) · [日本語](README.ja.md) · [Русский](README.ru.md)
22

3-
<!-- synced-with: README.md @ b5a3522 -->
3+
<!-- synced-with: README.md @ 612a256 -->
44

55
> Esta traducción fue generada con asistencia de IA. Las correcciones de hablantes nativos son bienvenidas vía PR.
66
@@ -343,7 +343,7 @@ y el recordatorio para que descubras este flujo de manera natural.
343343
| `supamem stats` | Contadores Welford schema-v2 desde `.supamem/state/` |
344344
| `supamem live` | 👀 Dashboard en vivo siguiendo el audit JSONL — pipe-safe (JSONL plano cuando no hay TTY); maneja rotación, redimensionado, Ctrl-C |
345345
| `supamem migrate` | Migración brownfield desde una colección `dev_memory` preexistente |
346-
| `supamem eval` | Correr el arnés de bench. `--suite goldens` (por defecto, corpus dorado de 33 consultas para regresión) o `--suite longmemeval_s` (descarga perezosa de LongMemEval_S, ~3 GB en la primera ejecución; el camino rápido de CI es un subconjunto de 10 preguntas estratificado por eje, las ~500 preguntas completas requieren `--full`). Emite un envelope JSON estilo MTEB a `~/.supamem/eval/<utc-iso>.json`. El juez por defecto es heurístico (offline); pasa `--judge ollama:<model>` para un juez Ollama local — los endpoints SaaS son rechazados (D-07). Extra opcional: `pip install supamem[eval]` para la tríada RAGAS (v0.3.0a2+). Modo legado `--regress` preservado. |
346+
| `supamem eval` | Correr el arnés de bench. `--suite goldens` (por defecto, corpus dorado de 33 consultas para regresión) o `--suite longmemeval_s` (descarga perezosa de LongMemEval_S, ~3 GB en la primera ejecución; el camino rápido de CI es un subconjunto de 10 preguntas estratificado por eje, las ~500 preguntas completas requieren `--full`). v0.3.0a4+: emite una pasada scoped + unscoped por pregunta; el gate de publicación es **scoped-only** ([ADR-0001](docs/adr/0001-scoped-only-bench-gate.md)). Nuevo `--suite longmemeval_scoped_smoke` empaquetado (≤5 preguntas, sin descarga perezosa) para CI. Emite un envelope JSON estilo MTEB a `~/.supamem/eval/<utc-iso>.json`. El juez por defecto es heurístico (offline); pasa `--judge ollama:<model>` para un juez Ollama local — los endpoints SaaS son rechazados (D-07). Extra opcional: `pip install supamem[eval]` para la tríada RAGAS (v0.3.0a2+). Modo legado `--regress` preservado. |
347347
| `supamem uninstall --client <name>` | Revertir `supamem install` limpiamente |
348348
| `supamem unpatch-agents` | 🔄 Revertir los parches de alcance de subagentes (v0.2.5+). Restaura los archivos de agentes a su forma anterior al parche según el manifiesto en `~/.cache/supamem/agent_patches.json`. Omite con advertencia los archivos que hayas editado desde entonces. Córrelo ANTES de `pip uninstall supamem` para una desinstalación limpia. |
349349

@@ -618,6 +618,13 @@ Semántica:
618618
Múltiples keys de `where` se AND-ean; los valores en lista dentro de una key se OR-ean
619619
(`MatchAny`).
620620

621+
| Key | Semántica |
622+
|-----|-----------|
623+
| `room` | Phase 7 — facet del clasificador de coding-path (`backend`, `frontend`, `tests`, ...). String o lista. Lo escribe `supamem index` por chunk. |
624+
| `path_prefix` | Phase 11 — match exacto left-anchored por segmentos de path contra `payload.path_prefixes`. String o lista. Lo escribe `supamem index` por chunk. |
625+
| `valid_to` | Phase 9 — solo acepta `"now"` como alias no-op de la cláusula temporal always-on. Cualquier otro valor lanza `ValueError`. |
626+
| `session_id` | **Solo bench** — lo escribe la ingestión LongMemEval (`supamem.eval.longmemeval_ingest`); es key pass-through. **`supamem index` NO lo escribe.** Lo usa la pasada scoped del bench Phase 14 contra la colección dedicada `supamem_eval_longmemeval_s`. Ver [ADR-0001](docs/adr/0001-scoped-only-bench-gate.md). |
627+
621628
### Migración
622629

623630
Los chunks legados (indexados antes de v0.3.0a3) no tienen `path_prefixes`. El primer
@@ -633,6 +640,48 @@ voltea el exit code del doctor.
633640

634641
---
635642

643+
## 📊 Benchmarks (v0.3.0a4+)
644+
645+
**Cambio metodológico.** `supamem eval --suite longmemeval_s` emite tanto una
646+
pasada **unscoped** como una **scoped** por pregunta. La pasada scoped usa
647+
un `where` filter por pregunta derivado de los session ids del haystack de
648+
LongMemEval (`{"session_id": [...]}`), ejercitando los payloads de filtro
649+
del lado del indexer (`room`, `path_prefix`, `valid_to`, `session_id`)
650+
agregados a lo largo de las Phases 7 / 9 / 11 / 14. La decisión del gate
651+
publicado (delta de `tokens_per_correct_answer` vs el baseline v0.1.5) lee
652+
la pasada **scoped**; unscoped se reporta en el mismo envelope para
653+
transparencia y nunca gating. Ver [ADR-0001](docs/adr/0001-scoped-only-bench-gate.md)
654+
para el racional completo.
655+
656+
**Caveat de reproducibilidad.** Los números scoped pueden no reproducirse
657+
en invocaciones unscoped por defecto de `dual_memory_search` /
658+
`qdrant_find`. Los usuarios que quieran números comparables deben pasar un
659+
`where={...}` explícito contra una colección cuyos chunks lleven el payload
660+
correspondiente — esta es una disclosure metodológica, no un defecto.
661+
662+
**Corpus baseline.** El baseline v0.1.5 fue **re-capturado** contra una
663+
colección de bench dedicada (`supamem_eval_longmemeval_s`). Los números
664+
absolutos pre-Phase-14 no son directamente comparables a los números
665+
post-Phase-14 — el corpus cambió. El número original de la devdocs
666+
collection se preserva como `legacy_devdocs_unscoped_tpca` en
667+
`eval/baselines/v0.1.5.json` para referencia histórica pero **NO** entra
668+
al gate.
669+
670+
**FUTURE-24 (rerank composition rework)** es un sibling unblocker
671+
trackeado por separado. La pasada scoped de Phase 14 corre con rerank-OFF
672+
para que el delta scoped-vs-unscoped medido atribuya limpiamente al
673+
scoping. Las claims públicas sobre las ganancias de scoping **no** se
674+
extrapolan a "y una vez que el rerank composition también se arregle, el
675+
gate cerrará por X% más".
676+
677+
**Smoke fixture.** Un fixture empaquetado en
678+
`src/supamem/eval/datasets/longmemeval_scoped_smoke.json` (≤5 preguntas,
679+
≤200 KB, self-contained) está expuesto como el nuevo suite
680+
`longmemeval_scoped_smoke` — corre en CI sin disparar la descarga
681+
perezosa de ~3 GB.
682+
683+
---
684+
636685
## 🚫 Lo que supamem **NO** hace
637686

638687
`supamem` **NO** auto-inyecta contexto de identity / wake-up / prelude en las llamadas

README.ja.md

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
**言語:** [English](README.md) · [简体中文](README.zh-CN.md) · [Español](README.es.md) · [日本語](README.ja.md) · [Русский](README.ru.md)
22

3-
<!-- synced-with: README.md @ b5a3522 -->
3+
<!-- synced-with: README.md @ 612a256 -->
44

55
> この翻訳は AI 支援によるものです。ネイティブスピーカーによる修正 PR を歓迎します。
66
@@ -335,7 +335,7 @@ pip uninstall supamem
335335
| `supamem stats` | `.supamem/state/` からの Welford schema-v2 利用カウンタ |
336336
| `supamem live` | 👀 audit JSONL を追跡するライブダッシュボード — パイプセーフ(非 TTY 時はプレーン JSONL);ローテーション、リサイズ、Ctrl-C を処理 |
337337
| `supamem migrate` | 既存 `dev_memory` コレクションからのブラウンフィールド移行 |
338-
| `supamem eval` | bench ハーネスを実行。`--suite goldens`(デフォルト、内蔵 33 クエリのリグレッション正解コーパス)または `--suite longmemeval_s`(初回実行時に LongMemEval_S を遅延フェッチ、~3 GB;CI 高速パスは軸別層化された 10 問サブセット、完全な ~500 問は `--full` でゲート)。MTEB 形式の JSON envelope を `~/.supamem/eval/<utc-iso>.json` に出力。デフォルトジャッジはオフラインのヒューリスティック;ローカル Ollama ジャッジは `--judge ollama:<model>` で指定 — SaaS エンドポイントは拒否されます(D-07)。オプション extra: `pip install supamem[eval]` で RAGAS トライアド有効(v0.3.0a2+)。レガシー `--regress` モードは温存。 |
338+
| `supamem eval` | bench ハーネスを実行。`--suite goldens`(デフォルト、内蔵 33 クエリのリグレッション正解コーパス)または `--suite longmemeval_s`(初回実行時に LongMemEval_S を遅延フェッチ、~3 GB;CI 高速パスは軸別層化された 10 問サブセット、完全な ~500 問は `--full` でゲート)。v0.3.0a4+:質問ごとに scoped と unscoped の 2 パスを発行し、公開 gate は **scoped 専用**([ADR-0001](docs/adr/0001-scoped-only-bench-gate.md))。CI 用に新たな内蔵 `--suite longmemeval_scoped_smoke`(≤5 問、遅延フェッチなし)を追加。MTEB 形式の JSON envelope を `~/.supamem/eval/<utc-iso>.json` に出力。デフォルトジャッジはオフラインのヒューリスティック;ローカル Ollama ジャッジは `--judge ollama:<model>` で指定 — SaaS エンドポイントは拒否されます(D-07)。オプション extra: `pip install supamem[eval]` で RAGAS トライアド有効(v0.3.0a2+)。レガシー `--regress` モードは温存。 |
339339
| `supamem uninstall --client <name>` | `supamem install` をクリーンに反転 |
340340
| `supamem unpatch-agents` | 🔄 サブエージェント到達性パッチを反転(v0.2.5+)。`~/.cache/supamem/agent_patches.json` のマニフェストに従って agent ファイルをパッチ前の形に復元。あなたが編集済みのファイルは警告付きでスキップ。クリーンなアンインストールのため `pip uninstall supamem` の前に実行してください。 |
341341

@@ -603,6 +603,13 @@ dual_memory_search(query="session", where={"valid_to": "now"})
603603

604604
`where` の複数キーは AND、同一キー内のリスト値は OR(`MatchAny`)です。
605605

606+
| キー | 意味 |
607+
|------|------|
608+
| `room` | Phase 7 — coding-path 分類器のファセット(`backend``frontend``tests` など)。文字列またはリスト。`supamem index` が chunk 単位で書き込みます。 |
609+
| `path_prefix` | Phase 11 — `payload.path_prefixes` に対する left-anchored の path-segment 完全一致。文字列またはリスト。`supamem index` が chunk 単位で書き込みます。 |
610+
| `valid_to` | Phase 9 — 常時オンの temporal 句のエイリアスとして `"now"` のみ受理。それ以外の値は `ValueError`|
611+
| `session_id` | **bench 専用** — LongMemEval ingestion(`supamem.eval.longmemeval_ingest`)が書き込む pass-through キー。**`supamem index` は書き込みません。** Phase 14 の scoped bench パスが専用コレクション `supamem_eval_longmemeval_s` に対して使用します。詳細は [ADR-0001](docs/adr/0001-scoped-only-bench-gate.md) を参照。 |
612+
606613
### マイグレーション
607614

608615
レガシー chunk(v0.3.0a3 より前にインデックスされたもの)は `path_prefixes` を持ちません。
@@ -618,6 +625,44 @@ exit code を変えることはありません。
618625

619626
---
620627

628+
## 📊 Benchmarks(v0.3.0a4+)
629+
630+
**方法論の変更。** `supamem eval --suite longmemeval_s` は質問ごとに
631+
**unscoped****scoped** の両方の検索パスを発行します。scoped パスは
632+
LongMemEval の haystack session id から導出した質問ごとの `where` フィルタ
633+
(`{"session_id": [...]}`)を使用し、Phase 7 / 9 / 11 / 14 で追加された
634+
indexer 側のフィルタ payload(`room``path_prefix``valid_to`
635+
`session_id`)をエンドツーエンドで動かします。公開 gate の判定
636+
(`tokens_per_correct_answer` の v0.1.5 baseline に対する delta)は **scoped**
637+
パスを読み、unscoped は同じ envelope に透明性のために載りますが gate には
638+
入りません。詳細は [ADR-0001](docs/adr/0001-scoped-only-bench-gate.md) を参照。
639+
640+
**再現性に関する注意。** scoped の数値は `dual_memory_search` /
641+
`qdrant_find` のデフォルト unscoped 呼び出しでは再現しない可能性があります。
642+
比較可能な数値が欲しいユーザーは、対応する payload を持つ chunk を含む
643+
コレクションに対して明示的に `where={...}` を渡す必要があります —— これは
644+
方法論の開示であり欠陥ではありません。
645+
646+
**Baseline コーパス。** v0.1.5 の baseline は専用 bench コレクション
647+
(`supamem_eval_longmemeval_s`)上で **再キャプチャ**されました。Phase 14
648+
以前の絶対値は Phase 14 以降の値と直接比較できません —— コーパスが変わった
649+
ためです。元の devdocs collection 由来の数値は
650+
`eval/baselines/v0.1.5.json``legacy_devdocs_unscoped_tpca` として歴史
651+
参照のために保存されますが、**gate には入りません**
652+
653+
**FUTURE-24(rerank composition rework)** は別途追跡される姉妹アンブロッカー
654+
です。Phase 14 の scoped パスは rerank-OFF で走るため、計測される
655+
scoped と unscoped の差分は scoping にきれいに帰属します。scoping の
656+
ゲインに関する公開クレームは「rerank composition も直れば gate がさらに
657+
X% 縮まる」とは **外挿しません**
658+
659+
**Smoke fixture。** 内蔵された静的 fixture
660+
`src/supamem/eval/datasets/longmemeval_scoped_smoke.json`(≤5 問、≤200 KB、
661+
self-contained)が新スイート名 `longmemeval_scoped_smoke` として公開され、
662+
~3 GB の遅延フェッチをトリガせずに CI で実行できます。
663+
664+
---
665+
621666
## 🚫 supamem が **やらないこと**
622667

623668
`supamem`**エージェント呼び出しに identity / wake-up / prelude コンテキストを自動

0 commit comments

Comments
 (0)