Skip to content

feat(cli-pr-monitor): cli-finding-classifier 統合 + Finding C strict (ADR-038 Phase 5) - #120

Merged
aloekun merged 2 commits into
masterfrom
feat/phase5-classifier-integration
May 6, 2026
Merged

feat(cli-pr-monitor): cli-finding-classifier 統合 + Finding C strict (ADR-038 Phase 5)#120
aloekun merged 2 commits into
masterfrom
feat/phase5-classifier-integration

Conversation

@aloekun

@aloekun aloekun commented May 6, 2026

Copy link
Copy Markdown
Owner

Summary

ADR-038 (試験運用) Phase 5 として、cli-pr-monitor poll stage に cli-finding-classifier.exe を subprocess 経由で統合。同時に PR #119 の CR review round 3 で再指摘された Finding C (normalized_issue 契約検証) を strict 化。

  • A. Phase 5 統合: 新 module classifier_runner.rs + ClassifierConfig (default OFF / 試験運用 flag) + state.classified_findings field + enrich_with_classifier step
  • B. Finding C strict: from_llm_output で trim 後に「改行」「>80 chars」を検出し fallback に倒す + NORMALIZED_ISSUE_MAX_CHARS=80 const 化

設計のポイント

  • block しない設計: classifier 失敗 (exe 不在 / spawn / stdin / timeout / parse) はすべて空 Vec を返し、cli-pr-monitor の poll は影響を受けない。ADR-038 §「失敗時の振る舞い」に整合
  • 疎結合 (subprocess 経由): cli-pr-monitor の依存ツリーに 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) を破壊しない
  • デフォルト OFF: ClassifierConfig.enabled = false。dogfood 段階で個別に opt-in する設計
  • iteration 間の保持: build_state_for_iterationexisting.classified_findings を引き継ぎ (takt auto-fix iter で追加)

検証結果

  • cli-finding-classifier: lib 15 pass (B 関連 +3 件) + bin 6 pass
  • lib-ollama-client: 8 pass
  • cli-pr-monitor: 148 pass (classifier_runner 4 + ClassifierConfig 2 含む)
  • workspace 全体 clippy --all-targets -- -D warnings clean
  • takt pre-push-review: APPROVE (2 iter, 14m 26s, convergence_verdict: fully_resolved)

scope 外 (本 PR では未対応)

  • prompt injection サニタイズ: 本 PR は classifier を invoke して state に保存するだけで、auto_fix execution の自動実行経路を作っていない。Claude / takt が後段で human_review に倒れた finding を判断する設計のため、現時点で実害なし。auto_fix を機械的に実行する経路を追加するタイミングで sanitization を導入予定 (PR feat(cli-finding-classifier): Ollama でローカル LLM 分類 CLI 追加 (ADR-038) #119 の WARN ベース)
  • ADR-038 line 61 textual fix: confidence=0.0action_confidence=0.0 の名称統一は別 PR の cleanup で対応 (機能影響なし)

Test plan

  • cargo test --workspace --lib --bins 全 pass
  • cargo clippy -p cli-pr-monitor -p cli-finding-classifier -p lib-ollama-client --all-targets -- -D warnings clean
  • pnpm build:all 成功 (.claude/cli-finding-classifier.exe 配置済、cli-pr-monitor.exe も再ビルド)
  • takt pre-push-review APPROVE
  • (post-merge dogfood) [classifier] enabled = true で 1 PR の review サイクルを実走、token 削減効果を実測 — 別タスクで実施

関連

Summary by CodeRabbit

  • 新機能

    • 検出結果の自動分類器を統合しました。ポーリング処理内で分類を実行し、分類結果を保持・更新します。
  • 改善

    • 正規化された問題説明の検証を強化し、最大長と単一行制約を追加しました。
  • 設定

    • 分類器の設定(有効化、モデル、エンドポイント、タイムアウト)を追加しました。既定値あり。
  • ドキュメント

    • 実装進捗ログと提案2の詳細、進捗・検証結果を追記しました。

…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 で対応)
@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@aloekun has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 53 seconds before requesting another review.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ee304013-b70c-4c75-b0d1-c69fc94a06b8

📥 Commits

Reviewing files that changed from the base of the PR and between fc07755 and 67e64bd.

📒 Files selected for processing (2)
  • src/cli-pr-monitor/src/classifier_runner.rs
  • src/cli-pr-monitor/src/stages/poll.rs
📝 Walkthrough

Walkthrough

LLM分類器をpr-monitorに統合。ClassifierConfig追加、CLI分類器ランナー新規実装、ポーリングループへのエンリッチ処理、PrMonitorStateの永続化フィールド追加、分類器側のnormalized_issue検証強化、および関連ドキュメント更新を行う。

