Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
285 changes: 285 additions & 0 deletions dev-reports/design/issue-171-context-knowledge-graph-design-policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
# 設計方針書: Issue #171 - contextコマンドのナレッジグラフ統合改善

## 1. Issue概要

| 項目 | 内容 |
|------|------|
| Issue番号 | #171 |
| タイトル | contextコマンドにナレッジグラフのエッジを統合する |
| 種別 | 改善(既存実装の最適化) |

### 背景
`context` コマンドにはナレッジグラフ統合が既に実装済みだが、以下の改善が必要:
1. 重みの最適化(0.8が低すぎる可能性)
2. スニペット品質の向上
3. リレーション優先度の改善

## 2. システムアーキテクチャ概要

### 対象レイヤーと責務

| レイヤー | 対象モジュール | 変更内容 |
|---------|---------------|---------|
| **Search** | `src/search/related.rs` | 重み定数の調整 |
| **CLI** | `src/cli/context.rs` | スニペット生成改善、リレーション優先度変更 |
| **Output** | `src/output/mod.rs` | RelationType enum に KG メタデータ構造体を追加 |

### データフロー(変更対象部分)

```
context コマンド
→ collect_related_context()
→ RelatedSearchEngine::find_related()
→ score_knowledge_graph() [重み調整 + メタデータ付加]
→ SymbolStore::find_knowledge_related() [メタデータ取得]
→ build_context_pack()
→ enrich_entry() [doc_subtypeベースのスニペット改善]
→ relation_to_string() [優先度変更]
→ JSON出力
```

## 3. 設計判断とトレードオフ

### 判断1: KNOWLEDGE_GRAPH_WEIGHTの調整

| 選択肢 | 説明 | 採否 |
|--------|------|------|
| A: 0.8 → 0.95 | ImportDependency(0.9)より高く、MarkdownLink(1.0)以下 | **採用** |
| B: 0.8 → 1.0 | MarkdownLinkと同等 | 不採用(リンクが明示的な関連のため上位維持) |
| C: KG枠を--max-filesの20%に予約 | 枠確保方式 | 不採用(スコアベースのマージが自然) |

**理由**: KGエッジは設計文書との関連を示す高品質なシグナルであり、ImportDependency(0.9)より重要な場合が多い。ただしMarkdownLink(1.0)は作者が意図的に張ったリンクであり、最高優先度を維持すべき。

**チューニング根拠**: 0.95はMarkdownLink(1.0)以下かつImportDependency(0.9)より高い唯一の0.05刻み値。テストケースで「KGエントリがImportDependencyより上位に来る」ことをアサーションで保証する。

**影響範囲の認識**: この重み変更はcontext以外のsuggest/why/before-changeコマンドにも影響する。全4コマンドで同一の重み優先順位が適切であることを確認済み(KGエッジは全コマンドで設計文脈として重要)。

### 判断2: RelationType::KnowledgeGraph の拡張方式

| 選択肢 | 説明 | 採否 |
|--------|------|------|
| A: フィールド直接追加 | KnowledgeGraph { issue_number, relation, doc_subtype } | 不採用(SRP/OCP違反) |
| B: 専用メタデータ構造体 | KnowledgeGraph(KnowledgeGraphMeta) | **採用** |
| C: 別の経路でメタデータを渡す | HashMap等で並行伝搬 | 不採用(煩雑) |

**理由(レビュー指摘 Stage1-M1 対応)**: RelationType は出力層の enum であり、KG メタデータを直接持たせると検索ドメインの知識が出力層に漏洩する。専用構造体に切り出すことで、KG固有の拡張が構造体内に閉じ、enum本体への変更を最小化できる。

### 判断3: スニペット生成の改善

| 選択肢 | 説明 | 採否 |
|--------|------|------|
| A: doc_subtypeベースのセクション抽出 | doc_subtypeに応じた見出し抽出 | **採用** |
| B: LLMベースの要約生成 | APIコスト・遅延が大きい | 不採用 |
| C: 現状維持(truncate_body) | 改善なし | 不採用 |

