Skip to content

feat(cli-pr-monitor): rate-limit 自動検出 + 再トリガー (Phase 4 / 順位 13)#97

Merged
aloekun merged 5 commits into
masterfrom
feat/cli-pr-monitor-rate-limit-auto-retrigger
Apr 30, 2026
Merged

feat(cli-pr-monitor): rate-limit 自動検出 + 再トリガー (Phase 4 / 順位 13)#97
aloekun merged 5 commits into
masterfrom
feat/cli-pr-monitor-rate-limit-auto-retrigger

Conversation

@aloekun
Copy link
Copy Markdown
Owner

@aloekun aloekun commented Apr 30, 2026

Summary

実装

check-ci-coderabbit

  • parse_rate_limit: CR コメント本文から Rate limit exceeded + Please wait N minutes M seconds を検出し、updated_at + 残時間 + 60s buffer で until_unix_secs を計算する
  • parse_iso8601_to_unix: ISO 8601 → unix epoch 秒の手動パース (chrono 依存追加なし、leap year 対応)
  • RateLimitInfo を JSON 出力に追加 (until_unix_secs, comment_created_at, wait_minutes, wait_seconds)

cli-pr-monitor

  • RateLimitConfig: auto_retry_enabled (default true) + max_retries (default 3)
  • state.rate_limit_retries: 累積 retry 回数 (state.json で persist)
  • state.rate_limit_last_retriggered_at: dedup key (advisor 指摘対応)
  • handle_rate_limit_retry: sleep → gh pr comment 投稿 → counter++

重要: dedup の必要性 (advisor finding)

comment_created_at で dedup しないと、同一 rate-limit comment が iteration を跨いで PR コメント一覧に残り、(until_unix_secs - now).max(0) = 0 となって即時 retrigger を繰り返してしまう。結果 max_retries=3 が数秒で消費され誤って action_required で抜ける。

シナリオ (バグなし版):

  1. Iter 1 (T=0): comment A 検出, last_retriggered=None → handle, retries=1, last_retriggered=A
  2. Iter 2 (T=120): 同じ comment A still in PR → dedup skip, 通常 polling cadence で待機
  3. Iter 3: CR が新たな rate-limit comment B 投稿 → last_retriggered=A != B → 再 handle

テスト

check-ci-coderabbit (56 passed)

  • rate_limit_detected_from_coderabbit_comment
  • rate_limit_picks_latest_when_multiple
  • rate_limit_no_match_when_unrelated_comment
  • rate_limit_no_match_when_no_wait_time
  • rate_limit_ignores_non_coderabbit
  • rate_limit_empty_json_returns_none
  • wait_time_full_format / wait_time_minutes_only / wait_time_singular_units / wait_time_no_match_returns_none
  • iso8601_* (4 tests, including leap year)

cli-pr-monitor (116 passed)

  • rate_limit_state_persists_retries_across_polls
  • rate_limit_default_config_allows_retry_within_limit
  • rate_limit_dedup_skips_repeated_comment (advisor finding カバー)
  • rate_limit_last_retriggered_at_persists_across_polls
  • update_state_populates_rate_limit / update_state_clears_rate_limit_when_absent

完了タスク

  • 順位 13 を docs/todo.md table から削除、todo3.md detail 削除
  • 残る Tier 2 rate-limit critical 系: 順位 19 (REJECT-ESCALATE) のみ

Test plan

  • check-ci-coderabbit: 56 unit tests pass (cargo test)
  • cli-pr-monitor: 116 unit tests pass (cargo test)
  • cargo clippy --all-targets -- -D warnings (両 crate clean)
  • cargo fmt --check clean
  • release exe build (pnpm build:cli-pr-monitor + build:check-ci-coderabbit)
  • dogfood: 次回の rate-limit 発火時に自動 retrigger が機能することを観察

Summary by CodeRabbit

  • 新機能
    • CodeRabbitのレート制限検出と、検出時刻に基づく設定可能な自動再試行(上限・重複回避含む)を導入。再試行の状態を永続化して必要時に静かな再トリガーを行う制御を追加。
  • ドキュメンテーション
    • タスク管理を4分冊へ再編成し、新パートを追加。実行順序と進行中項目(mutationテスト、並列ストレス実行等)を明文化。
  • 雑多
    • ロックファイルを除外する.gitignoreエントリを追加。

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 15ab1267-619e-490b-95f0-1fbfb837d41e

📥 Commits

Reviewing files that changed from the base of the PR and between 79b7c3d and b8933ef.

📒 Files selected for processing (4)
  • docs/todo.md
  • src/check-ci-coderabbit/src/main.rs
  • src/cli-pr-monitor/src/stages/poll.rs
  • src/cli-pr-monitor/src/state.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/todo.md

📝 Walkthrough

Walkthrough

GitHubのCodeRabbitボットコメントから「Rate limit exceeded」を検出・解析して待機期限を算出し、その情報をcheck-ci-coderabbitのJSON出力へ追加。cli-pr-monitorはConfigと状態を拡張してrate-limitの永続化・重複排除・自動リトライ(投稿+再試行管理)を行うようポーリングループを更新。関連ドキュメント(todo*.md)とユニットテストが追加・更新された。

