GrooveSeek

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

View the Project on GitHub alphabet-h/grooveseek

20. schema が宣言したものを索引に持たせる

背景と課題

ADR-0019 は、 frontmatter の key をパーサにすべて保持させ、groove-schema.toml がそのどれでも名指せる ようにして、そこで止まった。保持された key が届く先は groove validate だけで、それ以外は 何も無かった。それを求めたのと同じユーザ (#289) が、残りの代償がどこにあるかを示した。 4 つのメタデータ軸を持つ 74 文書のコーパスにおいて、1,036 件のタグの出現のうち 434 件は、 status / environment / team / source を tags へ写すためだけに存在している。 検索フィルタから見える frontmatter が tags しか無いからである。その写しを正しく保つには 外部バリデータが要り、topic は文書の種別に費やされてしまう。ユーザが求めたのは 1 つだけ である: 保持された key でのフィルタ、完全一致の文字列比較、演算子は無し、schema が宣言した key に限る。

本決定が答える問い: 宣言された key を索引へ持ち込むのは誰で、それはいつか — schema を 読む indexer か、それとも schema を読むクエリか。

判断の軸

検討した選択肢

  1. indexer が schema を読み、宣言された key の値を専用のテーブルへ格納する。search は そのテーブルでフィルタし、schema を一切読まない。 採用
  2. パーサが保持したスカラをすべて格納し、key の妥当性はクエリ時に schema に照らして 検証する。 却下: serve と groove search の両方が schema を読み込む必要が生じ、 schema を持たない知識ベースには別の規則が要り、索引は誰も宣言していない値を抱えることに なる
  3. documents 上の JSON カラムに持ち、tags と同じくクエリの後に Rust 側でフィルタする。 却下: テーブルを分ければクエリ自身が絞り込め、リストの値は 2 つ目のエンコーディングでは なく 2 行目になる
  4. 除外を演算子にする (status!=deprecated)。 却下: 報告者が求めたのは完全一致であり、 演算子は求めていない。2 つ目のフラグ --field-not / fields_not は、除外に完全一致と 同じ形を与え、値の文法には手を触れない

決定

結果と代償

参考