**設計**: KnowledgeRelatedResultのdoc_subtypeを活用し、ドキュメント種別に応じた適切なスニペット抽出を行う:
- `design_policy`: 「## 設計判断」セクションから抽出
- `work_plan`: 「## 作業項目」セクションから抽出
- `issue_review` / `design_review`: summary-report.mdの要約を優先
- その他/不明: 現状のtruncate_bodyをフォールバックとして維持

**セキュリティ**: doc_subtypeはDocSubtype enumでバリデーション済み(既知値のみ)。セクション抽出後も500文字上限を維持する(Stage4-S2対応)。

### 判断4: relation_to_string()の優先度変更

| 選択肢 | 説明 | 採否 |
|--------|------|------|
| A: KnowledgeGraphを3番目に移動 | **採用** |
| B: 複数リレーションを配列で返す | 出力フォーマット変更が大きい | 不採用(別Issue) |
| C: 現状維持(最低優先度) | KGラベルが隠れる問題が解消されない | 不採用 |

**変更後の優先度**:
1. MarkdownLink → "linked"
2. ImportDependency → "import_dependency"
3. **KnowledgeGraph → "knowledge_graph"** ← 6番目から移動
4. TagMatch → "tag_match"
5. PathSimilarity → "path_similarity"
6. DirectoryProximity → "directory_proximity"

**影響範囲の認識(Stage1-M2対応)**: この優先度変更は4コマンド共通のrelation_to_string()に影響する。全コマンドでKGの優先度を上げる意図が正しいことを確認済み。各コマンドのテストで順序を検証する。

## 4. 変更詳細設計

### 4.1 KnowledgeGraphMeta 構造体の新設

```rust
// src/output/mod.rs - KG メタデータ専用構造体(Stage1-M1 対応)
#[derive(Debug, Clone, Default)]
pub struct KnowledgeGraphMeta {
pub issue_number: Option<String>,
pub relation: Option<String>, // "has_design", "modifies" etc.
pub doc_subtype: Option<String>, // "design_policy", "work_plan" etc.
}

// RelationType enum
pub enum RelationType {
MarkdownLink,
ImportDependency,
TagMatch { matched_tags: Vec<String> },
PathSimilarity,
DirectoryProximity,
KnowledgeGraph(KnowledgeGraphMeta), // 専用構造体を使用
}
```

### 4.2 is_knowledge_graph() ヘルパーメソッド

```rust
// src/output/mod.rs - パターンマッチの集約(Stage2-M2 対応)
impl RelationType {
pub fn is_knowledge_graph(&self) -> bool {
matches!(self, RelationType::KnowledgeGraph(_))
}

pub fn kg_meta(&self) -> Option<&KnowledgeGraphMeta> {
match self {
RelationType::KnowledgeGraph(meta) => Some(meta),
_ => None,
}
}
}
```

### 4.3 score_knowledge_graph() の変更

```rust
// src/search/related.rs
pub(crate) fn score_knowledge_graph(
&self,
target: &str,
scores: &mut HashMap<String, (f32, Vec<RelationType>)>,
) -> Result<(), RelatedSearchError> {
let related = self
.store
.find_knowledge_related(target)
.map_err(RelatedSearchError::SymbolStore)?;
for result in related {
let meta = KnowledgeGraphMeta {
issue_number: Some(result.issue_number.clone()),
relation: Some(result.relation.clone()),
doc_subtype: result.doc_subtype.as_ref().map(|d| d.to_string()),
};
add_relation(
scores,
&result.file_path,
KNOWLEDGE_GRAPH_WEIGHT, // 0.8 → 0.95
RelationType::KnowledgeGraph(meta),
);
}
Ok(())
}
```

### 4.4 enrich_entry() のスニペット改善

```rust
// src/cli/context.rs - enrich_entry() 内
let has_knowledge_graph = relation_types
.iter()
.any(|r| r.is_knowledge_graph());

// KnowledgeGraph の場合、doc_subtypeに応じたスニペット抽出
if has_knowledge_graph {
// KGメタデータからdoc_subtypeを取得
let kg_meta = relation_types.iter()
.find_map(|r| r.kg_meta());

if let Some(meta) = kg_meta {
if let Some(ref subtype) = meta.doc_subtype {
// doc_subtypeに応じた適切なセクションを抽出
// フォールバック: 既存のtruncate_body()
// 上限: 500文字を維持(セキュリティ対応)
}
}
}
```

