feat(cli-pr-monitor): cli-finding-classifier 統合 + Finding C strict (ADR-038 Phase 5) - #120
Conversation
…inding C strict 化
Phase 5 (A): cli-pr-monitor poll stage への classifier 統合
- 新 module classifier_runner.rs: cli-finding-classifier.exe を subprocess invoke (stdin = findings JSON、stdout = classified findings JSON)。失敗時 (exe 不在 / spawn / stdin / timeout / parse) は空 Vec を返し block しない (ADR-038 §「失敗時の振る舞い」)
- ClassifierConfig 追加: enabled / model / endpoint / timeout_secs (default OFF、試験運用 flag)
- state.classified_findings field 追加 (serde default + skip_serializing_if = "Vec::is_empty" で後方互換)
- poll.rs に enrich_with_classifier step を追加 (build_state_for_iteration 直後、findings を enrich して state を再書き出し)
Finding C strict 化 (B): normalized_issue の契約検証強化
- from_llm_output で trim 後に「改行を含む」「80 文字超」を検出し fallback("contract violation: ...") に倒す
- max chars 上限 NORMALIZED_ISSUE_MAX_CHARS=80 を const 化 (prompts/classify.txt の "max 80 characters" 指示と一致)
- 回帰テスト 3 件追加: multi-line / 81 chars / 80 chars boundary
検証:
- cli-finding-classifier: 15 unit tests (lib) + 6 (bin) pass
- cli-pr-monitor: 148 unit tests pass (classifier_runner の 4 件 + ClassifierConfig 2 件含む)
- workspace 全体 clippy clean
scope 外 (本 PR では未対応):
- prompt injection サニタイズ (auto_fix execution 経路がまだ無いため、単に classifier を invoke して state に保存するだけの段階で実害なし。後続 PR で auto_fix を実行する経路を作るタイミングで導入予定)
- ADR-038 line 61 textual fix (action_confidence 名称統一、別 PR の cleanup で対応)
|
Warning Rate limit exceeded
To continue reviewing without waiting, purchase usage credits in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughLLM分類器をpr-monitorに統合。ClassifierConfig追加、CLI分類器ランナー新規実装、ポーリングループへのエンリッチ処理、PrMonitorStateの永続化フィールド追加、分類器側のnormalized_issue検証強化、および関連ドキュメント更新を行う。 Changes分類器統合と検証強化
Sequence DiagramsequenceDiagram
participant Poll as ポーリングループ
participant Runner as ランナー
participant Exe as CLI分類器
Poll->>Runner: classify_findings(config, findings)
Runner->>Runner: 入力検証・早期リターン
alt 入力有効かつ実行ファイル解決成功
Runner->>Exe: JSONをstdinで送信
Exe->>Exe: 分類処理(外部CLI)
Exe-->>Runner: JSON出力
Runner->>Runner: 出力をパース・Vec<ClassifiedFinding>を生成
Runner-->>Poll: 分類結果を返却
else 失敗(例: missing exe, timeout, parse error)
Runner-->>Poll: 空のVecを返却
end
Poll->>Poll: classified_findings を更新・永続化
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/cli-pr-monitor/src/stages/poll.rs (1)
109-109: 💤 Low valueiteration ごとの classifier 呼び出しコスト。
run_one_iteration毎にenrich_with_classifierが走ると、wakeup 経路で複数 iteration がある場合に Ollama を都度叩くことになります。現状はclassified_findings非空ガードで実質 1 回しか走らない実装ですが、上のコメントでガードを外すと毎 iteration でfindings.len()件の Ollama 呼び出しが発生します (timeout 30s × N findings)。Phase 5 試験運用としては許容範囲ですが、本採用前に「findings の内容 hash 変化時のみ再分類」程度のキャッシュ戦略を検討する価値があります。本 PR で対応必須ではないので参考までに。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli-pr-monitor/src/stages/poll.rs` at line 109, The current code calls enrich_with_classifier(&mut state, ctx.classifier_config) every run_one_iteration which can re-query Ollama per finding; implement a simple cache keyed by a content hash to avoid reclassification unless a finding's content changed: add a classification cache map on the state (e.g. state.classification_cache: HashMap<ContentHash, Classification>), compute a stable hash for each finding payload before calling enrich_with_classifier in run_one_iteration, filter/find only changed findings (or skip calling enrich_with_classifier entirely if none changed), update the cache with new classifications after enrich_with_classifier returns, and use state.classification_cache lookups to populate classified_findings so behavior is unchanged while avoiding redundant Ollama calls.src/cli-pr-monitor/src/classifier_runner.rs (1)
38-47: 💤 Low value
current_exe()失敗時に CWD 配下を探索する挙動が意図通りか確認したいです。
unwrap_or_default()でPathBuf::new()(空パス) を返した後、parent()はNone、unwrap_or(Path::new("."))で.に倒れて./cli-finding-classifier.exeを返します。exists()チェックがあるので致命的ではないですが、本来想定していない CWD 配下の同名 exe を誤って起動する余地が残ります (cli-pr-monitorは通常.claude/から起動される前提)。Windows-only かつ
current_exe()が失敗するのは極めて稀なため `` です。runner.rs::checker_exe_pathと挙動を揃えるだけで済むので、必要なら近傍 PR でまとめて対応するのが妥当です。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cli-pr-monitor/src/classifier_runner.rs` around lines 38 - 47, The current implementation uses unwrap_or_default() which makes current_exe() failures silently fall back to CWD (./cli-finding-classifier.exe); change classifier_exe_path() to only use the executable's parent if current_exe() succeeds and otherwise use the same fallback logic as runner.rs::checker_exe_path to avoid accidentally picking up a CWD binary—specifically replace the unwrap_or_default()/parent()/unwrap_or(...) chain with current_exe().ok().and_then(|p| p.parent().map(|d| d.join("cli-finding-classifier.exe"))).unwrap_or_else(|| /* use the same fallback PathBuf used in checker_exe_path */) so the behavior matches checker_exe_path().
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/cli-pr-monitor/src/classifier_runner.rs`:
- Around line 141-207: The child-process handling currently polls in
wait_with_timeout without draining stdout/stderr, risking pipe-buffer deadlock;
update the implementation so stdout/stderr are consumed while the child runs
(either spawn threads to read_to_end for child.stdout and child.stderr and then
construct an Output when the process exits inside wait_with_timeout, or change
the child's stderr to inherit/null to eliminate the pipe risk); locate usages in
wait_with_timeout and feed_stdin/parse_classifier_output to ensure you read the
pipes you created with Stdio::piped() (or change Stdio::stderr to inherit/null
where the child is spawned) so the classifier never blocks writing large stderr
output.
In `@src/cli-pr-monitor/src/stages/poll.rs`:
- Around line 222-236: The early-return guard in enrich_with_classifier prevents
new findings from being classified because it returns when
state.classified_findings is non-empty; remove the
"!state.classified_findings.is_empty()" check so enrich_with_classifier only
skips when config.enabled is false or state.findings is empty, call
classify_findings(config, &state.findings) each iteration, assign the result to
state.classified_findings and persist via write_state as currently done; ensure
this change aligns with build_state_for_iteration and
update_state_from_check_result semantics (or alternatively add explicit logic to
clear state.classified_findings when findings change if you prefer preserving
prior classifications).
---
Nitpick comments:
In `@src/cli-pr-monitor/src/classifier_runner.rs`:
- Around line 38-47: The current implementation uses unwrap_or_default() which
makes current_exe() failures silently fall back to CWD
(./cli-finding-classifier.exe); change classifier_exe_path() to only use the
executable's parent if current_exe() succeeds and otherwise use the same
fallback logic as runner.rs::checker_exe_path to avoid accidentally picking up a
CWD binary—specifically replace the unwrap_or_default()/parent()/unwrap_or(...)
chain with current_exe().ok().and_then(|p| p.parent().map(|d|
d.join("cli-finding-classifier.exe"))).unwrap_or_else(|| /* use the same
fallback PathBuf used in checker_exe_path */) so the behavior matches
checker_exe_path().
In `@src/cli-pr-monitor/src/stages/poll.rs`:
- Line 109: The current code calls enrich_with_classifier(&mut state,
ctx.classifier_config) every run_one_iteration which can re-query Ollama per
finding; implement a simple cache keyed by a content hash to avoid
reclassification unless a finding's content changed: add a classification cache
map on the state (e.g. state.classification_cache: HashMap<ContentHash,
Classification>), compute a stable hash for each finding payload before calling
enrich_with_classifier in run_one_iteration, filter/find only changed findings
(or skip calling enrich_with_classifier entirely if none changed), update the
cache with new classifications after enrich_with_classifier returns, and use
state.classification_cache lookups to populate classified_findings so behavior
is unchanged while avoiding redundant Ollama calls.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 503ee52a-d74f-425b-8819-7d933f9a87d1
📒 Files selected for processing (7)
docs/local-llm-offload-analysis.mdsrc/cli-finding-classifier/src/lib.rssrc/cli-pr-monitor/src/classifier_runner.rssrc/cli-pr-monitor/src/config.rssrc/cli-pr-monitor/src/main.rssrc/cli-pr-monitor/src/stages/poll.rssrc/cli-pr-monitor/src/state.rs
PR #120 の CodeRabbit 1 回目 review (17:55Z) の Major 2 件: 1. `classifier_runner.rs:wait_with_timeout` の deadlock リスク - 旧実装は `try_wait()` の spin-loop。child の stdout/stderr が pipe buffer (~64KB) を超えるとパイプが詰まり、try_wait は永遠に Ok(None) を返してハング - 修正: thread + mpsc::channel パターン。`wait_with_output()` がスレッド内で pipe を並行 drain しつつ child を待つ。timeout は recv_timeout で実現 - timeout 時に child を kill できないが、classifier exe 側に --timeout-secs を 渡しているため自己終了する設計 2. (false positive 却下、`resolved:` reply 投稿済) `poll.rs:enrich_with_classifier` の `!classified_findings.is_empty()` guard で stale 固着リスク - 該当 guard はコードに存在せず CR の hallucination - takt が補強テストとして追加した vacuous な regression test (assert!(true) のみ) を削除 検証: - cargo test -p cli-pr-monitor: 149 pass / 0 fail - cargo clippy: clean
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
…follow-up) PR #120 (ADR-038 Phase 5 land) の事後整理を 1 commit に集約 (docs-only): 1. ADR-038 line 61 textual fix (`docs/local-llm-offload-analysis.md` §8.C) - `confidence=0.0` → `action_confidence=0.0` に統一 - 実装の `ClassifiedFinding.action_confidence` schema 名称との整合 - 機能影響なし、永続 ADR の内部一貫性確保 2. PR #120 post-merge-feedback の採用 5 件を登録 (Bundle f) - 順位 80 (Tier 1, Bundle f): rate-limit auto-retry wakeup 予約ロジック整理 - 順位 81 (Tier 1, Bundle f): CR 投稿エラー auto-retry 拡張 - 順位 82 (Tier 3, Bundle f): ADR-018 update (transient failure auto-retry) - 順位 83 (Tier 2, 独立): 複合 AND guard 独立テスト - 順位 84 (Tier 3, 独立): code-review.md checklist 追記 - 詳細エントリは docs/todo5.md 末尾、priority table は docs/todo.md - Bundle f は新規フィードバックのため、頻度が確認できるまで優先度は再観測を経て判断 3. docs/local-llm-offload-analysis.md の更新 - §7 (実装進捗ログ) に Phase 5 land 記録 + Bundle f cross-reference 追加 - §8 (次の作業候補) で A/B を ✅ LANDED にマーク - 「先行 land を推奨」等の prioritization 表現を削除し、頻度未確定の新規フィードバックを優先しない方針を明記
…follow-up) (#121) PR #120 (ADR-038 Phase 5 land) の事後整理を 1 commit に集約 (docs-only): 1. ADR-038 line 61 textual fix (`docs/local-llm-offload-analysis.md` §8.C) - `confidence=0.0` → `action_confidence=0.0` に統一 - 実装の `ClassifiedFinding.action_confidence` schema 名称との整合 - 機能影響なし、永続 ADR の内部一貫性確保 2. PR #120 post-merge-feedback の採用 5 件を登録 (Bundle f) - 順位 80 (Tier 1, Bundle f): rate-limit auto-retry wakeup 予約ロジック整理 - 順位 81 (Tier 1, Bundle f): CR 投稿エラー auto-retry 拡張 - 順位 82 (Tier 3, Bundle f): ADR-018 update (transient failure auto-retry) - 順位 83 (Tier 2, 独立): 複合 AND guard 独立テスト - 順位 84 (Tier 3, 独立): code-review.md checklist 追記 - 詳細エントリは docs/todo5.md 末尾、priority table は docs/todo.md - Bundle f は新規フィードバックのため、頻度が確認できるまで優先度は再観測を経て判断 3. docs/local-llm-offload-analysis.md の更新 - §7 (実装進捗ログ) に Phase 5 land 記録 + Bundle f cross-reference 追加 - §8 (次の作業候補) で A/B を ✅ LANDED にマーク - 「先行 land を推奨」等の prioritization 表現を削除し、頻度未確定の新規フィードバックを優先しない方針を明記
…ow-up) (#122) PR #121 post-merge-feedback の採用 4 件 (Bundle g) 登録 + §8.A-2 (Phase 5 dogfood 計測計画) 策定を 1 commit に集約 (docs-only): 1. Bundle g 採用 4 件登録 (順位 85-88、PR #121 post-merge-feedback) - 順位 85 (Tier 1): cli-pr-monitor monitor state machine guard 強化 (`review_state: not_found && findings: []` を pending 据置) → 3 PR 連続観測 (PR #119/#120/#121) で頻度確認済 Tier 1 妥当性確定 - 順位 86 (Tier 2): state transition test 網羅 (順位 85 の回帰テスト) - 順位 87 (Tier 3): Multi-PR chaining ベストプラクティス codify → PR #119→#120→#121 の連鎖を再利用可能化 - 順位 88 (Tier 3): edge case 観測頻度 3 = Tier 1 昇格基準 codify → ユーザー方針 (新規フィードバックは頻度確認後優先) を明文化 - 詳細エントリは docs/todo5.md 末尾、bundle commentary は docs/todo.md - Bundle f (順位 80-82) との関係: f = retry logic、g = verdict logic で別軸 2. §8.A-2 Phase 5 dogfood 計画 策定 (docs/local-llm-offload-analysis.md) - ADR-038 §試験運用→本採用の未達条件 1 (5 PR dogfood) + 3 (token 削減確認) を達成する計画 - 構成: P-0 (config opt-in) + P-1〜P-5 (Tier 1 タスク優先で 5 PR) - Setup 手順 / 計測手順 / 判定基準 / 既知の注意事項 / session 跨ぎ運用ガイドを self-contained 形式で記載 - 別セッションで再開可能な構造 (本 doc 1 ファイルで全手順把握可) 3. 整合更新 - §7 § 効果実測の現状 を §8.A-2 参照に更新 (「未測定」を明示) - §8.E dependency を §8.A-2 完了 + 判定基準達成にリンク
…g + transition matrix tests (順位 85+86 / Bundle g-1) (#125) §A-2 Phase 5 dogfood P-1 (Bundle g-1)。3 PR 連続観測 (PR #119/#120/#121) で 発覚した monitor の誤 approved 判定を fix。 順位 85 (Tier 1, T1-1): - compute_verdict() に review_state guard 追加。CodeRabbit が未投稿 (review_state: not_found) もしくは進行中 (pending) のときは findings の有無に関わらず判定保留。空 findings を 'no problems' と誤同一視する false negative を防止。 順位 86 (Tier 2, T2-4): - mod tests に (action, review_state, findings) → verdict transition matrix を 12 unit test で網羅: - parked_rate_limit / parked_review_recheck (action 優先) - not_found + 空 / pending + 空 / not_found + findings (順位 85 fix) - success + 空 / minor / critical / high / major - skipped (skip_coderabbit 経路) - coderabbit field None (初期 state) - 既存 should_resume_wakeup_* テスト 7 件と並存、no regression build + deploy 済 (.claude/cli-pr-monitor.exe を release build で再生成)。
…ailure 明文化 (順位 80+82 / §A-2 P-5) (#129) * feat(cli-pr-monitor): rate-limit Posted 経路で park 予約 (順位 80) + ADR-018 transient failure 明文化 (順位 82) + §A-2 P-4 ledger (§A-2 P-5) §A-2 Phase 5 dogfood P-5 (Bundle f-1 partial)。PR #120 で観測された rate-limit auto-retry の silent exit (RateLimitOutcome::Posted → polling 継続 → max_duration timeout) を構造的に解消。 順位 80 (Tier 1, T1-1) — finalize_posted_retrigger に park 予約を追加: - Before: 投稿後 write_state → None 返し → polling 継続 → timeout で silent exit - After: 投稿後 state.action = parked_review_recheck + next_wakeup_at_unix = now + review_recheck_wait_secs を設定 + format_park_signal で PARK 出力 → Some(park_poll_result) で必ず terminal を返す - handle_rate_limit_branch / dispatch_rate_limit_outcome / finalize_posted_retrigger 各関数に review_recheck_wait_secs 引数を thread - 2 unit tests 追加 (success 経路 + write_state 失敗 action_required 経路) 順位 82 (Tier 3, T3-2) — ADR-018 に追記: - 対象 transient failure pattern を表形式で 4 種列挙 (rate-limit 待機型/即時型 + CR 投稿エラー + wakeup 未予約 fallback) - 順位 80 fix の実装ポイント (Before/After) を明文化 - 順位 81 (CR 投稿エラー) を defer した理由を 3 観測閾値ルールで説明 順位 81 (Bundle f-1 残部、Tier 1 T1-2): - 1 観測のみ (PR #120) で systemic 性未確認のため defer - 同型 error が 2 件以上観測されたら再活性化 (re-trigger 条件を ADR-018 で規定) - 本セッションのユーザー方針 feedback_no_unenforced_rules と整合 §A-2 計測ログ P-4 結果記録: - P-4 (PR #128): 1 finding (CR Nitpick: cross_module_* 命名 misleading) - classifier: action=human_review / confidence=0.9 (P-2 の 0.0 から大幅改善) - normalized_issue: Japanese 50 chars (length contract pass) - latency: 6.6s/件、fallback: 0/1 (P-2 の 1/1 から改善) - agreement: 1/1 (100%、私評価=human_review と一致) 170 active tests pass (新 2 件追加)、regression なし。 build + deploy 済 (.claude/cli-pr-monitor.exe)。 * docs(todo): 順位 80 + 82 (rate-limit park 予約 + ADR-018 update) 完了に伴い削除 + 順位 81 defer 注記
…rd の単独検証テスト + code-review.md checklist 追記 (順位 83 + 84) (#168) PR #120 W-001 follow-up。`enrich_with_classifier` の OR 結合された 2 つの early-return guard (`!config.enabled` / `state.findings.is_empty()`) を 1 件ずつ単独検証する test variant を追加し、責務分離を機械強制する。 順位 83 (T2 / S): - 既存 `enrich_with_classifier_skips_when_disabled` を sentinel ベースに 書き換え (空の `classified_findings` ではなく ClassifiedFinding sentinel で pre-populate → 早期 return しなかった場合の代入を mutation として 検出)。`!config.enabled` guard 単独検証。 - 新 `enrich_with_classifier_skips_when_findings_empty` 追加。`enabled=true` + `findings` 空で `findings.is_empty()` guard 単独検証。 - precondition assert で 2 guard が同時発火しない setup を明示化。 順位 84 (T3 / XS): - ~/.claude/rules/common/code-review.md の review checklist に 「複合 AND/OR の early-return guard を持つ関数のテストは各条件を 独立 variant で検証」を追記。由来 (PR #120 W-001) を補足説明として 併記し、次回 PR レビュー時の参照点に。 検証: - cli-pr-monitor stages::poll tests: 17/17 passed (新規 2 件 + 既存 15 件) - markdownlint: 0 errors Bundle f sub-PR f-2 + f-3 統合 land。Bundle f コア (f-1 = 順位 80/81/82) は systemic 性未確認のため defer 継続。
…139 land) (#169) * docs(todo): PR #168 post-merge-feedback 反映 — 順位 139 (ADR-NNN Test Isolation Patterns for Multi-Condition Guards) 新規追加 PR #168 post-merge-feedback の Tier 3 #2 採用結果として、複合 guard test の test isolation pattern を project-level ADR で codify する task を順位 139 として登録。ADR 番号は順位 135 codified placeholder policy に従い land 時 PR で確定する運用 (現状 ADR-NNN placeholder、PR #120 W-001 + PR #168 の 2 PR 横断 Frequency Medium で採用判断)。 * docs(adr): ADR-041 Test Isolation Patterns for Multi-Condition Guards (順位 139 land) — 順位 78 番号 placeholder 化 * fix(docs): CR finding 対応 — 順位 139 作業計画 checklist 整合 (PR description link/要約 完了マーク)
…der + facet P-1 fix (ADR-031) (#184) * docs(todo): PR #183 post-merge-feedback 採用 3 件 (順位 170-172、Bundle DG-RULES) 採用: PR #183 post-merge-feedback Tier 3 #1/#2/#3 (2026-05-29 ユーザー承認): - 順位 170 (T3-#1): git-workflow.md § Multi-PR chaining 拡張 — 1 PR 内 multi-commit + intent 明記 Frequency High (PR #119/#120/#121 + #183 の 4 観測)、~/.claude/ global 編集、派生プロジェクトへ自動波及 - 順位 171 (T3-#2): docs-governance.md に Operational vs Pointer reference 区別 section 追加 本 PR (#183) A01 修正で実適用した判定ロジックを codify、Bundle DG-RULES - 順位 172 (T3-#3): CR ephemeral artifact Nitpick の統一 skip 基準を新 memory に codify 本 PR で実施した Nitpick skip 判断 codify、Bundle DG-RULES、本リポジトリ専用 171 + 172 は Bundle DG-RULES として同 PR land 推奨 (docs/rule + memory の 2 層補強)。 メタ評価: 3 採用候補すべてが本セッション (#181-#183 chain) の dogfood で実体観測された 行動パターンの codify — Phase B 設計の self-reinforcing detection loop が機能した実例。 実装時の前提: - 170/171 は ~/.claude/ global 編集のため feedback_global_config_backup 適用必須 - 172 は ~/.claude/projects/.../memory/ 編集、本リポジトリ専用 (派生展開なし) * docs(todo): 順位 173 (S01) 追加 — PR #182 dry-run の combine_output dead-code finding * feat(phase-c): /weekly-review skill + SessionStart hook reminder + facet P-1 fix (ADR-031 Phase C) ADR-031 Phase C を実装。Phase B (PR #182) で land した takt workflow weekly-review を オーケストレートする skill と、~7 日経過 / failed marker 残存時に additionalContext で promote する SessionStart hook reminder + PR #182 pre-push P-1 finding (facet report_path drift) の修正を bundle。 Component A: skill /weekly-review (本リポジトリ内では非追跡、~/.claude/skills/weekly-review/SKILL.md として配置) - Phase 0: pending JSON 先読み + failed marker 検出 (resume / new run 判別) - Phase 1: pnpm exec takt -w weekly-review 起動 + pre-state 書込 - Phase 2: Report Directory → .claude/weekly-reviews/<date>.md + pending JSON 構築 - Phase 3: AskUserQuestion (multiSelect, severity-grouped) で採否一括選択 - Phase 4: 採用 finding を docs/todo.md 「## 現在進行中」配下に新セクション展開 - Phase 5: pending JSON consume + last-run timestamp 書込 + failed marker cleanup - Phase 6: 完了サマリー表示 - best-effort 失敗ポリシー (ADR-031 §): .failed marker で次セッション SessionStart promote Component B: SessionStart hook の weekly_review_reminder sub-feature - src/hooks-session-start/src/main.rs に WeeklyReviewReminderConfig 追加 - 2 nudge 経路: (1) last-run mtime > threshold_days (default 7)、(2) failed marker 残存 - 両方該当時は 1 nudge にまとめて出力 - 関数 50 行制約に対応するため build_*_lines helper を分離 (compute_weekly_review_reminder_nudge を 30 行に圧縮) - 6 新規 unit test (disabled / 失敗 marker 列挙 / staleness 発火 / failed 発火 / config parse / dir 不在) - .claude/hooks-config.toml に [session_start.weekly_review_reminder] section 追加 (enabled = true で opt-in、ADR-039 experimental pattern) Component C: aggregate-weekly.md の report_path documentation drift (P-1) 解消 - PR #182 pre-push simplicity reviewer Anomaly 1 (Medium / non-blocking) を Phase C 着手時に対応 - findings JSON の report_path が指す .claude/weekly-reviews/<date>.md は Phase C skill が copy する canonical location である旨を facet instruction で明示 - skill 未実装 (= Phase B のみ稼働) 時は dead pointer になるが Phase C land 後に realize される forward-pointing 記述として位置付けを明文化 ユーザー判断 (2026-05-29): - Q1 MVP scope: A (skill + hook + facet fix 3 component を同 PR で land) - Q2 failed marker recovery: A (含める、ADR-031 § 失敗ポリシー 完全実装) - Q3 Bundle CR-RL 先行: A (Phase C 先行、Bundle CR-RL = 順位 167-169 は別 PR) Phase D (e2e 検証) / Phase E (試験運用 dogfood) は別 PR で carry-forward、docs/handoff-weekly-review-phase-c-onwards.md § 4 で trackable。 * docs(handoff): Phase B handoff retire + Phase C 以降向け 新規 handoff 作成 Phase B (PR #182) land により handoff-rank-8-weekly-review-phase-b.md の retirement 条件 (本 doc § 11) を満たしたため、Phase C 以降向けの carry-forward doc を 新規作成し、本 doc を物理削除する。 新ファイル: docs/handoff-weekly-review-phase-c-onwards.md - Phase B 完了状況の summary table (carry-forward 用) - 7 観点責務 mapping (Phase C/D/E でも適用) - Phase C/D/E 工程計画 (旧 doc § 4 から carry-forward) - 重要な設計判断 (旧 doc § 5 + 本セッションでの実証 update) - Phase C 着手時の memory rule (旧 doc § 7 carry-forward) - Phase C 着手前提として Bundle CR-RL (順位 167-169) land 推奨 旧ファイル削除: docs/handoff-rank-8-weekly-review-phase-b.md - 永続価値 (7 観点 mapping、ユーザー判断記録、参照リソース) は新 doc に移管 - 残タスク (Phase C/D/E) は todo-summary.md 順位 8 で trackable + 新 doc § 4 - 永続参照リンクは grep -rn 'handoff-rank-8' で本 doc 自身のみ確認 - docs-governance.md § Retirement Workflow 4 step に整合 * fix(phase-c): CR Major auto-fix — weekly_review_last_run の fail-open 修正 (Missing vs Unreadable 分離) for #184 CodeRabbit Major (auto-fix mandate per memory feedback_review_severity_auto_fix): src/hooks-session-start/src/main.rs:513 weekly_review_days_since_last_run の 失敗時 Option<u64>::None 経由で fail-open 方針と逆の挙動 (mtime 取得失敗が staleness ヒット扱い、誤 nudge を毎回生成)。 修正: - enum WeeklyLastRunState { Missing, ElapsedDays(u64), Unreadable } 導入で 3 状態を明示分離 - Missing (= 未実行 / 初回) → reminder 発火 (初回利用ナビ) - ElapsedDays(d) → d >= threshold で発火 - Unreadable (= 権限エラー等) → reminder 抑制 (fail-open、ユーザーを誤通知で煩わせない) test 追加 (memory feedback_test_dry_antipattern 適用、各 variant 独立): - weekly_review_staleness_hits_for_missing_state - weekly_review_staleness_hits_for_elapsed_above_threshold - weekly_review_staleness_skips_for_elapsed_below_threshold - weekly_review_staleness_skips_for_unreadable_state (CR finding の fail-open 回帰防止) 検証: cargo test -p hooks-session-start で 58 tests pass (4 new + 54 existing)、 cargo clippy -p hooks-session-start --release -- -D warnings clean。 * fix(phase-c): CR Major M-2 + Minor N-1 auto-fix for #184 CodeRabbit re-review (commit 30f19f5 = 前 fix commit) で post された 2 件を修正: M-2 (Major, ADR-039 違反): weekly_review_reminder の default を OFF に変更 - .claude/hooks-config.toml line 36: enabled = true → enabled = false - 理由: ADR-039 experimental feature standard pattern (config opt-in 契約) に整合 - opt-in = repo config で明示 enable する運用、source の default は OFF - memory feedback_review_severity_auto_fix 適用 (Major 無条件自動修正) N-1 (Minor, docs 正確性): handoff doc に failed marker 経路を追記 - docs/handoff-weekly-review-phase-c-onwards.md line 55-56 - SessionStart reminder の 2 経路 (7 日経過 + failed marker 検出) を明示記述 - 実装契約と docs の整合を確保、Phase C 以降の仕様理解ずれを構造的に防止 検証: cargo test -p hooks-session-start 全 58 tests pass (binary 変更なし、config のみ)、 markdownlint clean。
Summary
ADR-038 (試験運用) Phase 5 として、
cli-pr-monitorpoll stage にcli-finding-classifier.exeを subprocess 経由で統合。同時に PR #119 の CR review round 3 で再指摘された Finding C (normalized_issue 契約検証) を strict 化。classifier_runner.rs+ClassifierConfig(default OFF / 試験運用 flag) +state.classified_findingsfield +enrich_with_classifierstepfrom_llm_outputで trim 後に「改行」「>80 chars」を検出し fallback に倒す +NORMALIZED_ISSUE_MAX_CHARS=80const 化設計のポイント
ureq/ Ollama を持ち込まず、cli-finding-classifier.exeを spawn する形で統合。schema (ClassifiedFinding) のみ複製し、ADR-038 で schema 変更が起きた際は両方を同期する責務をコメントで明示state.classified_findingsは#[serde(default, skip_serializing_if = "Vec::is_empty")]で既存 state.json と consumer (takt facets / Claude) を破壊しないClassifierConfig.enabled = false。dogfood 段階で個別に opt-in する設計build_state_for_iterationでexisting.classified_findingsを引き継ぎ (takt auto-fix iter で追加)検証結果
clippy --all-targets -- -D warningscleanconvergence_verdict: fully_resolved)scope 外 (本 PR では未対応)
auto_fixexecution の自動実行経路を作っていない。Claude / takt が後段でhuman_reviewに倒れた finding を判断する設計のため、現時点で実害なし。auto_fixを機械的に実行する経路を追加するタイミングで sanitization を導入予定 (PR feat(cli-finding-classifier): Ollama でローカル LLM 分類 CLI 追加 (ADR-038) #119 の WARN ベース)confidence=0.0→action_confidence=0.0の名称統一は別 PR の cleanup で対応 (機能影響なし)Test plan
cargo test --workspace --lib --bins全 passcargo clippy -p cli-pr-monitor -p cli-finding-classifier -p lib-ollama-client --all-targets -- -D warningscleanpnpm build:all成功 (.claude/cli-finding-classifier.exe配置済、cli-pr-monitor.exe も再ビルド)[classifier] enabled = trueで 1 PR の review サイクルを実走、token 削減効果を実測 — 別タスクで実施関連
Summary by CodeRabbit
新機能
改善
設定
ドキュメント