-
Notifications
You must be signed in to change notification settings - Fork 0
commandindexdev before-change <file> コマンドの実装 #142
Copy link
Copy link
Closed
Description
概要
ファイルを変更する前に知るべき設計制約・過去のレビュー指摘を集約して返すコマンド。git log走査 → Issue特定 → ナレッジグラフ文書取得 → セマンティックランキングの多段フロー。
前提
- ナレッジグラフ(knowledge_nodes / knowledge_edges)が実装済みであること
- BGE-M3によるセマンティック検索が動作すること(多言語embeddingモデル対応 (BGE-M3) #134 完了済み)
- ソースファイルとIssueの関連付け: 現在のナレッジグラフにはソースファイル→Issueのリンクが存在しないため、git logのコミットメッセージからIssue番号を抽出してファイルとIssueを紐づける仕組みを実装する必要がある
使用例
commandindexdev before-change src/config/z-index.ts期待される出力:
src/config/z-index.ts を変更する前に:
設計制約:
Issue #299: z-index体系を統一。新しい値はMAXIMIZED_EDITOR(55)の後に追加
→ dev-reports/design/issue-299-ipad-layout-fix-design-policy.md
Issue #104: iPad CSSフォールバックでz-index:55を前提とした実装あり
→ dev-reports/design/issue-104-ipad-fullscreen-bugfix-design-policy.md
過去のレビュー指摘:
Issue #299 stage4: clickjacking対策としてz-indexの層構造を維持すること
→ dev-reports/review/2026-02-18-issue299-security-review-stage4.md
関連する他のIssue:
Issue #112: sidebar transform(同じファイルを変更)
アーキテクチャ
設計方針
- git log走査ロジックは
src/cli/before_change.rsに新規関数として実装(既存のknowledge.rsのパスパターンベース抽出とは責務を明確に分離) - SymbolStoreの既存メソッドは変更せず、Issue番号起点の文書取得用に新メソッドを追加
- embedding未生成でも動作するよう、セマンティック検索はオプショナル
- インデックスパス解決は
resolve_index_path→symbol_db_path()/embeddings_db_path()の既存パターンに統一
モジュール構成(変更対象)
src/cli/before_change.rs # before-changeコマンド本体 + git log走査ロジック(新規)
src/cli/mod.rs # before_changeモジュール宣言追加
src/main.rs # Commands enumにBeforeChange追加、分岐追加
src/indexer/symbol_store.rs # find_knowledge_by_issue() メソッド追加
src/output/*.rs # BeforeChangeResult用フォーマッタ追加
src/cli/help_llm.rs # before-changeコマンド情報追加
tests/cli_args.rs # help-llmコマンド数テスト更新、トップレベルhelp期待値更新
tests/e2e_before_change.rs # E2Eテスト(新規)
実装
全体フロー
file → git log → issue番号群 → knowledge docs → セマンティックランキング
- ソースファイル → Issue 紐づけ(git log走査):
git log --max-count=N -- <file>のコミットメッセージからIssue番号(#NNN、(#NNN)、fixes #NNN、refs #NNNパターン)を抽出。merge commitも対象とする。パフォーマンスのため--max-commitsオプションで走査コミット数を制限(デフォルト: 200)。 - Issue起点の文書取得(ナレッジグラフ1ホップ): 特定されたIssue番号を起点に、
SymbolStore::find_knowledge_by_issue()でhas_design/has_review/has_workplanエッジを辿り、関連ドキュメントを取得 - セマンティック検索(ランキング・オプショナル): ステップ2で見つかったドキュメントの中から、対象ファイルのembedding(
EmbeddingStore::find_by_path()で取得)とのコサイン類似度でランキング。複数section embeddingの集約方針: 対象ファイル・文書それぞれ複数のsection embeddingを持つため、各ペアの最大コサイン類似度(max pooling)をスコアとする。embedding未生成の場合はスキップし、ナレッジグラフの関係性のみで結果を返す。 - 別インデックス参照(オプション):
--index-path指定時、resolve_index_path→symbol_db_path()/embeddings_db_path()で別worktreeのインデックスを参照
fn before_change(file_path: &str, index_path: Option<&Path>, max_commits: usize) -> Result<Vec<Finding>> {
// ステップ1: git logからIssue番号を抽出
let issue_numbers = extract_issues_from_git_log(file_path, max_commits)?;
// ステップ2: ナレッジグラフでIssue → ドキュメント取得(1ホップ)
let resolved_path = resolve_index_path(index_path)?;
let symbol_store = SymbolStore::open(&symbol_db_path(&resolved_path))?;
let docs = symbol_store.find_knowledge_by_issue(&issue_numbers)?;
// ステップ3: セマンティック検索でランキング(オプショナル)
let emb_path = embeddings_db_path(&resolved_path);
let findings = match EmbeddingStore::open(&emb_path) {
Ok(embedding_store) => {
let file_embs = embedding_store.find_by_path(file_path)?;
rank_by_max_similarity(&file_embs, &docs, &embedding_store)?
},
Err(_) => {
eprintln!("Warning: embedding store not found, skipping semantic ranking");
docs.into_iter().map(|d| Finding { doc: d, similarity: None }).collect()
},
};
Ok(findings)
}出力フォーマット
--format human,--format json,--format llm,--format path--format llmはエージェントのコンテキストとして直接利用可能- before-change固有の出力構造体
BeforeChangeResultを定義し、各フォーマッタにformat_before_change_*関数を追加
オプション
--index-path <PATH>: 別のworktree(develop等)のインデックスを参照。サブコマンドレベルで指定し、resolve_index_pathで解決。--limit <N>: 結果件数制限(デフォルト: 10)。全体の上位N件をスコア順で返す。--max-commits <N>: git log走査の最大コミット数(デフォルト: 200)
エラーハンドリング
- インデックス未作成: エラーメッセージで
commandindexdev index実行を案内 - embedding未生成(DB不存在): Warning を表示しつつナレッジグラフのみで動作
- 対象ファイルのembedding欠如: Info メッセージを表示しつつランキングなしで結果を返す
- 関連文書のembedding欠如: その文書を未ランクとして末尾に表示
- 対象ファイルがインデックスにない: 警告を表示しつつgit log走査のみで結果を返す
- 関連Issueが見つからない: 「関連する設計制約は見つかりませんでした」メッセージ
- 不正なファイルパス(空文字、先頭
-等): エラーメッセージで拒否 - gitリポジトリ外での実行: 明確なエラーメッセージを返す
受け入れ基準
-
before-change <file>で関連するナレッジドキュメント(設計書・レビュー結果)が返ること - git logからIssue番号を正しく抽出し、ソースファイルとIssueを紐づけられること(
#NNN、(#NNN)、fixes #NNN、refs #NNNパターン対応) - ナレッジグラフのIssue起点文書取得(Issue → 設計ポリシー・レビュー)が動作すること
- セマンティック検索による関連度ランキングが動作すること(embedding存在時、max pooling方式)
- embedding未生成時でもナレッジグラフのみで動作すること
-
--format humanで人間が読みやすい形式で出力されること -
--format jsonでJSON形式で出力されること -
--format llmでLLM向け形式で出力されること -
--format pathでパスのみ出力されること - 関連Issueが存在しないファイルに対して適切なメッセージが返ること
-
--index-pathで別worktreeのインデックスを参照できること(resolve_index_path経由) -
--limitで全体上位N件に結果が制限されること -
--max-commitsでgit log走査コミット数が制限されること - 不正なファイルパスを拒否すること
- gitリポジトリ外では明確なエラーを返すこと
-
help-llmの出力にbefore-changeコマンド情報が含まれること -
tests/cli_args.rsのトップレベルhelp期待値が更新されていること -
tests/cli_args.rsのhelp-llmコマンド一覧・件数テストが更新されていること -
before-change --helpがサブコマンドのヘルプを正しく表示すること - E2Eテスト: embeddingあり/なし、indexあり/なし、不正パス、非gitリポジトリのケース
- cargo test で全テストがパスすること
- cargo clippy で警告0件
影響範囲
- 既存の検索・indexingロジック: 直接影響なし(新規追加のみ)
- CLI公開面(--help / help-llm): トップレベルhelpにbefore-changeが追加される。help-llmのコマンド一覧・件数が変更される。これに依存する既存テストの更新が必要。
- 出力モジュール(output/*.rs): BeforeChangeResultとformat関数の追加が必要。既存のformat_*関数には影響しない。
- データモデル: knowledge_nodes/edgesテーブルの変更不要(読み取りのみ)
- 依存crate: 追加不要(既存のregex, rusqlite等で実装可能)
- パフォーマンス: git log走査(プロセス起動+履歴走査)とsection embedding総当たり比較(対象ファイルsection数×文書section数×文書件数)が新たなホットパス。履歴が深いファイルやsection数の多い文書群ではレイテンシ増加の可能性あり。--max-commits上限と--limit上限で制御。
- テスト: tests/cli_args.rsのトップレベルhelp・help-llm期待値更新、before-change --helpテスト追加、git repoセットアップを伴うE2Eテスト新規追加。
関連
- ナレッジグラフIssue(前提)
- 多言語embeddingモデル対応 (BGE-M3) #134 (BGE-M3) — 完了済み
- COMMANDINDEX_VISION.md Phase 2-3
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels