Skip to content

docs(todo): PR #85 post-merge-feedback の Tier 1-3 finding を全採用#86

Merged
aloekun merged 1 commit into
masterfrom
todo-add-pr85-findings
Apr 28, 2026
Merged

docs(todo): PR #85 post-merge-feedback の Tier 1-3 finding を全採用#86
aloekun merged 1 commit into
masterfrom
todo-add-pr85-findings

Conversation

@aloekun
Copy link
Copy Markdown
Owner

@aloekun aloekun commented Apr 28, 2026

Summary

PR #85 マージ後の post-merge-feedback (ADR-030) が抽出した 7 件の finding + 1 件の augmentation を採用し、docs/todo.md / docs/todo2.md に反映する。

反映内容

新規エントリ (docs/todo2.md、7 件)

順位 Tier タスク 工数
2 🚀 Tier 1 push 前 untracked __* ファイル警告 hook (T1-4) Small
3 🚀 Tier 1 cli-push-runner jj bookmark 未設定 early-exit (T1-3) S
4 🚀 Tier 1 PowerShell swallowed error custom_lint_rule (T1-2) XS
9 🔧 Tier 2 cli-pr-monitor プロセス正常終了 integration test (T2-2) S
13 💎 Tier 3 日付ベース見出しアンカー更新ルール (T3-1) XS
14 💎 Tier 3 jj conflict リカバリ手順 (T3-2) XS
15 💎 Tier 3 __ prefix scratch file 規約 (T3-3) XS

既存エントリ augmentation

  • ADR-032 PR-broken-link (順位 8): T2-1 finding (docs/todo2.md:7 の旧日付アンカー drift) を反映し、Markdown 内部アンカー (heading slug) の整合チェック を検査対象に追加

Tier 1 #1 は実装済

__* パターンの .gitignore 追加は PR #85 で実装済のため、新規エントリ化は不要 (戦略文と T1-4 entry 内で言及)。

docs/todo.md 更新

  • 推奨実行順序サマリー table を 10 → 17 行 に拡張
  • 戦略行: Tier 1 (1〜5) → Tier 2 (6〜9) → Tier 3 (10〜15) → Tier 4-5 (16〜17) に更新
  • 既存 4 タスクの「実行優先度」+ cross-references を新採番 (/17) に更新

動機

post-merge-feedback (ADR-030) が独立評価で抽出した再発防止策を Plankton 優先度付きでバックログ化することで、同種事故の再発を防止し改善サイクルを継続する。本 PR 自体が ADR-030 のフィードバックループの 1 周回目の出力となる。

Test plan

  • pre-push-review (simplicity + security) APPROVED
  • CI (lint / test / build / rust-test) パス
  • CodeRabbit レビュー異常なし
  • table renumber の一貫性を目視確認 (順位 1-17、依存参照、cross-ref)
  • 削除済みエントリ参照 (順位 N/10, 順位 N/13) の dangling 参照ゼロを grep で確認済 (push 前検証)

Summary by CodeRabbit

  • Documentation
    • タスク優先度体系を10段階から17段階へ更新
    • 推奨実行順序を全面的に整理・最適化
    • 複数の新規タスクエントリを追加
    • 品質ゲート要件の詳細化および内部チェック基準の拡張

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

docs/todo.md と docs/todo2.md における推奨実行順序の優先度体系を /10 スキームから /17 スキームへ全面更新し、PR #85 関連のフォローアップタスク(PowerShell lint ルール、cli-pr-monitor 統合テスト、グローバル文書化タスク等)を追加、タスク間の依存関係と実行優先度を再整理した。

Changes

