Skip to content

feat(hooks-post-tool-linter): paths filter + Phase D 初 real lint_screen dogfood (順位 102)#148

Merged
aloekun merged 1 commit into
masterfrom
d-3-paths-filter
May 12, 2026
Merged

feat(hooks-post-tool-linter): paths filter + Phase D 初 real lint_screen dogfood (順位 102)#148
aloekun merged 1 commit into
masterfrom
d-3-paths-filter

Conversation

@aloekun
Copy link
Copy Markdown
Owner

@aloekun aloekun commented May 12, 2026

Summary

Phase D D-3 = 順位 102 (paths filter を lint runner に実装) を land し、Phase D 初の real lint_screen dogfood metrics を観測。順位 115 (PR #147LINT_SCREEN_ENABLED env var override) land 後の最初の dogfood subject。

実装

  • globset 0.4 を依存追加 (BurntSushi 製、ripgrep の依存と同じ)
  • CustomRule::paths: Option<Vec<String>> 追加 (optional、既存 rule に影響なし)
  • CompiledRulepaths_glob: Option<GlobSet> を cache (repeated compile 回避)
  • compile_paths_glob() helper: None / Some(empty)None (filter なし)、glob valid → Some(GlobSet)、invalid → Err (rule drop)
  • rule_matches_path() helper: paths_glob None なら全 path 受容、Some なら GlobSet match で判定。Windows backslash path も / に normalize
  • run_custom_rulesextensions × pathsAND 結合 (両方マッチで rule 対象)
  • 関数長 50 行制限維持のため build_violation_json / collect_violations_for_rule に切り出し
  • CustomRule doc comment の planned: pathssupported: paths に更新

unit test 7 件

  • paths_filter_none_accepts_any_path / _empty_vec_accepts_any_path / _recursive_glob_matches_docs_only / _normalizes_windows_separators / _multiple_globs_or_semantics / _invalid_glob_drops_rule / run_custom_rules_extensions_and_paths_are_anded

意図的保留 (順位 118 として todo 化)

rule⑧ への paths = ["docs/**/*.md"] migration は当初計画していたが、D-2 (PR #146、順位 101) で追加した「root-level MD (CLAUDE.md / README.md) からの ../docs/ fire = true positive」design intent が scope narrow で壊れるため 保留。trade-off 検討 (保留継続 / broader glob / explicit list / rule split の 4 案) は順位 118 で別途実施。

★ Phase D 初の real lint_screen dogfood metrics

LINT_SCREEN_ENABLED=true env override で push pipeline 経由 lint_screen を起動。.takt/lint-screen-report.md に以下を観測:

Metric 観測値
screen_decision auto_fix
findings 件数 1 (minor severity)
finding 内容 unused-import rule、src/hooks-post-tool-linter/Cargo.toml:12globset を unused と誤検出
finding accuracy false positive (takt reviewer が「main.rs で全 symbol 使用済」と diff verification で dismiss)
fallback_reason なし (clean run、JSON parse error 無し)
## Diagnostic section 不在 = num_ctx 32768 で overflow 発生せず
lint_screen latency 推定 ~80-120s (pipeline 総 628s から takt 248s + その他を控除)
kill-switch (fallback > 50%) fallback 0/1 = 0% → 基準内 (Phase D guide §3)

観測の意義

  1. env override 経路の実証: PR feat(cli-push-runner): LINT_SCREEN_ENABLED env var override (順位 115) #147 で実装した LINT_SCREEN_ENABLED env var で [lint_screen] enabled = false (TOML default) を override し、commit-free な session opt-in が成立
  2. num_ctx 32768 の容量実証: ~270 line Rust diff (Cargo.toml + main.rs + Cargo.lock + docs) を overflow せず完走、Phase A 診断 log も emit せず
  3. lint_screen が takt reviewer の context として活用: reviewer 出力に「Lint-screen finding: false positive」と明示的に評価あり = advisory consumption が成立
  4. 1 false positive は Phase b' agreement 75% (= 25% disagreement) と整合: 想定範囲内、Phase E 採否判定では複数 PR 累積で評価

Phase E 判定材料 (本 PR で確定したデータ)

diff stat

ファイル 行数
src/hooks-post-tool-linter/Cargo.toml (globset = 0.4) +3
src/hooks-post-tool-linter/src/main.rs (paths field + helpers + 7 tests) +308 / -83
.claude/custom-lint-rules.toml (rule⑧ コメント更新、migration 保留 rationale) +10 / -3
Cargo.lock (globset transitive deps) +24
docs/local-llm-offload-analysis.md (Phase D D-3 状態) +1 / -1
docs/todo-summary.md (順位 102 削除 + 順位 118 追加) +1 / -1
docs/todo6.md (順位 102 entry 削除) -33
docs/todo8.md (順位 118 entry 追加) +27
合計 8 files, +375 / -121 ≒ 496 line changes

Test plan

  • cargo test -p hooks-post-tool-linter (102 tests pass、新規 7 + 既存 95、ZERO regression)
  • markdownlint (0 error) — analysis.md / todo*.md
  • takt pre-push-review APPROVE (2 iter、reviewer の build_violation_json doc comment carry-over 1 件を fix で解消後 2 回目 APPROVE)
  • ★ Phase D 初の real lint_screen dogfood metrics 観測 (本 PR 上記参照)
  • cli-push-runner.exe + hooks-post-tool-linter.exe を rebuild + deploy (env override + paths feature を deployed exe に反映)
  • CodeRabbit review (PR 作成後の自動 trigger)
  • (将来) 複数 PR 累積観測で Phase E 採否判定

関連

🤖 Generated with Claude Code

Summary by CodeRabbit

リリース ノート

  • 新機能

    • カスタム lint ルールにグロブベースのパスフィルタリング機能を追加しました。
  • ドキュメント

    • ルール設定および実装計画ドキュメントを更新しました。
    • パスフィルタリングの適用範囲検討をフォローアップタスクとして追加しました。

Review Change Stack

…hase D D-3)

PR #140 post-merge-feedback Tier 1 #2 採用。lint runner に glob ベースの paths filter
を追加し、path-sensitive な lint rule を explicit filter で表現可能にする。

実装 (src/hooks-post-tool-linter/src/main.rs + Cargo.toml):
  - globset = 0.4 を依存追加 (BurntSushi 製、ripgrep の依存と同じ)
  - CustomRule::paths: Option<Vec<String>> field 追加 (optional、既存 rule に影響なし)
  - CompiledRule に paths_glob: Option<GlobSet> を cache (lint 実行時の repeated compile を回避)
  - compile_paths_glob() helper: None / Some(empty) → None (filter なし)、glob valid → Some(GlobSet)、invalid → Err (rule drop)
  - rule_matches_path() helper: paths_glob None なら全 path 受容、Some なら GlobSet match で判定
  - Windows-style backslash path も  に normalize して match
  - run_custom_rules で extensions × paths を AND 結合 (両方マッチで rule 対象)
  - 関数長 50 行制限維持のため build_violation_json / collect_violations_for_rule に切り出し
  - CustomRule doc comment の planned: paths → supported: paths に更新

unit test 7 件追加:
  - paths_filter_none_accepts_any_path
  - paths_filter_empty_vec_accepts_any_path
  - paths_filter_recursive_glob_matches_docs_only
  - paths_filter_normalizes_windows_separators
  - paths_filter_multiple_globs_or_semantics
  - paths_filter_invalid_glob_drops_rule
  - run_custom_rules_extensions_and_paths_are_anded (AND 結合 E2E)

意図的保留 (順位 118 として todo 化):
  - rule⑧ への paths = ["docs/**/*.md"] migration は当初計画していたが、D-2 (順位 101)
    で追加した root-level MD (CLAUDE.md / README.md) からの ../docs/ fire 挙動が
    scope narrow で壊れるため保留。trade-off 検討は別 PR に分離。

cargo test pass: hooks-post-tool-linter 102 tests (新規 7 + 既存 95、ZERO regression)。

Phase D D-3: 順位 115 (PR #147) land 後の **初の real lint_screen dogfood**。
LINT_SCREEN_ENABLED=true 経路で push pipeline 経由 lint_screen を実行し、metrics
(screen_decision / findings / fallback_reason / Diagnostic section / latency) を観測。
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 12, 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: 6070e3e8-8d5f-45c2-9b2a-6e30ccf0cdf2

📥 Commits

Reviewing files that changed from the base of the PR and between fbe6a18 and 04f5b6a.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • .claude/custom-lint-rules.toml
  • docs/local-llm-offload-analysis.md
  • docs/todo-summary.md
  • docs/todo6.md
  • docs/todo8.md
  • src/hooks-post-tool-linter/Cargo.toml
  • src/hooks-post-tool-linter/src/main.rs
💤 Files with no reviewable changes (1)
  • docs/todo6.md

📝 Walkthrough

Walkthrough

このプルリクエストは、custom lint rules に glob ベースの paths フィルタリング機能を実装します。GlobSet 依存関係を追加し、CustomRule スキーマを拡張、rule マッチロジックに path 条件を統合、包括的な unit test を追加。Rule⑧への paths 適用は意図的に保留し follow-up タスクに分離します。

Changes

Glob ベースのパスフィルタリング実装

Layer / File(s) Summary
依存関係と CustomRule スキーマ拡張
src/hooks-post-tool-linter/Cargo.toml, src/hooks-post-tool-linter/src/main.rs
GlobSet v0.4 依存関係を追加。CustomRule 構造体に paths: Option<Vec<String>> フィールドを実装。In-file ドキュメントで optional paths フィールドの glob 構文と extension との AND セマンティクスを説明。
Glob コンパイル・パスマッチング・violation 構築
src/hooks-post-tool-linter/src/main.rs
compile_paths_glob で paths を GlobSet にコンパイル(None/empty を"フィルタなし"として扱い、invalid glob は rule をコンパイル時に排除)。rule_matches_path で Windows \/ に正規化してから glob 評価。build_violation_json で regex マッチから 1-indexed line number を計算し、構造化された LintViolation を生成。run_custom_rules で extension × paths を AND で結合。
Test ヘルパーと path フィルタ検証
src/hooks-post-tool-linter/src/main.rs
make_test_rule_with_paths test helper を追加。7 個の focused unit test で paths=None、空リスト、再帰的 glob、Windows バックスラッシュ正規化、複数 glob の OR、invalid glob 排除、extension × paths AND セマンティクスを検証。
Rule⑧ デザイン意思と task tracking
.claude/custom-lint-rules.toml, docs/todo-summary.md, docs/todo6.md, docs/todo8.md, docs/local-llm-offload-analysis.md
Rule⑧ に paths フィルタを適用しない設計方針を文書化(root-level MD の ../docs/ 参照を true positive として扱うため、scope narrow による検出不能を避ける)。Path filter 実装タスク(順位 102)を削除し、rule⑧ paths 適用範囲検討フォローアップ(順位 118)を追加。Phase D - D-3 の作業内訳を「glob filter helper と 7 unit tests」に更新。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • aloekun/claude-code-hook-test#146: CustomRule paths フィールドと Markdown エッジケースに関するドキュメント・テストを追加し、本 PR の paths 実装(glob フィルタリング、GlobSet 依存、テスト拡張)の基盤を整備。
  • aloekun/claude-code-hook-test#6: PR #6 で導入された hooks-post-tool-linter custom-lint エンジンを本 PR で拡張(optional glob ベースの paths フィルタリング、GlobSet 依存、関連 test・violation ヘルパー)。
  • aloekun/claude-code-hook-test#140: PR #140 で追加された no-docs-relative-back-to-docs rule のロジック(regex マッチング、violation 報告)が本 PR の paths フィルタ統合・refactoring の対象となり、extension × paths AND セマンティクスで影響。
🚥 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 タイトルは主要な変更(hooks-post-tool-linter への paths filter 実装と Phase D 初 real lint_screen dogfood)を明確に要約しており、変更セット全体の目的と一致しています。
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 f6c12cd into master May 12, 2026
1 check passed
@aloekun aloekun deleted the d-3-paths-filter branch May 12, 2026 14:03
aloekun added a commit that referenced this pull request May 12, 2026
…D 完遂状況反映 (#149)

PR #148 (D-3 = paths filter + 初 real lint_screen dogfood) merge 後の post-merge-feedback で
採用された Tier 2-1 を todo 系列に登録 + analysis.md の Phase D section を完遂状況に更新。

順位 119 (PR #148 T2-#1 採用、Tier 2 / Effort S):
  - MAX_CUSTOM_VIOLATIONS outer/inner loop break scope を explicit test で seal
  - PR #148 で発見した bug fix (inner break が outer に伝播しない問題) を test net で保護
  - takt reviewer が 'Behavioral change: improvement' と評価した動作を regression 防止

analysis.md Phase D section 更新:
  - 見出し: '🔄 進行中' → '✅ 計画完遂 2026-05-12'
  - PR 構成 table: 順位 115 (PR #147) / D-3 (PR #148) を land 済に更新
  - D-3 dogfood outcome table (7 metrics) を新規追加 = screen_decision auto_fix /
    findings 1 (false positive) / fallback_reason なし / Diagnostic 不在 / latency 推定
    80-120s / kill-switch 0% (基準内)
  - D-3 観測の意義 5 項目 (env override 実証 / num_ctx 32768 容量実証 / advisory
    consumption 成立 / Phase b' agreement 整合 / 順位 118/119 副産物)
  - Phase E 判定材料 (✅ 4 / ⚠️ 1 / ⏳ 1) と着手前提 (3-5 PR 累積、D-3 で 1/N 取得済) を追記

Phase E (採否判定 + retirement) は別セッションで実施予定 (本 PR は計画完遂 land のみ)。
aloekun added a commit that referenced this pull request May 13, 2026
* docs(todo,analysis): D-4 を 順位 39 に re-pivot + stale 順位 47 entry 削除

順位 47 (>vs>= boundary lint) は PR #126 (commit b677b9d, 2026-05-08) で
no-time-field-strict-greater rule として既に land 済 (custom-lint-rules.toml
line 208-243) を D-4 着手前検証で発見。memory rule feedback_verify_task_not_already_done
を適用して stale todo entry を削除し、D-4 を Round 2 計画から 順位 39 (takt workflow
`model` 必須化 lint rule) に繰上げ、D-5 を 順位 56 + 119 bundle に再構成。

変更:
- docs/local-llm-offload-analysis.md: D-4/D-5 row 更新 + 想定リスク に re-pivot 経緯追記
- docs/todo7.md: stale 順位 47 entry (38 行) 削除
- docs/todo-summary.md: 順位 47 row 削除

Phase E 着手前提 (5 PR 累積 dogfood) は変わらず、D-4〜D-7 で 4 PR 追加観測の方針継続。

* feat(hooks-post-tool-linter): takt-workflow-persona-without-model lint rule (順位 39 / Phase D D-4)

PR #98 post-merge-feedback Tier 1 #1 採用。takt workflow yaml で persona: を持つ step
に model: 未指定の場合を検出する custom lint rule (ルール⑨)。Bundle Z #B-α と同じ
決定論的防止層 (ADR-007 正規表現層)。

実装:
- .claude/custom-lint-rules.toml: 新規 rule takt-workflow-persona-without-model
  - pattern: multi-line regex で persona: 直後の field 行が model: 以外なら fire
  - field enumeration 方式 (Rust regex lookahead 非対応の pragmatic 対処)
  - extensions=[yaml] + paths=[.takt/workflows/*.yaml] で範囲限定 (順位 102 PR #148 で
    実装した paths filter を利用)
- .takt/workflows/post-pr-review.yaml: 2 site に model: sonnet 追加で clean baseline
  - line 23: judge block (loop_monitor) の persona: supervisor 直下
  - line 117: supervise step の persona: supervisor 直下 (Bundle Y2 完全性)
- .takt/workflows/pre-push-review.yaml: 1 site に model: sonnet 追加で clean baseline
  - line 26: judge block (loop_monitor) の persona: supervisor 直下
- src/hooks-post-tool-linter/src/main.rs: unit tests 6 件追加
  - takt_workflow_persona_detects_judge_block_violation
  - takt_workflow_persona_detects_supervise_step_violation
  - takt_workflow_persona_skips_when_model_directly_follows (clean baseline)
  - takt_workflow_persona_detects_multiple_violations_in_same_file
  - takt_workflow_persona_skips_non_yaml_extension (extensions filter)
  - deployed_takt_workflows_have_clean_baseline_for_persona_model_rule (regression test)

Phase D D-4 dogfood: real diff として lint_screen の dogfood data 蓄積を目的。
Round 2 計画 (D-3 + D-4〜D-7 = 累積 5 PR) の 2 PR 目。

cargo test: 108 passed (前 102 + 新 6)。

* fix(hooks-post-tool-linter): takt persona-without-model rule に 4 fields 追加 (PR #150 CR Major)

CodeRabbit Major finding (#150 (comment)):
persona 直後の field 列挙 から output_contracts / pass_previous_response /
required_permission_mode / parallel が漏れていた = false negative リスク。
4 fields を pattern alternation に追加し regression test も同梱。

変更:
- .claude/custom-lint-rules.toml: ルール⑨ pattern alternation に 4 fields 追加
- src/hooks-post-tool-linter/src/main.rs: 同期更新 + 新 test
  takt_workflow_persona_detects_required_permission_mode_violation で
  pre-push-review.yaml fix step (persona: coder → required_permission_mode:)
  pattern が検出されることを assert

cargo test: 109 passed (前 108 + 新 1、CR Major regression test)

CR Minor (line 5、未来日進捗) は project local time (JST) と CR UTC の時差解釈
ギャップに起因 (CR 時点 = 2026-05-12 20:04 UTC = 2026-05-13 05:04 JST)。
2026-05-13 は session-start hook が認識する local 今日であり、'着手' は本 PR で
発生した事実。project 内既存 PR land 日付も全て local time (timezone qualifier 無し)
で記載しており、本 PR の追記のみ qualifier 付与は逆に不整合を生む。
別 reply で resolved として close する。
aloekun added a commit that referenced this pull request May 13, 2026
… test (#151)

* feat(hooks): Phase D D-5 — comment-lint test 拡充 + MAX_CUSTOM_VIOLATIONS outer/inner break test (順位 56 + 119)

## D-5 実装 (順位 56 + 119 bundle)

### 順位 56: comment-lint hook test 拡充 (PR #104 T2-1+T2-2 bundle)

`src/hooks-post-tool-comment-lint-rust/src/main.rs`:
- UTF-8 multi-byte test 5 パターン追加: 漢字 + ASCII 混合 / 漢字単独 / emoji / BMP 外
  文字 (𝕊) / 結合文字 (e + U+0301)
- Block comment boundary test 6 パターン追加: 複数行 (start/end/middle 被覆) + 単行
  block comment (exact / starts-at / ends-at) で `span_overlaps_ranges` の
  inclusive-bounds 区間交差判定を体系化
- 既存 1 パターンずつのテストは保持 (regression 防止)

### 副産物: `byte_offset_to_line` char-boundary panic fix

UTF-8 漢字単独パターン test 着手時に発見した production bug を修正:

- 旧: `source[..clamped].bytes()` は `clamped` が char boundary でない場合 panic
- 新: `source.as_bytes()[..clamped].iter()` で byte slice 経由に変更 (char boundary 不要)
- 影響: needle 末尾が multi-byte 文字の場合 (例: 「漢字のみのコメント」を Edit/Write の
  new_string として渡す現実シナリオ) で hook が panic していたのを修正
- direct unit test `byte_offset_to_line_handles_mid_multibyte_offset` を追加して bug
  location を pinpoint

### 順位 119: MAX_CUSTOM_VIOLATIONS outer/inner loop break scope explicit test

`src/hooks-post-tool-linter/src/main.rs`:
- `run_custom_rules_outer_break_skips_subsequent_rules`: rule_a 単独で 21 件 →
  cap で 20 件、rule_b は呼ばれない (全 violation が "RULE_A") を assert
- `run_custom_rules_inner_cap_after_partial_first_rule`: rule_a 19 件 + rule_b 1 件 =
  20 件 (rule_b の inner break が mid-rule で発火) を type 分布で検証
- PR #148 で発見した `run_custom_rules` refactor の outer/inner loop break scope を
  test net で固定化

## test 結果

- hooks-post-tool-comment-lint-rust: 85 passed (前 84 + 新 1 direct unit + 11 integration)
- hooks-post-tool-linter: 111 passed (前 109 + 新 2)
- 合計 196 tests pass

## docs 整理

- docs/todo7.md: 順位 56 entry 削除
- docs/todo8.md: 順位 119 entry 削除
- docs/todo-summary.md: 順位 56 / 119 行削除
- docs/local-llm-offload-analysis.md: D-5 row を ✅ 着手済 に更新、bug fix を副産物として明記

## 並行: PR #150 post-merge-feedback 登録 (本セッション前から @ に含まれていた変更)

- docs/todo8.md: 順位 120 (rule comment + ADR-007 case study) / 順位 121 (4 fields
  個別 fixture test) / 順位 122 (development-workflow.md Step 0 stale entry 確認 step) 登録
- docs/todo-summary.md: 3 行追加

## Phase D 累積状況

D-3 (PR #148) + D-4 (PR #150) + D-5 (本 PR) = 3 PR 完了、Phase E 着手要件 (5 PR 累積)
まであと 2 PR (D-6 + D-7)。本 PR の dogfood は push 時に `LINT_SCREEN_ENABLED=true`
で opt-in 観測予定。

* docs(analysis): Phase D D-5 dogfood outcome を記録 (lint_screen 4 件目の data point)
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