Skip to content

feat(hooks-pre-tool-validate): jj-message-required preset で jj new / jj split の -m 必須化 (順位 144)#172

Merged
aloekun merged 5 commits into
masterfrom
feat-jj-message-required-hook
May 25, 2026
Merged

feat(hooks-pre-tool-validate): jj-message-required preset で jj new / jj split の -m 必須化 (順位 144)#172
aloekun merged 5 commits into
masterfrom
feat-jj-message-required-hook

Conversation

@aloekun
Copy link
Copy Markdown
Owner

@aloekun aloekun commented May 25, 2026

Summary

順位 144 (PR #171 T3-#8 採用) 単独実装。PreToolUse hook で jj new / jj split-m / --message 引数なし呼び出しを mechanical に block し、混合 commit 事故 + jj split editor hang を構造的に防止する。

Background

PR #171 セッションで jj new 忘れにより 順位 57 commit と 順位 91 commit の変更が混入する事故が発生 (後で jj split -m で recovery 済)。post-merge-feedback の analyzer 原案は ~/.claude/rules/common/git-workflow.md への docs 化だったが、feedback_no_unenforced_rules.md 適用でユーザー判断 hook による mechanical enforcement に方針変更 (2026-05-24 セッション、feedback_pipeline_over_rules.md 適用)。

Design

  • BlockedPattern 構造体拡張: exception: Option<Regex> field 追加 (Rust 標準 regex crate が negative lookahead 非対応のため 2 段判定で実装)
  • validate_command ロジック拡張: pattern match 後、exception regex が hit すれば continue で allow
  • 新 preset jj-message-required:
    • block pattern: (?im)(^|&&|;|\|\||\||&|\n)\s*(?:[A-Za-z_][A-Za-z0-9_]*=\S+\s+|command\s+|env\s+)*jj\s+(new|split)\b
    • exception regex: \s(-m|--message)\b
  • opt-in preset: default fallback には含めず、hooks-config.toml で明示有効化 (派生プロジェクト breaking change リスク軽減)

設計判断 (ユーザー承認済 2026-05-24)

  • A: jj new 引数なしも block (= -m を強制)
  • B: jj new <revision> (例: jj new master) で -m なしも block
  • C: jj split interactive (= -m なし) は editor hang issue があるため strong block
  • D: scope は jj 直接呼び出しのみ (pnpm jj-new 等のラッパーは scope 外)

Commits

  1. tk docs(todo): 順位 143 + 144 新規追加 (Bundle 171 entry 登録)
  2. yv refactor: BlockedPattern に exception field 追加 (Phase 1)
  3. ut feat: jj-message-required preset 追加 (Phase 2)
  4. ko test: block/allow/non-regression test 拡充 (Phase 3)
  5. uq chore: build + deploy exe + 順位 144 entry 削除 (Phase 4)

Test plan

  • cargo test -p hooks-pre-tool-validate: 158 pass (14 新規 test、既存 144 件 regression なし)
  • dogfood: .claude/hooks-pre-tool-validate.exe 直接 stdin 投入で確認
    • jj new → exit 2 + 修正手順 feedback ✅
    • jj new -m "WIP" → exit 0 (allow) ✅
  • AI review (takt pre-push-review): simplicity APPROVE + security APPROVE (1 iteration)

関連

Out of scope

  • 派生プロジェクト (techbook-ledger / auto-review-fix-vc) への deploy は本リポジトリ先行 dogfood 後判断 (memory feedback_dogfood_evals_two_phase.md 適用)
  • pnpm jj-new 等の wrapper 経由は scope D により対象外 (設計判断確定)

Summary by CodeRabbit

リリースノート

  • 新機能

    • jj new / jj split コマンドでメッセージ指定を必須化するプリセット「jj-message-required」を追加しました
    • ブロックパターンに例外ルールを設定できる機能を実装しました
  • テスト

    • 新プリセット・例外ルール機能に関する複数のテストケースを追加しました
  • ドキュメント

    • タスク追跡ドキュメントを更新しました

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 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: 5ce0c32a-75b4-4dea-a04d-1ac9b219bad0

📥 Commits

Reviewing files that changed from the base of the PR and between 51328e8 and 122b378.

📒 Files selected for processing (4)
  • .claude/hooks-config.toml
  • docs/todo-summary.md
  • docs/todo8.md
  • src/hooks-pre-tool-validate/src/main.rs

📝 Walkthrough

Walkthrough

BlockedPattern 型に exception フィールドを追加し、パターンマッチ後の条件付き許可ロジックを実装。新プリセット jj-message-required を導入して -m/--message オプション未指定時のコマンドをブロック。プリセット解決ロジックを関数分割で整理し、コンフィグ有効化とドキュメント更新を実施。

Changes

jj-message-required プリセット実装とドキュメント更新

Layer / File(s) Summary
BlockedPattern 型定義と既存プリセット初期化
src/hooks-pre-tool-validate/src/main.rs
BlockedPatternexception: Option<Regex> フィールドを追加。全既存プリセット(default、git、jj系、electron、jj-push、gh系、polling)の初期化に exception: None を明示的に付与し、従来のブロック動作を維持しながら新例外判定機構に対応。
プリセット解決ロジックのリファクタリング
src/hooks-pre-tool-validate/src/main.rs
プリセット構築を default_preset_namesresolve_preset_or_customcustom_regex_pattern へ関数分割。flat_map ベースで整理し、validate_command に exception マッチ時の許可分岐を追加。カスタム正規表現無効時は警告出力。
jj-message-required プリセットのテスト
src/hooks-pre-tool-validate/src/main.rs
空の jj new、revision指定、jj split、複合コマンド(&&、改行)、-m/--message 指定時の許可、jj-main-guard 併用時の挙動、対象外サブコマンドと pnpm ラッパー除外を検証。デフォルトフォールバック非含有(opt-in)を確認。
コンフィグ有効化とドキュメント更新
.claude/hooks-config.toml, docs/todo-summary.md, docs/todo8.md
.claude/hooks-config.tomljj-message-requiredblocked_patterns 配列に追加。コメントで -m/--message 未指定ブロックの意図を説明。docs/todo-summary.md と docs/todo8.md に複言語 fixture helper 標準化タスク(PR #171 T2-#4)を追加し、UTF-8マルチバイト向け helper API、配置方針、リファクタ計画、完了基準を記載。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • aloekun/claude-code-hook-test#27: src/hooks-pre-tool-validate/src/main.rsBlockedPattern プリセット追加と build_blocked_patterns/ブロック判定フロー拡張で、同じプリセット実装仕組みを共有。

  • aloekun/claude-code-hook-test#166: src/hooks-pre-tool-validate/src/main.rspre_tool_validate ブロック用プリセット追加・解決ロジック拡張で、同じプリセット登録フロー経路を使用。

  • aloekun/claude-code-hook-test#13: src/hooks-pre-tool-validate/src/main.rsBlockedPattern プリセット選択・テスト更新で、同じ「コマンドブロック用プリセット拡張」コード経路が関連。

🚥 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 プルリクエストのタイトルは、変更の主要な内容である「jj-message-required preset による jj new / jj split の -m 必須化」を正確に反映しており、簡潔で明確です。
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

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

@aloekun aloekun merged commit a6670c7 into master May 25, 2026
1 check passed
@aloekun aloekun deleted the feat-jj-message-required-hook branch May 25, 2026 05:12
aloekun added a commit that referenced this pull request May 25, 2026
* docs(adr): ADR-042 ルール vs 仕組み化の境界基準 — 試験運用 ADR 新設 + CLAUDE.md ADR list 追加

* docs(todo): 仕組み化方針切替 — todo9.md 新設 + 順位 142/143/144/145 + 146-151 追加 + 順位 44/61 hook 化転換 + 122→136 統合 (Bundle 既存ルール仕組み化)

PR #172 (順位 144 = jj-message-required hook) の dogfood 成功を受けた仕組み化方針切替に関する一連の todo system 更新:

- 順位 142 entry 追加 (PR #170 T3-#1 採用 ADR-041 補強 State Preservation Invariant pattern)
- 順位 143/144 entry 追加 (PR #171 post-merge-feedback Bundle 171 = 複言語 fixture helper + jj-message-required hook)
- 順位 145 entry 追加 (PR #172 T2-#1 採用 preset matrix test)
- 順位 146-151 entry 新規追加 (既存ルール仕組み化バンドル: secret detection / file length lint / test coverage CI gate / subprocess pipe truncate hook 拡張 / magic number lint / PR diff lines check)
- 順位 44 (gh CLI 使用規則) を docs 追記から PreToolUse hook 化方針に転換
- 順位 61 (CR review.body 手動 scan) を docs 追記から check-ci-coderabbit CLI 拡張方針に転換
- 順位 122 (新 todo 着手前の既実装確認) を 順位 136 (working copy staleness hook) に統合
- todo9.md 新設 (todo8.md 50KB 接近のため、新規追加先を todo9.md に移行)
- todo-summary.md 更新方針 + table 更新 + Bundle 171 タグ整備

memory rule `feedback_pipeline_over_rules.md` 適用 = rule docs → mechanism shift の体系的記録。

* chore(todo): land 済 entry 削除 + bundle-history 分離 (size 50KB 超過解消)
aloekun added a commit that referenced this pull request Jun 6, 2026
本 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 で表現)
aloekun added a commit that referenced this pull request Jun 6, 2026
…順位 177) (#198)

PostToolUse Edit / Write 直後にファイルサイズ閾値超過を検出して分割を促す mechanical layer
を実装。ファイル分割を user 判断ベース → mechanical layer に移管し、認知負荷削減 + 早期検出
を実現する。

## 背景

4 PR の同型観測 (Very High frequency) で systemic risk 閾値到達:
- PR #133: todo.md → todo2.md split
- PR #172: todo8.md → todo9.md split
- PR #186: todo9.md → todo10.md split
- PR #197: todo9.md → todo11.md split (本日 land)

順位 177 として todo10.md に登録済み、PR #197 で Tier 1 (優先実装) に格上げ。
ユーザー指示 (2026-06-07) で次の PR で消化と決定。

## 設計

配置: option B = 既存 hooks-post-tool-linter (generic linter) に Layer 0.5 として統合。
option A (新 binary) に対する優位性:
- 新 binary 追加なし → deploy 簡素 (Effort S 寄り)
- PostToolUse hook 数の最小化 (1 PR push で発火する hook 数を抑制)
- ADR-039 bounded lifetime dogfood サイクルを最短で開始可能

## 実装

### Layer 0.5 配置

main() を 4 layer helper に refactor (関数長 50 行制限内に収まる構造):
- Layer 0: UTF-8 整合性 (既存)
- Layer 0.5: file_size_check (新規、metadata-only) ★
- Layer 1: 正規表現 custom-rules (既存)
- Layer 2: 外部ツール pipeline (既存)

### Config schema

[post_tool_use.file_size_check] section (ADR-039 opt-in pattern 準拠):
- enabled = false (default OFF)
- threshold_bytes = 51200 (50KB、Claude Code 読み取り安定性閾値)
- paths = ["docs/**/*.md", "src/**/*.rs"] (default 対象 glob)
- touch_trigger = true (ratchet、既存超過は触られるまで grandfather)

Kill-switch: enabled = false で完全停止。

### Pure function design

check_file_size_threshold(file, size_bytes, config) は I/O フリーの純粋関数として実装、
file system access は呼び出し側 (run_file_size_layer) に分離。tests が deterministic に
書け、memory feedback_test_dry_antipattern に従い各 variant 独立 setup が trivial。

### touch_trigger ratchet の MVP 制限

touch_trigger = false (strict mode = 全 enabled paths を毎回スキャン) は ADR-039 bounded
lifetime dogfood 後の判定に倒し、MVP では config field 受理のみ (true/false 同挙動)。
3-5 PR の dogfood 観測後に default-ON 昇格 or strict mode 実装 or 却下を判定。

## ADR-007 amendment (Layer 0.5 追記)

ADR-007 § Layer 0.5 追記 section を新設し、file_size_check が Q1/Q2/Q3 判断フロー対象外
であることを codify。同型 (metadata-only、content 非依存) の future check は同 Layer 0.5
に追加することで regex / AST 層との責務境界を維持する原則を明文化。

## Tests

8 variant 独立 setup (memory feedback_test_dry_antipattern 適用):
1. enabled=false で短絡 (kill-switch 動作確認)
2. paths glob 不一致で skip
3. size 閾値内で skip
4. size 超過で feedback emit
5. docs/todo* に対する recovery hint 文脈別出し分け
6. paths が空配列の場合 skip
7. touch_trigger=false が MVP では true と同挙動
8. Windows backslash path の forward-slash 正規化

全 8 test pass、既存 141 test との non-regression 確認済 (cargo test 149/149 passed)。
cargo clippy --workspace -- -D warnings clean。

## Dogfood

threshold=30720 で hooks-config.toml を temporarily enable、docs/todo10.md (38155 bytes)
に hook 発火を実観測:
[file-size-check] docs/todo10.md: ファイルサイズ 38155 bytes が threshold 30720 bytes
(= 30.0 KB) を超過しています。ファイル分割を推奨します (docs/todo*.md の場合は新
todo<N+1>.md を新設して entry を移管).

小ファイル (docs/todo5.md 11909 bytes) は no-op を確認。dogfood 後 enabled=false /
threshold=51200 に revert 済 (production default = opt-in).

## 関連 docs 更新

- docs/todo10.md: 順位 177 entry 削除 (実装完了)
- docs/todo-summary.md: 順位 177 table 行 + 「直近優先 2026-06-07」call-out 段落 削除
- docs/adr/adr-007-custom-linter-layer-boundary.md: § Layer 0.5 追記 新設

## 参照

- memory feedback_pipeline_over_rules: rule → hook 切替の体系適用
- ADR-039: experimental feature 標準パターン (opt-in + kill-switch + bounded lifetime)
- ADR-007: custom-linter layer boundary (本 PR で Layer 0.5 追記)
- 順位 102 (PR #148 land): paths glob filter helper を再利用
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