diff --git a/docs/local-llm-offload-analysis.md b/docs/local-llm-offload-analysis.md index 81427f5..05495cd 100644 --- a/docs/local-llm-offload-analysis.md +++ b/docs/local-llm-offload-analysis.md @@ -2,7 +2,7 @@ > **位置づけ**: 本ファイルは「残作業の **次に何をするか** だけ」を持つ実行計画。完了済みの分析・実装・dogfood 計測・retrospective は [local-llm-offload-history.md](local-llm-offload-history.md) に切り出した。 > -> **状態**: 試験運用 (Phase a 完了 = PR #130 land / Phase b 完了 = conditional GO 2026-05-08, PR #131 / Phase c MVP 完了 = PR #132 land 2026-05-08 / **Phase c+ Bundle i 完了 = PR #135 land 2026-05-09 / §8.D 完了 = PR #136 land 2026-05-09 (num_ctx 8192、agreement 86.7% / verdict GO)**、Phase d 着手前提条件は全て充足済、kickoff 待機)。 +> **状態**: 試験運用 (Phase a 完了 = PR #130 land / Phase b 完了 = conditional GO 2026-05-08, PR #131 / Phase c MVP 完了 = PR #132 land 2026-05-08 / **Phase c+ Bundle i 完了 = PR #135 land 2026-05-09 / §8.D 完了 = PR #136 land 2026-05-09 (num_ctx 8192、agreement 86.7% / verdict GO) / Phase d kickoff prep 完了 = 2026-05-10 ([docs/local-llm-offload-phase-d-guide.md](local-llm-offload-phase-d-guide.md) 参照)**、実 dogfood (3-5 PR、long-running) 待機)。 > > **引退条件**: 以下のいずれかで本ファイルを削除する (docs-governance.md retirement workflow 準拠)。`local-llm-offload-history.md` も同タイミングで判断する。 > - 残作業 (§8.D / §8.E / §8.F, §1 Phase b/c/d) が **すべて land または却下** された場合 → permanent value (採用された設計判断、却下理由) を ADR-038 に migrate して両ファイルを削除 @@ -197,8 +197,23 @@ cargo test -p cli-finding-classifier --test lint_screen_evals -- \ #### 次に何をするか (優先度順) -1. **Phase d kickoff prep** (session 内で完結可能): `push-runner-config.toml [lint_screen] enabled = true` への切替判断、metrics 計測スクリプト整備、dogfood 運用ガイド作成、過去 dogfood 阻害要因 3 種 (findings ゼロ / review body 抽出漏れ / rate-limit) への対処設計。**前提条件 (a)-(d) は PR #135 + PR #136 で全充足済** -2. **Phase d 実 dogfood** (long-running、数日〜数週間): kickoff 後の通常 PR 3-5 件で lint_screen の token 削減 / latency / 大規模 diff JSON 完全性を実観測。`feedback_dogfood_evals_two_phase` (evals → dogfood の 2 段階) の dogfood 段階に該当 +1. **Phase d kickoff prep** ✅ **完了 (2026-05-10)**: 運用ガイド = [docs/local-llm-offload-phase-d-guide.md](local-llm-offload-phase-d-guide.md) として独立 doc 化。決定事項: (a) **session-only opt-in** (config commit せず session 内のみ enable / kill-switch 即可)、(b) metrics = **latency p50/p95 + fallback rate + Claude session input token 削減効果 (質的傾向)**、(c) kill-switch = **fallback rate > 50% で停止**。過去 dogfood の 3 obstacles (findings ゼロ / review body 抽出漏れ / rate-limit) は classifier 専用で lint_screen は CR 非依存のため scope 外と確定。**前提条件 (a)-(d) は PR #135 + PR #136 で全充足済** +2. **Phase d 実 dogfood** (long-running、数日〜数週間): kickoff 後の通常 PR 5 件で lint_screen の token 削減 / latency / 大規模 diff JSON 完全性を実観測。`feedback_dogfood_evals_two_phase` (evals → dogfood の 2 段階) の dogfood 段階に該当。具体運用は [docs/local-llm-offload-phase-d-guide.md](local-llm-offload-phase-d-guide.md) §1-3 に従う + + **dogfood 対象 PR roster** (`docs/todo-summary.md` から選定、size ramp-up 順序): + + | Order | 構成 | Effort | Diff Profile | dogfood signal | + |---|---|---|---|---| + | P-1 | Bundle h (順位 89+90) + Bundle g-2 (順位 87+88) | M | global rules markdown 4 file | docs-only で `informational` 期待、false-positive 検証 baseline | + | P-2 | Bundle j-1 (順位 94 — `../docs/` 相対パス detect lint rule) | S | TOML config + 軽い Rust regex | 小規模 mixed diff | + | P-3 | Bundle g-1 (順位 85+86 — cli-pr-monitor verdict guard + transition test) | M | Rust impl + Rust test | 中規模 Rust、`auto_fix` 期待 | + | P-4 | Bundle d (順位 68 — no-ephemeral-todo-reference self-exclusion test) | S | Rust test only | 狭 scope test diff | + | P-5 | Bundle c-1 (順位 63+64+67 — cli-merge-pipeline Drop guard + reaper + ADR) | L | Rust impl ×2 + ADR | 大規模 Rust (PR #132 868 行 stress 再現候補) | + + **設計判断のポイント**: + - **Effort 分布 M→S→M→S→L**: 前半小規模 / 後半大規模で kill-switch (fallback > 50%) signal の質を切り分け可能 (小規模で発動 = 設計 issue / 大規模で発動 = num_ctx 再到達) + - **Bundle h + g-2 を 1 PR に統合**: 共通テーマ「global rules consolidation (process/lifecycle codification)」、reviewer も「rule 追加 4 件まとめ」として認識しやすい + - **Bundle f 除外**: `(defer)` 表記 = systemic 性未確認のため Phase d で push 圧力を加えない 3. **Phase d 結果集約**: 計測結果から §8.E 採用 / §8.F 着手 / kill-switch を判定。dogfood 完了後 優先度低の独立 task (Phase d を block しない): diff --git a/docs/local-llm-offload-phase-d-guide.md b/docs/local-llm-offload-phase-d-guide.md new file mode 100644 index 0000000..6b1b0d9 --- /dev/null +++ b/docs/local-llm-offload-phase-d-guide.md @@ -0,0 +1,114 @@ +# Phase d (lint_screen 実環境 dogfood) 運用ガイド + +> **位置づけ**: ADR-038 試験運用配下の §8.E (lint screen facet) を 3-5 通常 PR で dogfood し、**本採用 / 却下** を判定するための operational guide。 +> +> **対象**: `cli-push-runner` の `lint_screen` stage (PR #132 / #135 / #136 で land 済)。`cli-finding-classifier` の dogfood (`local-llm-offload-history.md` §A-2) とは **別 feature**、CR 非依存。 +> +> **状態**: 試験運用 (kickoff prep land 後、実 dogfood は次回以降の通常 PR で実施)。 +> +> **引退条件**: Phase d 完了 (3-5 PR で実観測) → §8.E 採否判定 → ADR-038 を「採用」or「却下」に昇格 → 本ファイル削除 + analysis.md / history.md も同タイミングで再評価。 + +## 1. Setup (session-only opt-in) + +`push-runner-config.toml` は default OFF のまま。dogfood する session で **手動で `enabled = true` に切り替え (commit しない)**。 + +```bash +# 1. Ollama 起動確認 +curl -s http://localhost:11434/api/tags | jq '.models | map({name, size})' +# 期待: mistral:7b が含まれる + +# 2. config 切替 (commit しない、session 内のみ) +# push-runner-config.toml の [lint_screen] section で +# enabled = false → enabled = true +# 編集後、jj diff で確認 (push 時に意図せず commit に乗らないよう注意) + +# 3. cli-finding-classifier.exe deploy 確認 +ls -la .claude/cli-finding-classifier.exe +# 期待: ファイル存在、~2.2MB + +# 4. dogfood 完了後、必ず enabled = false に戻す (revert) +jj diff push-runner-config.toml # 確認 +# 編集して enabled = false に戻す、または jj restore push-runner-config.toml +``` + +**意義**: kill-switch が即可能、他人 / 派生プロジェクトの push に影響なし、設計 (default OFF, 試験運用 opt-in) との整合性。 + +## 2. 計測 (各 dogfood PR で実施) + +ユーザー判断 (Phase d kickoff、2026-05-10) で以下 3 metrics を採用: + +### 2-1. lint_screen latency p50/p95 + +```bash +# push 後、push-runner log から抽出 +grep "lint-screen.*出力:" .takt/runs//logs/*.jsonl +# 期待 format: "出力: .takt/lint-screen-report.md (Ns)" +``` + +3-5 PR 集計後に p50 / p95 を算出。**baseline**: Bundle i evals dogfood で p50=4.5s / p95=8.4s (eval fixtures、num_ctx=8192)。 + +### 2-2. fallback rate + +```bash +# .takt/lint-screen-report.md の冒頭に "fallback_reason" が記録されていれば fallback 経路 +grep -l "fallback_reason" .takt/lint-screen-report.md +# 5 PR 中の fallback 件数を数える +``` + +**threshold**: kill-switch = fallback > 50% (3 / 5 PR で fallback 発生で停止)。 + +### 2-3. Claude session input token 削減効果 + +**現状実装 caveat**: lint_screen は `.takt/lint-screen-report.md` 出力のみで、Claude には自動転送されない。token 削減効果を計測するには以下のいずれか: + +- (a) **手動転送**: dogfood 中に Claude が `.takt/lint-screen-report.md` を Read して advisory として参照する (実 dogfood で運用試行) +- (b) **将来実装**: takt facet `review-simplicity.md` instruction で advisory 読み込みを自動化 (PR #132 で部分的に実装済、Phase d 効果次第で深化判断) +- (c) **計測のみ**: Claude session の `/cost` 出力を dogfood 前後で記録 (lint_screen 利用 vs 非利用で比較、ただし他要因の混入あり) + +Phase d 期間中は **(a) 手動転送 + (c) /cost 計測** の組合せで **質的傾向**を観察。定量化は (b) 実装後に再計測。 + +## 3. Kill-switch criteria (fallback rate > 50%) + +3 / 5 PR (= 60%) で fallback が発生したら **即停止**: + +1. config を `enabled = false` に戻す (jj restore push-runner-config.toml で確実に revert) +2. fallback 原因を `.takt/lint-screen-report.md` の `fallback_reason` から特定: + - `ollama error: ...` → Ollama 側問題 (down / model unloaded / 通信) + - `JSON parse error: missing field ...` → mistral 出力崩壊 (順位 98 = num_ctx overflow detection で診断強化予定) + - `diff over limit` → `max_diff_lines` 設定不足 (config tweak で再 dogfood 可) + - `timeout` → `timeout_secs` 設定不足 (latency 増を許容するか re-tune) +3. ADR-038 §試験運用→採用条件の **未達** として retrospective を `local-llm-offload-history.md` に追記 +4. §8.D 改善 (prompt v2) または別技術 (llama2:13b 等) への switch 判断 + +## 4. 過去 dogfood 阻害要因の scope 再確認 + +**`local-llm-offload-history.md` §11.2 の 3 obstacles は本 Phase d では scope 外**: + +| 旧 obstacle | 旧 scope (classifier) | 本 Phase d (lint_screen) との関係 | +|---|---|---| +| findings ゼロ | CR が APPROVE で classifier 入力なし | ❌ scope 外: lint_screen は CR 非依存、`jj diff` を直接読む | +| review body 抽出漏れ | check-ci-coderabbit の parser scope 限界 | ❌ scope 外: lint_screen は CR review を読まない | +| CR rate-limit | per-hour commit quota で review blocked | ❌ scope 外: lint_screen は pre-push、CR より前に走る | + +代わりに **lint_screen 固有の懸念**: + +- **Ollama 起動状態**: dogfood session 開始時に確認 (Setup §1) +- **mistral:7b 出力安定性**: num_ctx 8192 で agreement 86.7% (eval fixtures)、実 PR diff で再計測する (本 Phase d の主目的) +- **push pipeline UX impact**: latency p95 監視 (現状 ~8s で許容範囲) + +## 5. Phase d 完了 → 結果集約 → §8.E 採否判定 + +3-5 PR 完了後: + +1. metrics 集計 (latency / fallback / token 質的傾向) を `local-llm-offload-history.md` の dogfood 計測ログ (§A-2 と同形式) に追記 +2. ADR-038 §試験運用→採用条件 (5 PR 以上 / token 削減 / classification 妥当性) との突合 +3. 採用判定: + - **採用**: ADR-038 を「採用」に昇格 + 派生プロジェクト deploy 計画 + 本ガイド削除 + - **却下**: ADR-038 を「却下」に更新 + lint_screen stage 物理削除 PR + 本ガイド削除 + - **継続**: 課題 ID 化 + 改善 task として todo 系列に追加 + 次 dogfood 計画策定 + +## 関連リンク + +- [docs/local-llm-offload-analysis.md](local-llm-offload-analysis.md) — Phase d を含む実行計画 (ephemeral) +- [docs/local-llm-offload-history.md](local-llm-offload-history.md) — §A-2 (classifier dogfood retrospective) / §11 (evals 形式への切替) +- [ADR-038](adr/adr-038-local-llm-finding-classification.md) — 提案 1 / 2 / 3 の元設計、本採用判定の base diff --git a/docs/todo-summary.md b/docs/todo-summary.md index b089cf8..29763fa 100644 --- a/docs/todo-summary.md +++ b/docs/todo-summary.md @@ -73,6 +73,7 @@ | 95 | 🔧 Tier 2 | **`docs/todo*.md` preamble file count 自動照合スクリプト (PR #133 T2-#4 採用) ★ Bundle j** | todo6.md | S | なし (PR #133 で todo6.md「六つ」/ todo7.md「七つ」が実 8 ファイルと乖離した実例。todo*.md 分割が今後も繰り返す pattern (todo3 → 4 → 5 → 6 → 7) のため CI 層で自動検証) | | 96 | 🔧 Tier 2 | **Markdown cross-reference validator CI step (PR #133 T2-#3 採用) ★ Bundle j** | todo6.md | M | 順位 10 (ADR-032 PR-broken-link) と方向性が近接、fold-in 検討の余地あり。順位 94 (regex 規約) + 順位 95 (count 照合) と組み合わせて docs/ 整合性の多層検証 | | 97 | 🔧 Tier 2 | **`with_num_ctx(X)` override 値 serialization 検証テスト (PR #136 T2-#1 採用)** | todo6.md | S | なし (PR #136 で追加した builder method の wiring を mockito で seal、Phase d で num_ctx tweak する局面の silent degrade 防止、CodeRabbit が見逃した test gap を post-merge-feedback agent が独立発見) | +| 98 | 🚀 Tier 1 | **`num_ctx` overflow detection — JSON parse error 検知時の context window 診断ログ (PR #137 T1-#1 採用)** | todo6.md | M | なし (PR #136 で誤診 pivot を発生させた blind spot を decisive に塞ぐ runtime hint、`lib-ollama-client` の response validation 層に warn log 追加、`prompt_eval_count` ≈ `num_ctx` cap で truncation を即診断) | **戦略**: Tier 1 を 2〜3 セッションで片付け → Tier 2 で ADR-032 の前提 + rate-limit + convergence cost 削減を進める → Tier 3 で ADR-032 を land + ドキュメント整備。Tier 4-5 は cleanup / 外部展開で daily efficiency への直接効果は小さい。 diff --git a/docs/todo6.md b/docs/todo6.md index 9fefb15..1028761 100644 --- a/docs/todo6.md +++ b/docs/todo6.md @@ -373,3 +373,57 @@ config.rs + push-runner-config.toml + review-simplicity.md + ADR で family_tag #### 詰まっている箇所 なし。Effort S / 既存 test の duplicate 風で実装容易。 + +--- + +### `num_ctx` overflow detection — JSON parse error 検知時の context window 診断ログ (PR #137 T1-#1 採用) + +> **動機**: PR #136 セッションで「mistral:7b の JSON schema breakdown」を観測した際、Claude は当初「prompt 設計の問題」と誤診し `§8.D v4 prompt 改訂ループ` という名前の誤った means に向かいかけた (実 root cause は `num_ctx` default 4096 超過)。advisor の指摘 + raw Ollama output dump で軌道修正されたが、**runtime layer に診断 hint が出ていれば pivot 時間を短縮できる** ことが判明。`lib-ollama-client` の response validation 層で JSON parse error 検知時に `num_ctx` / `prompt_eval_count` / response length を warn log で auto-emit することで、将来の同型事故 (LLM dogfood 全般で systemic に再発し得る) を decisive に診断できる。 +> +> **本タスクの位置づけ**: PR #137 post-merge-feedback Tier 1 #1 採用 (Severity Medium / Frequency Low / Effort M / Adoption Risk: 派生プロジェクト deploy コストのみ、低)。ADR-038 試験運用配下の infrastructure 強化、Phase d で num_ctx tweak する局面に入る前の安全網としても機能。 +> +> **参照**: `.claude/feedback-reports/137.md` Tier 1 #1、PR #136 で `__dump_raw_ollama.sh` で確認した `prompt_eval_count: 4096` 上限到達 (現在は scratch ファイル削除済、`docs/local-llm-offload-history.md` に経緯記録)、`src/lib-ollama-client/src/lib.rs` の `generate_raw_json` / `OllamaResponse` 構造体 +> +> **実行優先度**: 🚀 **Tier 1** — Effort M。Phase d kickoff 前か実 dogfood 中に整備するのが理想 (dogfood で実際に context overflow を起こした PR があれば即診断できる layer になる)。 + +#### 設計決定 (案) + +- **配置先**: `src/lib-ollama-client/src/lib.rs` の `generate_json::` ヘルパー (型付き parse 失敗時) または raw response 検証層 +- **emit 条件 (案)**: + - **A (主軸)**: `serde_json::from_str` が `missing field` 系 error を返した場合 → `prompt_eval_count` が response の `eval_count` field と比較して context cap に近接していれば warn log + - **B (補助)**: response length が threshold (例: 100 chars) 未満で truncate を疑える場合 + - **C (簡易)**: 常に `prompt_eval_count` / `eval_count` を debug log で emit (low-noise、auto OFF default) +- **emit 内容 (案)**: + ```text + [lib-ollama-client] WARN: Ollama JSON output may be truncated. + parse_error: + prompt_eval_count: (vs num_ctx: ) + eval_count: , response_length: chars + hint: 大規模 prompt は num_ctx を増やすことで解決可能 (with_num_ctx で override)。 + ``` +- **fallback 経路への副作用**: 既存 fallback (block しない、`human_review` + `fallback_reason` を埋める) は維持、log は副次的な diagnostic 出力のみ + +#### 作業計画 + +- [ ] `OllamaResponse` 構造体に `eval_count` / `prompt_eval_count` フィールドを追加 (現状 `response` / `error` のみ deserialize) +- [ ] `generate_json::` ヘルパー (型付き parse) で error 時に上記情報を warn log emit (`log::warn!` または `eprintln!`) +- [ ] threshold ベースの判定ロジック (主軸 A) を実装、補助 B はオプション +- [ ] tests: + - `warn_log_emitted_on_truncated_response_when_prompt_eval_count_high` (mockito + log capture) + - `no_warn_emitted_for_parse_errors_unrelated_to_truncation` (e.g., format-违反 JSON) +- [ ] PR #136 で観測した eval13/15 fixture の `prompt_eval_count: 4096` 状況を dogfood で再現し、log が emit されることを確認 +- [ ] cli-finding-classifier 経由でも log が表面化することを smoke 確認 (push-runner step ログに乗るか) +- [ ] 派生プロジェクト (techbook-ledger / auto-review-fix-vc) 向け deploy 判断 (lib-ollama-client は本リポ専用なら deploy 不要、共有なら別途配布計画) +- [ ] 本 todo6.md エントリを削除 + +#### 完了基準 + +- JSON parse error + context cap 近接の併発時に warn log が emit される +- 既存 fallback 経路 (block しない、graceful degradation) を破壊しない +- LLM dogfood セッションで「context window 起因か prompt 起因か」を log だけで切り分けられる構造 +- 単体テストで diagnostic log の emit 条件 + non-emit 条件の両方を seal + +#### 詰まっている箇所 + +- **派生プロジェクト deploy 戦略**: `lib-ollama-client` が本リポ専用なら deploy なし、共有 crate 化するなら別 repo への copy / git submodule / cargo registry の判断が必要。Phase d 着手判定と合わせて検討 +- **log destination**: `eprintln!` (cli 用途で十分) vs `tracing` / `log` crate 統合 (既存の cli-* との一貫性)。本 lib は現状 ureq + serde_json のみで logging crate なし、初期は `eprintln!` で warn 接頭辞付け、将来必要なら crate 統合という段階導入が自然