feat(hooks): merge 前 mechanical gate 強化 (clippy + 空 commit sweep) - #194
Conversation
- 順位 175: stop_quality / quality_gate に `cargo clippy --workspace -- -D warnings` step 追加 (PR #185 Tier 1 #1、Rust lint structural gap 補填) - 順位 155: cli-pr-monitor fix chain 末尾に `master..@` 範囲の空 commit sweep 追加 (PR #174 Tier 1 #1、kqvluqyv 事例の構造的予防) - 前提として既存 clippy errors 5 件を併せて修正 (question_mark / doc_lazy_continuation x3 / manual_strip) 新規テスト: parse_empty_change_ids 4 unit + sweep_empty_commits_in_pr_range 統合 2 件
📝 WalkthroughWalkthroughRust ワークスペース向けに cargo clippy を stop_quality/push-runner 品質ゲートへ追加し、cli-pr-monitor に PR 範囲の空 fix commit を列挙して jj abandon で削除する sweep 機能を実装・repush フローへ統合、関連 todo を削除しました。 変更Rust Clippy 品質ゲート追加
空 commit 自動クリーンアップ実装
設定拡張とテスト
コード品質向上(小変更)
Sequence Diagram(s)sequenceDiagram
participant RepushFlow as execute_repush_flow
participant RepushAction as execute_repush_action
participant Sweep as sweep_empty_commits_in_pr_range
participant JJLog as "jj log"
participant JJAbandon as "jj abandon"
RepushFlow->>RepushAction: perform RepushAction
RepushAction-->>RepushFlow: action result
RepushFlow->>Sweep: if fix_config.sweep.enabled
Sweep->>JJLog: run revset query (default_branch..@) for empty fix(review) commits
JJLog-->>Sweep: change_id list
Sweep->>JJAbandon: jj abandon <change_id> (for each)
JJAbandon-->>Sweep: abandon results
Sweep-->>RepushFlow: sweep complete
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 関連する可能性のあるプルリクエスト
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the 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 |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/cli-pr-monitor/src/stages/repush.rs (1)
145-169:⚠️ Potential issue | 🟠 Major | ⚡ Quick winfail-safe 分岐のあとで sweep を無条件実行しないでください。
上の分岐は
IdCaptureFailedやtry_abandon_empty_fix_commit()の安全側スキップでローカル履歴を触らない設計ですが、Line 169 で直後に再びjj abandonを走らせています。これだと「不確実なので何もしない」と判断したケースでも sweep が同じ空 commit を消し得るので、少なくとも安全に状態を信頼できる action に限定して呼ぶ必要があります。🤖 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/repush.rs` around lines 145 - 169, The unconditional call to crate::fix_commit::sweep_empty_commits_in_pr_range("master") must be removed and only invoked for actions that are allowed to mutate local history; update the match over RepushAction to call sweep_empty_commits_in_pr_range("master") inside the safe arms (e.g., RepushAction::AutoPush and RepushAction::CleanupEmptyFixCommit { .. }) instead of after the match, leaving the fail-safe arms (RepushAction::UserConfirmWithSeparatedFix, RepushAction::UserConfirmNoSeparation, RepushAction::SkipNoChange, RepushAction::FailSafeCaptureFailed and any IdCaptureFailed paths) without any sweep; keep the existing try_abandon_empty_fix_commit("fix_state=Created:", Some(&commit_id)) usage in CleanupEmptyFixCommit and add the sweep call there (and in run_auto_push result path) so only trusted flows run sweep_empty_commits_in_pr_range.
🤖 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 `@push-runner-config.toml`:
- Line 64: The comment "# PostToolUse / Stop hook では実行せず、イテレーション速度を保護する。" in
push-runner-config.toml is outdated because a Stop hook (see
[[stop_quality.steps]] name = "lint:rust" in .claude/hooks-config.toml) now
runs; update that comment to accurately reflect current behavior (e.g., state
that the hook runs on Stop and mention impact on iteration speed or that
lint:rust is executed on Stop) so operators aren't misled.
In `@src/cli-pr-monitor/src/fix_commit.rs`:
- Around line 217-238: run_cmd_direct returns combined stdout/stderr so the
current code passes merged output into parse_empty_change_ids which may pick up
jj warnings from stderr; change this by making the jj log invocation use only
stdout (call/run the underlying function to return stdout separately) or by
filtering the returned out before calling parse_empty_change_ids: feed
parse_empty_change_ids only lines that match a valid change_id pattern (e.g.
regex for expected ID format) or explicitly split and discard stderr-like lines;
update the code around run_cmd_direct, the variable out, and the call site
parse_empty_change_ids to ensure only valid stdout-derived change IDs are
processed before using change_ids (and keep JJ_CMD_TIMEOUT_SECS/ok handling
unchanged).
- Around line 203-248: The revset used in sweep_empty_commits_in_pr_range is too
broad (empty() & (default_branch..@)) and abandons any empty commit; narrow it
to only target fix-related commits by adding a provenance/summary filter (e.g.
require commit summary to match the fix pattern). Change the revset construction
in sweep_empty_commits_in_pr_range (the revset variable) to include a summary
regex like summary ~ "^fix\\(" (or another project-specific marker for fix
commits) so parse_empty_change_ids and the subsequent run_cmd_direct("jj",
&["abandon", cid], ...) only operate on intended fix commits; update the log
message accordingly and keep existing fail-open behavior.
In `@src/cli-pr-monitor/src/stages/repush.rs`:
- Line 169: Replace the hardcoded "master" call in repush.rs to respect the
experimental feature pattern: read an opt-in flag and kill-switch from config
(e.g., config.experimental.sweep_empty_commits or
config.kill_switchs.sweep_empty_commits), fetch the repository default branch
name (do not assume "master") and pass that variable into
sweep_empty_commits_in_pr_range, and add a bounded lifetime parameter (e.g.,
max_age_days from config) so the sweep only runs for a limited window; ensure
the sweep is skipped unless the opt-in is set and not globally disabled by the
kill-switch.
In `@src/hooks-pre-tool-validate/src/main.rs`:
- Around line 845-847: The current use of behind? after calling
count_commits_branch_ahead causes check_todo_staleness to return None when
lineage cannot be determined, bypassing the fail-closed behavior; change the
handling so None is treated as "stale" instead of propagating None: in
check_todo_staleness replace the behind? call with explicit matching or map_or
(e.g., treat None as >0) so stale is true when count_commits_branch_ahead
returns None, and update build_todo_staleness_message to likewise interpret a
None behind result as stale (return the same stale message path as for non-zero
behind) so both functions consistently treat None => stale; refer to
count_commits_branch_ahead, check_todo_staleness, build_todo_staleness_message
and the behind variable.
---
Outside diff comments:
In `@src/cli-pr-monitor/src/stages/repush.rs`:
- Around line 145-169: The unconditional call to
crate::fix_commit::sweep_empty_commits_in_pr_range("master") must be removed and
only invoked for actions that are allowed to mutate local history; update the
match over RepushAction to call sweep_empty_commits_in_pr_range("master") inside
the safe arms (e.g., RepushAction::AutoPush and
RepushAction::CleanupEmptyFixCommit { .. }) instead of after the match, leaving
the fail-safe arms (RepushAction::UserConfirmWithSeparatedFix,
RepushAction::UserConfirmNoSeparation, RepushAction::SkipNoChange,
RepushAction::FailSafeCaptureFailed and any IdCaptureFailed paths) without any
sweep; keep the existing try_abandon_empty_fix_commit("fix_state=Created:",
Some(&commit_id)) usage in CleanupEmptyFixCommit and add the sweep call there
(and in run_auto_push result path) so only trusted flows run
sweep_empty_commits_in_pr_range.
🪄 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: 16081d24-e75b-484d-ae11-7968a14a91ba
📒 Files selected for processing (9)
.claude/hooks-config.tomldocs/todo-summary.mddocs/todo10.mddocs/todo9.mdpush-runner-config.tomlsrc/cli-pr-monitor/src/fix_commit.rssrc/cli-pr-monitor/src/stages/repush.rssrc/cli-push-runner/src/stages/scratch_file_warning.rssrc/hooks-pre-tool-validate/src/main.rs
💤 Files with no reviewable changes (3)
- docs/todo10.md
- docs/todo9.md
- docs/todo-summary.md
| let (ok, out) = run_cmd_direct( | ||
| "jj", | ||
| &[ | ||
| "log", | ||
| "-r", | ||
| &revset, | ||
| "--no-graph", | ||
| "-T", | ||
| "change_id ++ \"\\n\"", | ||
| ], | ||
| &[], | ||
| JJ_CMD_TIMEOUT_SECS, | ||
| ); | ||
| if !ok { | ||
| log_info(&format!( | ||
| "[warn] sweep_empty_commits: jj log 失敗 (sweep skip): {}", | ||
| out.trim() | ||
| )); | ||
| return; | ||
| } | ||
|
|
||
| let change_ids = parse_empty_change_ids(&out); |
There was a problem hiding this comment.
jj log の結合出力をそのまま change_id 一覧として parse しないでください。
src/cli-pr-monitor/src/runner.rs:24-78 の run_cmd_direct() は成功時でも stdout/stderr を結合して返します。ここで jj log が warning を stderr に出すと、その行まで parse_empty_change_ids() に入り、存在しない ID を jj abandon に渡す形になります。ID 抽出は stdout のみに限定するか、少なくとも change_id として妥当な行だけを通してください。
🤖 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/fix_commit.rs` around lines 217 - 238, run_cmd_direct
returns combined stdout/stderr so the current code passes merged output into
parse_empty_change_ids which may pick up jj warnings from stderr; change this by
making the jj log invocation use only stdout (call/run the underlying function
to return stdout separately) or by filtering the returned out before calling
parse_empty_change_ids: feed parse_empty_change_ids only lines that match a
valid change_id pattern (e.g. regex for expected ID format) or explicitly split
and discard stderr-like lines; update the code around run_cmd_direct, the
variable out, and the call site parse_empty_change_ids to ensure only valid
stdout-derived change IDs are processed before using change_ids (and keep
JJ_CMD_TIMEOUT_SECS/ok handling unchanged).
There was a problem hiding this comment.
resolved: run_cmd_direct 非成功時は早期 return で parse 対象外。jj log 成功時は stderr emit せず structured な change_id 出力のみを parse する経路。dogfood で stderr leakage 観測時に別途追加防御を検討。
There was a problem hiding this comment.
@aloekun、説明ありがとうございます。整理できました。
- 失敗パス:
!okで即 return →parse_empty_change_idsは呼ばれない ✓ - 成功パス:
jj log --no-graph -T "change_id ++ \"\\n\""は structured template 出力のみ。成功時に jj が stderr へ warning を出すケースは通常ない ✓ - 追加の安全層: 実装では revset に
description(substring:"fix(review):")フィルタが入っており、diff 時点のドキュメントより scope がさらに絞られている ✓
dogfood で stderr leakage が観測された場合の段階的防御方針も妥当です。現状の実装で問題ないと判断します。
🧠 Learnings used
Learnt from: aloekun
Repo: aloekun/claude-code-hook-test PR: 119
File: src/cli-finding-classifier/src/lib.rs:86-96
Timestamp: 2026-05-06T14:17:51.353Z
Learning: In `src/cli-finding-classifier/src/lib.rs`, the `normalized_issue` field from LLM output is intentionally validated only with trim + non-empty filter (no newline/length checks). Strict validation (single-line, max 80 chars enforcement + fallback) is deferred to Phase 5 (cli-pr-monitor integration) or when an actual problem occurs. The current prompt template (`classify.txt`) includes a `max 80 chars` instruction that is considered sufficient guard in the meantime. Do not flag this as missing validation in code reviews.
Learnt from: aloekun
Repo: aloekun/claude-code-hook-test PR: 71
File: src/hooks-stop-feedback-dispatch/src/main.rs:127-135
Timestamp: 2026-04-23T17:49:44.755Z
Learning: In `aloekun/claude-code-hook-test`, `src/hooks-stop-feedback-dispatch/src/main.rs`, the stale-GC branch in `handle_pending()` unconditionally deletes `{pending}.lock` before acquiring the lock. This is an accepted tradeoff: the race window is ~0.001% (24h TTL vs 10–100ms dispatch), and acquiring the lock before stale cleanup was rejected because it would eliminate the only recovery path for leaked locks (from kill -9 etc.), causing permanent stuck state. The design relies on the 24h TTL as a backstop for leaked locks. Re-raise this finding only if: (1) double dispatch is observed in production, (2) a shorter stale TTL (e.g., 1h) is needed, or (3) the code is ported to a hostile multi-process environment.
Learnt from: aloekun
Repo: aloekun/claude-code-hook-test PR: 53
File: docs/todo.md:106-106
Timestamp: 2026-04-18T08:42:52.662Z
Learning: In `aloekun/claude-code-hook-test`, within `src/cli-pr-monitor`, `run_push()` is defined in `src/cli-pr-monitor/src/stages/push.rs` (line 15) as `pub(crate) fn run_push(config: &FixConfig) -> bool`. It is imported and called from `src/cli-pr-monitor/src/stages/repush.rs` via `use crate::stages::push::run_push;`. Do NOT flag references to `push.rs` for `run_push` as incorrect — `push.rs` is the canonical definition site.
Learnt from: aloekun
Repo: aloekun/claude-code-hook-test PR: 99
File: docs/pipeline-token-efficiency.md:222-242
Timestamp: 2026-05-01T17:18:31.023Z
Learning: In `aloekun/claude-code-hook-test`, `docs/pipeline-token-efficiency.md` is a phased improvement planning document. Specifications described within a "Phase N" section (e.g., `#B-β` Phase 2, `#B-γ` Phase 3) represent future planned implementations and should NOT be flagged as missing implementations in PRs that only cover an earlier phase. Always check the PR scope and the progress table at the bottom of the document to determine which phase is being implemented before raising findings about unimplemented specs.
Learnt from: aloekun
Repo: aloekun/claude-code-hook-test PR: 44
File: src/cli-pr-monitor/src/stages/repush.rs:40-54
Timestamp: 2026-04-16T15:41:17.548Z
Learning: In `aloekun/claude-code-hook-test`, `auto_push_severity` in `src/cli-pr-monitor` is a configuration preset (not a severity threshold comparator). Valid values are "none" / "critical" / "major", where both "critical" and "major" mean "always auto push" per ADR-019 L44-46. The function `should_auto_push(setting: &str)` in `src/cli-pr-monitor/src/stages/repush.rs` correctly returns `true` for both "critical" and "major" — do NOT flag this as missing threshold comparison logic. ADR-019 L52 prohibits double-judging AI evaluations in Rust, and ADR-019 L78 prohibits raw-findings-based auto push judgment.
Learnt from: aloekun
Repo: aloekun/claude-code-hook-test PR: 64
File: docs/adr/adr-022-automation-responsibility-separation.md:128-128
Timestamp: 2026-04-21T09:09:02.341Z
Learning: In aloekun/claude-code-hook-test, markdownlint-cli2 (0.22.0) can false-positive MD038 (no-space-in-code) on content inside fenced code blocks (``` ... ```). MD038 only applies to inline backtick code spans, not fenced code block content. Do not flag MD038 warnings for lines inside fenced code blocks in this repository.
Learnt from: CR
Repo: aloekun/claude-code-hook-test PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-05-25T14:21:38.565Z
Learning: Applies to hooks/**/*.rs : Implement Stop hooks as quality gates (ADR-004) to enforce code quality standards before proceeding
Learnt from: aloekun
Repo: aloekun/claude-code-hook-test PR: 38
File: src/cli-pr-monitor/src/runner.rs:109-115
Timestamp: 2026-04-15T05:44:09.231Z
Learning: In this Windows-only `cli-pr-monitor` tool, hardcoded Windows `.exe` expectations are intentional. Do not require cross-platform handling (e.g., avoid changing `.exe` suffix usage) when reviewing Rust code under `src/cli-pr-monitor/src/`—including logic such as `checker_exe_path()` and related `.exe` references in error messages.
Resolved findings: - [Minor] push-runner-config.toml:64 コメント説明が最新の設定と矛盾しています。 - [Major] src/cli-pr-monitor/src/fix_commit.rs:248 削除対象の revset が広すぎます。 - [Minor] src/cli-pr-monitor/src/fix_commit.rs:238 `jj log` の結合出力をそのまま change_id 一覧として parse しないでください。 - [Major] src/cli-pr-monitor/src/stages/repush.rs:169 新しい sweep を `master` 固定・常時有効で配線しないでください。 - [Major] src/hooks-pre-tool-validate/src/main.rs:847 `behind` 判定不能時に gate をバイパスしており fail-closed 契約に反しています
There was a problem hiding this comment.
♻️ Duplicate comments (1)
src/cli-pr-monitor/src/config.rs (1)
97-118:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftADR-039 の実験機能パターン要件が未充足です。
Line 97-118 の
SweepConfigは opt-in(enabled)のみで、kill-switch と bounded lifetime がありません。設定スキーマに両方を追加し、実行側で必ず評価してください。🔧 最小追加イメージ
pub(crate) struct SweepConfig { #[serde(default)] pub(crate) enabled: bool, + #[serde(default)] + pub(crate) kill_switch: bool, + #[serde(default = "default_sweep_ttl_days")] + pub(crate) ttl_days: u16, #[serde(default = "default_sweep_branch")] pub(crate) default_branch: String, } + +fn default_sweep_ttl_days() -> u16 { + 30 +}// repush 側イメージ(別箇所) if fix_config.sweep.enabled && !fix_config.sweep.kill_switch && !fix_config.sweep.is_expired() { sweep_empty_commits_in_pr_range(&fix_config.sweep.default_branch); }As per coding guidelines "Implement Experimental feature standard pattern with config opt-in, kill-switch, and bounded lifetime (ADR-039)".
🤖 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/config.rs` around lines 97 - 118, SweepConfig currently only provides opt-in via enabled; add the ADR-039 required kill-switch and bounded lifetime by adding a pub(crate) kill_switch: bool with serde default false and a pub(crate) expires_at: Option<DateTime<Utc>> (or equivalent timestamp string) plus an is_expired(&self) -> bool method that returns true if expires_at is Some and <= now; update Default for SweepConfig to set kill_switch = false and expires_at = None (or a sane default), and update the execution site that calls sweep_empty_commits_in_pr_range to guard with the full check: fix_config.sweep.enabled && !fix_config.sweep.kill_switch && !fix_config.sweep.is_expired() so the sweep runs only when enabled, not killed, and not expired.
🧹 Nitpick comments (1)
src/hooks-pre-tool-validate/src/main.rs (1)
2187-2231: ⚡ Quick win
build_todo_staleness_messageのbehind = Noneケースのテストがありません。既存テストは
behindがSome(0),Some(2),Some(3)のケースをカバーしていますが、今回追加された fail-closed 動作 (behind = None) のテストがありません。🧪 テスト追加案
#[test] fn build_todo_staleness_message_neither_returns_none() { let path = build_todo_path(""); let msg = build_todo_staleness_message(&path, Some(0), &[], "master"); assert!(msg.is_none()); } + + #[test] + fn build_todo_staleness_message_fail_closed_when_behind_none() { + let path = build_todo_path(""); + let msg = build_todo_staleness_message(&path, None, &[], "master"); + let msg = msg.expect("None behind should produce fail-closed message"); + assert!(msg.contains("lineage 判定不能")); + assert!(msg.contains("fail-closed")); + }🤖 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/hooks-pre-tool-validate/src/main.rs` around lines 2187 - 2231, Add a unit test covering the new fail-closed behavior when build_todo_staleness_message is called with behind = None: create a test (e.g., build_todo_staleness_message_behind_none_returns_stale) that calls build_todo_staleness_message(&path, None, &[], "main") and asserts the result is Some(...) and that the message contains the path, the branch name ("main"), and the stale indicator (e.g., "stale parent detected"); also add a second small case with a non-empty matches vector to assert it still includes the related-implementation text (e.g., "関連既実装の可能性") when matches are present. Ensure the tests refer to build_todo_staleness_message and use the existing build_todo_path helper for the 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.
Duplicate comments:
In `@src/cli-pr-monitor/src/config.rs`:
- Around line 97-118: SweepConfig currently only provides opt-in via enabled;
add the ADR-039 required kill-switch and bounded lifetime by adding a pub(crate)
kill_switch: bool with serde default false and a pub(crate) expires_at:
Option<DateTime<Utc>> (or equivalent timestamp string) plus an is_expired(&self)
-> bool method that returns true if expires_at is Some and <= now; update
Default for SweepConfig to set kill_switch = false and expires_at = None (or a
sane default), and update the execution site that calls
sweep_empty_commits_in_pr_range to guard with the full check:
fix_config.sweep.enabled && !fix_config.sweep.kill_switch &&
!fix_config.sweep.is_expired() so the sweep runs only when enabled, not killed,
and not expired.
---
Nitpick comments:
In `@src/hooks-pre-tool-validate/src/main.rs`:
- Around line 2187-2231: Add a unit test covering the new fail-closed behavior
when build_todo_staleness_message is called with behind = None: create a test
(e.g., build_todo_staleness_message_behind_none_returns_stale) that calls
build_todo_staleness_message(&path, None, &[], "main") and asserts the result is
Some(...) and that the message contains the path, the branch name ("main"), and
the stale indicator (e.g., "stale parent detected"); also add a second small
case with a non-empty matches vector to assert it still includes the
related-implementation text (e.g., "関連既実装の可能性") when matches are present. Ensure
the tests refer to build_todo_staleness_message and use the existing
build_todo_path helper for the path.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 092c1813-d53b-4d53-bc72-9aa75c297988
📒 Files selected for processing (4)
src/cli-pr-monitor/src/config.rssrc/cli-pr-monitor/src/fix_commit.rssrc/cli-pr-monitor/src/stages/repush.rssrc/hooks-pre-tool-validate/src/main.rs
…t patterns + experimental feature checklist (#195) * docs(todo): PR #194 follow-up 6 件登録 (順位 183-188) * test(hooks): behind=None fail-closed ケースの回帰 test 追加 (PR #194 T2-#1) * test(pr-monitor): sweep revset scope + alternative branch variant tests 追加 (PR #194 T2-#2) * docs(rules): jj integration test の不変式パターンを testing.md に codify (PR #194 T2-#3) * docs(adr): ADR-043 Security/Quality Gate Fail-Closed 原則 新設 (PR #194 T3-#2) * docs(adr): ADR-021 に § Revset Composability section 追記 (PR #194 T3-#3) * docs(adr): ADR-039 § 設計チェックリスト 追加 + patterns.md experimental feature section (PR #194 T3-#1) * docs(todo): PR #194 follow-up 6 件 land に伴い todo-summary/todo10 entry 削除 * fix(review): assert_descriptions_absent_in_pr_range を default_branch 引数化 (CR Major PR #195)
本 PR は以下 4 つの作業を 1 コミットに統合: ## A. PR #196 post-merge-feedback 採用 2 件 (順位 193, 194 登録) PR #196 (Bundle 195-FB) post-merge-feedback 8 件のうち 2 件採用、6 件却下/様子見。 採用 (todo10.md に entry 追加、todo-summary.md table に行追加): - 順位 193 (T2): Companion helper group 署名整合 compile-time validation test - 順位 194 (T3): development-workflow.md \"1. Plan First\" に Codification 重複確認 step 追記 却下/様子見の詳細は .claude/feedback-reports/196.md 参照。 ## B. queue 棚卸し (順位 ≤ 100 の 32 件を audit) 8 件削除 + 7 件改訂で queue の signal/noise 改善: 削除 8 件 (既存 land 確認、または動機失効): - 順位 41 (Bundle Y2 効果定量計測): 動機の主軸失効 (Bundle Z 完成 + Z2 不採用) - 順位 42, 43, 46 (rate-limit auto-retry 系): PR #97/#113/#129/#185 段階 land 完了 - 順位 45 (--list-findings Rust モード): PR #101 で land 済 - 順位 57 (Aggregation cap integration test): PR #171 で land 済 - 順位 93 (coding-style.md partial fix 例追加): ~/.claude/rules/common/ coding-style.md に既に section 存在 - 順位 97 (with_num_ctx serialization test): lib.rs:494 で mockito test 実体存在 改訂 7 件 (Status update 2026-06-06 を front-matter に追加、現状反映): - 順位 11: ADR-018 park / ADR-030 短命プロセス移行後の再現確認が前段 - 順位 19: ADR-037/043/PR #194 land 後の残余 case baseline 観測が前段 - 順位 27: Phase D-7 = PR #154 land 済を反映 - 順位 38: ADR-031 採用昇格済 (PR #192) → Bundle W/X land のみ残依存 - 順位 40: PR #175 push-runner bookmark_check 実装済 → skill 側は二重防御に縮小 - 順位 51: 採用案 C (fix.md instruction 追加) は land 済、残作業 = dogfood 観測のみ - 順位 92: ADR-038 採用昇格済 (PR #156) で Phase d 運用入り、動機書き換え cross-reference 修復: - 順位 49: 旧依存 Bundle a Sub-PR 2 (順位 42/43/46) 消滅を反映 - 順位 61: 旧依存 順位 45 land 済を反映 ## C. todo9.md → todo11.md 分割 todo9.md が 75KB / 890 行に到達し読み取り安定性閾値 (50KB) 超過のため分割: - todo9.md (37KB / 454 行): 既存ルール仕組み化バンドル (順位 146-151) + 週次 レビュー拡張 (順位 152-154) を保持 - todo11.md (41KB / 453 行、新規): PR-specific follow-up entries 10 件 (順位 157, 160, 161, 162, 163, 165, 170, 171, 172, 173) theme-based split で意味的分離 + 両ファイルとも 50KB 閾値以下に収まる。 todo-summary.md table の file 参照を Python script で一括更新 (10 件)、 todo-summary.md 冒頭の \"追加先ファイル\" 説明を todo10.md に更新。 ## D. 順位 177 優先度引上げ PostToolUse hook ファイルサイズ検出 task が 4 回目の同型観測に到達 (PR #133 + #172 + #186 + 本セッション = Very High frequency)。CLAUDE.md code-review.md \"同型 finding の閾値判定\" (3 観測 = Tier 1 昇格) を超え systemic risk 閾値到達。 3 箇所同期更新: - todo10.md entry 本体に Status update 2026-06-06 blockquote 追加、優先度を \"Tier 1\" → \"Tier 1 (優先実装)\" に格上げ - todo-summary.md table 行で Tier 列を太字 + 注記、dependency 列に urgency note - todo-summary.md 末尾の戦略 note に \"直近優先 (2026-06-06 ユーザー指示)\" 段落を新設、Bundle 195-FB-Followup (順位 193 + 194) の次の PR で消化推奨と specific call-out ## 統計 - 10 ファイル変更 (1 新規) - ~670 lines insertions, ~910 lines deletions (net ~240 行削減) - 全 todo*.md が 50KB 閾値以下に収まる (todo9: 37KB, todo10: 36KB, todo11: 41KB) ## 参照 - .claude/feedback-reports/196.md (採否確定 commit、PR #196 由来) - memory feedback_post_merge_feedback_adoption_requires_user_approval per ユーザー承認済 - memory feedback_todo_no_history (削除は痕跡なし、コメントマーカー不使用) - ADR-035 (docs-only PR 評価ポリシー) - ADR-033 (採番管理簡素化、順位 renumber は避けて semantic markers で表現)
…除) (#199) * feat(cli-pr-monitor): PastTime newtype + proptest for parse_iso8601/from_parts (Bundle W) Bundle W (順位 34 PBT + 順位 35 PastTime newtype) を Tier 1 として独立 land。 PR #96 で実証された Finding D class (saturating_sub silent semantic mismatch) を 型層で再発不能化し、proptest で regression net を確立。 ## 順位 35: PastTime newtype src/cli-pr-monitor/src/lock.rs に PastTime { epoch_secs, captured_now } を導入。 `from_iso8601_now` / `from_parts` で「parse 成功 + then <= now」の 2 ステップを construction に閉じ込め、`age_secs()` が常に非負となる invariant を構造的に保証。 旧 `parse_age_secs(iso8601) -> Option<i64>` は削除し、`read_fresh_lock` を PastTime ベースに refactor。public API への影響なし (lock module 内 closure)。 ## 順位 34: proptest properties src/cli-pr-monitor/Cargo.toml の [dev-dependencies] に proptest = "1" を追加。 lock.rs の #[cfg(test)] mod proptests に 5 properties を記述: - P1 past_time_age_is_correct_when_in_past: then <= now で age_secs == now - then - P2 past_time_rejects_future: then > now で必ず None (Finding D 直接対応) - P3 parse_iso8601_never_panics: 任意 string で panic しない - P4 parse_iso8601_rejects_pre_epoch_year: year < 1970 を必ず reject - P5 parse_iso8601_accepts_well_formed: 有効範囲内の正規 ISO 8601 を必ず accept PastTime 単体 unit test 4 件 (accepts_past / accepts_equal / rejects_future / accepts_unix_epoch_origin / rejects_far_future_year_9999) も追加。 実行時間: cargo test -p cli-pr-monitor lock:: で 0.04s (todo4.md 完了基準 「pre-push pipeline +1 秒以内」を充足)。 ## 依存解除 Bundle W は元来「順位 19 (REJECT-ESCALATE) land 後着手」とユーザー指示があったが、 順位 19 自身が Status update 2026-06-06 で「5-10 PR baseline 観測フェーズ」に移行 した結果、Tier 1 → Tier 2 の priority inversion + 待機解除タイミング未定でデッド ロックに近い状態だった。 依存解除の根拠 (advisor 検証済): - ADR-037 (fix-trust shortcut, PR #106 land): `convergence_verdict: fully_resolved` で COMPLETE 直行 → iteration が verdict ベースで有限化、無限 loop 経路は解消済 - ADR-043 (fail-closed 原則, PR #194 land): security/quality gate の semantic を構造化 - PR #194 (mechanical gate 強化): merge 前の検証層を拡充 これにより PBT 由来の test 失敗を fix loop が処理しきれず暴走する旧懸念は解消済。 docs/todo-summary.md 順位 34 row および docs/todo4.md 順位 34 実行優先度行に 依存解除の根拠を明記。 ## scope 外 - Finding E (concurrency race): proptest は data generation には強いが thread interleaving 網羅は苦手 (todo4.md 詰まっている箇所に既記載)。Bundle X (順位 36 cargo-mutants + 順位 37 stress runner) に委譲 - 派生プロジェクト deploy 計画: Bundle W land 後の別 task として todo 登録予定 ## 完了確認 - cargo build -p cli-pr-monitor: 成功 - cargo test -p cli-pr-monitor lock::: 23 passed (proptest 5 + PastTime 4 + 既存 14) - cargo clippy -p cli-pr-monitor --all-targets -- -D warnings: clean Refs: 順位 34, 35 (todo-summary.md), todo4.md Bundle W entries * docs(todo): Bundle W (順位 34 + 35) land 完了に伴い削除
…nd で代替経路実現済、PR #194-後 8 runs で escalation 候補 0 件 PR #199 (Bundle W) session 内合意 (ユーザー指示 2026-06-07): 「A の PR マージまで進ん だら、B. 順位 19 自体の Tier 再評価 のタスク化を進める」を実行し、実測値に基づき (C) retire を決定。 ## 決定根拠 (empirical data) PR #194 (mechanical gate 強化) land 後の takt run logs を集計: | Run | iteration 上限到達 | supervise step 到達 | escalation 候補 | |---|---|---|---| | 8 runs (pre-push-review 7 + post-pr-review 1) | 0/8 | 0/8 | 0/8 | REJECT-ESCALATE が解決するはずの「iteration 上限到達 + supervise/fix_supervisor の 無限ループ」が **PR #194 land 以降 1 件も観測されていない**。代替経路で十分実用に 耐えていることが定量的に確認できた: - ADR-037 (fix-trust shortcut、PR #106 land): `convergence_verdict: fully_resolved` で COMPLETE 直行 → iteration が verdict ベースで有限化 - ADR-043 (fail-closed 原則、PR #194 land): security/quality gate semantics 構造化 - PR #194 (mechanical gate 強化): merge 前 clippy + 空 commit sweep の決定論層追加 ## 変更内容 - docs/todo3.md: 順位 19 entry block を削除 (-46 行) - docs/todo-summary.md: table から 順位 19 row を削除 (-1 行) 順位 19 を gate にしていた Tier 1 (旧 順位 34/35) は既に PR #199 で priority inversion 解除済のため、本 retire で残るブロッキングはない。 ## 関連 PR / ADR - PR #199 (Bundle W、priority inversion 解除) - ADR-037 fix-trust shortcut - ADR-043 Security/Quality Gate Fail-Closed 原則 - PR #194 mechanical gate 強化 (clippy + 空 commit sweep)
…-1/T3-2 採用 (#200) * feat(cli-docs-lint): priority_inversion validator — Tier 1→Tier 2 依存を機械検知 PR #199 (Bundle W) で実観測した「Tier N が Tier N+k に依存 + 待ち先 Tier N+k 自身が 観測フェーズ」パターンを cli-docs-lint に validator 化。決定論的検出層で Claude 判断 介入なし (`feedback_pipeline_over_rules.md` 適用)。 ## 実装 - `src/cli-docs-lint/src/priority_inversion.rs` (新規): todo-summary.md table を parse し - 順位/Tier 抽出 (`parse_row`, `parse_tier`) - 依存記述から 順位 NN 参照を抽出 (`extract_referenced_ranks`、複合 `順位 NN/MM` 対応) - 「なし」プレフィックスで context note を排除 (`has_no_dependency_prefix`) - 依存先 Tier > 自分の Tier かつ resolved-marker なしを violation 化 - `src/cli-docs-lint/src/lib.rs`: `priority_inversion` module を export - `src/cli-docs-lint/src/main.rs`: `--check priority-inversion` mode + `all` 経路統合 + help / describe_mode に追記 ## resolved-marker 設計 依存記述内で「順位 NN ... land 済 / 完了 / retired / 採用昇格済」が 80 char window 以内に現れる場合 resolved 扱い (= inversion check skip)。「land 済 (2026-06-07)」のような 日付付きマーカーや「Bundle X land 済」のような bundle-level マーカーをカバー。 ## 性能 (F-2 対応、pre-push reviewer non-blocking finding) `parse_tier` / `extract_referenced_ranks` の regex は `std::sync::LazyLock<Regex>` で module 初期化時に 1 度だけ compile (per-row 再 compile を回避)。既存 codebase の OnceLock 利用 (cli-pr-monitor) と整合する std::sync::* family。 ## テスト fixture 設計 (F-3 対応、pre-push reviewer non-blocking finding) `check_content_skips_when_referenced_rank_missing_from_table` テストの fixture を `"順位 19 land 後推奨"` (resolved-marker 非含有) に変更。missing-rank 経路を厳密に exercise する形に修正し、将来 fixture に rank 19 行を追加した際の test 経路 silent shift (missing-rank → resolved-marker) を防止。 ## prefix-match 防御 (pre-push takt-fix で auto 補正) `has_resolved_marker_after` に `c.is_ascii_digit()` ガードを追加し、`"順位 19"` が `"順位 195"` 等の prefix match で誤検出するバグを防止。専用 unit test 追加。 ## テスト & dogfood - 38 unit tests pass (priority_inversion 18 + preamble 9 + cross_ref 11) - 現 docs/todo-summary.md に対し 0 violations (false positive なし) - pnpm lint:docs OK (preamble + cross-ref + priority-inversion) ## 統合 - `pnpm lint:docs` 経由で `--check all` 実行時に自動実行 - `.claude/cli-docs-lint.exe` rebuild + deploy 済 (release profile) - ADR-039 試験運用パターン継承 (kill-switch `CLI_DOCS_LINT_DISABLE=1`、3-5 PR dogfood 後に default-ON 昇格 / 却下を判定) * docs(todo): 順位 19 (REJECT-ESCALATE) retire — ADR-037/043 + PR #194 land で代替経路実現済、PR #194-後 8 runs で escalation 候補 0 件 PR #199 (Bundle W) session 内合意 (ユーザー指示 2026-06-07): 「A の PR マージまで進ん だら、B. 順位 19 自体の Tier 再評価 のタスク化を進める」を実行し、実測値に基づき (C) retire を決定。 ## 決定根拠 (empirical data) PR #194 (mechanical gate 強化) land 後の takt run logs を集計: | Run | iteration 上限到達 | supervise step 到達 | escalation 候補 | |---|---|---|---| | 8 runs (pre-push-review 7 + post-pr-review 1) | 0/8 | 0/8 | 0/8 | REJECT-ESCALATE が解決するはずの「iteration 上限到達 + supervise/fix_supervisor の 無限ループ」が **PR #194 land 以降 1 件も観測されていない**。代替経路で十分実用に 耐えていることが定量的に確認できた: - ADR-037 (fix-trust shortcut、PR #106 land): `convergence_verdict: fully_resolved` で COMPLETE 直行 → iteration が verdict ベースで有限化 - ADR-043 (fail-closed 原則、PR #194 land): security/quality gate semantics 構造化 - PR #194 (mechanical gate 強化): merge 前 clippy + 空 commit sweep の決定論層追加 ## 変更内容 - docs/todo3.md: 順位 19 entry block を削除 (-46 行) - docs/todo-summary.md: table から 順位 19 row を削除 (-1 行) 順位 19 を gate にしていた Tier 1 (旧 順位 34/35) は既に PR #199 で priority inversion 解除済のため、本 retire で残るブロッキングはない。 ## 関連 PR / ADR - PR #199 (Bundle W、priority inversion 解除) - ADR-037 fix-trust shortcut - ADR-043 Security/Quality Gate Fail-Closed 原則 - PR #194 mechanical gate 強化 (clippy + 空 commit sweep) * docs(todo): post-merge-feedback T2-1/T3-2 採用 — 順位 197/198 追加 PR #199 (Bundle W) の post-merge-feedback report (.claude/feedback-reports/199.md) で analyzer が ✅ 採用候補とした 2 件を、ユーザー承認 (2026-06-08) を経て docs/todo*.md 系列に登録する。 ## 順位 197: hooks-session-start orphan age 計算に proptest 追加 (T2-1) Bundle W (PR #199) で `cli-pr-monitor::lock` に PastTime newtype + proptest properties を 導入し、`saturating_sub` silent semantic mismatch (Finding D) を構造的に排除した。 同じ bug class が `src/hooks-session-start/src/main.rs:236` の orphan age 計算 (`now_unix.saturating_sub(start_unix)`) にも存在し、clock rewind / future timestamp で age=0 → orphan reaper が「young」判定でスキップ → `.failed` marker 未生成 → ADR-030 L2 recovery 停止という具体的 failure chain が確認済。Bundle W の pattern を hooks-session-start に展開する。 - Tier 2 / Effort M / Severity High / Frequency Medium / Adoption Risk None - proptest 1.x は既存 dev-dependencies、新規依存追加は hooks-session-start のみ ## 順位 198: ADR-NNN Timestamp invariant safety (T3-2) PR #96 Finding D + PR #199 Bundle W で同型 bug class が 2 件観測 (Frequency Medium)。 「時刻計算における silent failure class と型レベル防御」を永続化し、派生プロジェクト (techbook-ledger / auto-review-fix-vc) への transferability を確保する ADR を新設。 - Tier 3 / Effort M / Severity Medium / Frequency Medium / Adoption Risk None - 順位 135 codified placeholder policy 適用 (ADR 番号は land 時 PR で確定) - CLAUDE.md ADR list 追記 ## 変更ファイル - docs/todo10.md: 順位 197/198 詳細 entry を 2 セクション追加 - docs/todo-summary.md: table に順位 197/198 行を追加 * fix(cli-docs-lint): priority_inversion の resolved-marker window を char-based 化 (CR Major #1) PR #200 CodeRabbit review で指摘された Major finding を修正。 ## Bug `has_resolved_marker_after` の window 計算が以下の 2 点で spec とズレていた: 1. **byte vs char**: `(abs_pos + RESOLUTION_WINDOW_CHARS)` は **byte** 演算。日本語 1 文字 = 3 bytes なので「80 文字 window」のつもりが実質 ~27 文字 window に縮退 2. **window 開始位置**: `&haystack[abs_pos..]` で needle (順位 NN) 自体を window に含めていた。 spec は「順位参照の **直後** から N 文字以内」 具体 failure 例 (CR review 提示): - `"順位 19" + "あ"*40 + " land 済"` で、marker "land 済" は char-distance 41 (window 80 内) - 旧 byte-based: 80 bytes window は ~26 chars のみカバー → marker 圏外 → resolved 扱いされず → **false negative (= inversion 誤検出 → reviewer に noise)** ## Fix ```rust let window_end = haystack[after..] .char_indices() .nth(RESOLUTION_WINDOW_CHARS) .map(|(i, _)| after + i) .unwrap_or(haystack.len()); let window = &haystack[after..window_end]; ``` - 起点を `after` (needle 直後) に変更 - `char_indices().nth(N)` で N 文字目の byte offset を取得 → char-based window 不要になった `next_char_boundary` ヘルパー関数を削除。 ## Test regression test 追加 (`is_resolved_detects_marker_across_multibyte_gap`): - `"順位 19" + "あ".repeat(40) + " land 済"` で resolved 判定が true になることを assert - 旧実装ではこの test は fail する (byte window で marker 圏外) ## Doc update `RESOLUTION_WINDOW_CHARS` の doc に「**文字数** (バイト数ではない)」を明記。 multi-byte でも spec 通り動作することを comment で保証。 ## 検証 - cargo test -p cli-docs-lint: 19 priority_inversion tests pass (新規 regression 1 含む) - cargo clippy -p cli-docs-lint --all-targets -- -D warnings: clean - pnpm lint:docs: OK (preamble + cross-ref + priority-inversion) - .claude/cli-docs-lint.exe rebuild + deploy 済 Refs: CR comment on PR #200 (src/cli-docs-lint/src/priority_inversion.rs:182)
Summary
cargo clippy --workspace -- -D warningsを[stop_quality]+[quality_gate]に追加し Rust lint structural gap を補填execute_repush_flow末尾でmaster..@範囲の空 commit を sweep してjj abandon(kqvluqyv事例の構造的予防)feedback_minimize_pr_count_during_rate_limit適用)Why
stop_qualityはpnpm lint/pnpm lint:md/pnpm test/pnpm buildのみで Rust の cargo clippy が完全欠落しており、PR feat: Bundle CR-RL — CR rate-limit detection を新フォーマット対応に拡張 (順位 167-169) + 174 #185 開発時にdoc_lazy_continuationclippy error が手動実行まで未検出だった structural gap。本 PR 自身が dogfood として 5 件の pre-existing errors を land 前に検出。try_abandon_empty_fix_commitは tracked な単一 fix commit のみ対象。PR feat(cli-push-runner): Bundle 1 — 順位 1 scratch file warning hook + 順位 116/134 docs + 順位 8 planning #174 で観測した granduncle 位置のkqvluqyvのような untracked 空 commit を見逃し、次回 push で PR diff を汚染した構造的欠陥。master..@範囲を網羅 sweep する補完層を追加。Changes
Phase 1 — 既存 clippy errors 修正 (順位 175 の前提)
src/hooks-pre-tool-validate/src/main.rs:if behind.is_none() { return None; }→behind?;src/cli-push-runner/src/stages/scratch_file_warning.rs: doc list 段落区切り (doc_lazy_continuation×3)src/cli-push-runner/src/stages/scratch_file_warning.rs:name.strip_prefix(prefix)(manual_strip)Phase 2 — 順位 175: cargo clippy mechanical gate
.claude/hooks-config.toml:[stop_quality]にlint:ruststep 追加push-runner-config.toml:[quality_gate.groups]のrust-test→rust-lint-testrename し clippy を先頭追加 (cargo target dir のロック衝突回避のため同 group 統合)Phase 3 — 順位 155: 範囲 sweep
src/cli-pr-monitor/src/fix_commit.rs:sweep_empty_commits_in_pr_range()新規 +parse_empty_change_ids()pure helpersrc/cli-pr-monitor/src/stages/repush.rs:execute_repush_flow末尾で sweep 呼び出しdocs cleanup (2 commit 構成)
docs/todo10.md/docs/todo9.md/docs/todo-summary.md: 順位 175 + 155 完了 entry 削除 (memoryfeedback_todo_no_history適用)設計判断 (sweep 配置)
execute_repush_flow内で sweep を呼ぶ位置として 3 案を検討:match actionの 前: 現 iteration の push 前に sweep → AutoPush の場合も remote が cleanmatch actionの 中 (CleanupEmptyFixCommit と統合): tracked と untracked を統一処理match actionの 後 (採用): 既存 behavior を完全保護、追加的 sweep として動作案 3 採用理由: 既存
try_abandon_empty_fix_commitはreparent_at_to_pr_tipを含む丁寧な cleanup を行うため、sweep を先に走らせて @ を動かすと既存ロジックが [warn] でスキップされ reparent が機能しなくなる。1 iteration 遅れ で次回 push 前に清掃されるトレードオフを受け入れ、現 iteration の既存 flow を保護する。Test plan
cargo clippy --workspace -- -D warnings: pass (本 PR が pre-existing 5 件を修正)cargo test --workspace: 1200+ unit tests pass, 0 failedcargo test -- --ignored integration_sweep: 2/2 pass (jj 実依存、PR feat(cli-push-runner): Bundle 1 — 順位 1 scratch file warning hook + 順位 116/134 docs + 順位 8 planning #174kqvluqyv事例の最小再現で動作実証)pnpm build:all: 14 exes 全 release build 成功lint:ruststep が stop hook で発火するか / sweep が PR diff 汚染を防ぐかBundle 内 dogfood 観測
本 PR の Edit 中に
hooks-post-tool-comment-lint-rustが 3 回発火 (コメント禁止 7 件 + 関数長 50 行超過 3 件) し、設計修正 (コメント削除 + helper 抽出) を Claude 自身が即座に対応。順位 175 の clippy gate と同じ Bundle Z #B-α 決定論層 family の mechanical enforcement が land 前のセッション内で機能した実例。Summary by CodeRabbit
新機能
改善
変更
テスト