Semantic search over a Markdown knowledge base, served over MCP.
semver は「public API を壊すなら major が要る」と言うが、public API が何かは 言わない。ライブラリなら問い自体が答えになる — crate が export しているものが API である。しかしコマンドラインと MCP 面と HTTP transport と設定形式を持ち、 ユーザのホームディレクトリにファイルを書くプログラムでは、答えは「メンテナが そう言ったもの」でしかない。そしてメンテナが何も言わなければ、利用者は当然 観測できるものすべてだと解釈する。
本決定の日に実測した値:
| public な Rust アイテム | 408 個(24 個の pub mod にまたがる) |
| コマンドラインのフラグ | 138 個(10 サブコマンド) |
| MCP tool / prompt | 6 / 4、加えて kb:// resource スキーム |
| HTTP route | 5 |
| 設定セクション | 11、deny_unknown_fields が 25 箇所 |
| ディスク上の成果物 | 索引 DB / 設定 / 除外ファイル / eval セットと履歴 / サービス登録 |
これを全部 2.0.0 まで凍らせると、失敗の仕方が 2 つに 1 つになる。誰も依存して いない部分を永久に改善できないか、誰も気付かない変更のたびに major を出すか である。どちらも「どこが約束なのかを事前に書き下す」より悪い。
これを理屈でなく具体にしている項目が 1 つある。/ui の web 画面は自分の HTML で
自分を placeholder と名乗っており、作り直す予定になっている。宣言なしで 1.0.0 を
出せば、その作り直しが 2.0.0 になる。
cargo package -p grooveseek は “dependency groove-tray does not specify a
version” で失敗する(workspace が version 指定の無い path 依存を使っているため)。
crates.io 上でこの 408 個に依存できるものは存在しないので、1.0.0 を打っても
凍らない — 凍らせたくても凍らない/ui 刷新が major になるので却下安定な面を docs/stability.ja.md に書き下す(推測に委ねない)。
要約すると、コマンドライン / 機械可読な JSON / MCP の面 / /mcp と /healthz /
設定のキーと既定値 / 既定の embedding モデル / ユーザのファイルシステムに書かれる
名前。明示的に対象外なのは、管理用の web 面 / 人間向けの text 出力すべて /
DB の内部スキーマ / ログの文面 / Rust API。
このうち 3 点は、ポリシー側ではなくここに理由を置く。
Rust API を外し、grooveseek に publish = false を付ける。 文書化するだけで
なくマークするのは、意図を強制可能にするためである — cargo publish が拒否
するので、除外が事故で覆らない。これは問いを避けているのではない。crate は今日
実際に package できないので、この除外は現実の記述である。将来の公開は独立した
判断であり、それ自身の安定性宣言を伴う。
管理用の web 面は非安定。 /ui / /api/search / /api/admin/status は
GrooveSeek が認証を持たないため仕様として loopback 限定である。これらが相手に
しているのは自分のデータを見る運用者であって、統合する開発者ではない。
非安定と宣言することが、予定している刷新を minor に留める唯一の方法である。
設定に前方互換性は無く、未知キーはエラーのまま。 代案(警告して続行)は、
大きな失敗を小さな失敗と交換する。model の打ち間違いは、誰も読まない daemon の
stderr を警告 1 行が流れていく間に、既定モデルでナレッジベースを索引させてしまう。
設定ファイルはそれを読むバイナリの版に属する。ポリシーはそう書く — そうでないふりを
しない。
Origin 既定を
決めること、search レスポンスを全フィールド書き下すことの 3 つcargo package は今も失敗するが、それは見落としではなく意図になった。
もし将来この失敗を直すなら、それは公開すると決めたからであるべきで、
ついでの掃除としてやってはいけない