### 4.5 relation_to_string() の優先度変更

```rust
// src/cli/context.rs - relation_to_string()
// 1. MarkdownLink → "linked"
// 2. ImportDependency → "import_dependency"
// 3. KnowledgeGraph → "knowledge_graph" ← NEW POSITION
// 4. TagMatch → "tag_match"
// 5. PathSimilarity → "path_similarity"
// 6. DirectoryProximity → "directory_proximity"
```

### 4.6 add_relation() の重複処理(Stage2-M3 対応)

```rust
// src/search/related.rs - add_relation()
// KnowledgeGraph(meta) の場合、discriminant は同じだがメタデータが異なる場合がある
// 既存の discriminant チェックは維持(同一ファイルに対する複数KGエントリはスコア加算のみ)
// メタデータは最初のエントリのものを保持(find_knowledge_related のORDER BY で優先度制御済み)
```

## 5. 影響範囲

### 直接影響

| ファイル | 変更内容 | リスク |
|---------|---------|--------|
| `src/output/mod.rs` L122-130 | KnowledgeGraphMeta構造体新設、RelationType変更 | 高(型変更は広範囲影響) |
| `src/search/related.rs` L16 | KNOWLEDGE_GRAPH_WEIGHT 0.8→0.95 | 中(全4コマンドのランキング変動) |
| `src/search/related.rs` L456-474 | KGメタデータをRelationTypeに付加 | 低 |
| `src/cli/context.rs` L283-310 | スニペット生成改善 | 中(出力変更) |
| `src/cli/context.rs` L361-393 | 優先度変更 | 中(ラベル変更) |

### 間接影響(パターンマッチ更新必須)

| ファイル | 変更内容 |
|---------|---------|
| `src/cli/suggest.rs` | `matches!(r, RelationType::KnowledgeGraph)` → `r.is_knowledge_graph()` |
| `src/cli/why.rs` | 同上 |
| テストファイル | パターンマッチ更新 |

### 共有インフラへの影響

| コマンド | 影響 |
|---------|------|
| `context` | 直接対象 |
| `suggest` | 重み変更でランキング変動 + パターンマッチ更新 |
| `why` | 重み変更でランキング変動 + パターンマッチ更新 |
| `before-change` | 重み変更でランキング変動 |

## 6. テスト戦略

### 新規テスト

| テスト種別 | 対象 | 内容 |
|-----------|------|------|
| ユニットテスト | `related.rs` | score_knowledge_graph()のスコア値検証(KG > ImportDep アサーション) |
| ユニットテスト | `context.rs` | KGエントリのdoc_subtypeベーススニペット生成検証 |
| ユニットテスト | `context.rs` | relation_to_string()の新優先度検証 |
| ユニットテスト | `output/mod.rs` | is_knowledge_graph()、kg_meta()のテスト |
| ユニットテスト | `output/mod.rs` | KnowledgeGraphMeta全フィールドNone時の後方互換テスト |
| E2Eテスト | `context` | KGエッジを持つファイルでcontext実行、"knowledge_graph"エントリ確認 |

### リグレッションテスト

| 対象コマンド | 検証内容 |
|-------------|---------|
| `suggest` | 重み変更後の出力が妥当であること |
| `why` | 重み変更後の出力が妥当であること |
| `before-change` | 重み変更後の出力が妥当であること |
| 既存テスト全件 | `cargo test --all` パス |

## 7. セキュリティ設計

| 脅威 | 対策 | 優先度 |
|------|------|--------|
| パストラバーサル | 既存のファイルパス正規化を維持 | 維持 |
| SQLインジェクション | パラメータバインド(既存)を維持 | 維持 |
| doc_subtype不正値 | DocSubtype enumでバリデーション、不明値はフォールバック | 新規(中) |
| スニペット肥大化 | セクション抽出後も500文字上限を維持 | 新規(中) |