Cohort / File(s) Summary
推奨実行順序の優先度体系更新
docs/todo.md, docs/todo2.md
優先度体系を /10 から /17 へ統一変更。Tier ランク(Tier1–5)のポジション番号を新スキームへ再マッピング。複数セクションにおける実行優先度表記を一括更新。
PR #85 関連フォローアップタスク追加
docs/todo.md, docs/todo2.md
PR #85 の post-merge-feedback 対応に係る追加タスクを記載。jj/bookmark 周りの early-exit 動作、push 時の untracked __\* ファイル検出、PowerShell swallowed-error lint ルール、cli-pr-monitor 正常終了統合テスト、グローバル文書化3件(日付ベースヘッダの横断 grep、jj conflict 復旧手順、__ scratch ファイル命名規則)。
Quality Gate フェーズ仕様拡張
docs/todo2.md
broken-link-check フェーズに PR #85 anchor drift インシデント記録と内部 Markdown anchor の一級検証対象化(slug/存在確認含む)を追加。dogfood ステップによる検出確認プロセスを明記。

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • PR #85: 本 PR で反映・拡張される PR #85 の post-merge-feedback 対応タスクと直接対応、追加フォローアップタスク(PowerShell lint ルール、pr-monitor テスト等)の定義。
  • PR #45: 本 PR で参照される jj 変更検出・cli-pr-monitor repush ロジック(decide_repush、commit-id+diff)と自動化責任 ADR がこの PR で導入されたため、継続・拡張関係にある。
  • PR #82: 同じドキュメントファイル(docs/todo.md、docs/todo2.md)の実行順序体系・Tier スキーム・docs-only fast-path タスク定義を調整した関連変更。
🚥 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 PR タイトルは PR #85 の post-merge-feedback で抽出した Tier 1-3 finding の採用という主な変更内容を明確に示しており、docs/todo.md と docs/todo2.md の更新という実際の変更と一致しています。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/todo2.md (1)

7-7: ⚠️ Potential issue | 🟡 Minor

todo.md への内部アンカーが旧日付のままでリンク切れしています。

docs/todo.md の見出し更新(2026-04-28)後も、ここが ...-2026-04-27-更新 を参照しており遷移できません。アンカーを最新化してください。

