GrooveSeek

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

View the Project on GitHub alphabet-h/grooveseek

19. frontmatter の key はすべて保持し、名指しは schema に任せる

背景と課題

groove validate は文書の frontmatter を groove-schema.toml に照らして検査する。本リリース までは、schema が名指せる key は title / date / topic / depth / tags の 5 つだけで、 それ以外は名指せなかった。パーサが YAML ブロックをこの 5 つのフィールドを持つ struct へ デシリアライズし、serde の既定の挙動が、それ以外の key を下流の誰かが見る前にすべて 捨てていたからである。status を名指す schema は読み込みの時点で拒否され、「schema が 名指していない key を指摘する」strict モードは存在し得なかった。バリデータは、そのブロックが どの key を運んでいたかを一度も知らないからである。

74 文書のプラットフォームエンジニアリングのコーパスを運用しているユーザは、これをこう言い 表した (#252): ドメインのメタデータを持たないコーパスに strict モードは要らない。ドメインの メタデータを持つコーパスは strict モードを使えない。その frontmatter は 21 種類の key を 運んでおり、そのうち宣言できたのは 5 つだった。報告者が提案したのは loader への 1 行の 変更 — [fields.status] known = true — で、schema が key を検査せずに名指すための ものである。

ADR-0010 は、受け取ってから捨てていた --strict フラグを削除し、その復活の値段を付けた: [options].allow_unknown_fields がある 状態で足し直すなら、それは minor リリースである。

本決定が答える問い: frontmatter にどの key が存在するかを決めるのは、パーサか schema か。

判断の軸

検討した選択肢

  1. rule の key としての known = true (報告者の提案)。却下: 単体では成立しない。 パーサが依然として key を捨てるからである。そしてパーサが key を保持するのなら値も保持 してよく、その時点で known は「空のテーブル」を意味するだけのキーワードになる
  2. 未知の値を YAML へ再シリアライズした文字列として保持する。 形は 3 つではなく 2 つに なる。却下: pattern が YAML の構文に対して照合されることになり、mapping が type = "string" を通ってしまう
  3. 名前付きの 5 フィールドをすべて 1 つの map に畳み、アクセサを付ける。 一様になり、 schema のディスパッチは 1 回の lookup になる。却下: 今日、すべてのパーサ・indexer・ サーバとそれらのテストが 5 つのフィールドを名前で読んでおり、tags はその型が担保して いる Vec<String> の保証を失う
  4. 5 つのフィールドはそのままに、3 つの形を持つ extra: BTreeMap<String, FieldValue> を 足す。 採用
  5. type = "bool" を足す。 却下: enum = ["true", "false"] が既に表現している 1 つの形 の表明のために、「最初から最後まで文字列」の規則を壊す。ドキュメントにそう書くことにし、 読者に発見させるのをやめる
  6. タグの混在リストのために 2 つ目の正規表現 key を足す。 却下: 1 フィールドにつき pattern は 1 つというのは rule の限界であり、報告者の軸タグと自由タグの整合はフィールドを またぐ制約で、報告者の外部バリデータが持つべきものである

決定

結果と代償

参考