GrooveSeek

Semantic search over a Markdown knowledge base, served over MCP.

View the Project on GitHub alphabet-h/grooveseek

5. 文書のバイト数を索引に記録する

背景と課題

ADR-0004 は「resource の read は索引で縛る」と決め、したがって resources/listread が受け付ける ものだけを提示する必要があるとした。同時に、その性質が成り立っていない箇所を 1 つ記録している:

GET_DOCUMENT_MAX_BYTES (テキスト 1 MiB) を超える文書は、索引が 50 MiB まで 受け入れるので索引され、read で拒否される。これは知り得るが、知るには listing のたびに索引済みファイルを全部 stat するしかない […] 恒久的な修正は index 時に size を記録するか、2 つの cap を揃えるかで、それまでは既知の 制限であって主張ではない。

つまり 1 MiB〜50 MiB の Markdown / プレーンテキスト文書は、索引され、topic の 一覧に現れ、search hit に uri が付き、クライアントがそのリンクを辿ると 拒否される。バイナリ形式は影響を受けない — 50 MiB の cap で読まれ、抽出 テキストは拒否ではなく注記付きで切り詰められる (ADR-0004 で扱い済み)。

今この問いに答えなければならない理由は無かった。答える時機にしたのは kb-mcp doctor を足すからで、どちらも「索引が自分自身について何を知っているか」 の話であり、後回しにすると同じテーブルに 2 回目の migration をかけることになる。

決定要因

検討した選択肢

  1. listing のたびに索引済みファイルを全部 stat する — ADR-0004 が名指しして 退けた案
  2. 2 つの cap を揃える — read が返せる量を超えるテキストは索引しない
  3. index 時に byte size を documents に記録し、提示判定の述語で使う

決定

選択肢 3。

選択肢 1 は「提示」を索引の性質からその場の filesystem 探査へ変えるもので、 これはまさに ADR-0004 が引いた境界そのもの。しかも穴は塞がらない — listing と read の間にファイルが cap を跨げるため。

選択肢 2 は最悪の方向に後方非互換になる。GET_DOCUMENT_MAX_BYTES = 1 MiB は 索引とは無関係な理由 —「1 レスポンスで MCP クライアントに渡してよいテキスト量」— で決まっているので、揃えるとは索引側の上限をそこまで下げること。今日索引され 検索できている文書が黙って索引されなくなる。長いという理由で文書を落とす検索系は、 見つけた上で全文の inline を断る検索系より悪い。

選択肢 3 は ADR-0004 を保つ: size が「索引が知っていること」の一部になるので、 提示は索引についての言明のままでいられる。コストは nullable な列 1 つと、 最小の read cap を超える行だけを問い合わせるクエリ 1 本 — cap 超えの文書が 無いコーパスでは 0 行が返る。

ServableRulesresources/listsearch hit の uri両方の背後にある 唯一の述語になった。拡張子ごとの cap は max_bytes_for で当てる — load_document_blockingread_checked に渡すのと同じ chooser なので、 listing と read が別々の上限を持つことは構造的に起きない。この変更前は 2 つの面が registry 判定を別々に呼んでおり、述語が 1 つの呼び出しである間だけ無害だった。 片方に条件を 1 つ足した瞬間に、searchresources/read の拒むリンクを 配ることになる。

帰結