修正案(リンク先アンカー更新)
-> **推奨実行順序**: 全タスク横断のサマリーは [docs/todo.md](todo.md#推奨実行順序サマリー-2026-04-27-更新) を参照。本ファイルに記録する ADR-032 は sub-phase ごとに Tier が分散するため、各 Phase の冒頭に個別の優先度を記載。
+> **推奨実行順序**: 全タスク横断のサマリーは [docs/todo.md](todo.md#推奨実行順序サマリー-2026-04-28-更新-pr-85-post-merge-feedback-反映後) を参照。本ファイルに記録する ADR-032 は sub-phase ごとに Tier が分散するため、各 Phase の冒頭に個別の優先度を記載。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/todo2.md` at line 7, Update the broken internal anchor by replacing the
stale anchor string "...-2026-04-27-更新" in the link text with the current anchor
"...-2026-04-28-更新" so the reference resolves to the updated heading; locate the
anchor occurrence in the line containing the link text and update it
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@docs/todo2.md`:
- Line 7: Update the broken internal anchor by replacing the stale anchor string
"...-2026-04-27-更新" in the link text with the current anchor "...-2026-04-28-更新"
so the reference resolves to the updated heading; locate the anchor occurrence
in the line containing the link text and update it accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0f5a3e43-c985-469a-976d-4ea51830118f

📥 Commits

Reviewing files that changed from the base of the PR and between 070ab84 and 55376b6.

📒 Files selected for processing (2)
  • docs/todo.md
  • docs/todo2.md

@aloekun aloekun merged commit 53d4cfc into master Apr 28, 2026
1 check passed
@aloekun aloekun deleted the todo-add-pr85-findings branch April 28, 2026 05:16
aloekun added a commit that referenced this pull request Apr 29, 2026
PR #91 で受けた CodeRabbit findings 2 件を child commit として修正。

1. Major: PowerShell rule case-insensitivity (.claude/custom-lint-rules.toml:115-118)
   - PowerShell の `catch` keyword と `-ErrorAction` parameter は case-insensitive
     なので、`Catch {}` / `CATCH {}` / `-erroraction silentlycontinue` /
     `-ErrorAction SILENTLYCONTINUE` などの大文字バリアントは現 regex で見逃していた
   - 両 rule の pattern に Rust regex `(?i)` inline flag を追加して case-insensitive
     マッチに変更
   - test helper (ps_empty_catch_rule / ps_silent_error_rule) も同様に更新

2. Minor: docs/todo.md stale references (lines 68 / 250 / 264)
   - Bundle 1 の renumber (27 \u2192 25) で本文内の cross-reference が追従漏れ
   - line 68: `Tier 4 (順位 25/26)` \u2192 `24/25`
   - line 250: `Tier 5 (順位 26/26)` \u2192 `25/25`、`順位 25` \u2192 `順位 24`
   - line 264: `Tier 2 (順位 9/26)` \u2192 `7/25`、`順位 17 (ADR-032 PR-β)` \u2192 `順位 16`

実装 (TDD):
- 先に case-insensitive variant の 4 unit test を追加し、cargo test で FAIL を実証 (RED)
- (?i) flag 追加で GREEN \u2192 62 tests pass (旧 58 + 新 4)
- bad/good example も大文字混在ケースで影響なしを確認 (regex は (?i) 範囲)

順位 23 (todo.md 採番管理の簡素化 ADR 起案、PR #86 T3-3) で構造的解決予定。
本 fix は当面の対症療法として cross-ref を手作業で同期。
aloekun added a commit that referenced this pull request Apr 29, 2026
…Bundle 1) (#91)

* feat(lint): add PowerShell + Markdown anchor rules to ADR-007 layer

Bundle 1 (post-merge-feedback の旧順位 3 + 7 を 1 PR に統合):

- no-empty-powershell-catch (error): 空 `catch {}` ブロックでの swallowed error
  検出 (PR #85 T1-2 finding)
- no-silent-error-action (warning): `-ErrorAction SilentlyContinue` の検出
  (PR #85 T1-2 finding、片方単独 warning)
- no-mutable-anchor (warning): Markdown link の non-ASCII GFM fragment 検出
  (PR #89 T1-1 finding)

実装:
- .claude/custom-lint-rules.toml に 3 rule 追加
- src/hooks-post-tool-linter/src/main.rs に 13 unit test 追加
  (#7 の 4 edge case + ps1 / extension filter 全網羅)
- cargo test: 58 passed
- dogfood で 3 rule すべて発火確認

設計判断:
- ADR-007 既存 pattern (regex 層 / file 単位) に適合、ADR 更新不要
- #3 の "片方単独 warning / 組合せ error" spec は engine の per-line 設計で
  実現できないため、severity を rule 別に分離 (empty catch=error /
  SilentlyContinue=warning) で精神を保つ
- #7 は ADR-007 Q2 (string literal 誤検出) が borderline だが、MVP として
  regex 層採用。lookbehind 非対応のため backtick 内例は誤検出するが、
  task entry 削除で clean baseline 達成

Bundle 戦略 (post-merge-feedback ループ収束のため):
- 個別 PR なら 2 件 → 1 PR に統合 (50% 削減)
- summary table を 27 → 25 行に renumber、Tier breakdown 全更新

Closes feedback: PR #85 T1-2, PR #89 T1-1

* fix(lint): apply CodeRabbit findings on PR #91

PR #91 で受けた CodeRabbit findings 2 件を child commit として修正。

1. Major: PowerShell rule case-insensitivity (.claude/custom-lint-rules.toml:115-118)
   - PowerShell の `catch` keyword と `-ErrorAction` parameter は case-insensitive
     なので、`Catch {}` / `CATCH {}` / `-erroraction silentlycontinue` /
     `-ErrorAction SILENTLYCONTINUE` などの大文字バリアントは現 regex で見逃していた
   - 両 rule の pattern に Rust regex `(?i)` inline flag を追加して case-insensitive
     マッチに変更
   - test helper (ps_empty_catch_rule / ps_silent_error_rule) も同様に更新

2. Minor: docs/todo.md stale references (lines 68 / 250 / 264)
   - Bundle 1 の renumber (27 \u2192 25) で本文内の cross-reference が追従漏れ
   - line 68: `Tier 4 (順位 25/26)` \u2192 `24/25`
   - line 250: `Tier 5 (順位 26/26)` \u2192 `25/25`、`順位 25` \u2192 `順位 24`
   - line 264: `Tier 2 (順位 9/26)` \u2192 `7/25`、`順位 17 (ADR-032 PR-β)` \u2192 `順位 16`

実装 (TDD):
- 先に case-insensitive variant の 4 unit test を追加し、cargo test で FAIL を実証 (RED)
- (?i) flag 追加で GREEN \u2192 62 tests pass (旧 58 + 新 4)
- bad/good example も大文字混在ケースで影響なしを確認 (regex は (?i) 範囲)

順位 23 (todo.md 採番管理の簡素化 ADR 起案、PR #86 T3-3) で構造的解決予定。
本 fix は当面の対症療法として cross-ref を手作業で同期。

* fix(lint): detect multi-line empty catch blocks (file-level regex)

PR #91 の 2nd CodeRabbit review で指摘された Major finding を修正。

問題:
- run_custom_rules() が `for line in content.lines()` で行ごとに regex.find() を
  呼ぶ実装だったため、PowerShell 慣用形 `} catch {\n}` の複数行空ブロックが
  検出できなかった (no-empty-powershell-catch は error severity なのに false
  negative)。
- 既存パターン (console.log( / no-personal-paths / no-mutable-anchor 等) は
  すべて行内完結のため挙動変化なし。SilentlyContinue は \s+ で改行を跨ぎ得るが、
  PowerShell の backtick 行継続を含む正当な使用も検出対象として妥当。

修正:
- run_custom_rules() を file-level マッチに変更
  (`compiled.regex.find_iter(&content)` でファイル全体を走査)
- match の byte offset から改行カウントで line 番号を逆算
  (`content[..m.start()].bytes().filter(|b| *b == b'\n').count() + 1`)
- MAX_CUSTOM_VIOLATIONS の上限と既存テスト挙動はそのまま維持

実装 (TDD):
- ps_empty_catch_detects_multiline_block test を追加し RED 確認
  (既存実装で 0 件検出 → 1 件期待で FAIL)
- 修正後 GREEN \u2192 63 tests pass (旧 62 + 新 1)

* fix(lint): exclude external URLs from no-mutable-anchor (path `:` exclusion)

PR #91 の 3rd CodeRabbit review で指摘された Minor finding を修正。

問題:
- regex `\]\([^)#]*#[^\x00-\x7F)]+` は path 部に `:` を許容するため、
  `[link](https://example.com/#日本語)` のような外部 URL の fragment を
  GFM anchor と誤判定 (false positive)。
- 外部 URL の fragment は GFM anchor ではないため、warning rule の
  alert fatigue を招く。

修正:
- regex を `\]\([^)#:]*#[^\x00-\x7F)]+` に変更 (path 部から `:` を除外)。
  http(s):// を含む URL は path 部マッチで止まるため対象外になる。
- protocol-relative URL (`//example.com/...`) は `:` を含まないため除外
  できないが、Markdown 文書では稀なので許容。
- CodeRabbit 提案の negative lookahead は Rust regex 非対応なので、
  character class 否定 1 文字追加で同等効果を実現。

実装 (TDD):
- md_mutable_anchor_skips_external_url_with_fragment test を追加 → RED
  (`[spec](https://example.com/#日本語)` で 1 件検出 → 0 件期待で FAIL)
- pattern 修正後 GREEN \u2192 64 tests pass (旧 63 + 新 1)
aloekun added a commit that referenced this pull request Apr 29, 2026
* feat(adr): ADR-033 todo numbering simplification (試験運用)

PR #85/#86/#88/#89/#90/#91/Bundle 1 で連続発生した renumber 作業の構造的負債を
解消する ADR を起案。

問題:
- docs/todo.md の本文中 `順位 N` cross-reference が線形コストで増加
- PR #91 では 4 件追加に対し本文 8 箇所修正、過去 PR で stale reference の
  追従漏れによる CodeRabbit Minor 指摘が発生 (a15b263 で修正)
- 採番のみが情報源で、本文と表の往復が発生

決定 (選択肢 B 採用):
- 絶対番号 (`順位 N`) は推奨実行順序サマリー table のみに保持
- 本文での参照は task 名 (heading text or 略称) で行う
- table の `依存` 列のみ絶対番号を許可 (table 内なので renumber 同期可能)
- 「Tier N (順位 X/Y)」表記の `(順位 X/Y)` 部分は除去 → `Tier N` のみ残す

却下した選択肢:
- 選択肢 A (renumber script の自動化): 保守コスト新規発生、問題のすり替え
- 選択肢 C (現状維持): convergence loop の一因、線形増加は止まらない

本 commit は ADR と CLAUDE.md リンク追加のみ。本文 cross-ref の一括変換と
新規 entry template は次の commit で実施。

References:
- docs/adr/adr-013, adr-022, adr-028
- .claude/feedback-reports/86.md Tier 3 #3 (起案動機の起源)
- PR #91 a15b263 (stale reference 起因の Minor 指摘実例)

* refactor(docs): remove inline rank references from todo files

ADR-033 のガイドライン適用。docs/todo.md / todo2.md / todo3.md の本文中
`順位 N` cross-reference をすべて task 名参照に変換。

変更対象:
- docs/todo.md: 戦略 section の 12 箇所、Tier 4/5 entry の (順位 X/Y) 表記、
  週次レビュー entry の cross-ref
- docs/todo2.md: ADR-032 series の Phase ごと優先度表記、reviewer facet /
  各 Tier 1/2/3 entry の (順位 X/Y) と inline 参照
- docs/todo3.md: Stop hook lint:md / AI 生成一時スクリプト / cli-pr-monitor
  polling 延長 / post-pr-review rate-limit / .failed marker / Recovery 経路 /
  REJECT-ESCALATE entry の inline 参照を全て task 名に変換

維持した absolute number:
- docs/todo.md の推奨実行順序サマリー table の `順位` 列 (source of truth)
- table の `依存` 列の絶対番号 (table 内なので renumber と同期可能)
- table 内 cell の歴史的 `旧順位 N` 表記 (完了済み task の参照)

未変換の例外:
- docs/todo2.md line 696 の採番管理 ADR 元 entry の `(順位 24/26)` は
  本 PR の Commit 3 で entry 全体を削除するため未変換 (削除待ち)

検証:
```sh
grep -nE '順位 [0-9]+' docs/todo.md docs/todo2.md docs/todo3.md
# 期待: docs/todo.md table 列のみ + docs/todo2.md 採番管理 ADR 元 entry のみ
```

References:
- docs/adr/adr-033-todo-numbering-simplification.md (本 ADR の決定)

* docs(todo): remove completed numbering simplification ADR entry

ADR-033 land により採番管理簡素化 task が完了したため、運用ルール
(memory feedback_todo_no_history.md) に従い元 entry を削除する。

変更:
- docs/todo2.md: "todo.md 採番管理の簡素化 ADR 起案 (PR #86 T3-3)" entry
  全体 (40 行) を削除
- docs/todo.md summary table:
  - 旧順位 27 (採番管理 ADR) 行を削除
  - 旧順位 28 (ADR-030 Phase E/F) → 順位 27 に renumber
  - 旧順位 29 (ADR-030 takt-test-vc) → 順位 28 に renumber、依存表記の
    `順位 28 Phase F` も `順位 27 Phase F` に追従
  - サマリー header 日付ラベルを "Bundle 1 完了後" → "ADR-033 land 後" に更新

検証:
- 本文 cross-ref は Commit 2 で除去済のため、本 commit の renumber は
  table 行と `依存` 列のみで完結 (ADR-033 の効果を本 PR 内で実証)
- markdownlint pass (PostToolUse hook で各 Edit ごとに検証)

* fix(adr): apply CodeRabbit findings on PR #92

PR #92 で受けた CodeRabbit Minor findings 2 件を child commit として修正。
両 finding は self-consistent: Finding 1 の改善 regex が Finding 2 の placeholder
残存を機械的に検出可能になる。

1. Minor: ADR-033 line 111 の検証 regex が数値以外の placeholder を見逃す
   - 旧: `順位 [0-9]+` (数値のみマッチ)
   - 新: `順位 [0-9A-Za-z_-]+` (英字 placeholder `順位 X` / `順位 N` も検出)
   - 期待コメントも更新し、placeholder 検出意図を明記

2. Minor: docs/todo3.md line 511 (REJECT-ESCALATE entry の動機セクション) で
   `.claude/ filter (順位 X = T2-1+T3-2 Bundle)` という placeholder が残存
   - 旧: `.claude/ filter (順位 X = T2-1+T3-2 Bundle)`
   - 新: `.claude/ filter + ADR-030 制約明記 task (PR #91 T2-1 + T3-2 Bundle)`
   - ADR-033 「本文はタスク名参照」方針に準拠

検証 (改善 regex で 0 件達成):
```sh
grep -nE "順位 [0-9A-Za-z_-]+" docs/todo.md docs/todo2.md docs/todo3.md   | grep -vE "推奨実行順序サマリー|^[^:]+:[0-9]+:\| [0-9]+ \|"
# 結果: 0 行
```
aloekun added a commit that referenced this pull request Apr 29, 2026
…1) (#93)

- hooks-pre-tool-validate に preset_polling_anti_pattern を追加
- 検出パターン: `until COND; do BODY; sl<>p N; done` 形式
  および `while !` 版 (regex は \bdo\b 制約で loop syntax のみマッチ)
  echo 文字列や --until=DATE フラグの誤検出は \bdo\b 制約で排除
- .claude/hooks-config.toml で本プロジェクト用に opt-in
  (デフォルトフォールバックには非追加、後方互換維持)
- 14 件のテスト追加 (block 6 / allow 7 / 後方互換 1)
  後追加 negative test 3 件: echo string / git --until flag / for loop は誤検出しない

動機: PR #86 で実証された rate-limit 40% 浪費 (1 セッション) の再発防止。
背景タスクは task-notification 経由で自走するため polling 不要。
ブロック時は Monitor tool / run_in_background / 単発取得への誘導メッセージを表示する。

Note: 当初設計案にあった "run_in_background -> polling" の cross-tool-call
検出は YAGNI 適用で見送り (transcript 読み取りが必要、複雑度に対する効果が
低い)。in-command 検出で PR #86 の canonical case を捕捉できる。

todo.md 推奨実行順序 Phase 1 (順位 3) 完了。
aloekun added a commit that referenced this pull request Apr 30, 2026
PR #88 で実証された rate-limit 浪費 (Claude Code Max を 1 時間で 40% 消費) への
直接対策。tool 側の polling 動作を 2 軸で改善し、Polling anti-pattern 検出 (PR
#86 T1-1, 完了済) と組み合わせて 3 層の rate-limit 抑制を成立させる。

## 順位 12 本実装

### 重複起動 file lock (新 module: src/cli-pr-monitor/src/lock.rs)

- `start_monitoring` の polling + takt 並走を `.claude/pr-monitor.lock` で
  1 アクティブ監視にゲート
- atomic create-or-fail (`OpenOptions::create_new`) で TOCTOU race を排除
- AlreadyExists 時のみ既存 lock の stale 判定にフォールバック
  - fresh (start_time が threshold 内): Busy 返却 → caller は no-op exit
  - stale (threshold 超過 / parse 不能): overwrite で takeover
- stale_threshold = 1800s (max_duration_secs 600s の 3x 安全マージン)
- Drop guard で正常終了時 cleanup、crash 時は次インスタンスが stale 経由で takeover
- guard 対象は `start_monitoring` のみ。`--observe` (read-only) と
  `--mark-notified` (one-shot mutation) は対象外で並走可能

### ポーリング間隔延長 (config.rs)

- DEFAULT_POLL_INTERVAL を 120s → 180s
- 単独セッションでも polling 回数を 5 → ~3 サイクル/監視に削減 (~40% 削減)
- max_duration_secs (600s) は維持

### ISO 8601 parser (lock.rs 内蔵)

- chrono 依存を増やさず手書き parse で start_time の age を計算
- うるう年・月日・時分秒を正確にハンドル (`is_leap` / `days_from_epoch` テスト済)
- util::utc_now_iso8601() の出力 format と round-trip することを test で検証

## テスト

- 9 件の lock test 追加 (cli-pr-monitor 全体 106 passed):
  - acquire / drop の基本動作
  - fresh lock が second acquire を block
  - stale lock の takeover (1980 timestamp で確実に stale)
  - corrupt lock (parse 不能) の takeover
  - **concurrent_acquire_only_one_wins**: 8 thread 同時 acquire で 1 つだけが
    Acquired になることを検証 (advisor 指摘の TOCTOU race を真に検証する test)
  - lock_format_matches_util_iso8601: util との format alignment 確認
  - parse_iso8601 / is_leap 単体動作

## docs/todo 系列の更新 (Bundle V 登録 + Phase 3 完了反映、同 PR 同梱)

ユーザー方針 (memory: feedback_minimize_pr_count_during_rate_limit) により、
直前 session の Bundle V 登録 (順位 31-33 の table 追加 + 詳細エントリ) と本
Phase 3 完了反映 (順位 12 削除 + narrative 整合化) を同 PR で land する。

- docs/todo.md: 順位 12 削除 + Bundle V 順位 31-33 追加 + narrative 三段構え
  (Polling anti-pattern + cli-pr-monitor lock + post-pr-review rate-limit) に更新
- docs/todo3.md: 順位 12 詳細エントリ削除 + Bundle V 詳細 3 件追加

## 期待効果

- 重複起動セッション間の polling 並走を確実に防止
- DEFAULT_POLL_INTERVAL 延長で単独セッションの polling 総回数を ~40% 削減
- rate-limit 抑制 3 層 (Claude 側 polling 禁止 + tool 側ポーリング頻度削減 +
  review 単位の自動再トリガー [Tier 2 残]) のうち 2 層を完成
aloekun added a commit that referenced this pull request Apr 30, 2026
…Bundle V 登録 (#96)

* feat(cli-pr-monitor): 重複起動 file lock + ポーリング間隔延長 (Phase 3 / 順位 12)

PR #88 で実証された rate-limit 浪費 (Claude Code Max を 1 時間で 40% 消費) への
直接対策。tool 側の polling 動作を 2 軸で改善し、Polling anti-pattern 検出 (PR
#86 T1-1, 完了済) と組み合わせて 3 層の rate-limit 抑制を成立させる。

## 順位 12 本実装

### 重複起動 file lock (新 module: src/cli-pr-monitor/src/lock.rs)

- `start_monitoring` の polling + takt 並走を `.claude/pr-monitor.lock` で
  1 アクティブ監視にゲート
- atomic create-or-fail (`OpenOptions::create_new`) で TOCTOU race を排除
- AlreadyExists 時のみ既存 lock の stale 判定にフォールバック
  - fresh (start_time が threshold 内): Busy 返却 → caller は no-op exit
  - stale (threshold 超過 / parse 不能): overwrite で takeover
- stale_threshold = 1800s (max_duration_secs 600s の 3x 安全マージン)
- Drop guard で正常終了時 cleanup、crash 時は次インスタンスが stale 経由で takeover
- guard 対象は `start_monitoring` のみ。`--observe` (read-only) と
  `--mark-notified` (one-shot mutation) は対象外で並走可能

### ポーリング間隔延長 (config.rs)

- DEFAULT_POLL_INTERVAL を 120s → 180s
- 単独セッションでも polling 回数を 5 → ~3 サイクル/監視に削減 (~40% 削減)
- max_duration_secs (600s) は維持

### ISO 8601 parser (lock.rs 内蔵)

- chrono 依存を増やさず手書き parse で start_time の age を計算
- うるう年・月日・時分秒を正確にハンドル (`is_leap` / `days_from_epoch` テスト済)
- util::utc_now_iso8601() の出力 format と round-trip することを test で検証

## テスト

- 9 件の lock test 追加 (cli-pr-monitor 全体 106 passed):
  - acquire / drop の基本動作
  - fresh lock が second acquire を block
  - stale lock の takeover (1980 timestamp で確実に stale)
  - corrupt lock (parse 不能) の takeover
  - **concurrent_acquire_only_one_wins**: 8 thread 同時 acquire で 1 つだけが
    Acquired になることを検証 (advisor 指摘の TOCTOU race を真に検証する test)
  - lock_format_matches_util_iso8601: util との format alignment 確認
  - parse_iso8601 / is_leap 単体動作

## docs/todo 系列の更新 (Bundle V 登録 + Phase 3 完了反映、同 PR 同梱)

ユーザー方針 (memory: feedback_minimize_pr_count_during_rate_limit) により、
直前 session の Bundle V 登録 (順位 31-33 の table 追加 + 詳細エントリ) と本
Phase 3 完了反映 (順位 12 削除 + narrative 整合化) を同 PR で land する。

- docs/todo.md: 順位 12 削除 + Bundle V 順位 31-33 追加 + narrative 三段構え
  (Polling anti-pattern + cli-pr-monitor lock + post-pr-review rate-limit) に更新
- docs/todo3.md: 順位 12 詳細エントリ削除 + Bundle V 詳細 3 件追加

## 期待効果

- 重複起動セッション間の polling 並走を確実に防止
- DEFAULT_POLL_INTERVAL 延長で単独セッションの polling 総回数を ~40% 削減
- rate-limit 抑制 3 層 (Claude 側 polling 禁止 + tool 側ポーリング頻度削減 +
  review 単位の自動再トリガー [Tier 2 残]) のうち 2 層を完成

* fix(review): apply CodeRabbit fixes for #96

Resolved findings:
- [Major] src/cli-pr-monitor/src/lock.rs:109 `Acquired` を「実際には lock できていない」ケースにも返しています。
- [Major] src/cli-pr-monitor/src/lock.rs:205 壊れた `start_time` で panic します。

* fix(lock): CodeRabbit 指摘 (#96 round 2) を反映

Finding D (Major, parse_age_secs): 未来日時 (時計巻き戻し / 破損 future timestamp)
が saturating_sub で age=0 となり永続 fresh 扱いになる bug を修正。明示的に
then > now を None (stale 扱い) で返し、crash recovery が機能するようにする。
test future_timestamp_lock_is_taken_over を追加。

Finding E (Minor, concurrent test flakiness): 1 barrier 構成だと先行 thread の
guard が判定後に即 drop されて後続 thread が逐次 Acquired する race window が
存在した。start barrier + finish barrier の 2 barrier 構成にし、全 thread が
判定終了まで Acquired guard を保持するよう修正。

両者とも CR の suggestion 準拠。lock test 全 13 件 pass、clippy 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