From 55ceed97e6d3ee5ad21fc5fe45fa3113a1313313 Mon Sep 17 00:00:00 2001 From: aloekun Date: Mon, 18 May 2026 13:04:27 +0900 Subject: [PATCH] =?UTF-8?q?test(hooks):=20Bundle=20k-2=20=E2=80=94=20TOML?= =?UTF-8?q?=20positive/negative=20test=20+=20extensions=20=E6=8B=A1?= =?UTF-8?q?=E5=BC=B5=E6=99=82=20test=20=E8=BF=BD=E5=8A=A0=20reminder=20com?= =?UTF-8?q?ment=20(=E9=A0=86=E4=BD=8D=20124=20+=20127)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 順位 124 (Tier 1): TOML positive + negative test 追加 PR #151 T1-#1 採用、PR #152 で再観測 (Frequency Medium)。 既存 `no_ephemeral_todo_self_exclusion_invariant_holds_on_deployed_toml` は self-exclusion 不変条件のみ確認、TOML での検出力 test が不在だった gap を 構造的に塞ぐ: - `no_ephemeral_todo_detects_toml_ephemeral_reference`: TOML + ephemeral 参照 → 1 violation 検出 (positive) - `no_ephemeral_todo_toml_skips_permanent_adr_reference`: TOML + ADR 参照 → 0 violation (negative、pattern 正確性も seal) self-trigger 回避: fixture content は既存 `build_concrete_digit_fixture(3)` (format! interpolation) を再利用。 ## 順位 127 (Tier 3): extensions 拡張時 test 追加義務の comment 明文化 PR #151 T3-#2 採用、PR #152 で再観測。 `.claude/custom-lint-rules.toml` の `no-ephemeral-todo-reference` rule 上に 9 行のコメントブロックを追加: extensions 変更時は同 PR で positive/negative test を追加することを次回 rule 編集者の目に入る位置に置く。 `feedback_no_unenforced_rules.md` 例外 = 既存実践の明文化 + guide 効果 (機械強制ではなく point-of-edit reminder)。 ## 検証 - cargo test -p hooks-post-tool-linter: 121 passed / 0 failed - 新規 2 test (positive / negative) を含む 8 tests (no_ephemeral_todo 系列) 全通過 ## Net 差分 - `.claude/custom-lint-rules.toml`: +9 lines (reminder comment) - `docs/todo-summary.md`: -2 lines (順位 124 + 127 削除) - `docs/todo8.md`: -44 lines (詳細 entries 削除) - `src/hooks-post-tool-linter/src/main.rs`: +41 lines (2 test + doc comment) production code path 変更なし。exe rebuild 不要。 --- .claude/custom-lint-rules.toml | 9 ++++++ docs/todo-summary.md | 2 -- docs/todo8.md | 44 -------------------------- src/hooks-post-tool-linter/src/main.rs | 41 ++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 46 deletions(-) diff --git a/.claude/custom-lint-rules.toml b/.claude/custom-lint-rules.toml index 7cd0496..242e6e0 100644 --- a/.claude/custom-lint-rules.toml +++ b/.claude/custom-lint-rules.toml @@ -184,6 +184,15 @@ good = 'See [推奨実行順序](todo-summary.md#recommended-order-summary) _*` +# 系列に追加すること。test 不在のまま extensions を変更すると検出力 regression が +# silent に発生する (yaml/yml = PR #110、toml = PR #151 で実観測の gap)。 +# # Self-exclusion 設計: # Rust regex は lookbehind 非対応のため負 lookahead は使用不可。本ファイル自身は # .toml 拡張子で対象内だが、message / why / example 内に concrete `docs/todoN.md` diff --git a/docs/todo-summary.md b/docs/todo-summary.md index 6460ed7..2d0d73a 100644 --- a/docs/todo-summary.md +++ b/docs/todo-summary.md @@ -70,9 +70,7 @@ | 120 | 💎 Tier 3 | **`takt-workflow-persona-without-model` rule コメント拡張 + ADR-007 case study 追記 (PR #150 T1-#1 採用、実体 Tier 3 — analyzer 誤分類)** | todo8.md | XS | なし (実体は docs/comment 修正のみで mechanical enforcement なし → Tier 3 reclassify。次回 takt yaml schema 拡張時の rule 更新フロー文書化 + enumeration-based pattern の case study 記録、Tier 1 #2 ADR case study と同 PR で land 効率的) | | 121 | 🔧 Tier 2 | **`takt_workflow_persona_detects_required_permission_mode_violation` doc 修正 + 残り 3 fields 個別 fixture test 追加 (PR #150 T2-#1 採用)** | todo8.md | S | なし (4 fields のうち 3 fields は個別 fixture test 不在、doc comment と実態乖離。pass_previous_response / output_contracts / parallel の individual test を追加して将来 regex 変更時の regression 検知を担保) | | 122 | 💎 Tier 3 | **`development-workflow.md` Step 0 に「新 todo 着手前の既実装確認」チェックステップ追加 (PR #150 T3-#1 採用)** | todo8.md | XS | なし (memory rule `feedback_verify_task_not_already_done.md` を canonical workflow へ昇格。`jj log --limit 20 ` は決定的コマンドのため `feedback_no_unenforced_rules.md` 例外 = 既存実践の明文化 + 機械実行可能で採用、グローバル設定変更前に `~/.claude/` バックアップ取得必須) | -| 124 | 🚀 Tier 1 | **`no-ephemeral-todo-reference` rule の TOML positive test 追加 (PR #151 T1-#1 採用、PR #152 で再観測)** | todo8.md | S | なし (extensions 拡張が複数 PR にわたり反復する pattern (yaml/yml = PR #110、toml 等)、test gap 累積を構造的に防ぐ。Frequency Medium で採用基準を満たす) | | 125 | 🔧 Tier 2 | **UTF-8 マルチバイト boundary test を他の string-processing hooks に横展開 (PR #151 T2-#1 採用)** | todo8.md | M | なし (PR #151 で `byte_offset_to_line` char-boundary panic bug を test 拡充で発見、同型関数を持つ他 hooks に systemic 防御を確保。test 拡充が production fault detection に直結する事例の横展開) | -| 127 | 💎 Tier 3 | **extensions 拡張時の test 追加 pattern をコード comment で明文化 (PR #151 T3-#2 採用、順位 124 と同 PR 推奨、PR #152 で再観測)** | todo8.md | XS | なし (`feedback_no_unenforced_rules.md` 例外 = 既存実践の明文化 + 機械強制ではなく guide 効果。順位 124 と同 PR で test location を正確に参照、順位 122 と同じロジック) | | 128 | 💎 Tier 3 | **CLAUDE.md § Cross-File Reference Lifecycle に多ファイル同時削除 retirement condition checklist を追加 (PR #153 T3-#2 採用)** | todo8.md | XS | なし (PR #133 (todo.md 分割) + PR #153 (analysis.md 分割) の successful pattern を明文化、`feedback_no_unenforced_rules.md` 例外 = 既存実践の明文化 + guide 効果、順位 122 / 127 と同じロジック、`~/.claude/` global 配下で派生プロジェクトに自動波及) | | 133 | 💎 Tier 3 | **docs-governance §Retirement Workflow に「diff context 由来 false alarm 防止 = grep hit は実ファイル Read で確認」明記 (PR #156 T3 #1 採用)** | todo8.md | XS | なし (PR #156 で 5 件以上の false alarm 発生、`feedback_no_unenforced_rules.md` 例外 = 既存実践の明文化 + guide 効果、順位 122 / 127 と同じロジック、`~/.claude/` global 配下で派生プロジェクトに自動波及) | | 134 | 💎 Tier 3 | **ADR-035 に docs-only PR 評価の適用外基準リスト追加 (mutation / error handling / DRY / YAGNI / function length / test coverage / magic-number 等) (PR #156 T3 #2 採用)** | todo8.md | S | なし (Severity Medium = reviewer の criteria 誤適用による unnecessary review overhead / 開発体験劣化、ADR-035 は分類基準のみ定義済で適用外基準が未明示、`feedback_no_unenforced_rules.md` 例外 = ADR への追加で機械強制ではなく reviewer / Claude の judgment 補助) | diff --git a/docs/todo8.md b/docs/todo8.md index 541aba5..b608f0d 100644 --- a/docs/todo8.md +++ b/docs/todo8.md @@ -160,28 +160,6 @@ --- -### `no-ephemeral-todo-reference` rule の TOML positive test 追加 (PR #151 T1-#1 採用、**PR #152 で再観測**) - -> **動機**: PR #151 の CodeRabbit nitpick (および本 PR で発見されなかった latent gap) で、`no-ephemeral-todo-reference` rule が TOML ファイルを extensions に持つ場合の positive test (= 実際に violation を検出することの assertion) が不在と判明。既存テスト `no_ephemeral_todo_self_exclusion_invariant_holds_on_deployed_toml` は self-exclusion 確認のみで、検出力の test ではない。 -> -> **本タスクの位置づけ**: PR #151 post-merge-feedback Tier 1 #1 採用 → PR #152 post-merge-feedback で再確認 (Severity Medium / Frequency Medium / Effort S / Adoption Risk None)。extensions 拡張が複数 PR にわたって反復する pattern (yaml/yml = PR #110、toml = PR #129?) があり、test gap が累積するリスクを構造的に防ぐ。PR #152 post-merge-feedback でも「yaml/yml test gap (PR #110) + TOML test gap (PR #151) の 2 PR 連続観測」と同根の指摘あり。 -> -> **参照**: `.claude/feedback-reports/151.md` Tier 1 #1、`src/hooks-post-tool-linter/src/main.rs` test module - -#### 作業計画 - -- [ ] test fixture: `.toml` 拡張子ファイルに `docs/todo3.md` 等の ephemeral 参照を含む 2-3 行 fixture を作成 -- [ ] test ケース: `run_custom_rules` が 1 件以上の violation を返し、`type == "NO_EPHEMERAL_TODO_REFERENCE"` を確認 -- [ ] negative test: 同じ TOML fixture で `docs/adr/adr-007.md` 等の permanent 参照は violation 0 件であることを確認 -- [ ] 本エントリ削除 + todo-summary.md 行削除 - -#### 完了基準 - -- TOML 拡張子で rule が機能することが explicit test で seal される -- 将来 extensions から TOML を誤削除した場合に test fail で検出される - ---- - ### UTF-8 マルチバイト boundary test を他の string-processing hooks に横展開 (PR #151 T2-#1 採用) > **動機**: PR #151 で `byte_offset_to_line` の char-boundary panic bug を test 拡充 (UTF-8 漢字単独 needle) で発見した。同型関数 (byte offset から行番号変換 / needle 検索 + slice 操作) は他の string-processing hooks にも存在する可能性が高く、横展開 test で systemic 防御を確保すべき。 @@ -205,28 +183,6 @@ --- -### extensions 拡張時の test 追加 pattern をコード comment で明文化 (PR #151 T3-#2 採用、順位 124 と同 PR 推奨、**PR #152 で再観測**) - -> **動機**: 順位 124 (TOML positive test) の根因である「extensions 配列を変更しても対応する test が追加されない」pattern を、`custom-lint-rules.toml` または `no_ephemeral_todo_reference_rule()` 関数の近傍コメントに明記。「extensions を変更した際は対応する positive/negative test を追加すること」のリマインダを次回 rule 変更時に目に入る位置に置く。 -> -> **本タスクの位置づけ**: PR #151 post-merge-feedback Tier 3 #2 採用 → PR #152 post-merge-feedback で再確認 (Severity Low / Frequency Medium / Effort XS / Adoption Risk None)。memory rule `feedback_no_unenforced_rules.md` に抵触するように見えるが、本 case は **既存実践の明文化 + 機械強制ではなく guide 効果** のため例外採用 (順位 122 と同じロジック)。PR #152 post-merge-feedback でも「point-of-edit reminder は enforcement ゼロでも omission 抑止効果あり」と同様の判断で再採用された。 -> -> **参照**: `.claude/feedback-reports/151.md` Tier 3 #2、`.claude/custom-lint-rules.toml`、`src/hooks-post-tool-linter/src/main.rs` - -#### 作業計画 - -- [ ] `.claude/custom-lint-rules.toml` の `no-ephemeral-todo-reference` rule entry の上に 2-3 行 comment 追加: 「⚠️ extensions を変更する場合: 同 PR で positive + negative test を `src/hooks-post-tool-linter/src/main.rs` に追加すること」 -- [ ] 派生プロジェクト (techbook-ledger / auto-review-fix-vc) への deploy 要否を検討 (`.claude/custom-lint-rules.toml` は project 個別なので deploy 不要) -- [ ] 順位 124 (TOML test 追加) の作業中に test の location を確認して、comment 内の path 参照を正確に書く -- [ ] 本エントリ削除 + todo-summary.md 行削除 - -#### 完了基準 - -- 次回 extensions 変更時に rule 編集者が test 追加を忘れにくくなる -- comment が機械強制ではなく guide として機能する (PR review 時の checklist としても再利用可) - ---- - ### CLAUDE.md § Cross-File Reference Lifecycle に多ファイル同時削除 retirement condition checklist を追加 (PR #153 T3-#2 採用) > **動機**: PR #153 で旧 `docs/local-llm-offload-analysis.md` を `phase-d-outcomes.md` に分割した際 (3 ファイルは Phase E 採用昇格 = 2026-05-15 に retire 済)、retirement clause を **3 ファイル (analysis.md / history.md / phase-d-outcomes.md) 同時削除** に統一する作業が developer/AI の手動 review でしか担保されていなかった。advisor 指摘で明示的に「3 ファイルすべてに同じ retirement clause を書く」ステップを踏んだが、これは structural pattern として再利用可能 (今後の docs/* 50KB 分割でも同じ checklist が必要)。同パターンが drift すると ephemeral artifact の lifecycle 整合が崩れ、stale pointer が増殖するリスクあり。 diff --git a/src/hooks-post-tool-linter/src/main.rs b/src/hooks-post-tool-linter/src/main.rs index 24ba4fd..9bd11f3 100644 --- a/src/hooks-post-tool-linter/src/main.rs +++ b/src/hooks-post-tool-linter/src/main.rs @@ -1992,6 +1992,47 @@ extensions = ["ts", "js"] assert!(violations.is_empty()); } + /// 順位 124 (PR #151 T1-#1 採用、PR #152 で再観測): TOML 拡張子で rule⑥ が機能することを + /// explicit に seal する positive test。既存の self-exclusion invariant test + /// (`no_ephemeral_todo_self_exclusion_invariant_holds_on_deployed_toml`) は + /// "self-trigger しない" 方向の test であり、検出力の test ではない。本 test は将来 + /// extensions から "toml" を誤削除した場合に test fail で検出する safety net。 + #[test] + fn no_ephemeral_todo_detects_toml_ephemeral_reference() { + let dir = tempfile::tempdir().unwrap(); + let file = write_file( + dir.path(), + "config.toml", + &build_concrete_digit_fixture(3), + ); + let rules = compile_test_rules(vec![no_ephemeral_todo_reference_rule()]); + let violations = run_custom_rules(file.to_str().unwrap(), &rules); + assert_eq!( + violations.len(), + 1, + "rule⑥ should fire on TOML file with ephemeral todo reference" + ); + } + + /// 順位 124 補完: TOML 拡張子でも `docs/adr/...` 等の permanent 参照は fire しないことを + /// assert する negative test。拡張子だけでなく pattern の正確性も seal する。 + #[test] + fn no_ephemeral_todo_toml_skips_permanent_adr_reference() { + let dir = tempfile::tempdir().unwrap(); + let file = write_file( + dir.path(), + "config.toml", + "doc_link = \"see docs/adr/adr-007-foo.md for context\"\n", + ); + let rules = compile_test_rules(vec![no_ephemeral_todo_reference_rule()]); + let violations = run_custom_rules(file.to_str().unwrap(), &rules); + assert!( + violations.is_empty(), + "rule⑥ should NOT fire on TOML file with permanent ADR reference (got {} violations)", + violations.len() + ); + } + #[test] fn no_ephemeral_todo_self_exclusion_invariant_holds_on_deployed_toml() { let path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))