fix(retrieval): collapse rows of the same entity so top_k counts entities [mcp, docs, tests] - #201
Conversation
…ties [mcp, docs, tests]
Add an entity aggregation stage between the reorder stages and the trim in
src/mcp.ts. Rows are grouped by the referent they point at: a file's `doc`
row and its `diff` rows across commits become one result, an issue or PR and
its comments / reviews become one result. The representative is the
highest-ranked row of the group, and the rows it absorbed are attached as
`same_entity { count, others[] }` rather than dropped. The overfetch is now
unconditional so `rerank: false` also fills top_k after the collapse.
同一の実体が複数行として索引されるため、`top_k: 10` の実測で独立した情報が 6
前後しか返っていなかった(本番索引、2026-08-01、rrf + rerank)。diff を索引し
続けるのは意図的なので、畳むのは索引側ではなく表示段に置いた。
畳む軸は referent 側に限る。同じ対象の複数の版を畳んでも対象の数は減らないが、
「作業」で畳むと 1 つの commit が触った別々のファイルが 1 枠になり、実際に独立
した対象が隠れるため。したがって key は commit SHA を持たず、issue と、それを
閉じる PR も 2 実体のまま残す(両者を結ぶ `Closes #N` は索引に無い)。
代表に最新版を固定しないのは「いつ変わったか」を問うクエリへの答えを消さない
ため。そのクエリでは該当する古い diff が最上位に来るので、それが代表になる。
repo 横断の複製(軸 (c))は判定材料が索引に無いので対象外。
Closes #189
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
github-rag-mcp | 6304a22 | Aug 02 2026, 07:32 AM |
liplus-lin-lay
left a comment
There was a problem hiding this comment.
Self-review (auto mode, parent agent)
受け入れ条件
- 同一 commit が触った別々のファイルが畳まれない — 満たす。
entityKeyはfile:{repo}:{path}で commit SHA を key に含めない。テスト「keeps two files touched by ONE commit as two entities」で固定 - 「いつ変わったか」クエリで該当 diff が代表として残る(負の対照) — 満たす。代表は最終順序の先頭行で、最新版を pin しない。テスト「does not pin the newest version」で固定
- 重複率の回帰テスト — 2026-08-01 実測の候補プールを再構成した 2 本。既知の重複(同一ファイルの doc + diff / 別 commit の同一ファイル / PR とその review / issue とその comment)が畳まれ、既知の非重複(同一 commit の別ファイル / issue #1317 と PR #1318 / repo 横断の複製)が畳まれないことを両方向で固定
top_kに対し独立実体 9 以上 — unit test 側では閉じない条件。再構成プールでの挙動は固定されているが、本条件は実インデックスに対する実測。merge 後の deploy 完了を待って本番の 2 クエリで確認する(本 session 内で実施)
制約
- 索引側は変更しない — ingest 経路に変更なし。集約は
src/mcp.tsの融合後・trim 前のみ top_kの意味を変えない — 要求件数ぶんの独立実体が返る。そのために overfetch を無条件化した(下記)same_entityは追加フィールド — 既存フィールドの型・意味は不変。無視する client は #189 以前と同じ形を見る
判断が要った点
overfetch の無条件化 は仕様が明示していなかった必然の随伴変更。従来は post-filter / time filter / rerank 有効のいずれかでのみ 5 倍取りしていたが、集約が全経路で行を畳む以上、rerank: false 経路では要求 top_k を満たせなくなる。予算(top_k × 5 / 上限 50)自体は不変なので、既定経路(rerank 有効)の取得量は変わらない。増えるのは rerank: false のデバッグ経路のみ。
wiki_doc を file: 名前空間に入れない 判断は #189 の定義と整合する。wiki page は referent あたり 1 行しか存在せず畳む対象が無い一方、名前空間を共有すると同名の repo doc と誤って畳む。畳まない側に倒すのが安全側。
same_entity.count が代表を含む(常に 2 以上)。issue の例が曖昧だったので実測データ(1 ファイルが 3 行)に照らして解釈し、明示的に文書化されている。妥当。
既知の境界(欠陥ではない)
graph_expand: true で追加される近傍行は集約を通らず、trim 後に追記される。これらは graph_hop / graph_from で明示的に区別された opt-in の拡張であり top_k の外側なので、top_k が実体を数えるという性質は損なわれない。近傍が既存代表と同一実体になる経路は理論上あるが、本 issue の対象は top_k プール内の枠の奪い合いであってここではない。
scope からの逸脱
軸 (c) の follow-up issue が二重に立った(#200 / #202)。原因は親側の伝達漏れで、委譲前に親が #200 を立てていたことを subagent に渡していなかった。#189 本文と本 PR が参照する #202 を残し、#200 は固有の検討材料 2 件を #202 へ移した上で close 済み。PR 側の修正は不要。
次のステップ
auto mode につき human gate なし。self-review pass → merge → deploy 後に実インデックスで受け入れ条件の残り 1 本を確認。
Closes #189
何を変えたか
融合・rerank・time sort の後、
filtered.slice(0, requestedTopK)の手前に集約段を追加した(src/mcp.ts)。判定ロジックはsrc/aggregate.tsに切り出してある。doc行と同一ファイルのdiff行はfile:{repo}:{doc_path ?? file_path}、issue / PR とその comment / review はthread:{repo}:{number}。それ以外(wiki_doc/release/ key となるフィールドが欠けた行)はrow:{vector_id}で畳まれない。same_entity { count, others[] }を付す。countは代表を含むので必ず 2 以上、1 件以上畳んだ場合のみ出る。フィールド追加のみで既存フィールドは変えていない。rerank: falseでも候補プールがtop_kを上回っていないと要求件数を返せない。畳む軸を referent に限った理由
同じ対象の複数の版を畳んでも対象の数は減らないので、集約が独立した情報を隠すことはない。一方「作業」で畳むと、1 つの commit が触った別々のファイルが 1 枠になり、実際に独立した対象が隠れる。したがって key は commit SHA を持たない。issue #1317 と PR #1318 も 2 実体のまま残す(両者を結ぶ
Closes #Nは索引に無く、入れるには索引側の変更が要る=制約違反)。代表に最新版を固定しないのは「いつ変わったか」を問うクエリへの答えを消さないため。そのクエリでは該当する古い diff が最上位に来るので、それが代表として残る。
repo 横断の複製(軸 (c))は判定材料が索引に無いため対象外。別 issue に切り出した(#202)。
テスト
src/aggregate.test.ts(node pool、14 件)。想定される観測
top_kの意味が「行数」から「実体数」に変わる。呼び出し側が要求した件数は従来どおり返る。検証
npm test(118 + 53 pass)、tsc --noEmit、node scripts/check-schema-drift.mjs、wrangler deploy --dry-run、mcp-serverのnpm test(10 pass)をローカルで実行済み。