Skip to content

suggestコマンドのナレッジグラフ展開が過剰(80件提案) #167

@Kewton

Description

@Kewton

概要

#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.rsgroup_and_limit_by_issue() は引数構造が異なるため直接再利用せず、同様のロジックを suggest.rs 内に実装する。

KG文書取得API: find_documents_by_issue() を使用する。このAPIは doc_subtype フィールド付きの結果を返すため、has_review のフィルタリングに file_path の文字列パターンマッチが不要となり、doc_subtypeDocSubtype enum値で直接判定できる。具体的には、doc_subtype == IssueReview || doc_subtype == DesignReview を保持し、doc_subtype == StageReview を除外する。find_knowledge_by_issue() + フィルタリングの案と比較して、以下の利点がある:

  • doc_subtypeDocSubtype 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の目的は「どこから調べ始めるか」のガイドであり、全文書の網羅ではない。

受け入れ基準

機能要件

  • modifies リレーションのドキュメントが suggest 結果に含まれないこと
  • has_progress リレーションのドキュメントが suggest 結果に含まれないこと
  • has_review リレーションのうち doc_subtypeIssueReview または DesignReview のドキュメントのみ保持され、StageReview のドキュメントが除外されること
  • has_designhas_workplan のドキュメントが、上限制御に達した場合に relation_priority に基づき has_design > has_workplan > has_review の順で採用されること
  • 1 Issue あたりのナレッジグラフ由来ドキュメント数が MAX_KG_DOCS_PER_ISSUE(4件)以下であること
  • KG由来ステップ数が制御対象となっていること。全体提案数は既存戦略ステップ数 + KGステップ数(issueコマンド + contextコマンド)となり、KGステップ数の上限は MAX_ISSUE_NUMBERS(3) × (1 + MAX_KG_DOCS_PER_ISSUE(4)) = 15 であること

テスト要件

  • filter_and_limit_kg_docs() 関数のユニットテストが存在すること
    • modifies リレーションが除外されるテスト
    • has_progress リレーションが除外されるテスト
    • has_reviewdoc_subtype == IssueReview / DesignReview のみ保持され StageReview が除外されるテスト
    • DocSubtype の解釈が issue コマンド側の定義と矛盾しないことの確認テスト
    • relation_priority に基づくソート順のテスト
    • Issue単位の上限制御(MAX_KG_DOCS_PER_ISSUE)のテスト

E2Eテスト要件

  • ナレッジグラフにIssue関連文書が多数登録された状態で suggest を実行し、提案数が15-20件程度に収まること
  • modifies リレーションのファイルが context ステップとして出力されないこと
  • 複数Issueがヒットした場合に、各Issueあたりの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ノードとして存在する。そのため、modifiesretain() 除外により自動的に対応される。

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セクション)

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