Changes

分類器統合と検証強化

Layer / File(s) Summary
設定スキーマ
src/cli-pr-monitor/src/config.rs
ClassifierConfigを追加し、Configclassifier: ClassifierConfigフィールドを導入。デフォルト値(enabled=false, model="mistral:7b", endpoint="http://localhost:11434", timeout_secs=30)を実装。テスト追加。
状態スキーマ
src/cli-pr-monitor/src/state.rs
PrMonitorStateclassified_findings: Vec<ClassifiedFinding>フィールドを追加。serde属性と初期化を追加し、テスト初期化を更新。
ランナー実装(コア)
src/cli-pr-monitor/src/classifier_runner.rs
新規モジュール。ClassifiedFinding型、classifier_exe_path()classify_findings()を実装。CLI実行ファイルの解決、JSON入出力、タイムアウト、子プロセス管理、失敗時は空Vecを返す(ADR-038に準拠)。ユニットテストを追加。
ポーリングループ統合
src/cli-pr-monitor/src/stages/poll.rs
PollContextclassifier_configを注入。各イテレーション後にenrich_with_classifier()を呼び出し、既存のclassified_findingsを保持・更新して状態を永続化。テストのコンテキスト初期化を更新。
既存モジュール参照
src/cli-pr-monitor/src/main.rs
mod classifier_runner;を追加して新モジュールをコンパイル対象にする。
分類器ライブラリの検証強化
src/cli-finding-classifier/src/lib.rs
normalized_issueの長さ上限を80文字に設定。マルチラインや超過長の入力に対してフォールバック理由を設定し、検証ロジックと関連テストを追加。
ドキュメント更新
docs/local-llm-offload-analysis.md
ステータス表現を更新し「実装進捗ログ」セクションを追加、ADR-038参照や検証結果・進捗記録を記載。旧Next Stepsを置換。

Sequence Diagram

sequenceDiagram
    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 を更新・永続化
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • aloekun/claude-code-hook-test#38: モジュール分割を導入したPRと同じcli-pr-monitorファイル群を変更しており、今回のclassifierランナー追加がそのモジュール構造に依存している。
  • aloekun/claude-code-hook-test#97: ConfigおよびPrMonitorStateへのフィールド追加やpollステージ改修と重複する変更セットを含むため関連。
  • aloekun/claude-code-hook-test#114: pollループの制御や状態フィールドを変更するPRで、ポーリングフローへの機能追加と衝突/相互影響の可能性が高い。
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルは主な変更内容(cli-finding-classifier の統合と Finding C の厳密化)を明確に説明しており、ADR-038 Phase 5 というフェーズ参照も含まれています。変更セットの核心的な内容をよく要約しています。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@aloekun

aloekun commented May 6, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@aloekun

aloekun commented May 6, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/cli-pr-monitor/src/stages/poll.rs (1)

109-109: 💤 Low value

iteration ごとの 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()Noneunwrap_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

📥 Commits

Reviewing files that changed from the base of the PR and between 9f368a2 and fc07755.

📒 Files selected for processing (7)
  • docs/local-llm-offload-analysis.md
  • src/cli-finding-classifier/src/lib.rs
  • src/cli-pr-monitor/src/classifier_runner.rs
  • src/cli-pr-monitor/src/config.rs
  • src/cli-pr-monitor/src/main.rs
  • src/cli-pr-monitor/src/stages/poll.rs
  • src/cli-pr-monitor/src/state.rs

Comment thread src/cli-pr-monitor/src/classifier_runner.rs
Comment thread src/cli-pr-monitor/src/stages/poll.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
@aloekun

aloekun commented May 6, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@aloekun
aloekun merged commit 3b6a847 into master May 6, 2026
1 check passed
@aloekun
aloekun deleted the feat/phase5-classifier-integration branch May 6, 2026 19:04
aloekun added a commit that referenced this pull request May 7, 2026
…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 表現を削除し、頻度未確定の新規フィードバックを優先しない方針を明記
aloekun added a commit that referenced this pull request May 7, 2026
…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 表現を削除し、頻度未確定の新規フィードバックを優先しない方針を明記
aloekun added a commit that referenced this pull request May 7, 2026
…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 完了 + 判定基準達成にリンク
aloekun added a commit that referenced this pull request May 7, 2026
…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 で再生成)。
aloekun added a commit that referenced this pull request May 7, 2026
…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 注記
aloekun added a commit that referenced this pull request May 21, 2026
…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 継続。
aloekun added a commit that referenced this pull request May 22, 2026
…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/要約 完了マーク)
aloekun added a commit that referenced this pull request May 29, 2026
…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。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant