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
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
- [ADR-037: takt fix-trust shortcut — convergence_verdict による Iter 3 短絡](docs/adr/adr-037-takt-fix-trust-shortcut.md) *(試験運用)*
- [ADR-038: ローカル LLM による CodeRabbit findings classification](docs/adr/adr-038-local-llm-finding-classification.md) *(試験運用)*
- [ADR-039: Experimental feature 標準パターン (config opt-in + kill-switch + bounded lifetime)](docs/adr/adr-039-experimental-feature-standard-pattern.md) *(試験運用)*
- [ADR-040: Local LLM Context Size と Resource Trade-off](docs/adr/adr-040-local-llm-context-size.md) *(試験運用)*

## Build

Expand Down
30 changes: 30 additions & 0 deletions docs/adr/adr-027-push-review-simplicity-focus.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,36 @@ security-review (同じ workflow 内で並列実行) の execute median は 62s
- security-review の slowdown は別トラックで調査 (model 指定以外に context サイズが効いている可能性)。
- 次回のこの種の性能 ADR では、baseline/target とも **median で記述する** (p75 値を typical として扱わない)。

## Metrics override 判断基準 (PR #142 追記)

simplicity-review が複雑度 metrics (関数長 / ネスト深さ / 重複等) で flag した行が、PR の本質的責務と独立した **incidental change** であった場合、reviewer は明示的に override 判定を下す。本 ADR では override の判断境界と記述様式を以下に codify する。

### Incidental change vs Responsibility change の線引き

| 種類 | 例 | metrics 判定の扱い |
|---|---|---|
| **Incidental change** | `cargo fmt` による空白/改行整形、import 整理、無関係な未使用コード除去 (`cargo fix --allow-dirty`)、エディタ自動 trailing whitespace 除去 | override OK (本 PR の責務外) |
| **Responsibility change** | 本 PR の fix 本体、新 function 追加、API 変更、bug fix のための ネスト改修 | metrics 判定を尊重 (override 禁止、改善 or 受け入れ rationale 必須) |

判断境界の essential rule: **「diff の hunk を消したら PR の主目的が達成不能になるか」** で判定。Yes → responsibility / No → incidental。

### Override 記述様式

reviewer report で incidental override を行う場合は、以下の 3 項目を明示:

```markdown
- **Override**: <metrics 違反項目>
- **Reason**: incidental (e.g., cargo fmt による 2 行整形 / 既存 import の alphabetize)
- **Rationale**: 本 PR の主責務 (<PR title 引用>) と独立しており、削除しても主目的を阻害しない
```

理由を残さない silent override は禁止 (将来の review で「なぜ flag が消えたか」を逆引きできなくなる)。

### 由来

- PR #142 (Phase A 診断 log 実装) の simplicity-review で `cargo fmt` 整形による 1-2 行 diff 増加が metrics override 判定対象になった事例があり、incidental / responsibility の線引きが不明瞭だった
- post-merge-feedback T3-#4 採用、Frequency Low / Severity Low / Effort XS

## 次ステップ (スコープ外)

- **call chain drift lint の導入**: ADR 内のコードシンボル参照と実コードの整合性を lint で検証する仕組み
Expand Down
25 changes: 25 additions & 0 deletions docs/adr/adr-038-local-llm-finding-classification.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,31 @@ Ollama 不在 / timeout / parse 失敗 / invalid action は **fallback として

これは [docs/local-llm-offload-analysis.md](../local-llm-offload-analysis.md) §6 の方針 (「失敗してもリトライ可能 / Claude が後段で検証」) と整合する。

### Diagnostic logging の scope と移行条件 (PR #142 / Phase A)

JSON parse error 時の context overflow 診断 log は **`eprintln!` で stderr に出力する** 設計 (`src/lib-ollama-client/src/lib.rs` の `emit_overflow_diagnostic`)。これは現状の consumer (`cli-finding-classifier` / `cli-push-runner` lint_screen stage) がすべて CLI 起動で stderr を report に取り込む前提に基づく。

**structured logging (log / tracing crate) への移行条件**:

- `lib-ollama-client` が CLI 以外 (例: 長期常駐 daemon / web service) から呼ばれるようになった場合
- 複数 consumer が log level / target filter で diagnostic 出力を制御したいニーズが生じた場合
- log aggregation (Loki / Datadog 等) への連携を求める要件が出た場合

これらが揃うまでは `eprintln!` で十分。早期の structured logging 導入は依存追加 (log + env_logger / tracing + subscriber) のコストに対して得られる柔軟性が見合わない。