Changes

Cohort / File(s) Summary
ドキュメント・タスク追跡
docs/todo.md, docs/todo3.md, docs/todo4.md
タスク追跡体系を4ファイルへ拡張。docs/todo4.mdを追加し、todo3からrate-limit項目を削除、実行順序と優先度を再定義。
Rate-limit 検出と出力(チェックプロセス)
src/check-ci-coderabbit/src/main.rs
CodeRabbitコメントから「Rate limit exceeded」を抽出し、待機分秒を正規表現で取得、イベント時刻をISO→Unixへ変換、until_unix_secsを算出してrate_limitオブジェクトをCheckResultへ追加。該当コメントをparse_new_commentsから除外。多くのユニットテスト追加。
設定スキーマ拡張
src/cli-pr-monitor/src/config.rs
トップレベルConfigrate_limit: RateLimitConfigを追加。auto_retry_enabled(default true)とmax_retries(default 3)をserdeデフォルトで導入し、テストを追加。
ポーリング/自動リトライ統合
src/cli-pr-monitor/src/stages/monitor.rs, src/cli-pr-monitor/src/stages/poll.rs
start_monitoringがフルConfigを渡すよう変更。run_poll_loop&Configを受け取り、状態復元(rate_limit, retries, last_retriggered)を行い、重複排除、auto-retry判定、静かな再トリガー投稿(run_gh_quiet)とリトライ回数管理、エラー時の早期終了を実装。専用ハンドラとユニットテスト追加。
状態モデル拡張
src/cli-pr-monitor/src/state.rs
RateLimitState型を追加し、PrMonitorStaterate_limit: Option<...>, rate_limit_retries: u32, rate_limit_last_retriggered_at: Option<String>を追加。update_state_from_check_resultでの復元/消去ロジックとテストを追加。
その他
.gitignore
.claude/pr-monitor.lockを無視対象に追加。

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub API (PR & comments)
    participant CCI as check-ci-coderabbit
    participant PM as cli-pr-monitor (poll loop)
    participant PS as PrMonitorState
    participant GHC as gh CLI (quiet comment)

    GH->>CCI: PR とコメント一覧を提供
    CCI->>CCI: "Rate limit exceeded" を検出・regexで分秒抽出・created_at→Unix変換
    CCI->>PM: CheckResult(rate_limit)
    PM->>PS: 状態復元 (rate_limit, retries, last_retriggered_at)
    alt rate_limit present
        PM->>PM: 重複排除 (コメント時刻比較)
        alt auto_retry_enabled かつ retries < max_retries
            PM->>PM: 必要時間を計算して待機(sleep)
            PM->>GHC: 静かな再トリガーコメントを投稿
            GHC-->>PM: 投稿結果
            PM->>PS: retries++ と last_retriggered_at 更新(永続化)
        else
            PM->>PM: max_retries到達または永続化失敗 → action_requiredで退出
        end
    else
        PM->>PM: 通常ポーリング継続
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルは CLI PR モニターの rate-limit 自動検出と再トリガー機能追加を明確に説明しており、変更内容の主要ポイント(Phase 4 実装)を正確に反映しています。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/cli-pr-monitor/src/config.rs (1)

282-282: 💤 Low value

テストカバレッジ: RateLimitConfig のパーステスト追加を推奨

既存の config_fix_defaults / config_fix_custom と同様に、rate_limit セクションのパーステストを追加すると、設定ファイルからの読み込みが期待通りに動作することを保証できます。

💡 テスト追加案
#[test]
fn config_rate_limit_defaults() {
    let toml_str = "[monitor]\n";
    let config: Config = toml::from_str(toml_str).unwrap();
    assert!(config.rate_limit.auto_retry_enabled);
    assert_eq!(config.rate_limit.max_retries, 3);
}

