From 937c0e408f7a632a77601c8eab41c3f781139771 Mon Sep 17 00:00:00 2001 From: aloekun Date: Mon, 11 May 2026 00:21:52 +0900 Subject: [PATCH 1/3] =?UTF-8?q?docs:=20=E9=A0=86=E4=BD=8D=20101-105=20(PR?= =?UTF-8?q?=20#140=20T1-#1/#2/#3=20+=20T3-#1/#2=20=E6=8E=A1=E7=94=A8)=20?= =?UTF-8?q?=E7=99=BB=E9=8C=B2=20+=20analysis.md=20P-2=20=E5=AE=8C=E4=BA=86?= =?UTF-8?q?=E5=8F=8D=E6=98=A0=20(classifier=20preview=20metrics=20+=20fall?= =?UTF-8?q?back=20rate=20100%=20trend=20signal)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/local-llm-offload-analysis.md | 14 ++- docs/todo-summary.md | 5 + docs/todo6.md | 168 +++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 1 deletion(-) diff --git a/docs/local-llm-offload-analysis.md b/docs/local-llm-offload-analysis.md index b17df48..b46fe69 100644 --- a/docs/local-llm-offload-analysis.md +++ b/docs/local-llm-offload-analysis.md @@ -205,7 +205,7 @@ cargo test -p cli-finding-classifier --test lint_screen_evals -- \ | Order | 構成 | Effort | Diff Profile | dogfood signal | |---|---|---|---|---| | P-1 | Bundle h (順位 89+90) + Bundle g-2 (順位 87+88) ✅ **完了 (PR #139、2026-05-10)** | M | global rules markdown 4 file (project diff は ADR-039 + cross-link + todo cleanup のみ) | classifier preview のみ取得 (real pipeline 未実行)。詳細は本 table 直後の **P-1 dogfood outcome** 参照 | - | P-2 | Bundle j-1 (順位 94 — `../docs/` 相対パス detect lint rule) | S | TOML config + 軽い Rust regex | 小規模 mixed diff | + | P-2 | Bundle j-1 (順位 94 — `../docs/` 相対パス detect lint rule) ✅ **完了 (PR #140、2026-05-10)** | S | TOML config + 軽い Rust regex (203 行 mixed diff) | classifier preview のみ取得 (real pipeline 未実行)。詳細は本 table 直後の **P-2 dogfood outcome** 参照 | | P-3 | Bundle g-1 (順位 85+86 — cli-pr-monitor verdict guard + transition test) | M | Rust impl + Rust test | 中規模 Rust、`auto_fix` 期待 | | P-4 | Bundle d (順位 68 — no-ephemeral-todo-reference self-exclusion test) | S | Rust test only | 狭 scope test diff | | P-5 | Bundle c-1 (順位 63+64+67 — cli-merge-pipeline Drop guard + reaper + ADR) | L | Rust impl ×2 + ADR | 大規模 Rust (PR #132 868 行 stress 再現候補) | @@ -222,6 +222,18 @@ cargo test -p cli-finding-classifier --test lint_screen_evals -- \ - **観測 caveat**: post-merge-feedback agent が PR #139 で初観測した `baselinebaseline` (table cell 内連続単語重複) は session/prepush 間で観測が矛盾 (jj cache stale 疑い、未確定)。Frequency Low 単独で T1 #1 連続重複単語 lint / T1 #2 jj cache validation は様子見 / 却下。3 PR 観測閾値で再評価 - **real pipeline 経由 P-1 metric**: P-2 (Bundle j-1) 移行時に再検討 = lint_screen を session-only opt-in で動かす機会を改めて作る (commit pollution 回避と integration test の trade-off は P-2 で再判断) + **P-2 dogfood outcome (PR #140、2026-05-10)**: + + - **classifier preview metrics** (cli-finding-classifier 直叩き、real pipeline 経由ではない、P-1 と同方針 = commit pollution 回避): + - latency: 46s (P-1 = 23s の ~2x、203-line diff にも関わらず latency 増。入力依存性 + mistral 内部状態の variance (cold/warm) 両候補) + - findings: 0 (空配列) + - screen_decision: `human_review` (fallback path activated) + - fallback_reason: 同 P-1 (`JSON parse error: missing field 'screen_decision'`、line 94 column 1) + - **Fallback rate trend (累積)**: 2/2 = 100%。Phase d guide §3 の kill-switch criteria (3/5 PR で fallback = 60% で停止) は real pipeline 経由なら **既に発動相当**。classifier preview ベースの観測で参考値、P-3 移行時に kill-switch 厳密判定の必要性を再評価 + - **Phase d 学習**: 順位 98 (`num_ctx` overflow detection diagnostic warn log) の優先度を再々確認 = Rust+TOML+MD 混合 diff (203 行) でも崩壊で diff size 起因単独ではない signal、P-3 着手前の優先実装を強く推奨 + - **post-merge-feedback (8 findings → 5 件採用)**: T1 #1/#2/#3 + T3 #1/#2 を採用 → **順位 101-105** として登録済。T2 #1 (大文字バリアント test 必須化) は不採用 = 「Tier 2 偽装の必須化ルール = unenforced rule pattern」として `feedback_no_unenforced_rules.md` に検知 signal 3 項目を追記。T2 #2 (mistral fallback 率監視) は様子見 (Phase d 3 PR 観測閾値で Tier 1 昇格再検討)。詳細は `.claude/feedback-reports/140.md` + - **real pipeline 経由 P-2 metric**: P-3 移行時に再検討 (P-1 → P-2 で本 trade-off 判断は共通結論で固定化、P-3 で改めて見直しの必要性は低いが kill-switch 100% trend を踏まえ再評価) + **設計判断のポイント**: - **Effort 分布 M→S→M→S→L**: 前半小規模 / 後半大規模で kill-switch (fallback > 50%) signal の質を切り分け可能 (小規模で発動 = 設計 issue / 大規模で発動 = num_ctx 再到達) - **Bundle h + g-2 を 1 PR に統合**: 共通テーマ「global rules consolidation (process/lifecycle codification)」、reviewer も「rule 追加 4 件まとめ」として認識しやすい diff --git a/docs/todo-summary.md b/docs/todo-summary.md index 0d18d93..9aa375d 100644 --- a/docs/todo-summary.md +++ b/docs/todo-summary.md @@ -71,6 +71,11 @@ | 98 | 🚀 Tier 1 | **`num_ctx` overflow detection — JSON parse error 検知時の context window 診断ログ (PR #137 T1-#1 採用)** | todo6.md | M | なし (PR #136 で誤診 pivot を発生させた blind spot を decisive に塞ぐ runtime hint、`lib-ollama-client` の response validation 層に warn log 追加、`prompt_eval_count` ≈ `num_ctx` cap で truncation を即診断) | | 99 | 💎 Tier 3 | **ADR-038 に PR #138 learning 2 件を追記 (cost-aware 実装層選択 + attention dilution pitfall) (PR #138 T3-#1+#2 採用)** | todo6.md | S | なし (lint_screen が takt facet → Rust stage に pivot した cost 根拠 + Phase b' v2 の diff header full 追加で agreement 75%→50% 33pt 低下した attention dilution 観測の 2 件を ADR に codify、次回 LLM 系 feature 開発時の prior assumption に) | | 100 | 💎 Tier 3 | **`development-workflow.md` に 「同一ファイル複数編集の 1 task 統合」 + 「partial completion + 後続 PR 追補明記」 を追補 (PR #139 T3-#1 採用)** | todo6.md | XS | なし (PR #119/#120/#121 sub-PR 分割 + PR #139 partial completion で systemic に観測された 2 暗黙知を `~/.claude/rules/common/development-workflow.md` に codify、`feedback_no_unenforced_rules.md` 例外 = 既存実践の明文化のため非機械強制でも採用相当) | +| 101 | 🚀 Tier 1 | **rule⑧ depth-1 非-docs MD edge case test 追加 (PR #140 T1-#1 採用)** | todo6.md | S | なし (rule⑧ で depth-1 root MD ファイル (例: `./CLAUDE.md`) から `../docs/` 参照が false positive にならないかが未検証、3 ソース (PR diff/prepush/session) で観測された test gap、md_no_docs_relative_* test group に追加) | +| 102 | 🚀 Tier 1 | **`paths` filter を lint runner に実装 (PR #140 T1-#2 採用)** | todo6.md | M | なし (rule⑧ で `extensions = ["md"]` のみで pattern semantics に依存して self-limit したが、path-sensitive な lint rule 追加時に同設計-実装 gap が systemic に再発、`src/hooks-post-tool-linter/src/filter.rs` 等で paths filter サポート + 単体 test 同 commit) | +| 103 | 🚀 Tier 1 | **lint runner サポートフィールドを code comment で明示化 (PR #140 T1-#3 採用)** | todo6.md | S | なし (`src/hooks-post-tool-linter/src/main.rs` の CustomRule struct 定義近傍に「サポート field: extensions / pattern / severity / message / why、planned: paths」を code comment 追加、TOML コメントのみだと rule author が lint runner 実装を参照する動線が無いため次の設計-実装 gap を構造的に予防) | +| 104 | 💎 Tier 3 | **ADR-007 amendment: semantic self-limitation 安全条件 + lint rule 最小テストチェックリスト (PR #140 T3-#1 採用)** | todo6.md | S | なし (rule⑧ で `paths` filter 不在を pattern semantics で代替した判断の rationale を ADR-007 に追記。「semantic self-limitation OK な条件」と「explicit `paths` filter 必須な条件」、lint rule 最小テストチェックリスト = pattern detection / case-insensitive / false positive skip の 3 項目最低化、3 ソース観測) | +| 105 | 💎 Tier 3 | **グローバル CLAUDE.md に lint runner サポートフィールド一覧表 (PR #140 T3-#2 採用)** | todo6.md | XS | なし (`~/.claude/CLAUDE.md` に `pattern` / `extensions` / `severity` (planned: `paths`) の field 一覧を表形式で追加、派生プロジェクト (techbook-ledger / auto-review-fix-vc) で rule porting 時の理解統一、順位 103 の code comment と相補) | **戦略**: Tier 1 を 2〜3 セッションで片付け → Tier 2 で ADR-032 の前提 + rate-limit + convergence cost 削減を進める → Tier 3 で ADR-032 を land + ドキュメント整備。Tier 4-5 は cleanup / 外部展開で daily efficiency への直接効果は小さい。 diff --git a/docs/todo6.md b/docs/todo6.md index 6af030c..15d4295 100644 --- a/docs/todo6.md +++ b/docs/todo6.md @@ -380,3 +380,171 @@ config.rs + push-runner-config.toml + review-simplicity.md + ADR で family_tag #### 詰まっている箇所 なし。Effort XS、global rule への追記のみで副作用最小。配置先 (Feature Implementation Workflow 直後 vs 別 § で独立) は実装時の判断。 + +--- + +### rule⑧ depth-1 非-docs MD edge case test 追加 (PR #140 T1-#1 採用) + +> **動機**: PR #140 で追加した rule⑧ (`no-docs-relative-back-to-docs`) は `extensions = ["md"]` のみで pattern semantics に依存して self-limit する設計。**depth-1 非-docs MD ファイル** (例: project root の `CLAUDE.md` / `README.md` / `.claude/README.md` 等) から `../docs/` を参照するケースが false positive にならないかが未検証で、3 ソース (PR diff / prepush takt review / post-merge-feedback session) で同一の test gap が独立指摘された。 +> +> **本タスクの位置づけ**: PR #140 post-merge-feedback Tier 1 #1 採用 (Severity Medium / Frequency Medium = 3 ソース観測 / Effort S / Adoption Risk None)。 +> +> **参照**: `.claude/feedback-reports/140.md` Tier 1 #1、`src/hooks-post-tool-linter/src/main.rs` の `md_no_docs_relative_*` test group、ADR-007 (custom lint rule layer 線引き) +> +> **実行優先度**: 🚀 **Tier 1** — Effort S。md_no_docs_relative_* test group に edge case を 1-2 件追加。 + +#### 設計決定の余地 + +- **意図する挙動の確定が先**: depth-1 root MD (例: `./CLAUDE.md`) から `../docs/` を参照するケースは現実には稀だが、もし発生したら **fire (false positive)** になるか、それとも skip すべきか? +- **判断基準案**: pattern `(?i)\]\(\.\./docs/` は path semantics で「現在 file が docs 配下にいる前提」だが、root file から参照すると `../docs/` = repo の親階層 (= リポジトリ外) を指すため **常に broken link**。よって **fire = 正解** と整理可能 (false positive ではなく true positive、ユーザーが意図しても broken link になる) +- 上記整理を test 名に反映 (`md_no_docs_relative_detects_root_level_back_reference` 等) + +#### 作業計画 + +- [ ] depth-1 root MD ファイル fixture (`CLAUDE.md` / `.claude/README.md` 等) からの `../docs/` 参照を test に追加 +- [ ] 「fire = true positive」整理を test 名と comment で明示 +- [ ] 既存 5 test と合わせて 6-7 test 構成に整理 +- [ ] markdownlint / cargo test pass 確認 +- [ ] 順位 102 (`paths` filter 実装) と組み合わせると本 test の意図が変わる可能性、land 順序を確認 +- [ ] 本 todo6.md エントリ削除 + todo-summary.md 行削除 + +#### 完了基準 + +- depth-1 非-docs MD からの `../docs/` 参照が test で明示的に扱われる (fire = true positive 整理込み) +- 全 cargo test pass + +--- + +### `paths` filter を lint runner に実装 (PR #140 T1-#2 採用) + +> **動機**: rule⑧ (PR #140) の TOML コメントで「`paths` filter は lint runner 未実装、`extensions` のみ」と明記し pattern semantics で self-limit したが、これは設計-実装 gap の workaround。今後 path-sensitive な lint rule (例: `tests/` 内のみ / `src/cli-*/` のみ等) を追加するたびに同じ workaround を強いる systemic pattern が予測される。`src/hooks-post-tool-linter/src/filter.rs` (or 等価な path filter モジュール) で `paths = [...]` glob filter をサポートする。 +> +> **本タスクの位置づけ**: PR #140 post-merge-feedback Tier 1 #2 採用 (Severity Medium / Frequency Medium = systemic / Effort M / Adoption Risk None)。 +> +> **参照**: `.claude/feedback-reports/140.md` Tier 1 #2、`src/hooks-post-tool-linter/src/main.rs` の `CustomRule` struct (line ~76-87)、PR #140 rule⑧ TOML コメント、ADR-007 (custom lint rule の正規表現/AST 層線引き) + +#### 設計決定の余地 + +- **glob 構文**: `**/*.md` 形式で十分か / `regex` ベースの方が柔軟か → 既存 `extensions` が単純 string match なので glob で平仄を取る方が自然 +- **AND vs OR**: `extensions` と `paths` 両方指定時の filter 結合 (両方 match を要求 = AND が直感的) +- **test 規模**: 単体 test を同 commit に含める (PR #140 教訓: rule 追加と同 PR で test 不在を防ぐ) + +#### 作業計画 + +- [ ] 設計決定 (glob 構文 / AND-OR / test 戦略) を確定 +- [ ] `CustomRule` struct に `paths: Option>` を追加 (Optional で既存 rule に影響なし) +- [ ] glob match 実装 (例: `globset` crate or 既存 `glob` 機能で代替) +- [ ] `extensions` × `paths` の組合せ test (path match / 不一致 / 未指定で AND fallback の各ケース) +- [ ] rule⑧ を `paths = ["docs/**/*.md"]` で書き換え (semantic self-limit から explicit filter へ) +- [ ] 順位 101 の test 整理と整合性確認 (本実装後に depth-1 root MD は paths filter で skip される設計に変わる可能性) +- [ ] ADR-007 amendment (順位 104) と同 PR で land 推奨 (rationale 同期) +- [ ] 本 todo6.md エントリ削除 + todo-summary.md 行削除 + +#### 完了基準 + +- `paths` filter が動作 (test 検証) +- rule⑧ の TOML コメントから「paths filter 未実装」記述が消え、explicit filter に置き換わる +- 後続 path-sensitive rule 追加時の動線が確立 + +--- + +### lint runner サポートフィールドを code comment で明示化 (PR #140 T1-#3 採用) + +> **動機**: PR #140 で rule⑧ を実装する際、lint runner の `CustomRule` struct がサポートする field 一覧 (現状: `extensions`, `pattern`, `severity`, `message`, `why`, `fix`, `example`) は `src/hooks-post-tool-linter/src/main.rs` のソースを読まないと分からない。TOML コメント (custom-lint-rules.toml の冒頭) のみだと **rule author が lint runner 実装を参照する動線がない**。code comment で明示すると次の rule 追加時に同じ設計-実装 gap を構造的に予防できる。 +> +> **本タスクの位置づけ**: PR #140 post-merge-feedback Tier 1 #3 採用 (Severity Low / Frequency Medium / Effort S / Adoption Risk None)。 +> +> **参照**: `.claude/feedback-reports/140.md` Tier 1 #3、`src/hooks-post-tool-linter/src/main.rs` `CustomRule` struct 定義 (line ~76-87)、PR #140 rule⑧ TOML コメント + +#### 設計決定の余地 + +- **配置先**: `CustomRule` struct 直前の doc comment (`///`) で「サポート field の semantics と将来 planned field」を一覧化 +- **記述粒度**: 各 field の serde attribute 表記 + 要旨 1 行ずつ。`paths` (planned) も含めて next-author が動線を辿れるように + +#### 作業計画 + +- [ ] `CustomRule` struct 直前に doc comment を追加 (現サポート field 一覧 + planned: `paths`) +- [ ] custom-lint-rules.toml 冒頭コメントから「ソース main.rs 参照」のリンク (line 番号 or symbol 名) を追加 +- [ ] 順位 102 (`paths` filter 実装) と同 PR で land すると `planned: paths` を `supported: paths` に書き換える単一 commit で完結 +- [ ] markdownlint / cargo doc 確認 +- [ ] 本 todo6.md エントリ削除 + todo-summary.md 行削除 + +#### 完了基準 + +- `CustomRule` struct の doc comment にサポート field 一覧が記載される +- TOML コメント側からも main.rs への動線が明示される + +--- + +### ADR-007 amendment: semantic self-limitation 安全条件 + lint rule 最小テストチェックリスト (PR #140 T3-#1 採用) + +> **動機**: rule⑧ (PR #140) で `paths` filter 不在を pattern semantics で代替した判断は妥当だったが、**どんな条件下で semantic self-limitation が安全か** / **explicit filter が必須な条件は何か** が ADR-007 に明文化されていない。3 ソース (PR diff / prepush / session) でこの documentation 不足を独立指摘。同時に lint rule 最小テストチェックリスト (pattern detection / case-insensitive / false positive skip の 3 項目) も ADR レベルで確立すると future rule author の prior が安定化する。 +> +> **本タスクの位置づけ**: PR #140 post-merge-feedback Tier 3 #1 採用 (Severity Low / Frequency Low = 3 ソース観測 / Effort S / Adoption Risk None)。 +> +> **参照**: `.claude/feedback-reports/140.md` Tier 3 #1、`docs/adr/adr-007-custom-linter-layer-boundary.md`、PR #140 rule⑧ 設計判断 + +#### 追加する 2 section (ADR-007 への amendment) + +##### (a) Semantic self-limitation の安全条件 vs explicit filter 必須条件 + +- **OK**: pattern が path-context を含意する場合 (例: `](../docs/` は parent-dir 経由で docs/ を再参照 → docs/ 配下以外では自然な記述形式と区別される) +- **NG**: pattern が path-agnostic で paths filter 必須 (例: `eprintln!` は src/ 全体で頻出、特定 crate のみに限定したい場合は path filter が必要) +- **判断 flow chart**: 「pattern semantics で false positive が **動機**: 派生プロジェクト (techbook-ledger / auto-review-fix-vc 等) で hooks を porting する際、lint runner がサポートするフィールド (`pattern` / `extensions` / `severity` / `message` / `why`、planned: `paths`) を一目で把握できる reference が グローバル CLAUDE.md に存在しない。順位 103 (code comment) と相補的で、cross-project 可視性を即時向上。 +> +> **本タスクの位置づけ**: PR #140 post-merge-feedback Tier 3 #2 採用 (Severity Low / Frequency Medium / Effort XS / Adoption Risk None)。 +> +> **参照**: `.claude/feedback-reports/140.md` Tier 3 #2、`~/.claude/CLAUDE.md` (global、リンクのみ方針 = `feedback_claude_md_link_only.md`)、`src/hooks-post-tool-linter/src/main.rs` `CustomRule` struct + +#### 設計決定の余地 + +- **`feedback_claude_md_link_only.md` との整合**: グローバル CLAUDE.md は「リンクのみ」方針。table 形式で field 一覧を inline すると memory rule に違反する可能性 +- **代替案 1**: グローバル CLAUDE.md には「lint runner field reference は `~/.claude/rules/...` 配下に独立 doc」とリンクのみ書き、本体 doc は `~/.claude/rules//lint-runner-fields.md` 等に配置 +- **代替案 2**: project 内 ADR-007 amendment (順位 104) で field 一覧を含めて、グローバル CLAUDE.md は ADR-007 へのリンクのみ +- **判断**: 順位 104 land 後に決定。重複が無いように lifecycle 整合性を取る + +#### 作業計画 + +- [ ] 順位 104 (ADR-007 amendment) の land 後、配置案 1 / 2 / 別案を決定 +- [ ] `feedback_claude_md_link_only.md` 方針を再確認 +- [ ] 配置先に table 追加 (現サポート field + planned + 派生プロジェクト porting 時の参照点) +- [ ] グローバル CLAUDE.md にリンク追加 (memory rule 遵守) +- [ ] 派生プロジェクト 2 つ (techbook-ledger / auto-review-fix-vc) に本変更を伝播する deploy step を確認 +- [ ] 本 todo6.md エントリ削除 + todo-summary.md 行削除 + +#### 完了基準 + +- 派生プロジェクトの rule porting 時に field reference を 1 hop で参照可能 +- `feedback_claude_md_link_only.md` 違反なし + +#### 詰まっている箇所 + +- 配置先決定が順位 104 (ADR-007 amendment) の land と依存。順位 104 で field 一覧を inline するなら本タスクはリンク追加のみで済むが、ADR は判断基準中心であれば独立 reference doc が必要 From d2ebf3d70cf81c5ea6de45f910a794b3158aa300 Mon Sep 17 00:00:00 2001 From: aloekun Date: Mon, 11 May 2026 01:34:34 +0900 Subject: [PATCH 2/3] =?UTF-8?q?docs(todo):=20=E9=A0=86=E4=BD=8D=2085+86=20?= =?UTF-8?q?(Bundle=20g-1)=20=E3=81=AF=20PR=20#125=20=E3=81=A7=20land=20?= =?UTF-8?q?=E6=B8=88=E3=82=92=E5=8F=8D=E6=98=A0=20=E2=80=94=20stale=20todo?= =?UTF-8?q?=20entries=20=E5=89=8A=E9=99=A4=20+=20analysis.md=20P-3=20?= =?UTF-8?q?=E5=AE=8C=E4=BA=86=E5=8F=8D=E6=98=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/local-llm-offload-analysis.md | 8 +++--- docs/todo-summary.md | 4 +-- docs/todo5.md | 41 ------------------------------ 3 files changed, 5 insertions(+), 48 deletions(-) diff --git a/docs/local-llm-offload-analysis.md b/docs/local-llm-offload-analysis.md index b46fe69..68c94d0 100644 --- a/docs/local-llm-offload-analysis.md +++ b/docs/local-llm-offload-analysis.md @@ -206,9 +206,9 @@ cargo test -p cli-finding-classifier --test lint_screen_evals -- \ |---|---|---|---|---| | P-1 | Bundle h (順位 89+90) + Bundle g-2 (順位 87+88) ✅ **完了 (PR #139、2026-05-10)** | M | global rules markdown 4 file (project diff は ADR-039 + cross-link + todo cleanup のみ) | classifier preview のみ取得 (real pipeline 未実行)。詳細は本 table 直後の **P-1 dogfood outcome** 参照 | | P-2 | Bundle j-1 (順位 94 — `../docs/` 相対パス detect lint rule) ✅ **完了 (PR #140、2026-05-10)** | S | TOML config + 軽い Rust regex (203 行 mixed diff) | classifier preview のみ取得 (real pipeline 未実行)。詳細は本 table 直後の **P-2 dogfood outcome** 参照 | - | P-3 | Bundle g-1 (順位 85+86 — cli-pr-monitor verdict guard + transition test) | M | Rust impl + Rust test | 中規模 Rust、`auto_fix` 期待 | - | P-4 | Bundle d (順位 68 — no-ephemeral-todo-reference self-exclusion test) | S | Rust test only | 狭 scope test diff | - | P-5 | Bundle c-1 (順位 63+64+67 — cli-merge-pipeline Drop guard + reaper + ADR) | L | Rust impl ×2 + ADR | 大規模 Rust (PR #132 868 行 stress 再現候補) | + | ~~P-3~~ | ~~Bundle g-1 (順位 85+86)~~ ⚠️ **roster から除外** — PR #125 で land 済を P-3 着手時に発見、stale todo 削除のみで実装作業なし | — | — | — | + | P-3 (繰上げ) | Bundle d (順位 68 — no-ephemeral-todo-reference self-exclusion test) | S | Rust test only | 狭 scope test diff (旧 P-4) | + | P-4 (繰上げ) | Bundle c-1 (順位 63+64+67 — cli-merge-pipeline Drop guard + reaper + ADR) | L | Rust impl ×2 + ADR | 大規模 Rust (PR #132 868 行 stress 再現候補) (旧 P-5) | **P-1 dogfood outcome (PR #139、2026-05-10)**: @@ -235,7 +235,7 @@ cargo test -p cli-finding-classifier --test lint_screen_evals -- \ - **real pipeline 経由 P-2 metric**: P-3 移行時に再検討 (P-1 → P-2 で本 trade-off 判断は共通結論で固定化、P-3 で改めて見直しの必要性は低いが kill-switch 100% trend を踏まえ再評価) **設計判断のポイント**: - - **Effort 分布 M→S→M→S→L**: 前半小規模 / 後半大規模で kill-switch (fallback > 50%) signal の質を切り分け可能 (小規模で発動 = 設計 issue / 大規模で発動 = num_ctx 再到達) + - **Effort 分布 (旧 M→S→M→S→L → 実 M→S→S→L)**: ~~前半小規模 / 後半大規模で kill-switch (fallback > 50%) signal の質を切り分け~~ 旧 P-3 (M = Bundle g-1) が PR #125 で land 済発見により roster から除外、4 PR roster に縮小。Effort 分布は M→S→S→L に変化、size ramp-up の中段で M が抜けたため小規模 (P-3) → 大規模 (P-4) の jump がやや大きい。kill-switch signal の切り分けは P-4 (L) で num_ctx 再到達検証として有効 - **Bundle h + g-2 を 1 PR に統合**: 共通テーマ「global rules consolidation (process/lifecycle codification)」、reviewer も「rule 追加 4 件まとめ」として認識しやすい - **Bundle f 除外**: `(defer)` 表記 = systemic 性未確認のため Phase d で push 圧力を加えない 3. **Phase d 結果集約**: 計測結果から §8.E 採用 / §8.F 着手 / kill-switch を判定。dogfood 完了後 diff --git a/docs/todo-summary.md b/docs/todo-summary.md index 9aa375d..250d893 100644 --- a/docs/todo-summary.md +++ b/docs/todo-summary.md @@ -60,8 +60,6 @@ | 81 | 🚀 Tier 1 | **cli-pr-monitor: CR 投稿エラー (`Failed to post review comments`) auto-retry 拡張 (PR #120 T1-2 採用) ★ Bundle f (defer)** | todo5.md | M | 1 観測のみで systemic 性未確認 (§A-2 P-5 PR で defer 判断、ADR-018 §追記 2026-05-08 で re-trigger 条件 = 2 件以上の同型観測を規定) | | 83 | 🔧 Tier 2 | **cli-pr-monitor: 複合 AND guard の各条件を独立テストで検証 (PR #120 T2-1 採用)** | todo5.md | S | なし (PR #120 W-001、`enrich_with_classifier_skips_when_disabled` の test setup で複合条件分離不全) | | 84 | 💎 Tier 3 | **グローバルルール: code-review.md に「early-return guard テスト分離」チェックリスト追記 (PR #120 T3-1 採用)** | todo5.md | XS | なし (順位 83 の知見を global rule に codify、`~/.claude/rules/common/code-review.md`、独立並列実施可) | -| 85 | 🚀 Tier 1 | **cli-pr-monitor: monitor state machine guard 強化 (`review_state: not_found && findings: []` を pending 据置) (PR #121 T1-1 採用) ★ Bundle g** | todo5.md | S | なし (PR #119/#120/#121 で 3 PR 連続観測、Frequency Medium 閾値到達済み、Severity High = 誤 approved リスク、Bundle f #80 と関連だが verdict logic 側) | -| 86 | 🔧 Tier 2 | **cli-pr-monitor: state transition test の網羅追加 (順位 85 の回帰テスト) (PR #121 T2-4 採用) ★ Bundle g** | todo5.md | S | 順位 85 と同 PR (Bundle g、`(review_state, findings) → verdict` transition matrix を表形式テストで定義、`src/cli-pr-monitor/tests/` 新規作成) | | 91 | 🔧 Tier 2 | **`[lint_screen]` config parse テスト (PR #132 T2-#4 採用) ★ Bundle i** | todo6.md | S | なし (PR #132 で追加した push-runner-config.toml の `[lint_screen]` section に対する toml::from_str テスト、CodeRabbit nitpick 起点、silent field rename 防止) | | 92 | 🔧 Tier 2 | **scale-aware eval fixtures (200+ 行) — Phase d 投入前の必須 infrastructure (PR #132 T2-#5 採用) ★ Bundle i** | todo6.md | M | 順位 91 と同 PR 推奨 (Bundle i コア、PR #132 smoke で観測した mistral:7b 大規模 diff JSON 不完全 (`missing field 'screen_decision'`) を fixture 化、Phase d 着手前の改善 ループ reference point 確保) | | 93 | 💎 Tier 3 | **`coding-style.md` Cross-File Reference Lifecycle に partial fix 例を追記 (PR #132 T3-#8 採用)** | todo6.md | XS | なし (PR #94 / #111 / #132 で反復した「変更差分外ファイルへの partial fix 再発」パターンを anti-pattern 例として codify、独立並列実施可) | @@ -101,7 +99,7 @@ **Bundle h (PR #123 post-merge-feedback、experimental feature 標準パターン + ephemeral lifecycle 強化、2026-05-07)** ✅ 完了: 順位 89 (Experimental feature 標準パターン = ADR-039 として codify) + 順位 90 (ephemeral 大規模 content の ADR 昇格基準 + config コメント lifecycle anti-pattern を `~/.claude/rules/common/{docs-governance,coding-style}.md` に追加) で land。**却下** (4 件): T1 #3 (`enabled = true` 検出 lint、誤検出確実) / T1 #4 (見出し参照誤り検出 hook、NLP 必要) / T2 #2 (env var override、ROI 不成立) / T3 #4 (ADR-039 config hardcode policy、ADR-038 でカバー済)。**様子見** (4 件): T1 #1 (ephemeral 計画書参照 lint、命名規則 codify 先行) / T1 #2 (jq 括弧不均衡 lint、再発頻度低) / T2 #1 (classifier endpoint fallback integration test、takt test infra 調査依存) / T3 #3 (config コメント ADR 参照修正、XS opportunistic)。 -**Bundle g (PR #121 post-merge-feedback、monitor verdict logic + session pattern codify、2026-05-07)**: PR #121 (ADR-038 textual fix + Bundle f registration) の dogfood で post-pr-monitor の **verdict 評価ロジック** に edge case を再観測 (PR #119/#120/#121 で計 3 PR 連続)。**4 件採用** (Tier 1 #85、Tier 2 #86、Tier 3 #87/#88) で **2 軸対策**: (1) **monitor verdict guard 層** = 順位 85 (`review_state: not_found && findings: []` を pending 据置) + 順位 86 (state transition matrix の表形式テスト)、(2) **session pattern codify 層** = 順位 87 (Multi-PR chaining ベストプラクティス) + 順位 88 (edge case 3 観測 = Tier 1 昇格基準)。**Sub-PR 構成**: g-1 (順位 85 + 86、Rust 実装 + test、Effort S+S、`src/cli-pr-monitor/tests/` 新規作成) / **g-2 (順位 87 + 88、global rule 追記) は land 済 — Bundle h と同 PR で codify 完了**。**Bundle f との関係**: Bundle f は retry logic (rate-limit + 投稿エラー)、Bundle g は verdict logic (review_state 評価) で別軸。両者を land すると post-pr-monitor の robustness が retry/verdict/state 全方向で堅牢化。**頻度評価**: 順位 85 は 3 PR 観測済で Tier 1 妥当性確認済、順位 86 は 85 の dependent。 +**Bundle g (PR #121 post-merge-feedback、monitor verdict logic + session pattern codify、2026-05-07)** ✅ 完了: 4 件採用 (Tier 1 #85、Tier 2 #86、Tier 3 #87/#88) を 2 PR で land。**g-1 (順位 85 + 86、Rust 実装 + verdict transition matrix tests) は PR #125 で land 済** (`compute_verdict` の review_state == "not_found" / "pending" guard + 12 verdict transition tests in `src/cli-pr-monitor/src/stages/monitor.rs`)。**g-2 (順位 87 + 88、global rule 追記)** は Bundle h と同 PR (#139) で land 済。Bundle f との関係: Bundle f は retry logic (rate-limit + 投稿エラー)、Bundle g は verdict logic (review_state 評価) で別軸、両者 land で post-pr-monitor の robustness が retry/verdict/state 全方向で堅牢化された状態。 **Bundle f (PR #120 post-merge-feedback、cli-pr-monitor robustness、2026-05-07)**: PR #120 (ADR-038 Phase 5: cli-finding-classifier 統合) の dogfood で post-pr-monitor の wakeup state 遷移に複数の edge case を観測。**5 件採用** (Tier 1 #80/#81、Tier 3 #82、Tier 2 #83、Tier 3 #84) で **3 層対策**: (1) 実装層 = 順位 80 / 81 (rate-limit + CR 投稿エラーの auto-retry path 整理) + 順位 82 (ADR-018 設計明文化、同 PR 推奨)、(2) test 層 = 順位 83 (複合 guard の独立 variant test)、(3) ガイド層 = 順位 84 (code-review.md checklist 追記、独立並列可)。**Sub-PR 分割推奨**: f-1 (順位 80 + 81 + 82、cli-pr-monitor + ADR、Effort M+M+S、Bundle f コア) / f-2 (順位 83、test 拡充、Effort S、独立) / f-3 (順位 84、global rule、Effort XS、独立)。Bundle f はローカル LLM dogfood (ADR-038) の副産物として cli-pr-monitor の堅牢化を進める位置づけで、`docs/local-llm-offload-analysis.md` §7 (実装進捗ログ) に dogfood signal として記録。 diff --git a/docs/todo5.md b/docs/todo5.md index ea66aee..ecc07d1 100644 --- a/docs/todo5.md +++ b/docs/todo5.md @@ -246,44 +246,3 @@ --- -### cli-pr-monitor: monitor state machine guard 強化 (`review_state: not_found && findings: []` を pending 据置) (PR #121 T1-1 採用) ★ Bundle g - -> **動機**: PR #119 / #120 / #121 で **3 PR 連続観測**: `review_state: "not_found"` (CR 未投稿) + `findings: []` のとき、monitor が "no findings = approved" と同一視して誤 approved 判定を出す。CodeRabbit review が後から到着しても見逃される潜在 risk。Frequency Medium 閾値到達済み (`.claude/feedback-reports/121.md` Tier 1 #1)。 -> -> **参照**: PR #119 round 3 / PR #120 multiple wakeups / PR #121 multiple wakeups の dogfood 観測、`.claude/feedback-reports/121.md` Tier 1 #1 -> -> **実行優先度**: 🚀 **Tier 1** — Severity High (誤 approved リスク)、Effort S (state machine に条件分岐追加)、Adoption Risk なし (additive guard)。Bundle f #80 と関連するが別側面 (Bundle f は retry logic、本件は verdict logic)。 - -#### 作業計画 - -- [ ] `cli-pr-monitor/src/stages/monitor.rs` (or 関連 verdict 評価箇所) に `(review_state == "not_found", findings.is_empty())` を pending 据置にするガードを追加 -- [ ] 順位 86 と同 PR で land (回帰テスト同時整備) - -#### 完了基準 - -- `review_state: "not_found" + findings: []` のケースで verdict が "approved" にならず "pending" 据置になる -- 順位 86 の state transition test で本動作が machine-enforce される - ---- - -### cli-pr-monitor: state transition test の網羅追加 (順位 85 の回帰テスト) (PR #121 T2-4 採用) ★ Bundle g - -> **動機**: 順位 85 の修正に対する regression 防止網。`(review_state, findings) → verdict` の transition matrix を表形式で定義。現状 `src/cli-pr-monitor/tests/` が 0 件なので新規作成。 -> -> **参照**: `.claude/feedback-reports/121.md` Tier 2 #4 -> -> **実行優先度**: 🔧 **Tier 2** — Severity Medium、Effort S、Frequency Medium (monitor edge case は複数 PR で再観測)。 - -#### 作業計画 - -- [ ] `src/cli-pr-monitor/tests/pr_monitor_state_test.rs` を新規作成 -- [ ] `(not_found, empty)` / `(not_found, populated)` / `(success, empty)` / `(success, populated)` 等の transition matrix を表形式テストで定義 -- [ ] 順位 85 と同 PR で land - -#### 完了基準 - -- transition matrix 全 cell に対する verdict の expected/actual が assertion で検証される -- 順位 85 のガード追加が test の 1 cell で fix されることを確認 - ---- - From 11dc06bf690d79fe3b418744343e040969a1f118 Mon Sep 17 00:00:00 2001 From: aloekun Date: Mon, 11 May 2026 01:56:32 +0900 Subject: [PATCH 3/3] =?UTF-8?q?test(custom-lint):=20rule=E2=91=A5=20no-eph?= =?UTF-8?q?emeral-todo-reference=20self-exclusion=20=E5=9B=9E=E5=B8=B0?= =?UTF-8?q?=E3=83=86=E3=82=B9=E3=83=88=E8=BF=BD=E5=8A=A0=20+=20analysis.md?= =?UTF-8?q?=20P-3=20=E5=AE=8C=E4=BA=86=E5=8F=8D=E6=98=A0=20(=E9=A0=86?= =?UTF-8?q?=E4=BD=8D=2068=20/=20Bundle=20d=20/=20Phase=20d=20P-3=20?= =?UTF-8?q?=E7=B9=B0=E4=B8=8A=E3=81=92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/local-llm-offload-analysis.md | 13 +++- docs/todo-summary.md | 3 +- docs/todo5.md | 43 ----------- src/hooks-post-tool-linter/src/main.rs | 101 +++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 46 deletions(-) diff --git a/docs/local-llm-offload-analysis.md b/docs/local-llm-offload-analysis.md index 68c94d0..4270284 100644 --- a/docs/local-llm-offload-analysis.md +++ b/docs/local-llm-offload-analysis.md @@ -207,7 +207,7 @@ cargo test -p cli-finding-classifier --test lint_screen_evals -- \ | P-1 | Bundle h (順位 89+90) + Bundle g-2 (順位 87+88) ✅ **完了 (PR #139、2026-05-10)** | M | global rules markdown 4 file (project diff は ADR-039 + cross-link + todo cleanup のみ) | classifier preview のみ取得 (real pipeline 未実行)。詳細は本 table 直後の **P-1 dogfood outcome** 参照 | | P-2 | Bundle j-1 (順位 94 — `../docs/` 相対パス detect lint rule) ✅ **完了 (PR #140、2026-05-10)** | S | TOML config + 軽い Rust regex (203 行 mixed diff) | classifier preview のみ取得 (real pipeline 未実行)。詳細は本 table 直後の **P-2 dogfood outcome** 参照 | | ~~P-3~~ | ~~Bundle g-1 (順位 85+86)~~ ⚠️ **roster から除外** — PR #125 で land 済を P-3 着手時に発見、stale todo 削除のみで実装作業なし | — | — | — | - | P-3 (繰上げ) | Bundle d (順位 68 — no-ephemeral-todo-reference self-exclusion test) | S | Rust test only | 狭 scope test diff (旧 P-4) | + | P-3 (繰上げ) | Bundle d (順位 68 — no-ephemeral-todo-reference self-exclusion test) ✅ **完了 (PR、2026-05-11)** | S | Rust test only (187 行) | classifier preview のみ取得 (real pipeline 未実行)。詳細は本 table 直後の **P-3 dogfood outcome** 参照 | | P-4 (繰上げ) | Bundle c-1 (順位 63+64+67 — cli-merge-pipeline Drop guard + reaper + ADR) | L | Rust impl ×2 + ADR | 大規模 Rust (PR #132 868 行 stress 再現候補) (旧 P-5) | **P-1 dogfood outcome (PR #139、2026-05-10)**: @@ -234,6 +234,17 @@ cargo test -p cli-finding-classifier --test lint_screen_evals -- \ - **post-merge-feedback (8 findings → 5 件採用)**: T1 #1/#2/#3 + T3 #1/#2 を採用 → **順位 101-105** として登録済。T2 #1 (大文字バリアント test 必須化) は不採用 = 「Tier 2 偽装の必須化ルール = unenforced rule pattern」として `feedback_no_unenforced_rules.md` に検知 signal 3 項目を追記。T2 #2 (mistral fallback 率監視) は様子見 (Phase d 3 PR 観測閾値で Tier 1 昇格再検討)。詳細は `.claude/feedback-reports/140.md` - **real pipeline 経由 P-2 metric**: P-3 移行時に再検討 (P-1 → P-2 で本 trade-off 判断は共通結論で固定化、P-3 で改めて見直しの必要性は低いが kill-switch 100% trend を踏まえ再評価) + **P-3 (繰上げ) dogfood outcome (PR、2026-05-11)**: + + - **classifier preview metrics** (cli-finding-classifier 直叩き、real pipeline 経由ではない、P-1/P-2 と同方針): + - latency: **11s** (P-1=23s / P-2=46s から大幅短縮、187-line diff の input + warm context 推定) + - findings: 0 (空配列) + - screen_decision: `human_review` (fallback path activated) + - fallback_reason: `JSON parse error: missing field 'screen_decision'` (line 1 column 692) + - **Fallback rate trend (累積)**: **3/3 = 100%**。Phase d guide §3 の kill-switch criteria (3/5 PR で fallback = 60% で停止) は real pipeline 経由なら **既に発動超過**。classifier preview ベースで全 3 回失敗 → 順位 98 (`num_ctx` overflow detection) を **Phase d 結果集約より先に実装** することを強く推奨 (kill-switch 厳密判定の前提整備) + - **Latency variance signal**: P-1=23s / P-2=46s / P-3=11s の振れ幅は input size と弱相関 (P-2 が最短入力で最長 latency)、**mistral 内部状態 (cold/warm context)** が支配的要因の仮説を強化。real pipeline 計測時は cold start を避ける warmup 戦略の設計が必要 + - **post-merge-feedback**: 本 PR merge 後に取得 (現時点で未実施) + **設計判断のポイント**: - **Effort 分布 (旧 M→S→M→S→L → 実 M→S→S→L)**: ~~前半小規模 / 後半大規模で kill-switch (fallback > 50%) signal の質を切り分け~~ 旧 P-3 (M = Bundle g-1) が PR #125 で land 済発見により roster から除外、4 PR roster に縮小。Effort 分布は M→S→S→L に変化、size ramp-up の中段で M が抜けたため小規模 (P-3) → 大規模 (P-4) の jump がやや大きい。kill-switch signal の切り分けは P-4 (L) で num_ctx 再到達検証として有効 - **Bundle h + g-2 を 1 PR に統合**: 共通テーマ「global rules consolidation (process/lifecycle codification)」、reviewer も「rule 追加 4 件まとめ」として認識しやすい diff --git a/docs/todo-summary.md b/docs/todo-summary.md index 250d893..4483400 100644 --- a/docs/todo-summary.md +++ b/docs/todo-summary.md @@ -53,7 +53,6 @@ | 65 | 🚀 Tier 1 | **exe + `--help` を PreToolUse でブロックして src/ Read に誘導 (PR #109 T1-3 採用) ★ Bundle c** | todo7.md | S | なし (PR #109 SIGPIPE の直接トリガ = AI が `cli-merge-pipeline.exe --help` 実行 → exe は --help 未対応で merge 本体実行を構造的に防止、今後追加 exe にも自動適用) | | 66 | 💎 Tier 3 | **長時間 subprocess の pipe truncate 禁止ルールをグローバル明文化 (PR #109 T3-1 採用) ★ Bundle c** | todo7.md | XS | なし (順位 65 = 決定論層、本ルール = 判断ガイド層、`~/.claude/rules/common/development-workflow.md` 等に追加) | | 67 | 💎 Tier 3 | **ADR-030 に abrupt 終了時の振る舞いを spec として明記 (PR #109 T3-2 採用) ★ Bundle c** | todo7.md | XS | 順位 63 / 64 と同 PR (実装と仕様の整合性確保、L1 in-process Drop guard + L2 out-of-process reaper の責務分離 + SLA 化) | -| 68 | 🔧 Tier 2 | **`no-ephemeral-todo-reference` self-exclusion invariant 単体テスト追加 (PR #110 T2-1 採用) ★ Bundle d** | todo5.md | S | なし (PR #110 直接対策、placeholder N 戦略の machine-enforceable 保護、TP/FP/Edge 3 軸テスト) | | 69 | 💎 Tier 3 | **`no-ephemeral-todo-reference` の `yaml`/`yml` extensions 追加理由をコメントで明記 (PR #110 T3-1 採用) ★ Bundle d** | todo5.md | XS | なし (rule⑥ コメント欄に 1-2 行追記、設計 doc と実装の経緯保存、git blame 不要化) | | 78 | 💎 Tier 3 | **ADR-038 (Rust timestamp arithmetic safety) + CLAUDE.md security 拡充 (PR #115 T3-1 採用) ★ Bb-3 follow-up** | todo5.md | S | なし (config が user-editable system boundary のとき `sanitize()` 値域検証を必須化し dependent arithmetic に `// SAFETY: により上限保証` コメントを要求するパターンを ADR + CLAUDE.md に codify、Rust 固有の checked_add + MAX_SAFE capping + time-dependent test の 3 層を明文化) | | 79 | 💎 Tier 3 | **`docs-governance.md` § Retirement Workflow に「残タスクの lifecycle 整合」要件明記 (PR #117 T3-1 採用)** | todo5.md | XS | なし (PR #117 で順位 15 を Bb-3 で吸収済として削除した際、現 Step 2「残タスクを priority table に登録」が priority table から除外するケース = 完了/deprioritize/defer を未定義だった実証。除外時の commit/PR で 3 値のいずれかを明示する要件を追加して将来の同型 ambiguity を構造的に防ぐ) | @@ -105,7 +104,7 @@ **Bundle c (PR #109 post-merge-feedback 堅牢化、2026-05-04)**: PR #109 で post-merge-feedback workflow が SIGPIPE で silent 中断され `.failed` marker 未生成という ADR-030 仕様違反が実証された。5 件採用 (Tier 1 #63/#64/#65 + Tier 3 #66/#67) で **3 層防御** を構築: (1) 事前防止 = 順位 65 (exe + `--help` を PreToolUse block) + 順位 66 (グローバルルールの subprocess pipe truncate 禁止)、(2) in-process recovery = 順位 63 (Drop guard / signal trap で abrupt 終了時の `.failed` marker 保証)、(3) out-of-process backstop = 順位 64 (`meta.json status=running` 5-15 分放置 reaper)。順位 67 (ADR-030 spec 拡張) は実装と同 PR で仕様/実装の整合性確保。**Sub-PR 分割推奨**: c-1 (順位 63 + 64 + 67、Rust 実装 + ADR、Effort M+M+XS、コア層) / c-2 (順位 65 + 66、hook + global rule、Effort S+XS、trigger 防止層)。c-1 と c-2 は独立に land 可能だが c-1 land 後の dogfood で recovery 機構を実証してから c-2 を入れると順位の合理性が見える順序になる。 -**Bundle d (PR #110 post-merge-feedback、2026-05-04)**: PR #110 (Bundle "docs quality pre-write") merge 後の post-merge-feedback で 6 findings 中 3 件採用。共通テーマは「PR #110 で導入した `no-ephemeral-todo-reference` rule (順位 29 採用分) の robustness 強化 + 設計 doc / 実装の乖離 ガード」。**順位 68 (T2 self-exclusion test)** は placeholder N 戦略の機械的保護で OBS-3 (fragile naming convention) 対策、**順位 69 (T3 yaml/yml コメント)** は OBS-2 (spec-impl 乖離) 対策。順位 70 (code-review checklist) は Bundle e で land 済。残り順位 68 (test infra) と 順位 69 (config コメント) は scope 異なるため独立 PR 推奨。 +**Bundle d (PR #110 post-merge-feedback、2026-05-04)**: PR #110 (Bundle "docs quality pre-write") merge 後の post-merge-feedback で 6 findings 中 3 件採用。共通テーマは「PR #110 で導入した `no-ephemeral-todo-reference` rule (順位 29 採用分) の robustness 強化 + 設計 doc / 実装の乖離 ガード」。**順位 68 (T2 self-exclusion test)** は **本 PR (Phase d P-3 繰上げ) で land 済** = `hooks-post-tool-linter` の 6 件 unit test (TP / FP / Edge / 大文字無視 / 拡張子限定 / deployed TOML self-exclusion invariant)。**順位 69 (T3 yaml/yml コメント)** は OBS-2 (spec-impl 乖離) 対策で別 PR で対応予定。順位 70 (code-review checklist) は Bundle e で land 済。 **Bundle f + retirement (PR #111 post-merge-feedback + 計画書 retire、2026-05-05)** ✅ 完了: PR #111 (Bundle e) merge 後の post-merge-feedback で 10 findings 中 4 件採用 (順位 71/72/73/74 = Tier 3 XS×4) + 順位 62 (Document Governance) + `docs/docs-pr-iteration-efficiency.md` retirement を **1 PR で集約 land**。Sub-PR 分割推奨ルール (順位 73 自身が codify する内容) を本 PR で **dogfood**: 順位 73 が land する PR 自身が「分割 vs 統合」判断対象 → ファイル削除 + 順位 62 + Bundle f を統合した結果、scope は 5 ファイル touch (global rules 2 + ADR 2 + 削除 1) + cleanup で clean、Bundle 分割で得られる review 容易性より統合 PR の atomic な lifecycle 完結性が勝った。共通テーマ: 「PR #111 自己違反事例 → self-application 強化」 + 「Document Governance を global rule に codify」 + 「計画書 retirement を実例化」の 3 layer 同時 land。 diff --git a/docs/todo5.md b/docs/todo5.md index ecc07d1..6e91783 100644 --- a/docs/todo5.md +++ b/docs/todo5.md @@ -10,49 +10,6 @@ ## 現在進行中 -### `no-ephemeral-todo-reference` self-exclusion invariant の単体テスト追加 (PR #110 T2-1 採用) ★ Bundle d - -> **動機**: PR #110 で導入した `.claude/custom-lint-rules.toml` rule⑥ (`no-ephemeral-todo-reference`) は、ルール定義ファイル自身が `.toml` 拡張子で対象内になるため、message / why / example 内に concrete `docs/todoN.md` (N = digit) を書かない placeholder 戦略で self-trigger を回避している。この invariant は **naming convention 依存** で、将来の例文追記時に concrete digit を含む文字列を入れると self-trigger が発生して silent regression を起こすリスク (PR #110 pre-push reviewer OBS-3 で documented)。 -> -> **本タスクの位置づけ**: PR #110 post-merge-feedback Tier 2 #1 採用 (Severity Medium / Frequency Low / Effort S / Adoption Risk None / ✅ 採用)。machine-enforceable な invariant 保護で、将来の例文追加で self-exclusion が壊れた時に CI で即検出。 -> -> **参照**: `.claude/feedback-reports/110.md` Tier 2 #1、`.claude/custom-lint-rules.toml` rule⑥ の self-exclusion 設計コメント、PR #110 pre-push reviewer OBS-3 -> -> **実行優先度**: 🔧 **Tier 2** — Effort S。self-exclusion テストインフラの新設。 - -#### 設計決定 (案) - -- **配置先候補** (着手時に決定): - - **案 A**: `tests/custom-lint-rules/` に独立 test crate を新設し、`hooks-post-tool-comment-lint-rust` の lint engine を呼び出して assert - - **案 B**: `src/hooks-post-tool-comment-lint-rust/tests/` 配下に integration test を追加 (既存 hook crate に同居) - - 推奨: **案 B** (既存 crate の lint engine を直接 invoke でき、テスト infra 二重投資を避ける) -- **テスト内容**: - - **TP test**: 任意の `.rs` / `.toml` ファイルに `docs/todo3.md` 等の concrete digit reference を含む input → rule⑥ が warning を 1 件生成することを assert - - **FP test (self-exclusion invariant)**: `.claude/custom-lint-rules.toml` の rule⑥ 部分 (placeholder `N` を含む example.bad / message / why) を input として渡し、rule⑥ が warning を **生成しない** ことを assert - - **Edge case test**: `docs/todoN.md` (N = letter) / `docs/todo*.md` (literal asterisk) / `docs/todo[0-9]*.md` (regex source の literal) いずれも warning を生成しないこと - -#### 作業計画 - -- [ ] 配置先 (案 A / B) を `src/hooks-post-tool-comment-lint-rust/` の構造を確認のうえ決定 -- [ ] lint engine を test 経由で呼び出す API を確認 (既存 unit test があれば流用) -- [ ] 上記 3 種類のテストケースを実装 -- [ ] cargo test で 全 pass を確認 -- [ ] 派生プロジェクト (`techbook-ledger` / `auto-review-fix-vc`) で同 hook を deploy する場合のテスト追従も検討 -- [ ] 本 todo5.md エントリを削除 - -#### 完了基準 - -- self-exclusion invariant が test で機械的に保護される (将来 concrete digit を rule⑥ 内に書くと CI で fail) -- TP / FP / Edge case の 3 軸でカバー -- 既存テストとの統合が破綻しない (cargo test 全 pass) - -#### 詰まっている箇所 - -- lint engine の test 用 API 公開状況: hooks-post-tool-comment-lint-rust crate が library crate を expose していない場合、test infra 整備自体に追加 effort が発生する可能性 -- self-exclusion invariant の future-proof 性: rule⑥ の設計が変わって新しい extension が追加された場合、test fixtures の更新も必要 - ---- - ### `no-ephemeral-todo-reference` の `yaml`/`yml` extensions 追加理由をコメントで明記 (PR #110 T3-1 採用) ★ Bundle d > **動機**: PR #110 で `no-ephemeral-todo-reference` rule の `extensions` に `yaml` / `yml` を追加したが、`docs/todo3.md` の設計 doc には `["rs", "toml", "jsonc", "json", "ts", "tsx", "js", "jsx", "py", "ps1"]` のみ記載されていた。実装時に「YAML config もファイルパス参照を含みうる」判断で `yaml` / `yml` を含めたが、その理由が `.claude/custom-lint-rules.toml` rule⑥ コメントに残っていない。将来の rule 参照者が「なぜ yaml/yml が含まれているか」を git blame で追う必要が出る。 diff --git a/src/hooks-post-tool-linter/src/main.rs b/src/hooks-post-tool-linter/src/main.rs index c4dfed8..b1f76e9 100644 --- a/src/hooks-post-tool-linter/src/main.rs +++ b/src/hooks-post-tool-linter/src/main.rs @@ -1609,6 +1609,107 @@ extensions = ["ts", "js"] assert!(violations.is_empty()); } + fn no_ephemeral_todo_reference_rule() -> CustomRule { + let stem = "todo"; + let pattern = format!(r"(?i)docs/{stem}[0-9]*\.md"); + make_test_rule( + "no-ephemeral-todo-reference", + &pattern, + &[ + "rs", "toml", "jsonc", "json", "yaml", "yml", "ts", "tsx", "js", "jsx", "py", + "ps1", + ], + ) + } + + fn build_concrete_digit_fixture(digit: u32) -> String { + let stem = "todo"; + format!("const MSG: &str = \"see docs/{stem}{digit}.md\";\n") + } + + fn build_zero_digit_fixture() -> String { + let stem = "todo"; + format!("pub const NOTE: &str = \"linked from docs/{stem}.md baseline\";\n") + } + + fn build_letter_placeholder_fixture() -> String { + let stem = "todo"; + let placeholder = "N"; + format!( + "/// example: \"docs/{stem}{placeholder}.md\" ({placeholder} = digit) is the placeholder form\n" + ) + } + + fn build_asterisk_literal_fixture() -> String { + let stem = "todo"; + let glob = "*"; + format!("pub const GLOB: &str = \"docs/{stem}{glob}.md\";\n") + } + + #[test] + fn no_ephemeral_todo_detects_concrete_digit_reference() { + let dir = tempfile::tempdir().unwrap(); + let file = write_file(dir.path(), "config.rs", &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); + } + + #[test] + fn no_ephemeral_todo_detects_zero_digit_form() { + let dir = tempfile::tempdir().unwrap(); + let file = write_file(dir.path(), "lib.rs", &build_zero_digit_fixture()); + 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); + } + + #[test] + fn no_ephemeral_todo_skips_letter_placeholder() { + let dir = tempfile::tempdir().unwrap(); + let file = write_file( + dir.path(), + "explainer.rs", + &build_letter_placeholder_fixture(), + ); + 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()); + } + + #[test] + fn no_ephemeral_todo_skips_asterisk_literal() { + let dir = tempfile::tempdir().unwrap(); + let file = write_file(dir.path(), "doc_glob.rs", &build_asterisk_literal_fixture()); + 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()); + } + + #[test] + fn no_ephemeral_todo_only_targets_listed_extensions_md_skipped() { + let dir = tempfile::tempdir().unwrap(); + let file = write_file(dir.path(), "note.md", &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!(violations.is_empty()); + } + + #[test] + fn no_ephemeral_todo_self_exclusion_invariant_holds_on_deployed_toml() { + let path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("..") + .join("..") + .join(".claude") + .join("custom-lint-rules.toml"); + let rules = compile_test_rules(vec![no_ephemeral_todo_reference_rule()]); + let violations = run_custom_rules(path.to_str().unwrap(), &rules); + assert!( + violations.is_empty(), + "self-exclusion invariant broken: rule⑥ self-triggered on deployed custom-lint-rules.toml" + ); + } + fn ps_rule_with_pattern(id: &str, pattern: &str) -> CustomRule { make_test_rule(id, pattern, &["ps1"]) }