### 90% 閾値の rationale + tuning 方針 (PR #142 / Phase A)

`overflow_hint()` は `prompt_eval_count >= num_ctx * 0.90` で hint を emit する保守設計。**90% 採用根拠**:

- mistral:7b の prompt_eval_count は num_ctx の cap で clamp される (Ollama の internal 仕様、Phase B で実測確認)。100% 到達 = 確定 overflow だが、90% 到達 = overflow 寸前で同一症状を予兆できる
- false positive の負担は warn log 1 件のみ (block しない)、false negative (= overflow を見逃す) の方が debug cost が高い

**tuning 方針**:

- **Phase C/D dogfood で得た data が蓄積するまで本閾値を変更しない**。根拠なき早期変更で false positive 増加 / false negative 増加のいずれかに振れるリスクが高い
- Phase D 完了時 (3-5 PR 観測) に hint emit 件数と実 overflow 件数を突合し、precision / recall を確認して再評価
- 派生プロジェクト (techbook-ledger / auto-review-fix-vc) で diff 規模 / prompt 構造が異なる場合は、本リポジトリ baseline と別系統で再 calibration を検討

### プロンプト

`src/cli-finding-classifier/prompts/classify.txt` に同梱 (`include_str!`)。`--prompt-file` で差し替え可能。テンプレート placeholders は `{severity}` `{file}` `{line}` `{issue}` `{suggestion}`。
Expand Down
93 changes: 93 additions & 0 deletions docs/adr/adr-040-local-llm-context-size.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# ADR-040: Local LLM Context Size と Resource Trade-off

## ステータス

試験運用 (2026-05-12)

> 本 ADR は [ADR-039 (試験運用標準パターン)](adr-039-experimental-feature-standard-pattern.md) 配下の knowledge record。本 ADR 自体は実装変更を持たず、ADR-038 (Local LLM finding classification) で進行中の Phase D/E で得た empirical data を permanent record として固定する性格を持つ。

## コンテキスト

ADR-038 配下の lint_screen / finding-classifier では `lib-ollama-client` の `DEFAULT_NUM_CTX` を Phase A → Phase C で `2048 → 8192 → 16384 → 32768` と段階的に拡大した。各段階で観測した latency / VRAM 使用量 / `step_timeout` 整合性は、将来 num_ctx を再選定する局面 (派生プロジェクトへの porting / 別 model 採用 / diff 規模変化) で再利用価値の高い empirical data だが、現状は以下に分散していて参照が難しい:

- `src/lib-ollama-client/src/lib.rs` L128-139 の dogfood evolution コメント
- `push-runner-config.toml` L8-10 の step_timeout 履歴コメント
- `docs/local-llm-offload-analysis.md` (ephemeral 計画書、retire 予定)

ephemeral artifact (analysis.md) には permanent data を残さない原則 (`~/.claude/rules/common/docs-governance.md` § Ephemeral 大規模コンテンツの ADR 昇格基準) に従い、Phase D/E 進行中で再利用機会が高い本 data を ADR として固定する。

## 決定

`mistral:7b` を Ollama 経由で本リポジトリの lint_screen / finding-classifier 用途で利用する際の **context size 選定の trade-off** を以下に codify し、ephemeral 経路 (lib.rs コメント / analysis.md) を本 ADR への参照に置き換える。

### 実測値 (mistral:7b on RTX 3070 8GB)