## 8. 品質基準

| チェック項目 | コマンド | 基準 |
|-------------|----------|------|
| ビルド | `cargo build` | エラー0件 |
| Clippy | `cargo clippy --all-targets -- -D warnings` | 警告0件 |
| テスト | `cargo test --all` | 全テストパス |
| フォーマット | `cargo fmt --all -- --check` | 差分なし |
38 changes: 38 additions & 0 deletions dev-reports/issue/171/issue-review/hypothesis-verification.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 仮説検証レポート: Issue #171

## 検証対象の仮説

Issue本文の主張: 「`context`コマンドはimport依存のみで関連ファイルを収集する。ナレッジグラフの設計制約・レビュー知見は含まれない。」

## 検証結果: **Rejected(否定)**

### 根拠

コードベースを確認した結果、ナレッジグラフのcontext統合は**既にmainブランチに実装済み**です。

#### 1. related.rs: ナレッジグラフスコアリング

- **L10-16**: `KNOWLEDGE_GRAPH_WEIGHT: 0.8` が定義済み
- **L255**: `find_related()` 内で `score_knowledge_graph()` が呼び出される
- **L456-474**: `score_knowledge_graph()` メソッドが `store.find_knowledge_related(target)` を呼び、結果を `KnowledgeGraph` リレーションとしてスコアに追加

#### 2. context.rs: ナレッジグラフエントリのエンリッチメント

- **L283-285**: `has_knowledge_graph` フラグで `RelationType::KnowledgeGraph` を検出
- **L292**: knowledge_graph エントリに heading と snippet を付与
- **L388-391**: `relation_to_string()` で "knowledge_graph" 文字列に変換

#### 3. symbol_store.rs: ナレッジグラフDB

- `knowledge_nodes` / `knowledge_edges` テーブルが定義済み
- `find_knowledge_related()` メソッドがファイルからIssue経由で関連ドキュメントを検索

### 潜在的な改善点

1. `relation_to_string()` で `KnowledgeGraph` の優先度が最低(他のリレーションに隠れる可能性)
2. `KNOWLEDGE_GRAPH_WEIGHT: 0.8` はIssue期待値(3.0)と乖離
3. スニペットの内容がIssue期待の「判断理由の要約」と異なる可能性(現在はbodyの先頭を切り詰めるのみ)

## 結論

