Semantic search over a Markdown knowledge base, served over MCP.
.xls (レガシー BIFF) サポートの取り下げ.xls は v0.11.0 〜 v0.13.1 で index 可能だった).xls は v0.11.0 で .docx / .xlsx / .pptx と一緒に追加され、
calamine の reader を .xlsx と共有していた。
バイナリ parser のセキュリティ監査で、この 2 形式はメモリ特性を共有しておらず、
.xls 経路を正当化していたコメントが誤りであることが判明した。
.xlsx はストリームとして読まれる。.xls は違う: calamine::Xls::new() が
workbook を eager に parse し、全シートを BTreeMap<String, SheetData> に保持した上で
各シートに Range::from_sparse を呼ぶ。これは値の入ったセルの bounding rectangle を求め、
vec![Data::default(); rows * cols] として密に確保する。
ソースは「BIFF がシートを 65,536 × 256 に制限しているから安全」と主張していた。 それが縛るのはシートであって workbook ではない。 実測:
| 項目 | 値 |
|---|---|
size_of::<calamine::Data>() |
32 B |
| 最大シート (65,536 × 256) | 16,777,216 セル = 512 MB |
worksheet_range() は clone を返す |
読み出し中のシートはピーク 1 GB |
| workbook の上限 | 無し — (シート数) × 512 MB |
対角 2 セル分のレコードだけでシートを最大矩形にできるので、数十 KB の細工ファイルで 十分な数のシートを宣言すればメモリを使い切れる。しかも割り当て失敗はエラーを返さず プロセスを異常終了させるため、他形式を守っている per-file skip も parser の panic guard も 構造的に効かない。監視ディレクトリに 1 ファイル置かれるだけでサーバが落ちうる。
.xls は 2007 年以前の形式で要望も出ておらず、kb-mcp が index する内容
(セルのテキスト) は .xlsx への変換で保たれる。ただし変換は一般には
無損失ではない: VBA マクロは .xlsm を要し、その他のレガシー固有機能も
失われたり変質したりしうる。原本は置き換えず残すこと。calamine がファイルを開く前の pre-check で確保量を縛る。 CFB (OLE2)
コンテナを自前で辿って BOUNDSHEET / DIMENSIONS レコードを読み、シート数と
宣言された範囲を得て、Xls::new() の実行前に過大な workbook を拒否する。選択肢 4 (取り下げ) を採用する。新規依存を増やさずに穴を塞げる唯一の選択肢であり、 ユーザに生じるコストがファイル変換で済むから。
[parsers].enabled に "xls" を書くと、起動時に理由付きで拒否される。
該当する workbook の推奨経路は .xlsx への変換。
他を採らなかった理由:
cfb) と BIFF レコード走査の実装が要る。なお、
監査が当初提案した位置 (worksheet_range() の中または直前) には check を置けない。
その関数に到達した時点で密な確保は Xls::new() の内側で完了しており、Xls は
ReaderRef を実装していないので borrow ベースの accessor が無く、clone すら避けられない。
pre-check は厳密に Xls::new() より前で走る必要がある。sheets が個数上限の無いマップであることを見落としていた。
この件を再検討する人は、形式が謳う上限が「どの単位に」かかっているのかを、
それを bound として扱う前に必ず確認すること。.xls ファイルは calamine に到達しない。[parsers].enabled に "xls" を残したままアップグレードすると、
無言の機能低下ではなく起動エラーになる。これが関連する修正を 1 つ強制した:
kb-mcp index は、データベースを開く前・埋め込みモデルを読む前・(--force 時は)
リセットを行う前に [parsers].enabled を検証するようになった。以前は、
今は拒否される id を持つ config がデータベースを空にしてからエラー終了し、
index が丸ごと消えていた。kb-mcp serve は、[parsers].enabled がもうカバーしない拡張子の文書が index に
残っている場合に警告を出す。その行は次の kb-mcp index で削除されるが、serve は
index しないため、サーバのみ動かしている環境では残り続け、検索には出るのに
get_document が拒否するヒットとして表面化する。警告は件数と例を示すだけで
何も削除しない — enabled を狭めるのは一時的な場合が多いため。XlsParser とその単体テストはツリーに残るが、registry からは到達不能。
意図的に残している — 選択肢 1 を後から実装するときに、抽出経路を作り直さずに済むように。.xls の資産を持つユーザは変換が必要。ツリー内に移行手段は無い。Registry::from_enabled が "xls" を理由付きで拒否する (単体テストあり)。[parsers].enabled の検証があらゆる副作用より前に走る — 拒否された config は
データベースを残さず、モデルもダウンロードしない。CHANGELOG.md の v0.14.0 → Removed.xls が拒否されたという
ユーザ報告」。