Semantic search over a Markdown knowledge base, served over MCP.
ADR-0004 は「resource の
read は索引で縛る」と決め、したがって resources/list は read が受け付ける
ものだけを提示する必要があるとした。同時に、その性質が成り立っていない箇所を
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 をかけることになる。
search の uri は一緒に変わること。2 つの面が 1 つの問いに
答えているのに、共有述語を通っていたのは片方だけだった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 行が返る。
ServableRules が resources/list と search hit の uri の両方の背後にある
唯一の述語になった。拡張子ごとの cap は max_bytes_for で当てる —
load_document_blocking が read_checked に渡すのと同じ chooser なので、
listing と read が別々の上限を持つことは構造的に起きない。この変更前は 2 つの面が
registry 判定を別々に呼んでおり、述語が 1 つの呼び出しである間だけ無害だった。
片方に条件を 1 つ足した瞬間に、search が resources/read の拒むリンクを
配ることになる。
documents に size_bytes INTEGER (nullable) が増える。既存 DB には open 時に
追加される (他の forward migration と同じ)resources/list が空になる。安全に見える側の解釈が
破壊的という位置documents 行を書くあらゆる箇所で書かれる。バイトは変わったが chunk は
変わらなかった frontmatter-only の更新経路も含むrebuild_index は content hash が
一致するファイルに Unchanged を返し、その経路は document 行を一切書かない。
つまり「2 つの書き込み経路からしか書かない migration」は、それが書かれた対象で
ある「何も変わっていない KB」でこそ決して走らない。backfill は代わりに disk scan
から読み (backfill_fts の隣)、WHERE size_bytes IS NULL が実 read の記録した
size を上書きしないよう守るresources/list から消え、topic 本文からも消え、
search hit に uri が付かなくなる。hit そのものは残る — 未登録拡張子と
まったく同じ扱いで、文書は見つかり続け、拒否される read へのリンクだけが付かないkb-mcp doctor が「cap を超える文書」と「size 未記録の文書」の両方を報告するので、
この migration が作る状態は黙って残らず可視になる