基本的な統合は完了済み。Issueは既存実装の改善・拡張を意図している可能性がある。Issue本文の更新が必要。
1 change: 1 addition & 0 deletions dev-reports/issue/171/issue-review/original-issue.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"body":"## 概要\n\n`context`コマンドはimport依存のみで関連ファイルを収集する。ナレッジグラフの設計制約・レビュー知見は含まれない。\n\n## 現状\n\n```bash\ncommandindexdev context src/config/z-index.ts --max-files 5\n# → z-index.test.ts (import_dependency)\n# → MarkdownEditor.tsx (import_dependency)\n# → Modal.tsx (import_dependency)\n# → ...\n# 設計ポリシーやレビュー文書は含まれない\n```\n\n## 期待される結果\n\n```json\n{\n \"context\": [\n {\"path\": \"tests/unit/config/z-index.test.ts\", \"relation\": \"import_dependency\", \"score\": 2.2},\n {\"path\": \"dev-reports/design/issue-299-ipad-layout-fix-design-policy.md\", \"relation\": \"knowledge_graph\", \"score\": 3.0,\n \"snippet\": \"z-index指定方式をinline style方式で統一\"},\n {\"path\": \"src/components/ui/Modal.tsx\", \"relation\": \"import_dependency\", \"score\": 2.1}\n ]\n}\n```\n\nimport依存(コード構造)とナレッジグラフ(設計文脈)が統合されて初めて、AIエージェントに必要な「文脈パック」になる。\n\n## 対象バリュー\n\n- **文脈先回り**: contextがコード構造だけでなく設計意図を含めば、AIが1回のcontext取得で全体像を把握できる\n\n## 実装案\n\n- `context`の関連ファイル収集に、既存のrelated検索(import/path/link等)に加えてknowledge_graphエッジを追加\n- ナレッジグラフ由来のファイルにはスニペット(判断理由の要約)を付与\n- `--max-files`の枠内でimport依存とナレッジグラフをスコア順でマージ","title":"contextコマンドにナレッジグラフのエッジを統合する"}
51 changes: 51 additions & 0 deletions dev-reports/issue/171/issue-review/stage1-review-context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"must_fix": [
{
"id": "M1",
"title": "Issueの前提が事実と異なる",
"description": "Issue本文は「contextコマンドはimport依存のみで関連ファイルを収集する」と述べているが、実際にはrelated.rsにscore_knowledge_graph()メソッド、context.rsにKnowledgeGraph関連の処理、symbol_store.rsにfind_knowledge_related()メソッドが既に実装されている。",
"suggestion": "Issue本文の「現状」セクションを修正し、ナレッジグラフ統合が既に実装済みであることを明記する。残存する具体的なギャップにフォーカスしたIssueに書き換える。"
},
{
"id": "M2",
"title": "受け入れ基準が未定義",
"description": "Issueには期待される出力のJSON例はあるが、テスト可能な受け入れ基準が明示されていない。",
"suggestion": "具体的な受け入れ基準を追加する:(1) KGエントリが出力に含まれること、(2) スニペットに設計判断の要約が含まれること、(3) --max-files枠内でスコア順マージされること。"
}
],
"should_fix": [
{
"id": "S1",
"title": "KNOWLEDGE_GRAPH_WEIGHTが低すぎる可能性の検証",
"description": "現在のKNOWLEDGE_GRAPH_WEIGHT: 0.8はIssueの期待するスコア3.0と大きく乖離。--max-filesの枠内でKGエッジが出力されない可能性がある。",
"suggestion": "実際にKGエッジを持つファイルに対してcontextコマンドを実行し検証する。含まれない場合は重みの調整またはKG枠の最低確保を検討する。"
},
{
"id": "S2",
"title": "スニペット品質の改善が未定義",
"description": "現在のスニペットは本文の単純な切り詰めであり、Issueが期待する「判断理由の要約」とは異なる。",
"suggestion": "スニペット生成ロジックの改善を具体化する。例:knowledge_edgesのmetadataにsummaryがあればそれを優先利用、見出し直後の1〜2文を抽出等。"
},
{
"id": "S3",
"title": "relation_to_string()でのKnowledgeGraph優先度が最低",
"description": "同一ファイルがimport_dependencyとknowledge_graphの両方で関連する場合、knowledge_graphのラベルが表示されない。",
"suggestion": "複数relationの表示対応、またはKGの優先度引き上げを検討する。"
}
],
"nice_to_have": [
{
"id": "N1",
"title": "既存実装のテストカバレッジ確認",
"description": "KG統合のテストが十分か確認し、不足があれば追加する。",
"suggestion": "score_knowledge_graph()、find_knowledge_related()、context.rsのKnowledgeGraph分岐に対するテストの有無を確認する。"
},
{
"id": "N2",
"title": "CLIオプションでKG統合の有効/無効切替",
"description": "KGデータが存在しない環境向けに--no-knowledge-graphフラグを検討。",
"suggestion": "スコープ外として別Issueにしても良い。"
}
],
"summary": "Issueの前提が事実と異なる。ナレッジグラフのcontext統合は既に実装済みであり、Issueを「既存KG統合の改善」にリフレームすべき。具体的なギャップ(重み調整、スニペット品質向上、複数relation表示)に焦点を当てる必要がある。"
}
8 changes: 8 additions & 0 deletions dev-reports/issue/171/issue-review/stage2-apply-result.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"applied": [
{"id": "M1", "action": "Issue本文を全面改訂。前提を「既に実装済みだが改善が必要」に修正。現状の実装済み機能を明記。"},
{"id": "M2", "action": "受け入れ基準セクションを追加。5項目のテスト可能な基準を定義。"}
],
"skipped": [],
"issue_updated": true
}
Loading
Loading