#[test]
fn config_rate_limit_custom() {
    let toml_str = r#"
[monitor]

[rate_limit]
auto_retry_enabled = false
max_retries = 5
"#;
    let config: Config = toml::from_str(toml_str).unwrap();
    assert!(!config.rate_limit.auto_retry_enabled);
    assert_eq!(config.rate_limit.max_retries, 5);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli-pr-monitor/src/config.rs` at line 282, Add parsing tests for
RateLimitConfig similar to existing config_fix_defaults/config_fix_custom:
create two unit tests named config_rate_limit_defaults and
config_rate_limit_custom that deserialize a Config via toml::from_str and assert
the RateLimitConfig fields (auto_retry_enabled and max_retries) have the
expected default and custom values; reference the Config struct and its
rate_limit field (RateLimitConfig) and use assertions on auto_retry_enabled and
max_retries to verify proper parsing and defaulting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cli-pr-monitor/src/stages/poll.rs`:
- Around line 238-246: The log format in poll.rs prints "retry={}/{}` but passes
rl.until_unix_secs as the second placeholder; update the logging so the second
value is the configured max retries instead: either add a max_retries parameter
to handle_rate_limit_retry (or otherwise obtain rate_limit_config.max_retries)
and use that in the format args, or simplify the format to a single "retry={}"
using state.rate_limit_retries + 1; adjust the log_info call that references
sleep_secs, rl.wait_minutes, rl.wait_seconds, state.rate_limit_retries, and
rl.until_unix_secs accordingly to replace rl.until_unix_secs with
rate_limit_config.max_retries (or remove the second placeholder).

---

Nitpick comments:
In `@src/cli-pr-monitor/src/config.rs`:
- Line 282: Add parsing tests for RateLimitConfig similar to existing
config_fix_defaults/config_fix_custom: create two unit tests named
config_rate_limit_defaults and config_rate_limit_custom that deserialize a
Config via toml::from_str and assert the RateLimitConfig fields
(auto_retry_enabled and max_retries) have the expected default and custom
values; reference the Config struct and its rate_limit field (RateLimitConfig)
and use assertions on auto_retry_enabled and max_retries to verify proper
parsing and defaulting.
🪄 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: 079e8c4f-d36c-49ba-a8d5-0abf12108255

📥 Commits

Reviewing files that changed from the base of the PR and between 5f5c79b and 6451dfb.

📒 Files selected for processing (8)
  • docs/todo.md
  • docs/todo3.md
  • docs/todo4.md
  • src/check-ci-coderabbit/src/main.rs
  • src/cli-pr-monitor/src/config.rs
  • src/cli-pr-monitor/src/stages/monitor.rs
  • src/cli-pr-monitor/src/stages/poll.rs
  • src/cli-pr-monitor/src/state.rs

Comment thread src/cli-pr-monitor/src/stages/poll.rs
PR #89 T2-1 の自動化。CodeRabbit が `Rate limit exceeded` コメントを投稿した
場合、reset 時刻 + 60s buffer まで sleep し `@coderabbitai review` を再投稿する。

## 実装

- check-ci-coderabbit: rate-limit comment を検出し reset 時刻を計算する
  `parse_rate_limit` を追加。`Please wait N minutes M seconds` の正規表現抽出 +
  ISO 8601 → unix epoch 秒の手動パース (chrono 依存追加なし)。

- cli-pr-monitor: poll loop に rate-limit retry ブランチを追加
  - `RateLimitConfig`: auto_retry_enabled (default true) + max_retries (default 3)
  - `state.rate_limit_retries`: 累積 retry 回数を state.json で persist
  - `state.rate_limit_last_retriggered_at`: dedup key (advisor 指摘対応)
  - `handle_rate_limit_retry`: sleep → gh pr comment 投稿 → counter++

## dedup の必要性 (advisor finding)

`comment_created_at` で dedup しないと、同一 rate-limit comment が iteration を
跨いで PR コメント一覧に残り、`(until_unix_secs - now).max(0) = 0` となって
即時 retrigger を繰り返す。結果 max_retries=3 が数秒で消費され誤って
`action_required` で抜ける。`rate_limit_last_retriggered_at` で同じ created_at
を skip し、CR が新しい rate-limit comment を投稿した時点で再度対象にする。

## テスト

- check-ci-coderabbit: rate-limit detection / parsing 11 tests 追加 (56 passed)
- cli-pr-monitor: poll dedup + state persistence 4 tests 追加 (116 passed)

## 完了タスク

- 順位 13 を docs/todo.md table から削除、todo3.md detail 削除
- 順位 19 (REJECT-ESCALATE) が rate-limit critical 系の最後の Tier 2 残
aloekun added a commit that referenced this pull request Apr 30, 2026
- handle_rate_limit_retry の log format 修正: retry={}/{} の 2 番目に
  rl.until_unix_secs (unix 秒) が渡されていたバグ。max_retries に修正。
  以前は "retry=1/1735689600" のような意味不明な出力になっていた。
- RateLimitConfig の parse test 追加 (defaults + custom)。既存
  config_fix_defaults / config_fix_custom と同パターンで網羅。
@aloekun aloekun force-pushed the feat/cli-pr-monitor-rate-limit-auto-retrigger branch from 6451dfb to 0c7c67b Compare April 30, 2026 11:33
- handle_rate_limit_retry の log format 修正: retry={}/{} の 2 番目に
  rl.until_unix_secs (unix 秒) が渡されていたバグ。max_retries に修正。
  以前は "retry=1/1735689600" のような意味不明な出力になっていた。
- RateLimitConfig の parse test 追加 (defaults + custom)。既存
  config_fix_defaults / config_fix_custom と同パターンで網羅。
- 前 commit で誤って snapshot された .claude/pr-monitor.lock を削除
  (.gitignore 追加は後続 commit で実施)。
@aloekun aloekun force-pushed the feat/cli-pr-monitor-rate-limit-auto-retrigger branch from 0c7c67b to e7b8d49 Compare April 30, 2026 11:42
@aloekun
Copy link
Copy Markdown
Owner Author

aloekun commented Apr 30, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

✅ 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
Copy link
Copy Markdown
Owner Author

aloekun commented Apr 30, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 30, 2026

✅ 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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
docs/todo.md (1)

69-70: ⚡ Quick win

ADR-033: 「順位◯」の絶対参照をテーブル外で使わないように調整してほしいです。

Bundle W の説明文中で (順位 34) / (順位 35) のように絶対順位をテーブル外に持ち出しています。ADR-033 の「絶対番号はテーブル内に限定」に合わせると、将来の並び替え時に文章とテーブルの不整合リスクが下がります。

🛠️ Proposed fix
-**仕様を proptest properties で明文化 (順位 34) + `PastTime` 等の型で invalid state を unrepresentable に (順位 35)** することで、ルール (ask-based) では塞げない bug class を構造的に排除する。
+**仕様を proptest properties で明文化 + `PastTime` 等の型で invalid state を unrepresentable に** することで、ルール (ask-based) では塞げない bug class を構造的に排除する。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/todo.md` around lines 69 - 70, Remove the hard-coded absolute rank
references like "(順位 34)" and "(順位 35)" from the Bundle W and Bundle X
paragraphs and replace them with neutral references (e.g., "see ADR-033 table",
"refer to the ADR-033 rank table", or use relative language such as "the rank in
the ADR-033 table") so the prose references the ADR-033 table rather than
embedding absolute numbers; update occurrences around the symbols "Bundle W",
"Bundle X", "Finding D", "Finding E", and the parenthetical rank mentions to use
the table pointer or relative wording.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/check-ci-coderabbit/src/main.rs`:
- Around line 355-396: parse_rate_limit is selecting any coderabbit rate-limit
comment (including older sessions) because it doesn't restrict by the current
session start; update it to accept the current session start (e.g. push_time
unix seconds or ISO string) and filter out comments whose created_at is before
that push_time (do this before selecting latest). Concretely: change
parse_rate_limit signature to take a push_time parameter, parse each
candidate.created_at to unix (using parse_iso8601_to_unix) and only keep those
with comment_unix >= push_time, then continue with the existing sorting,
extract_wait_time, and until_unix_secs computation; reference parse_rate_limit,
extract_wait_time, parse_iso8601_to_unix and start_monitoring /
parse_new_comments / parse_findings for consistent session-based filtering.
- Around line 932-937: The parsed comments JSON currently yields both
new_comments and rate_limit but parse_new_comments treats "Rate limit exceeded"
as a normal comment, causing decide() to return action_required and abort
recovery; fix by filtering out rate-limit comments: either update
parse_new_comments to exclude comments that match the rate-limit signature (the
same pattern parse_rate_limit detects) or, after calling parse_new_comments and
parse_rate_limit, remove any comments that match rate_limit from new_comments;
additionally ensure the actionable/decision path in decide() (and the retry
branch in src/cli-pr-monitor/src/stages/poll.rs) short-circuits when
rate_limit.is_some() so rate-limit presence does not trigger action_required.

In `@src/cli-pr-monitor/src/stages/poll.rs`:
- Around line 182-185: The code currently ignores write_state errors after
setting state.rate_limit_last_retriggered_at and continues; instead check the
Result from write_state(&state) and if it returns Err, stop the automatic retry
flow by marking the state for human action (e.g., set state.action_required =
Some("failed_persist_rate_limit_retriggered") or similar), attempt to persist
that updated state (call write_state again or log and escalate), and then exit
the retry path (do not continue the loop—return or break) so
handle_rate_limit_retry and rate_limit_retries/dedup are not left inconsistent
(refer to write_state, state.rate_limit_last_retriggered_at,
handle_rate_limit_retry, rate_limit_config.max_retries, and
state.action_required).

---

Nitpick comments:
In `@docs/todo.md`:
- Around line 69-70: Remove the hard-coded absolute rank references like "(順位
34)" and "(順位 35)" from the Bundle W and Bundle X paragraphs and replace them
with neutral references (e.g., "see ADR-033 table", "refer to the ADR-033 rank
table", or use relative language such as "the rank in the ADR-033 table") so the
prose references the ADR-033 table rather than embedding absolute numbers;
update occurrences around the symbols "Bundle W", "Bundle X", "Finding D",
"Finding E", and the parenthetical rank mentions to use the table pointer or
relative wording.
🪄 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: de0d83f2-2c35-410e-96de-2bbdf9f48a28

📥 Commits

Reviewing files that changed from the base of the PR and between 6451dfb and e7b8d49.

📒 Files selected for processing (9)
  • .gitignore
  • docs/todo.md
  • docs/todo3.md
  • docs/todo4.md
  • src/check-ci-coderabbit/src/main.rs
  • src/cli-pr-monitor/src/config.rs
  • src/cli-pr-monitor/src/stages/monitor.rs
  • src/cli-pr-monitor/src/stages/poll.rs
  • src/cli-pr-monitor/src/state.rs
✅ Files skipped from review due to trivial changes (2)
  • .gitignore
  • docs/todo4.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/todo3.md

Comment thread src/check-ci-coderabbit/src/main.rs Outdated
Comment thread src/check-ci-coderabbit/src/main.rs Outdated
Comment thread src/cli-pr-monitor/src/stages/poll.rs Outdated
CR review @ commit e7b8d49 で検出された 3 Major + 1 Nitpick を修正。

## 修正内容

### Finding 1 (Major): parse_rate_limit に push_time フィルタ追加
過去セッションの rate-limit comment を新セッション開始時に誤って拾うバグを修正。
`comment.created_at >= push_time` フィルタを追加し、parse_new_comments / parse_findings
と同じ規則に揃える。これにより本 PR 検証中に観測された 22 分遅延の根因の一つが解消される。

### Finding 2 (Major): parse_new_comments で rate-limit comment 除外
rate-limit comment が new_comments にカウントされると `decide()` が action_required
を早期 return し、poll.rs の rate-limit retry 経路に入らずに監視終了するバグ。
"Rate limit exceeded" を含む comment を新規コメント集計から除外する。22 分遅延のもう
一つの根因。

### Finding 3 (Major): write_state 失敗時の自動 retry 停止
retrigger 後の state 永続化に失敗すると、次 iteration で `rate_limit_retries` と
`rate_limit_last_retriggered_at` の復元に失敗し、dedup と max_retries が壊れて
`@coderabbitai review` 重複投稿の可能性がある。失敗時は action_required で抜ける。

### Finding 4 (Nitpick): docs/todo.md 順位 絶対参照削除
ADR-033 の「絶対番号は table のみに保持」原則に従い、Bundle W/X 説明文から
`(順位 34)` `(順位 35)` 等の絶対参照を削除しタスク名参照に置換。

### .gitignore: pr-monitor.lock 除外
cli-pr-monitor の重複起動防止 lock file (PR #88 / #96 で導入) が .gitignore
漏れで PR snapshot に混入する事故を防ぐ。

## テスト

- check-ci-coderabbit: 59 tests pass (rate_limit_filters_out_past_session_comments,
  rate_limit_includes_comment_at_exact_push_time, comments_excludes_rate_limit を追加)
- cli-pr-monitor: 118 tests pass
- clippy + fmt clean (変更パッケージ)
@aloekun aloekun force-pushed the feat/cli-pr-monitor-rate-limit-auto-retrigger branch from e7b8d49 to 79b7c3d Compare April 30, 2026 13:59
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/todo.md`:
- Around line 60-61: The second-layer description currently references only "PR
`#88` T2-4" but should include PR `#96` for accurate history; edit the text in
docs/todo.md (the line describing 第2層 / cli-pr-monitor ポーリング延長 + 重複起動ロック) to
change the parenthetical from "(PR `#88` T2-4、完了済)" to "(PR `#88` T2-4 / `#96`、完了済)"
so the record shows both PRs.

In `@src/check-ci-coderabbit/src/main.rs`:
- Around line 359-415: In parse_rate_limit, switch the timestamp basis from
created_at to updated_at when computing until_unix_secs: fetch latest.updated_at
(falling back to created_at only if updated_at is missing), pass that to
parse_iso8601_to_unix, and use it in the comment_unix + wait + 60s calculation;
also update the returned RateLimitInfo.comment_created_at (or add a
comment_updated_at field) to record the actual timestamp used. Locate symbols:
parse_rate_limit, GhComment.updated_at / created_at, extract_wait_time,
parse_iso8601_to_unix, and RateLimitInfo, and add a unit test where created_at
!= updated_at to ensure the updated_at path is exercised.

In `@src/cli-pr-monitor/src/stages/poll.rs`:
- Around line 179-203: The code marks a rate-limit event as handled even when
the retrigger (comment posting) fails by immediately incrementing
state.rate_limit_retries and setting state.rate_limit_last_retriggered_at;
change the flow so that retries/last_retriggered_at and state persistence are
only updated after a confirmed successful retrigger. Concretely, modify
handle_rate_limit_retry (or its caller) to return a success indicator (e.g.,
Result<(), Error> or bool) from the actual comment/post action, then in the
block that currently calls handle_rate_limit_retry(&rl, &mut state, ...) only
advance state.rate_limit_retries and set state.rate_limit_last_retriggered_at
and call write_state() when that indicator shows success; if the retrigger
fails, do not mutate those fields and instead return a
PollResult::action_required (or propagate the error) so the event stays eligible
for future retries. Ensure the same change is applied to the analogous logic
around lines 274-295.
- Around line 163-183: The rate-limit retry branch runs before timeout checks
and can block longer than the remaining monitoring budget; modify the logic in
the rate-limit handling (where state.rate_limit is used and
handle_rate_limit_retry(...) is called) to first compute remaining_monitor_secs
= max_duration - elapsed_since_start and if remaining_monitor_secs <= 0 set the
overall state to timed_out/action_required and skip retry, otherwise limit the
sleep duration passed to handle_rate_limit_retry to min(rl.sleep_secs,
remaining_monitor_secs); also apply the same remaining-time guard to the other
rate-limit retry sites that call handle_rate_limit_retry (the similar blocks
around the other occurrences) and set state.rate_limit_last_retriggered_at only
when a retry actually proceeds.
🪄 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: 76a11112-2a68-4f51-884d-adb13f59990c

📥 Commits

Reviewing files that changed from the base of the PR and between e7b8d49 and 79b7c3d.

📒 Files selected for processing (4)
  • .gitignore
  • docs/todo.md
  • src/check-ci-coderabbit/src/main.rs
  • src/cli-pr-monitor/src/stages/poll.rs
✅ Files skipped from review due to trivial changes (1)
  • .gitignore

Comment thread docs/todo.md Outdated
Comment thread src/check-ci-coderabbit/src/main.rs
Comment thread src/cli-pr-monitor/src/stages/poll.rs Outdated
Comment thread src/cli-pr-monitor/src/stages/poll.rs
aloekun added 2 commits April 30, 2026 23:38
CR review @ commit 79b7c3d で検出された 3 Major + 1 Minor のうち
Finding 1 (updated_at) を除く 3 件を修正。

## 修正内容

### Finding 2 (Major): rate-limit sleep を max_duration で cap
`handle_rate_limit_retry` に `remaining_monitor_secs` 引数を追加し、
sleep が監視残り予算を超える場合は Err を返して retry を停止する。
これまでは max_duration を素通りして 30 分超ブロックする可能性があった。

### Finding 3 (Major): handle_rate_limit_retry を Result 化
gh pr comment 投稿失敗 / PR 番号未確定の場合に retries++ や
last_retriggered_at 更新を実施しないよう、関数を Result<(), String> に
変更。caller は Ok 時のみ dedup key を更新し、Err 時は action_required
で抜ける。これにより失敗 retrigger が dedup で perma-skip 化する
silent failure を防ぐ。

### Finding 4 (Minor): docs/todo.md 第2層 PR 参照に #96 追記
"(PR #88 T2-4、完了済)" → "(PR #88 T2-4 / #96、完了済)" に履歴整合。

## テスト追加 (2 件)

- rate_limit_retry_returns_err_when_sleep_exceeds_budget:
  remaining=60s だが sleep=600s 必要なケースで Err を返し state 不変を確認
- rate_limit_retry_returns_err_when_pr_number_missing:
  PR 番号未確定で Err を返し state 不変を確認

## 未対応 (任意)

Finding 1 (updated_at): CR が rate-limit comment を編集する挙動は実観測なし。
将来的な堅牢性向上のため todo 化候補。
…nd 3 Finding 1 実観測対応)

CR が rate-limit comment を編集して wait 時間を更新するケースが本 PR の dogfood で
実観測された (created_at=2026-04-30T11:11:51Z, updated_at=2026-04-30T14:38:32Z で
"wait 21 minutes" に編集)。created_at 基準だと reset 時刻を 3 時間以上前として誤算定し、
premature retrigger → CR 再 rate-limit → comment edit のループに陥る危険があった。

## 修正内容

- GhComment に updated_at フィールドを追加
- rate_limit_event_time(): updated_at fallback created_at を返すヘルパー追加
- parse_rate_limit: 計算基準を event_time に変更 (フィルタ / sort / until 計算)
- RateLimitInfo.comment_created_at: 値の意味を「event_time」に拡張 (フィールド名は維持)
- state.rs RateLimitState.comment_created_at の doc 更新

## テスト追加 (3 件)

- rate_limit_uses_updated_at_when_present:
  実観測ケース (created_at != updated_at) で updated_at 基準計算を確認
- rate_limit_falls_back_to_created_at_when_updated_at_missing:
  既存挙動の後方互換性を確認
- rate_limit_edited_comment_yields_new_dedup_key:
  編集前後で dedup key が変化することを確認 (新 wait 時間で再 trigger 可能)
@aloekun aloekun merged commit 83396c7 into master Apr 30, 2026
1 check passed
@aloekun aloekun deleted the feat/cli-pr-monitor-rate-limit-auto-retrigger branch April 30, 2026 15:43
aloekun added a commit that referenced this pull request May 1, 2026
* feat(takt): Bundle Y2 - analyze facets を haiku 化

post-merge-feedback の 3 facets (analyze-pr / analyze-session /
analyze-prepush-reports) と post-pr-review の analyze step を
sonnet → haiku に変更。aggregate / fix / supervise は sonnet 維持で
品質担保。

analyze 系は「情報源から finding を抽出する分類タスク」で deep reasoning
不要。期待効果: PR #97 ベースラインから session あたり 15-20 分削減 + 該当
step の token cost 1/3。

token 効率改善計画書 (docs/pipeline-token-efficiency.md) も同コミットで
初出公開。進捗管理表で #A-1 / #C-1 を「採用済 (Bundle Y2)」マーキング。
Bundle Z (#B-*) / Bundle Z2 (#D-*) は別 PR で実装予定。

検証: AgentModelSchema (node_modules/takt/dist/core/models/schema-base.js)
は ['opus', 'sonnet', 'haiku'] enum で haiku alias を accept。
npx takt prompt で両 workflow が parse 通ることを確認済み。

* docs(pipeline-token-efficiency): 進捗表の placeholder を PR #98 に更新

Bundle Y2 (#A-1 / #C-1) の進捗表エントリを「採用済 (Bundle Y2) | 2026-05-01 |
(本 PR)」から実 PR 番号 #98 に書き換え。advisor 指摘の埋め忘れ防止のため、
親 commit (Bundle Y2 実装) と同 PR 内で完結させる。

PR #98 の post-pr-review takt 初回 run は 1 iteration / 1m 13s で APPROVED。
旧 baseline (1.5-2.5 min/iter) から早速 Bundle Y2 効果が反映された観測値。
aloekun added a commit that referenced this pull request May 3, 2026
* docs(pipeline-token-efficiency): 完了済 Bundle 整理 + 残作業を 3 PR 計画に再編

* feat(cli-pr-monitor): rate-limit 検出時に post-pr-review takt invoke を skip (#C-3)

CR rate-limit が active な状態で polling を抜けた場合、stale な findings に対する
takt 分析は空打ちになるため (1-2 分の浪費)、PR #97 で追加した検出機構を流用して
takt invoke を skip する。

- PollResult に rate_limit: Option<RateLimitState> field を追加
- 8 つの PollResult 終了点すべてで state.rate_limit を伝播
- monitor.rs で has_coderabbit_findings + collect_findings 成功後、
  rate_limit.is_some() を check して takt branch を skip + log

参照: docs/pipeline-token-efficiency.md PR 1

* feat(cli-merge-pipeline): trivial PR で post-merge-feedback を skip (#A-2)

doc-only PR や 1-commit fix PR では post-merge-feedback の ROI が低いため、
gh pr view で取得した diff summary を判定して skip する。

判定条件 (3 つすべて満たす場合のみ skip):
  - changed files が全て .md
  - かつ commit 数 = 1
  - かつ +/- 合計 < TRIVIAL_PR_LINE_LIMIT (50)

実装:
- feedback.rs に PrDiffSummary / fetch_pr_diff_summary / parse_pr_diff_summary を追加
- main.rs run_ai_step で feedback::run 前に skip 判定
- 判定失敗時は WARN log を残して通常 flow に fallback (誤 skip による学習機会損失を最小化)

unit test 9 件追加:
- 境界 (TRIVIAL_PR_LINE_LIMIT 直前 / 上限と一致)
- multi-commit / non-md 混在 / 空 files の non-trivial 判定
- 大文字 .MD 拡張子の認識
- 必須 field 欠損時の Err 返却

参照: docs/pipeline-token-efficiency.md PR 1
aloekun added a commit that referenced this pull request May 4, 2026
… 59/60 + ADR-035/036/037) (#108)

* docs(todo): 順位 59 (ADR-035 docs 評価ポリシー / PR #107 T3-1) を追加

PR #107 post-merge-feedback の Tier 3 #1 採用に伴い、docs/todo.md 表と
todo5.md 詳細を追加。

- 順位 59 (Tier 3, M): ADR-035 docs 評価ポリシー
  - docs-only 変更への code review criteria 誤適用を排除する global policy
  - review-security.md の既存 trust boundary criterion を ADR で集約
  - review-simplicity.md / analyze-coderabbit.md にも一貫展開
  - false REJECT 削減 + 開発体験劣化抑制

判定根拠 (順位 58 で導入した rubric ベース):
- Severity Medium / Frequency Medium / Effort M / Adoption Risk None / ✅ 採用

* docs(efficiency): docs-pr-iteration-efficiency.md を新規作成

docs-only PR の iteration 改善に関する task 分類・bundle 案を集約する index
を docs/ に新規追加。各 task の作業詳細は docs/todo*.md 系列に置き、本ファイル
は概要 + リンクに留める設計。

掲載内容:
- 現状の課題 / ボトルネック分析 (5 観点)
- 改善 task 分類 (HIGH / MEDIUM / LOW IMPACT、合計 12 順位)
- 推奨 bundle 案 (Bundle 'docs PR streamline' = 順位 59+31+32 を最優先)
- 関連ドキュメント (todo.md / pipeline-token-efficiency.md / ADR-019/027/035)

役割: 試験運用 (bundle が消化されたら役割を終える計画書)。pipeline-token-
efficiency.md と並列の領域特化計画書として機能する。

動機: 本セッションで 「docs-only PR の iteration 改善に当たる task をピック
アップしてほしい」「毎回この情報を調べるのは手間」 とのユーザー要望に対応。
分析結果を再調査せず参照可能にする。

* docs(efficiency): coderabbit-monitoring-efficiency.md を新規作成

CodeRabbit 監視機能改善 (rate-limit 自動回復) に関する task 分類・bundle 案
を集約する index を docs/ に新規追加。各 task の作業詳細は docs/todo*.md
系列に置き、本ファイルは概要 + リンクに留める設計。

掲載内容:
- 現状の課題 (CodeRabbit 無課金 = 1 時間 3 reviews 上限、47 分 rate-limit
  で auto-retry がバウンスする致命点)
- ボトルネック分析 (6 観点: 長時間 rate-limit / polling 負荷 / silent loss /
  structured findings / 自動 trigger 信頼性 / ポリシー暗黙化)
- 改善 task 分類 (HIGH / MEDIUM / LOW IMPACT、合計 9 順位)
- 推奨 bundle 案 (Bundle 'CR auto-monitoring core' = 順位 53/54/55、
  Bundle 'CR rate-limit auto-retry robustness' = 順位 42/43/46/49)
- 推奨実行順序: 53 → 42-43-46-49 → 54 → 55 (1 と 2 は並行可)
- 関連ドキュメント (ADR-009/018/019/034、todo.md、pipeline-token-
  efficiency.md、docs-pr-iteration-efficiency.md)

役割: 試験運用 (bundle 消化後に役割終了)。pipeline-token-efficiency.md /
docs-pr-iteration-efficiency.md と並列の領域特化計画書として機能。

動機: 本セッションで 'CodeRabbit の監視機能改善に関する task をピックアップ
してほしい'、'毎回この情報を調べるのは手間' とのユーザー要望に対応。

* docs(retire): pipeline-token-efficiency.md retire — ADR-036/037 化 + 順位 60 移管 + 削除

PR #97 セッション起源の計画書 docs/pipeline-token-efficiency.md (481 行) を
役割完了として retire。重要な設計決定は ADR に永続保存し、残作業 1 件のみを
todo に移管した上で計画書ファイル本体を削除する。

新規 ADR (2 件):
- ADR-036: Bundle Z 3 層アーキテクチャ
  - 決定論層 (#B-α PR #99/#105) → 制約付き修正 (#B-β PR #103)
    → 異常検知レビュアー (#B-γ PR #106) の 3 層スタック設計
  - 'upper layer skips what lower layer catches' 原則
  - 二重 miss 対策 (Calibration: avoid over-narrowing) を残置
- ADR-037: takt fix-trust shortcut (convergence_verdict 機構)
  - post-pr-review / pre-push-review の fix step が
    'convergence_verdict: fully_resolved' で COMPLETE 直行する設計
  - 'LLM が出した結果を後段で再検証しない' 原則
  - Honesty constraint で安全網 bypass リスク管理

ADR-034 更新:
- #D-4 (Claude 応答スタイル簡素化) を ❌ 不採用 に確定 (2026-05-04 ユーザー判断)
  Bundle Z Phase 2/3 完了後の再評価で副作用観測手段確立が見えないため
  永続的に見送り。潜在 2.5-4M tokens 削減は採用しない
- '将来の検討事項' から #D-4 再評価条件セクションを削除
- pipeline-token-efficiency.md への参照を '(削除済)' に annotate

順位 60 新規登録 (旧 #A-3、唯一の残作業):
- analyze-session の transcript filter 絞り込み (Tier 3 / M)
- input range を PR 作成 commit〜merge に限定し input token 30-50% 削減

ファイル削除:
- docs/pipeline-token-efficiency.md (481 行) を削除
  内容は git log で復元可能、主要設計は ADR-036/037 に集約

参照更新 (5 ファイル):
- docs/coderabbit-monitoring-efficiency.md: 関連リンクから dead link
  削除、ADR-036/037 を追加
- docs/docs-pr-iteration-efficiency.md: 同上
- docs/todo4.md: 順位 41 (Bundle Y2 効果定量計測) は動機失効を明記
  (Bundle Z 完成 + Z2 不採用)、本格着手前にユーザー判断要。
  順位 44/45 の参照を '(削除済)' に annotate
- docs/todo5.md: 順位 51 の参照を ADR-036 に置換
- CLAUDE.md: ADR-036 / ADR-037 を index に追加

動機:
ユーザー方針 '本当に必要な決定事項はADRに残し、不要になったTodoファイルや
作業計画のファイルは定期的に削除' に従い、計画書 retire の標準パターンを
本セッションで確立。今後類似の '計画書' (試験運用フラグ付き docs/) は
役割完了時に同パターンで retire する。

* fix(todo): 順位 41 entry の retire 済前提と旧フロー文言の不整合を解消 (#108 CR Minor)

CodeRabbit が PR #108 review で 'outside diff range comment' として指摘した
docs/todo4.md 順位 41 (Bundle Y2 効果定量計測) の line 371/378 残存問題を修正。

- 削除: 'Line 371: 想定削減量達成判定に基づき計画書 retire / 追加 Bundle 提案'
  (計画書はすでに retire 済のため、retire 判定ステップが矛盾)
- 削除: 'Line 378: Bundle Z / Z2 の ROI 判断材料として活用可能なデータが揃う'
  (Bundle Z は完成、Bundle Z2 = #D-4 は不採用で本目的の役割消滅)
- 修正: '結果を本 todo entry 内 (もしくは新規 ADR) に記録 — 旧計画は ...'
  → '結果を本 entry または新規 ADR に記録 (= 完了)' に簡素化

判定対象を「本 entry/ADR への記録完了」に統一し、retire 済前提との整合を確保。

備考 (別観察): 本指摘は CodeRabbit が 'outside diff range comment' として
review body 内に含めて投稿したため、inline comment 前提の takt
analyze-coderabbit step では 0 findings 判定 (= 検出漏れ) となった。
takt analyzer の coverage gap として将来の post-merge-feedback で扱う。
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