Skip to content

[BUG] suggest の英語入力でキーワード部分一致により無関係ファイルを推薦 #127

@Kewton

Description

@Kewton

再現手順

commandindexdev index --path .
commandindexdev suggest --for "add fullscreen feature to terminal display" --format json

期待される動作

src/hooks/useFullscreen.ts, src/components/worktree/TerminalDisplay.tsx 等、タスクに直接関連するファイルが推薦される。

実際の動作

suggestコマンドの出力(戦略ステップリスト)において、以下のファイルがpath引数として推薦された:

1. commandindexdev context -- 'tests/unit/components/app-version-display.test.tsx'
2. commandindexdev search --related 'tests/unit/components/app-version-display.test.tsx'
3. commandindexdev impact -- 'tests/unit/components/app-version-display.test.tsx'
4. commandindexdev context -- 'dev-reports/review/2026-02-18-issue299-security-review-stage4.md'
5. commandindexdev context -- 'src/lib/terminal-highlight.ts'

最上位に app-version-display.test.tsx が推薦されている。BM25検索の内部スコアリングにおいて、body/heading/tagsフィールド内の「display」キーワードが高スコアとなったことが原因(pathフィールドはSTRING型で全文検索対象外のため、ファイル名の部分一致ではない)。

問題点

  • BM25のキーワードマッチングが heading/body/tags フィールドの「display」「terminal」等の汎用語にマッチし、意味的に無関係なファイルが上位に来る
  • useFullscreen.ts(最も関連性の高いファイル)が推薦に含まれていない
  • テストファイルがソースファイルより上位に来ている(スコアペナルティ/フィルタリング機構なし)
  • 現在のスキーマにファイル種別(test/source/doc)を示すフィールドがないため、BM25レベルでのブースト調整ができない

根本原因分析

  1. src/indexer/reader.rs: QueryParser が heading, body, tags の3フィールドを等価重みで検索(ブーストなし)
  2. src/indexer/schema.rs: path は STRING(完全一致)、file_type フィールドなし
  3. src/cli/suggest.rs: search_entry_files() が BM25 のみで検索(ハイブリッド検索未使用)
  4. src/cli/suggest.rs: deduplicate_by_file() はファイル種別によるスコア調整なし

改善方針

Phase 1: BM25スコアリング改善(本Issueスコープ)

実装方針: suggest.rs 内のポストプロセスとして実装。reader.rs には変更を加えない(search/impact/related コマンドへの影響をゼロにするため)。

  • search_entry_files() 内で deduplicate_by_file() の後にスコア減衰関数を適用するパイプラインを構築
  • ファイルパスベースのパターンマッチでファイル種別を判定:
    • テストファイル(test, spec): スコアを減衰(例: ×0.3)
    • ドキュメント/レポート(.md, dev-reports/): スコアを減衰(例: ×0.5)
    • ソースコードファイル: 標準スコア(×1.0)
  • 減衰係数は定数化(TEST_FILE_PENALTY, DOC_FILE_PENALTY

ファイル種別判定:

  • is_test_file(), is_doc_file() を純粋関数として切り出し
  • 既存の manifest.rsFileType::from_extension() の活用を検討

Phase 2: ハイブリッド検索統合(別Issue)

  • BM25結果が0件でなくても semantic search の結果で補完するハイブリッド戦略
  • suggest の戦略生成ロジック全体への影響が大きいため別Issueで対応

受け入れ基準

  • suggestの結果において、テストファイルのスコアがソースファイルより低くなること
  • suggestの結果において、ドキュメント/レポートファイルのスコアがソースファイルより低くなること
  • 再現手順の入力("add fullscreen feature to terminal display")で、テストファイルが最上位に来ないこと
  • ファイル種別判定関数(is_test_file, is_doc_file)のユニットテストが追加されていること
  • 既存のテスト(cargo test --all)が全てパスすること
  • cargo clippy --all-targets で警告0件

影響範囲

コンポーネント 影響
suggest.rs 変更対象: ポストプロセスにスコア減衰関数を追加
reader.rs 変更なし: search/impact/related への波及を防止
search.rs / impact.rs 変更なし: 本Issueスコープ外
hybrid.rs / related.rs 変更なし: 本Issueスコープ外
既存テスト 影響なし: deduplicate_by_file のシグネチャ変更なし

技術的制約

  • tantivy の QueryParser はドキュメント属性によるブーストを標準機能として持たないため、BM25検索後のポストプロセスでスコア調整する方式を採用
  • deduplicate_by_file のスコア集約戦略(現在 max)の変更は本Issueスコープ外
  • searchコマンドへのスコア減衰適用は Phase 2 以降で検討(スコア減衰関数は再利用可能に設計)

環境

  • commandindexdev 0.1.0

深刻度

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions