Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions .claude/custom-lint-rules.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ steps = [
bad = "console.log('user data:', userData);"
good = "logger.debug('user data:', userData);"

[rules.test_coverage]
# rule① は ts/tsx/js/jsx (= 全て非主要拡張子) のため other_ext_tests のみ。
# 順位 137 の必須カバレッジは「rule あたり 1+ positive test」(主要拡張子 = rs/toml/yaml/yml)。
other_ext_tests = ["run_custom_rules_detects_console_log"]

# ─── ルール②: 個人を特定する絶対パス禁止 (PII) ───
#
# 由来: PR #75 (post-merge-feedback) で 3 箇所同時発生 (ADR-030 line 143、todo.md line 35/48)、
Expand Down Expand Up @@ -77,6 +82,14 @@ steps = [
bad = '具体的なファイル所在: `C:\Users\alice\.claude\projects\<project-id>\` 配下'
good = '具体的なファイル所在: `%USERPROFILE%\.claude\projects\<project-id>\` 配下'

[rules.test_coverage]
# rule② は md/txt (= 全て非主要拡張子)。順位 137 PR で test gap 補填 (3 tests 新規追加)。
other_ext_tests = [
"no_personal_paths_detects_windows_user_path_in_md",
"no_personal_paths_detects_unix_home_path_in_txt",
"no_personal_paths_skips_placeholder_paths",
]

# ─── ルール③: PowerShell 空 catch ブロック禁止 (swallowed error) ───
#
# 由来: PR #85 で `__parse_transcripts.ps1:8` の空 `catch {}` が CodeRabbit Major 指摘。
Expand Down Expand Up @@ -108,6 +121,18 @@ steps = [
bad = 'try { Get-Item $path } catch {}'
good = 'try { Get-Item $path } catch { Write-Verbose "expected miss: $_"; $null }'

[rules.test_coverage]
# rule③ は ps1 のみ (非主要拡張子)。複数 case-variant の安定性 seal。
other_ext_tests = [
"ps_empty_catch_detects_violation",
"ps_empty_catch_detects_with_internal_whitespace",
"ps_empty_catch_skips_non_empty_block",
"ps_empty_catch_only_targets_ps1",
"ps_empty_catch_detects_capitalized_keyword",
"ps_empty_catch_detects_uppercase_keyword",
"ps_empty_catch_detects_multiline_block",
]

# ─── ルール④: PowerShell -ErrorAction SilentlyContinue 警告 ───
#
# 由来: 同 PR #85。空 catch との組合せで二重に swallowed error を生む。
Expand Down Expand Up @@ -136,6 +161,16 @@ steps = [
bad = '$data = ConvertFrom-Json $raw -ErrorAction SilentlyContinue'
good = 'try { $data = ConvertFrom-Json $raw -ErrorAction Stop } catch { Write-Error "Invalid JSON: $_"; throw }'

[rules.test_coverage]
# rule④ は ps1 のみ (非主要拡張子)。PowerShell case-insensitive variant の安定性 seal。
other_ext_tests = [
"ps_silent_error_detects_basic_form",
"ps_silent_error_skips_stop_action",
"ps_silent_error_skips_ignore_action",
"ps_silent_error_detects_lowercase_param",
"ps_silent_error_detects_mixed_case",
]

# ─── ルール⑤: Markdown 非 ASCII GFM アンカー検出 (mutable anchor) ───
#
# 由来: PR #89 で CodeRabbit が日本語 heading への GFM 自動 anchor link を Major 指摘。
Expand Down Expand Up @@ -172,6 +207,17 @@ steps = [
bad = 'See [推奨実行順序](todo-summary.md#推奨実行順序サマリー)'
good = 'See [推奨実行順序](todo-summary.md#recommended-order-summary) <!-- with <a id="recommended-order-summary"></a> in target file -->'

[rules.test_coverage]
# rule⑤ は md のみ (非主要拡張子)。GFM anchor の positive / negative variant を網羅。
other_ext_tests = [
"md_mutable_anchor_detects_inline_fragment",
"md_mutable_anchor_detects_path_with_fragment",
"md_mutable_anchor_skips_ascii_fragment",
"md_mutable_anchor_skips_link_without_fragment",
"md_mutable_anchor_skips_path_only_link",
"md_mutable_anchor_skips_external_url_with_fragment",
]

# ─── ルール⑥: 非 docs ファイルからの ephemeral todo 参照禁止 ───
#
# 由来: PR #94 で 3 種類のファイル (Rust raw string literal / TOML config comment /
Expand Down Expand Up @@ -219,6 +265,29 @@ steps = [
bad = 'BLOCK_MESSAGE: &str = "詳細: docs/todoN.md (N = 数字) の \"<section>\" 参照";'
good = 'BLOCK_MESSAGE: &str = "詳細: docs/adr/adr-NNN-feature.md 参照";'

[rules.test_coverage]
# rule⑥ は主要拡張子 4 つ (rs/toml/yaml/yml) + 非主要 8 つを extensions に含む。
# 順位 137 PR で yaml/yml の test gap を補填 (positive 2 + negative 1 新規追加)。
other_ext_tests = ["no_ephemeral_todo_only_targets_listed_extensions_md_skipped"]

[rules.test_coverage.main_ext_tests]
rs = [
"no_ephemeral_todo_detects_concrete_digit_reference",
"no_ephemeral_todo_detects_zero_digit_form",
"no_ephemeral_todo_skips_letter_placeholder",
"no_ephemeral_todo_skips_asterisk_literal",
]
toml = [
"no_ephemeral_todo_detects_toml_ephemeral_reference",
"no_ephemeral_todo_toml_skips_permanent_adr_reference",
"no_ephemeral_todo_self_exclusion_invariant_holds_on_deployed_toml",
]
yaml = [
"no_ephemeral_todo_detects_yaml_ephemeral_reference",
"no_ephemeral_todo_yaml_skips_permanent_adr_reference",
]
yml = ["no_ephemeral_todo_detects_yml_ephemeral_reference"]

# ─── ルール⑦: Rust 時刻フィールドの strict `>` 比較禁止 (boundary inconsistency 防止) ───
#
# 由来: PR #101 で `parse_listed_findings` の `c.created_at > push_time` が CodeRabbit
Expand Down Expand Up @@ -256,6 +325,23 @@ steps = [
bad = "comments.iter().filter(|c| c.created_at > push_time)"
good = "comments.iter().filter(|c| c.created_at >= push_time)"

[rules.test_coverage]
# rule⑦ は rs のみ (主要拡張子)。時刻フィールド variant + 境界 case の網羅的 seal。

[rules.test_coverage.main_ext_tests]
rs = [
"rs_time_field_strict_greater_detects_created_at_gt_push_time",
"rs_time_field_strict_greater_detects_submitted_at_gt_since",
"rs_time_field_strict_greater_detects_updated_at_gt_threshold",
"rs_time_field_strict_greater_detects_comment_event_time",
"rs_time_field_strict_greater_skips_inclusive_comparison",
"rs_time_field_strict_greater_skips_strict_less_than",
"rs_time_field_strict_greater_skips_le_inclusive",
"rs_time_field_strict_greater_skips_numeric_rhs",
"rs_time_field_strict_greater_skips_doc_comment_with_inclusive",
"rs_time_field_strict_greater_skips_unrelated_field",
]

# ─── ルール⑧: docs/ 内 Markdown の `../docs/` 相対パストラップ検出 ───
#
# 由来: PR #133 (50KB 分割系列、Bundle j-1 = 順位 94 採用) で
Expand Down Expand Up @@ -306,6 +392,17 @@ steps = [
bad = "[ADR-036](DOTDOT/docs/adr/adr-036-...) <!-- DOTDOT は ../ の意。実際は `..` 2 文字 -->"
good = "[ADR-036](adr/adr-036-...)"

[rules.test_coverage]
# rule⑧ は md のみ (非主要拡張子)。docs 配下 + root-level 両方の back-reference を網羅。
other_ext_tests = [
"md_no_docs_relative_detects_pr133_pattern",
"md_no_docs_relative_detects_uppercase_path",
"md_no_docs_relative_skips_same_directory_link",
"md_no_docs_relative_skips_parent_to_other_dir",
"md_no_docs_relative_detects_root_level_back_reference",
"md_no_docs_relative_detects_root_readme_back_reference",
]

# ─── ルール⑨: takt workflow yaml で persona: を持つ step に model: 必須 ───
#
# 由来: Bundle Y2 (PR #98) で post-pr-review.yaml supervise step に model: が
Expand Down Expand Up @@ -352,6 +449,19 @@ good = ''' persona: supervisor
model: sonnet
instruction: loop-monitor-reviewers-fix'''

[rules.test_coverage]
# rule⑨ は yaml のみ (主要拡張子)。multi-line regex variant + paths filter は別 test で網羅。

[rules.test_coverage.main_ext_tests]
yaml = [
"takt_workflow_persona_detects_judge_block_violation",
"takt_workflow_persona_detects_supervise_step_violation",
"takt_workflow_persona_skips_when_model_directly_follows",
"takt_workflow_persona_detects_multiple_violations_in_same_file",
"takt_workflow_persona_detects_required_permission_mode_violation",
"takt_workflow_persona_skips_non_yaml_extension",
]

# ─── ルール⑩: `let _ = write_*` swallowed error 検出 (silent failure 防止) ───
#
# 由来: PR #155 simplicity-review が BLOCKING 指摘した `write_skip_report` の Result を
Expand Down Expand Up @@ -389,3 +499,17 @@ steps = [
[rules.example]
bad = "let _ = write_state(&state);"
good = "if let Err(e) = write_state(&state) { log_warn(&format!(\"state write failed: {}\", e)); }"

[rules.test_coverage]
# rule⑩ は rs のみ (主要拡張子)。Drop / if-let-Err / named-binding 等の variant を網羅。

[rules.test_coverage.main_ext_tests]
rs = [
"no_write_result_discard_detects_simple_let_underscore",
"no_write_result_discard_detects_write_skip_report_pattern",
"no_write_result_discard_detects_write_failed_marker_in_drop",
"no_write_result_discard_skips_proper_if_let_err_pattern",
"no_write_result_discard_skips_non_write_prefix_calls",
"no_write_result_discard_skips_named_binding_starting_with_underscore",
"no_write_result_discard_only_targets_rust_extension",
]
2 changes: 0 additions & 2 deletions docs/todo-summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@
| 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 補助) |
| 135 | 💎 Tier 3 | **todo entry の ADR 番号 hardcode 撤廃 — 「ADR-NNN (採番未確定、land 時に確定)」placeholder 採用 (順位 78 番号 conflict 2026-05-16 観測由来)** | todo8.md | XS | なし (順位 78 (旧 ADR-038 → ADR-041) で番号 conflict が顕在化、queue 滞留 entry の hardcode が後発 PR の採番と衝突する構造リスクを convention で予防、`~/.claude/rules/common/docs-governance.md` に 2-3 行追記。採番予約簿は管理コスト過剰のため見送り、land 時 PR で空き番号確定の軽量運用に統一) |
| 136 | 🚀 Tier 1 | **working copy staleness 検出 hook 2 段構え: SessionStart (jj git fetch + lineage 報告) + PreToolUse (stale 時 docs/todo*.md edit block) — 本セッション cleanup-stale-rank-39 由来** | todo8.md | M | なし (本セッションで実証された「stale parent で docs/todo*.md 読込 → 既削除 entry を再度削除提案」failure mode の structural enforcement。Claude Code Web 並列セッション運用前提下で再発確実。`feedback_no_unenforced_rules.md` 例外 = 2 つの hook で機械強制可能、案 A 予防層 + 案 B 最終 backstop の二段構え、ADR-039 experimental pattern 適用) |
| 137 | 🚀 Tier 1 | **Rule-Test Coverage Check Cargo test — `.claude/custom-lint-rules.toml` の extensions ⇔ `src/hooks-post-tool-linter/src/main.rs` test 関数名 mechanical 検証 (PR #163 T1-#1 採用)** | todo8.md | M | なし (PR #110/#151/#152/#155 4 PR 観測 = Frequency High、PR #163 順位 127 で passive reminder comment を追加したが analyzer が「PR #152 同根再発を防止できなかった実証ベース → mechanical enforcement が必要」と判定、`feedback_no_unenforced_rules.md` 原則 = 機械検知なら active enforcement layer のみが防止層として有効) |
| 138 | 💎 Tier 3 | **Rule Extension Test Pattern を `~/.claude/rules/common/testing.md` に明文化 (PR #163 T3-#1 採用)** | todo8.md | XS | なし (PR #151/#152/#163 で確立した pattern の canonical 文書化、`~/.claude/` global 配下のため派生プロジェクト (techbook-ledger / auto-review-fix-vc) へ自動波及、順位 137 = mechanical layer の 2 層構成として運用、Frequency High = 4 PR 観測で ROI 確認済) |

**戦略**: Tier 1 を 2〜3 セッションで片付け → Tier 2 で ADR-032 の前提 + rate-limit + convergence cost 削減を進める → Tier 3 で ADR-032 を land + ドキュメント整備。Tier 4-5 は cleanup / 外部展開で daily efficiency への直接効果は小さい。

Expand Down
Loading