| num_ctx | VRAM 使用量 | per-invoke latency (lint-screen prompt + 200-500 行 diff) | overflow 発生 |
|---|---|---|---|
| 2048 (Ollama default) | ~400MB | 評価不可 (prompt 単体で overflow) | 確実 |
| 4096 | ~450MB | (実測スキップ、PR #135 で 8192 へ直接) | 確実 |
| **8192 (Phase b'/c MVP)** | ~512MB | **5-20s** (median ~7s、Bundle i evals 15 件 p50=4.6s / p95=8.4s) | 大規模 diff (200+ 行) で発生 (Bundle i eval13 / eval15) |
| 16384 (Phase A 試行) | ~1GB | ~15-40s | PR #141 (487 行 diff) で 100% overflow 再観測 |
| **32768 (Phase C 確定値、mistral:7b theoretical max)** | ~2GB | **30-90s** (mean ~50s、3 PR replay 平均) | 確認なし (487 行 diff まで) |

### Trade-off 軸 (context 選定時の判断基準)

| 軸 | 8K | 32K |
|---|---|---|
| **Latency** | 5-20s/invoke = UX 許容範囲 | 30-90s/invoke = pipeline 滞留が顕在化 |
| **Memory** | 512MB = 同時に他 model 起動可能 | 2GB = `mistral:7b` 単独占有、`llama2:13b` swap 不可 |
| **Accuracy** | 大規模 diff で truncation → fallback rate 高 (Bundle i 73.3% agreement) | overflow 解消 → fallback rate < 50% に低下 (Phase C smoke で 33% 達成) |
| **Timeout 整合性** | `step_timeout = 180s` で 12 件 mistral invoke ([cargo test -- --ignored]) を完走 | `step_timeout = 600s` (= 3.33x) が必要、`push-runner-config.toml` 側で整合化 |

### `step_timeout` 比例係数の根拠

`push-runner-config.toml` の `step_timeout` は num_ctx に対して **sublinear** に拡大する (context 4x = 8K → 32K に対して timeout は 3.33x = 180s → 600s)。per-token budget で見ると `180s / 8192 = 22 ms/token` ↔ `600s / 32768 = 18.3 ms/token` で、大規模 context の方が per-token 推論コストがわずかに低い (KV cache の locality 効果と推定):

- Phase b' (8K): 180s で 12 件 mistral invoke (`cargo test --ignored`) を完走
- Phase C (32K): 269s 観測 (= 180s 超過、cargo test 全体) → 600s に拡大
- per-invoke latency が num_ctx に対して概ね線形に拡大する経験則 (overflow 解消後の純粋な inference time)

**reference 値** (派生プロジェクトでの derivation 用):

| num_ctx | 採用 step_timeout | 根拠 |
|---|---|---|
| 8192 | 180s | Phase b' 実測 (12 件 mistral invoke、cargo test --ignored 完走) |
| 32768 | 600s | Phase C 実測 (269s 超過観測 → 2x margin で確定) |

派生プロジェクトでは上記 reference 値を最初の見積もりに使い、実測 cargo test 経過時間の **2x margin** で補正する (例: 観測 250s → 500s に設定)。

### Context 選定の判断 flow

新規 LLM 系 feature 導入時 / num_ctx 再選定時の判断順序:

1. **prompt + 想定入力の token 量を実測** (`prompt_eval_count` を Phase A diagnostic log で取得可)
2. token 量の **1.5x を初期 num_ctx 候補** とする (margin で truncation 回避)
3. 候補値が `mistral:7b theoretical max (32768)` を超える場合は、prompt 圧縮 / diff truncation / 別 model (llama2:13b 等 8K context) への切替を検討
4. 選定した num_ctx に対して上記 reference table から initial `step_timeout` を取り、実測 cargo test 経過時間の 2x margin で補正
5. dogfood で fallback rate / latency p95 を実観測し、`overflow_hint` (ADR-038、90% 閾値) の emit 件数を監視

## 帰結

### Pros

- num_ctx 再選定時の判断基準が ADR として permanent 化、ephemeral 計画書 retire 時の data loss を防ぐ
- `step_timeout` 比例係数の根拠が明示化、将来の derivation 時に再発見コストが消える
- `src/lib-ollama-client/src/lib.rs` の evolution コメントが本 ADR への 1-line reference で済み、code comment 肥大化が解消

### Cons / リスク

- mistral:7b 固有の実測値のため、別 model (llama2:13b / qwen2.5:7b 等) では再 calibration が必要
- RTX 3070 8GB の VRAM 制約に依存する値、より大容量 GPU では memory 軸の trade-off が変わる
- 実測 latency は warm context 前提、cold start (model load 直後) では 1.5-2x の variance がある

### 試験運用 → 本採用への昇格条件

ADR-038 が「採用」に昇格 (Phase E 完了) するタイミングで、本 ADR も「採用」に昇格する。ADR-038 が「却下」の場合は、本 ADR の data は historical record として保持する (revert はせず、`lib-ollama-client` 利用機会が再来した時のための knowledge prior)。

## 関連

- [ADR-038](adr-038-local-llm-finding-classification.md) — Local LLM finding classification、本 ADR の data 元
- [ADR-039](adr-039-experimental-feature-standard-pattern.md) — 試験運用標準パターン、本 ADR の運用基盤
- `src/lib-ollama-client/src/lib.rs` — `DEFAULT_NUM_CTX = 32768`、Phase C 確定値
- `push-runner-config.toml` L8-10 — `step_timeout = 600` の根拠
- `docs/local-llm-offload-analysis.md` (ephemeral) — Phase A/B/C 進行ログ、retire 時に本 ADR へ data migrate 済
Loading