概要
#157 の修正でsuggestがナレッジグラフを参照するようになったが、Issue関連の全ファイルを1件ずつcontextコマンドに展開するため、提案数が80件に膨らみ実用的でない。
再現手順
commandindexdev suggest --for "Issue #299のiPadレイアウト修正の設計判断を理解したい"
実際の結果
80件の提案。Issue #299の全関連ファイル(JSON成果物、stage別レビューコンテキスト等を含む)が個別にcontext展開される:
1. commandindexdev issue 299 --format json (OK - これは適切)
2. commandindexdev context -- 'dev-reports/design/issue-299-...' --max-files 5
3. commandindexdev context -- 'dev-reports/issue/299/pm-auto-dev/...' --max-files 5
...
58. commandindexdev context -- 'tests/unit/config/z-index.test.ts' --max-files 5
...(計75件のIssue関連context + 5件のBM25ベース提案)
期待される結果
KG由来ステップを大幅に削減し、全体で15-20件程度の提案。代表文書に絞る:
1. commandindexdev issue 299 --format json
2. commandindexdev context -- 'dev-reports/design/issue-299-ipad-layout-fix-design-policy.md' --max-files 5
3. commandindexdev context -- 'dev-reports/issue/299/work-plan.md' --max-files 5
4. commandindexdev context -- 'dev-reports/issue/299/issue-review/summary-report.md' --max-files 5
5. commandindexdev context -- 'dev-reports/issue/299/multi-stage-design-review/summary-report.md' --max-files 5
改善案
フィルタリング戦略
prepend_knowledge_steps() の前段で、ナレッジグラフから取得したドキュメント一覧に対しフィルタリングとIssue単位の上限制御を実施する。
実装方針: suggest.rs 内に filter_and_limit_kg_docs() 関数を新設し、フィルタリング・ソート・グルーピングを一括で行う。before_change.rs の group_and_limit_by_issue() は引数構造が異なるため直接再利用せず、同様のロジックを suggest.rs 内に実装する。
KG文書取得API: find_documents_by_issue() を使用する。このAPIは doc_subtype フィールド付きの結果を返すため、has_review のフィルタリングに file_path の文字列パターンマッチが不要となり、doc_subtype の DocSubtype enum値で直接判定できる。具体的には、doc_subtype == IssueReview || doc_subtype == DesignReview を保持し、doc_subtype == StageReview を除外する。find_knowledge_by_issue() + フィルタリングの案と比較して、以下の利点がある:
doc_subtype(DocSubtype enum)による型安全なフィルタリングが可能
file_path パターンマッチへの依存を排除し、ファイルパス構造の変更に対して堅牢
- 既存APIの活用によりコード量を削減
複数Issue集約フロー: find_documents_by_issue() は単一Issue用APIであるため、複数Issueがヒットした場合は各Issue番号について個別に find_documents_by_issue(issue) を呼び出し、issue_number を付与した Vec<KnowledgeDocResult> 相当のDTOに変換後、全Issueの結果を結合して filter_and_limit_kg_docs() に渡す。
1. modifies リレーションの除外
before_change.rs と同様に、retain() で fileノード(modifies リレーション)をフィルタリング除外する:
docs.retain(|d| d.relation != KnowledgeRelation::Modifies);
ソースコードの個別展開はsuggestの目的(どこから調べ始めるかのガイド)に合致しない。
2. ドキュメント種別による優先度フィルタリング
| 優先度 |
リレーション |
条件 |
扱い |
| 最優先 |
has_design |
常に含める |
retain |
| 最優先 |
has_workplan |
常に含める |
retain |
| 次点 |
has_review |
doc_subtype == IssueReview || doc_subtype == DesignReview |
retain |
| 除外 |
has_review |
doc_subtype == StageReview(stage別個別レビュー) |
フィルタリング除外 |
| 除外 |
has_progress |
全て |
フィルタリング除外 |
| 除外 |
modifies |
全て(fileノード) |
フィルタリング除外 |
3. Issue単位の上限制御
filter_and_limit_kg_docs() 関数内で、Issue単位にグルーピングし、relation_priority に基づくソート後、上位 MAX_KG_DOCS_PER_ISSUE 件を選択する:
const MAX_KG_DOCS_PER_ISSUE: usize = 4;
MAX_KG_DOCS_PER_ISSUE = 4 の根拠: 期待結果の代表文書4種(design, work-plan, issue-review summary, design-review summary)と整合させるため。
ソート順: relation_priority によりソートする。上限制御に達した場合に relation_priority に基づき has_design > has_workplan > has_review(summary のみ)の順で採用される。同一優先度内では取得順を維持する。
relation_priority の値について: before_change.rs 側で定義されている relation_priority の値を採用する。before_change は同様のIssue単位上限制御を先行実装しており、リレーション種別間の優先度に関する設計判断が既に行われているため、一貫性を保つ目的で同じ優先度値を使用する。将来的に KnowledgeRelation::priority() メソッドとして共通モジュールに抽出することを検討する(本Issueのスコープ外)。
処理フロー
各issue_numberについて find_documents_by_issue(issue) を呼び出し
→ issue_number を付与した Vec<KnowledgeDocResult> 相当のDTOに変換
→ 全Issueの結果を結合
→ filter_and_limit_kg_docs() で以下を一括処理:
1. retain() で modifies / has_progress / has_review(StageReview) を除外
2. relation_priority でソート
3. Issue 単位にグルーピングし MAX_KG_DOCS_PER_ISSUE 件に制限
→ prepend_knowledge_steps() でステップ生成
suggestの目的は「どこから調べ始めるか」のガイドであり、全文書の網羅ではない。
受け入れ基準
機能要件
テスト要件
E2Eテスト要件
品質要件
補足
issueコマンドステップとcontextステップの重複について
prepend_knowledge_steps() は Issue 番号ごとに issue <N> --format json ステップを生成し、ナレッジグラフのドキュメントごとに context ステップを生成する。両者は異なるコマンド種別のため重複は発生しない。ただし、将来的に issue コマンドの出力に関連ドキュメントパスが含まれるようになった場合は重複の可能性があるため、その時点で検討する。
JSON成果物の扱いについて
JSON成果物(*-context.json, *-result.json 等)はナレッジグラフのドキュメントノードには含まれず、modifies リレーションのfileノードとして存在する。そのため、modifies の retain() 除外により自動的に対応される。
relation_priorityの共通化について
relation_priority のソートロジックは before_change.rs にも存在する。将来的に KnowledgeRelation::priority() メソッドとして共通モジュールに抽出することを検討する(本Issueのスコープ外)。
他コマンドへの影響
本変更は suggest.rs 内に閉じた変更であり、before_change コマンド等の他コマンドに影響しないことを確認済み。ただし、suggestのKG取得経路は変更されるため回帰確認が必要。
内部依存の変更
本変更により suggest モジュールが IssueDocumentEntry および DocSubtype を新たに参照するようになる。これらは issue コマンド側で定義された型であり、suggest と issue 間に新しいモジュール間依存が発生する。
パフォーマンス影響
find_documents_by_issue() は単一Issue用APIであるため、複数Issueがヒットした場合はIssue数分のSQLiteクエリが発生する。最大で MAX_ISSUE_NUMBERS(3) 回のクエリとなり、従来の1回に比べて最大3回に増加する。ローカルSQLiteアクセスのためレイテンシへの影響は軽微と想定されるが、将来的にIssue上限数を増やす場合はバッチクエリAPIの検討が必要となる。
E2E基準の補足
E2Eテストの合否判定はKG由来ステップ数を主体とする。全体提案数はBM25ベースの戦略ステップ数に依存して変動するため、KGステップ数(issueコマンド + contextコマンド)が MAX_ISSUE_NUMBERS × (1 + MAX_KG_DOCS_PER_ISSUE) 以内であることを主要な検証基準とする。
テスト環境
- commandindex 0.1.0
- CommandMateリポジトリ(2910ファイル、124690セクション)
概要
#157 の修正でsuggestがナレッジグラフを参照するようになったが、Issue関連の全ファイルを1件ずつ
contextコマンドに展開するため、提案数が80件に膨らみ実用的でない。再現手順
commandindexdev suggest --for "Issue #299のiPadレイアウト修正の設計判断を理解したい"実際の結果
80件の提案。Issue #299の全関連ファイル(JSON成果物、stage別レビューコンテキスト等を含む)が個別にcontext展開される:
期待される結果
KG由来ステップを大幅に削減し、全体で15-20件程度の提案。代表文書に絞る:
改善案
フィルタリング戦略
prepend_knowledge_steps()の前段で、ナレッジグラフから取得したドキュメント一覧に対しフィルタリングとIssue単位の上限制御を実施する。実装方針:
suggest.rs内にfilter_and_limit_kg_docs()関数を新設し、フィルタリング・ソート・グルーピングを一括で行う。before_change.rsのgroup_and_limit_by_issue()は引数構造が異なるため直接再利用せず、同様のロジックをsuggest.rs内に実装する。KG文書取得API:
find_documents_by_issue()を使用する。このAPIはdoc_subtypeフィールド付きの結果を返すため、has_reviewのフィルタリングにfile_pathの文字列パターンマッチが不要となり、doc_subtypeのDocSubtypeenum値で直接判定できる。具体的には、doc_subtype == IssueReview || doc_subtype == DesignReviewを保持し、doc_subtype == StageReviewを除外する。find_knowledge_by_issue()+ フィルタリングの案と比較して、以下の利点がある:doc_subtype(DocSubtypeenum)による型安全なフィルタリングが可能file_pathパターンマッチへの依存を排除し、ファイルパス構造の変更に対して堅牢複数Issue集約フロー:
find_documents_by_issue()は単一Issue用APIであるため、複数Issueがヒットした場合は各Issue番号について個別にfind_documents_by_issue(issue)を呼び出し、issue_numberを付与したVec<KnowledgeDocResult>相当のDTOに変換後、全Issueの結果を結合してfilter_and_limit_kg_docs()に渡す。1.
modifiesリレーションの除外before_change.rsと同様に、retain()で fileノード(modifiesリレーション)をフィルタリング除外する:ソースコードの個別展開はsuggestの目的(どこから調べ始めるかのガイド)に合致しない。
2. ドキュメント種別による優先度フィルタリング
has_designhas_workplanhas_reviewdoc_subtype == IssueReview || doc_subtype == DesignReviewhas_reviewdoc_subtype == StageReview(stage別個別レビュー)has_progressmodifies3. Issue単位の上限制御
filter_and_limit_kg_docs()関数内で、Issue単位にグルーピングし、relation_priorityに基づくソート後、上位MAX_KG_DOCS_PER_ISSUE件を選択する:ソート順:
relation_priorityによりソートする。上限制御に達した場合にrelation_priorityに基づきhas_design>has_workplan>has_review(summary のみ)の順で採用される。同一優先度内では取得順を維持する。処理フロー
suggestの目的は「どこから調べ始めるか」のガイドであり、全文書の網羅ではない。
受け入れ基準
機能要件
modifiesリレーションのドキュメントが suggest 結果に含まれないことhas_progressリレーションのドキュメントが suggest 結果に含まれないことhas_reviewリレーションのうちdoc_subtypeがIssueReviewまたはDesignReviewのドキュメントのみ保持され、StageReviewのドキュメントが除外されることhas_design、has_workplanのドキュメントが、上限制御に達した場合にrelation_priorityに基づきhas_design>has_workplan>has_reviewの順で採用されることMAX_KG_DOCS_PER_ISSUE(4件)以下であることMAX_ISSUE_NUMBERS(3) × (1 + MAX_KG_DOCS_PER_ISSUE(4)) = 15であることテスト要件
filter_and_limit_kg_docs()関数のユニットテストが存在することmodifiesリレーションが除外されるテストhas_progressリレーションが除外されるテストhas_reviewのdoc_subtype == IssueReview / DesignReviewのみ保持されStageReviewが除外されるテストDocSubtypeの解釈がissueコマンド側の定義と矛盾しないことの確認テストrelation_priorityに基づくソート順のテストMAX_KG_DOCS_PER_ISSUE)のテストE2Eテスト要件
suggestを実行し、提案数が15-20件程度に収まることmodifiesリレーションのファイルがcontextステップとして出力されないことMAX_KG_DOCS_PER_ISSUE件以下であること品質要件
cargo test --allが全てパスすることcargo clippy --all-targets -- -D warningsで警告0件であること補足
issueコマンドステップとcontextステップの重複について
prepend_knowledge_steps()は Issue 番号ごとにissue <N> --format jsonステップを生成し、ナレッジグラフのドキュメントごとにcontextステップを生成する。両者は異なるコマンド種別のため重複は発生しない。ただし、将来的にissueコマンドの出力に関連ドキュメントパスが含まれるようになった場合は重複の可能性があるため、その時点で検討する。JSON成果物の扱いについて
JSON成果物(
*-context.json,*-result.json等)はナレッジグラフのドキュメントノードには含まれず、modifiesリレーションのfileノードとして存在する。そのため、modifiesのretain()除外により自動的に対応される。relation_priorityの共通化について
relation_priorityのソートロジックはbefore_change.rsにも存在する。将来的にKnowledgeRelation::priority()メソッドとして共通モジュールに抽出することを検討する(本Issueのスコープ外)。他コマンドへの影響
本変更は
suggest.rs内に閉じた変更であり、before_changeコマンド等の他コマンドに影響しないことを確認済み。ただし、suggestのKG取得経路は変更されるため回帰確認が必要。内部依存の変更
本変更により
suggestモジュールがIssueDocumentEntryおよびDocSubtypeを新たに参照するようになる。これらはissueコマンド側で定義された型であり、suggest と issue 間に新しいモジュール間依存が発生する。パフォーマンス影響
find_documents_by_issue()は単一Issue用APIであるため、複数Issueがヒットした場合はIssue数分のSQLiteクエリが発生する。最大でMAX_ISSUE_NUMBERS(3)回のクエリとなり、従来の1回に比べて最大3回に増加する。ローカルSQLiteアクセスのためレイテンシへの影響は軽微と想定されるが、将来的にIssue上限数を増やす場合はバッチクエリAPIの検討が必要となる。E2E基準の補足
E2Eテストの合否判定はKG由来ステップ数を主体とする。全体提案数はBM25ベースの戦略ステップ数に依存して変動するため、KGステップ数(
issueコマンド + contextコマンド)がMAX_ISSUE_NUMBERS × (1 + MAX_KG_DOCS_PER_ISSUE)以内であることを主要な検証基準とする。テスト環境