-
Notifications
You must be signed in to change notification settings - Fork 0
whyコマンドの出力に重複エントリが含まれる #158
Copy link
Copy link
Closed
Description
概要
why コマンドの出力で、同一Issueのレビュー文書が2回ずつ表示される(dedup不足)。
再現手順
commandindexdev why dev-reports/design/issue-299-ipad-layout-fix-design-policy.md実際の結果
Why: dev-reports/design/issue-299-ipad-layout-fix-design-policy.md
Issue #299
[review] dev-reports/issue/299/multi-stage-design-review/summary-report.md
[review] dev-reports/issue/299/pm-auto-dev/iteration-1/progress-report.md
[review] dev-reports/issue/299/issue-review/summary-report.md
[review] dev-reports/review/2026-02-18-issue299-security-review-stage4.md
[review] dev-reports/review/2026-02-18-issue299-impact-analysis-review-stage3.md
[review] dev-reports/review/2026-02-18-issue299-design-principles-review-stage1.md
[review] dev-reports/review/2026-02-18-issue299-consistency-review-stage2.md
[review] dev-reports/issue/299/multi-stage-design-review/summary-report.md ← 重複
... (同一リストが繰り返される)
[workplan] dev-reports/issue/299/work-plan.md
[workplan] dev-reports/issue/299/work-plan.md ← 重複
[modifies] modifies: 84 files
期待される結果
各ファイルが1回のみ表示される。
原因分析(検証済み)
根本原因1: SQL JOINによるCartesian Product
find_knowledge_related() (symbol_store.rs:1074) のSQLクエリで、入力ファイルからIssueへの全incoming edge (ke1) とIssueから兄弟ノードへの全outgoing edge (ke2) をJOINしている。同一Issueから入力ファイルへ異なるrelationの複数エッジが存在する場合、(ke1の数) × (ke2の数) のCartesian productが生成され、sibling行がエッジ数の倍数分重複する。
根本原因2: why.rs のdedup処理不足
run_why() (why.rs:109-125) のIssue別グルーピング処理で、同一 (file_path, relation) の重複チェックを行わず Vec::push() で無条件追加している。
根本原因3: modifies集約のデータモデル不整合
run_why() (why.rs:127-133) で modifies をカウント集約し file_path: "modifies: N files" として WhyDocumentEntry に混入させている。これにより path/json フォーマットで実パスではない合成文字列が出力される。
修正方針
修正1: SQLクエリに SELECT DISTINCT を追加
find_knowledge_related()のSQLにSELECT DISTINCTを追加し、DB層で重複を排除
修正2: アプリケーション層でのdedup追加
run_why()のグルーピングループでHashSet<(String, String)>等を使い(file_path, relation)ペアの重複を防御的に除去
修正3: modifies集約の適切な表現
WhyIssueEntryにmodifies_count: Option<usize>フィールドを追加WhyDocumentEntryのfile_pathに合成文字列を格納しない- human/llm フォーマットでのみ
modifies: N filesを表示 - json フォーマットでは
modifies_countフィールドとして出力 - path フォーマットでは実パスのみを返す(modifies情報は出力しない)
- 全 formatter(human/json/path/llm)と既存テストを同時に更新する
修正4: テスト追加・更新
find_knowledge_related()のCartesian Product再現テストrun_why()の重複入力dedupテスト- modifiesカウントの正確性テスト
- 既存 formatter テストの期待値見直し(json/pathからsynthetic path削除)
- modifies_count の表示/非表示パターンテスト
影響範囲
find_knowledge_related() の呼び出し元
src/cli/why.rs- whyコマンド(本修正の主対象)src/search/related.rs:461-470- search --related コマンド- 重複行があると
add_relation()(related.rs:191-203) が同一パスに重みを重複加算 - SELECT DISTINCT追加により重複由来の過大スコアが是正される(正しい副作用)
- ランキング結果の順位変動があり得ることを許容する
- 重複行があると
WhyIssueEntry の JSON スキーマ変更
modifies_count: Option<usize>フィールド追加- CLI利用者やテストフィクスチャがJSON形状に依存している場合は互換性に注意
パフォーマンス
- DISTINCT + HashSet の二層dedup。LIMIT 100 の範囲内なのでコストは軽微だが、二層でコストが発生する
出力フォーマット
- human/json/path/llm すべてに影響
- 全 formatter の更新が必要
受け入れ基準
-
whyコマンドの出力で同一ファイルが複数回表示されない - 同一 (file_path, relation) ペアが1回のみ出力される
- modifies カウントが正確(重複によるカウント水増しがない)
-
why --jsonで合成文字列("modifies: N files")が file_path に出力されない -
why --jsonで modifies_count が適切なフィールドとして出力される -
why --pathが実ファイルパスのみを返す(合成文字列を含まない) - search --related で同一relation によるスコア水増しが起きない(順位変動は許容)
- Cartesian Product再現ケースの回帰テストが存在する
- 既存 formatter テストが更新され全パスする
-
cargo test --all全パス -
cargo clippy --all-targets -- -D warnings警告0件
スコープ外
- 複数経路で発見された場合のマージ表示(別Issue化を推奨)
- LIMIT 100 の定数化(別Issue化を推奨)
テスト環境
- commandindex 0.1.0 (スキーマv4)
- CommandMateリポジトリ(2910ファイル、124690セクション)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels