diff --git a/docs/local-llm-offload-analysis.md b/docs/local-llm-offload-analysis.md index 9108556..d8ea624 100644 --- a/docs/local-llm-offload-analysis.md +++ b/docs/local-llm-offload-analysis.md @@ -2,7 +2,7 @@ > **位置づけ**: 本ファイルは「残作業の **次に何をするか** だけ」を持つ実行計画。完了済みの分析・実装・dogfood 計測・retrospective は [local-llm-offload-history.md](local-llm-offload-history.md) に切り出した。 > -> **状態**: 試験運用 (Phase a 完了 = PR #130 land / Phase b 完了 = GO 達成 2026-05-08, PR #131、Phase c/d は未着手)。 +> **状態**: 試験運用 (Phase a 完了 = PR #130 land / Phase b 完了 = conditional GO 2026-05-08, PR #131 / Phase c MVP 完了 = PR #132 land 2026-05-08、Phase d は未着手)。 > > **引退条件**: 以下のいずれかで本ファイルを削除する (docs-governance.md retirement workflow 準拠)。`local-llm-offload-history.md` も同タイミングで判断する。 > - 残作業 (§8.D / §8.E / §8.F, §1 Phase b/c/d) が **すべて land または却下** された場合 → permanent value (採用された設計判断、却下理由) を ADR-038 に migrate して両ファイルを削除 @@ -57,11 +57,45 @@ - **実行**: `cargo test -p cli-finding-classifier --test lint_screen_evals -- --ignored --nocapture run_lint_screen_against_all_fixtures` - **出力**: per-eval の precision / recall / F1 / 正規化 P/R / TP/FP/FN + aggregate metrics + decision confusion matrix (3x3) + GO/NO-GO 判定 -### Phase c — §8.E 実装 (lint screen facet) +### Phase c — §8.E 実装 (lint screen facet) ✅ **MVP land in PR #132 (2026-05-08)** -- takt facet `ollama-lint-screen` を追加し、pre-push 時に diff の lint 一次フィルタを mistral:7b に逃す -- 初期 dogfood で実 PR の lint 一次フィルタ動作確認 -- 詳細仕様は §8.E 参照 +最終的に「takt facet」ではなく **`cli-push-runner` の Rust stage** として実装 (理由: takt facet は Sonnet で動くため Claude tokens 節約という主目的と矛盾、push-runner step なら mistral:7b 直接呼出で目的達成)。 + +#### 実装したもの (PR #132) + +- 配置: `src/cli-push-runner/src/stages/lint_screen.rs` (新 stage) +- 起動: `cli-finding-classifier.exe --mode lint-screen` を subprocess で呼び出し、stdin に diff、stdout に LintScreenResult JSON +- 出力: `.takt/lint-screen-report.md` (markdown table 形式、`severity / rule / file / line / issue / suggestion` を pipe escape 付きで出力) +- パイプライン位置: `quality_gate → diff → lint_screen → takt → push` (gating なし、report のみ) +- config: `[lint_screen]` section を `push-runner-config.toml` に追加 (default `enabled = false`、試験運用 opt-in) +- fallback: exe 不在 / diff 空 / diff 過大 (`max_diff_lines = 5000` default) / timeout (`timeout_secs = 60` default) / Ollama down / JSON parse 失敗 → すべて skip + warn (push を block しない) +- reviewer 連携: `.takt/facets/instructions/review-simplicity.md` に「lint-screen-report.md があれば advisory として読む」instruction 追加 + +#### Phase c MVP の意図的 scope 制限 (Phase b' conditional GO 反映) + +- **gating しない**: lint-screen の決定 (`screen_decision`) を根拠に既存 reviewers をスキップしたり model を切替えたりしない (Phase b' 75% agreement なので誤指摘リスク回避) +- **auto-fix 経路なし**: `auto_fix` 判定でも実コードに自動 patch を当てない。reviewer の context 補強のみ +- **default OFF**: 手動 opt-in を踏まないと起動しない (ADR-038 試験運用配下) + +#### Phase c MVP smoke で観測した重要事象 + +868 行の現実 PR diff (Phase c 自身) を流したところ、mistral:7b の JSON 出力が壊れた: + +```json +{"lint_findings":[],"screen_decision":"human_review","fallback_reason":"ollama error: parse: JSON parse error: missing field `screen_decision`"} +``` + += mistral:7b は大規模 diff で **structured output schema を欠落** させがち。Phase b' eval fixtures (10-30 行/件) では出ない failure mode。fallback path が graceful に処理し push pipeline をブロックしない設計が機能した一方、**Phase d 投入前に scale-aware fixture (200+ 行) で改善ループを回す必要** が判明。 + +#### Phase c+ (Phase d 着手前の必須 follow-up、Bundle i) + +PR #132 post-merge-feedback で採用された 2 件 + 1 件: + +- **順位 91 (`[lint_screen]` config parse テスト)**: `config.rs` test module に `[lint_screen]` section の deserialize 検証を追加 (silent field rename 防止) — Effort S +- **順位 92 (scale-aware eval fixtures 200+ 行)**: 大規模 diff fixture を 3 件以上追加し、mistral:7b の JSON 完全性を Phase d 投入前に測定 — Effort M +- **順位 93 (coding-style.md partial fix 例追記)**: 反復観測された anti-pattern を global rule に codify — Effort XS + +詳細は [docs/todo6.md](todo6.md) Bundle i 参照。 ### Phase d — PR-based 実環境 dogfood @@ -79,12 +113,13 @@ - **見積**: 半日 (prompt 変更 + 簡易ベンチで安定性検証) - **ROI**: ★ (実害は小、UX 微改善) -### §8.E — 提案 1 (lint screen facet) — Phase b GO 後 +### §8.E — 提案 1 (lint screen facet) ✅ MVP land 済 (PR #132、2026-05-08) -- **目的**: takt の新 facet `ollama-lint-screen` で pre-push 時に diff の lint 一次フィルタを mistral:7b に逃す -- **依存**: **Phase b で agreement rate ≥ 80% 達成** (旧依存の §A-2 dogfood は無効化、Phase a evals に置換) -- **見積**: 1〜2 日 -- **ROI**: 提案 1 として中程度。Phase b 集計次第で優先度変動 (基準未達なら §8.D 先行 → 再 evals 経路) +- **当初目的**: takt の新 facet `ollama-lint-screen` で pre-push 時に diff の lint 一次フィルタを mistral:7b に逃す +- **実装方針の変更**: takt facet (Sonnet 動作) ではなく **`cli-push-runner` の Rust stage** として実装 (Claude tokens 節約という主目的との整合)。詳細は §1 Phase c 参照 +- **MVP scope**: report 出力のみ (gating なし、auto-fix なし、default OFF)。conditional GO (75%) を反映した安全 scope +- **Phase c+ (Bundle i)**: scale-aware fixture (順位 92) / config parse test (順位 91) / coding-style anti-pattern 追記 (順位 93) を Phase d 投入前に処理 +- **Phase d 着手前提**: Bundle i land + 大規模 diff の JSON 不完全問題への一次対策 (現状 fallback graceful、頻度測定がなければ判断不能) ### §8.F — 提案 3 (PR body draft) — §8.E 採用後 @@ -104,21 +139,33 @@ ## 4. 別セッションでの再開チェックリスト ```bash -# 1. master 最新化 +# 1. master 最新化 (Phase a/b/c MVP まで land 済) jj git fetch && jj edit master -# 2. Phase a infrastructure が master に反映済か確認 +# 2. Phase a/c infrastructure が master に反映済か確認 ls src/cli-finding-classifier/evals/lint-screen-evals.json +ls src/cli-push-runner/src/stages/lint_screen.rs cargo test -p cli-finding-classifier --test lint_screen_evals # schema validation 12 件 pass +cargo test -p cli-push-runner # 47+ 件 pass -# 3. Ollama 起動確認 (Phase b 用) +# 3. Ollama 起動確認 (Phase b 再走 / Phase c smoke / Phase d で必要) curl -s http://localhost:11434/api/tags | jq '.models | map({name, size})' -# 4. Phase b 実行 (実 LLM agreement rate 計測) +# 4. Phase b 再現確認 (75% agreement deterministic、Bundle i 着手前に baseline 確認) cargo test -p cli-finding-classifier --test lint_screen_evals -- \ --ignored --nocapture run_lint_screen_against_all_fixtures + +# 5. Phase c MVP smoke (lint_screen step を一時的に enabled=true で起動) +# push-runner-config.toml [lint_screen] enabled = true に設定 (commit しない) +# 任意の小さい diff で pnpm push して .takt/lint-screen-report.md が生成されるか確認 ``` +#### 次に何をするか (優先度順) + +1. **Bundle i 着手** ([docs/todo6.md](todo6.md) 順位 91 + 92): `[lint_screen]` config parse test + scale-aware fixture (200+ 行) を Phase d 投入前に整備 +2. **順位 93 (coding-style.md partial fix 例追記)**: 独立並列実施可、global rule 強化 +3. **Phase d 着手** (Bundle i land 後): PR-based 実環境 dogfood で token 削減 / latency / 大規模 diff の JSON 完全性を 3-5 PR で計測 + §8.D / §8.E / §8.F の実装に着手する場合は、本ファイル該当節 + history §10.6/§10.7 を参照。 ## 関連リンク diff --git a/docs/todo-summary.md b/docs/todo-summary.md index ca016c4..12292d5 100644 --- a/docs/todo-summary.md +++ b/docs/todo-summary.md @@ -69,6 +69,9 @@ | 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、独立並列実施可) | +| 94 | 🚀 Tier 1 | **`docs/` 内 Markdown の `../docs/` 相対パストラップ検出 lint rule (PR #133 T1-1 採用) ★ Bundle j** | todo6.md | S | なし (PR #133 で `docs/todo7.md` L103 が `../docs/adr/...` で broken link 化した実例。`docs/` 配下から `../docs/` は常に誤りで FP 極小、`(?i)\]\(\.\./docs/` の regex 1 行で決定論的に防止) | +| 95 | 🔧 Tier 2 | **`docs/todo*.md` preamble file count 自動照合スクリプト (PR #133 T2-#4 採用) ★ Bundle j** | todo6.md | S | なし (PR #133 で todo6.md「六つ」/ todo7.md「七つ」が実 8 ファイルと乖離した実例。todo*.md 分割が今後も繰り返す pattern (todo3 → 4 → 5 → 6 → 7) のため CI 層で自動検証) | +| 96 | 🔧 Tier 2 | **Markdown cross-reference validator CI step (PR #133 T2-#3 採用) ★ Bundle j** | todo6.md | M | 順位 10 (ADR-032 PR-broken-link) と方向性が近接、fold-in 検討の余地あり。順位 94 (regex 規約) + 順位 95 (count 照合) と組み合わせて docs/ 整合性の多層検証 | **戦略**: Tier 1 を 2〜3 セッションで片付け → Tier 2 で ADR-032 の前提 + rate-limit + convergence cost 削減を進める → Tier 3 で ADR-032 を land + ドキュメント整備。Tier 4-5 は cleanup / 外部展開で daily efficiency への直接効果は小さい。 @@ -107,3 +110,5 @@ **PR #113 (Bb-1 = Bundle b PR-1) post-merge-feedback (2026-05-05)**: 9 findings に対して **1 件のみ採用** (順位 75 = T2-2 の `finalize_parked` write_state 失敗時 fail-safe 回帰テスト)。T1 #1/#2 (lint rule 案) は NLP 必要 / FP リスクで却下、T2-1 (Windows path test) / T2-3 (state cycle integration) / T2-4 (CronCreate format lint) は ROI 不見合いで不採用、**T3-1 / T3-2 (`~/.claude/rules/common/coding-style.md` への ルール追記)** は **ユーザー判断で却下** — 「強制力のないルール追加は却下: 機械検知できなければ何もしない方がマシ。ルール乱立は重要ルール埋没の害悪」(memory: feedback_no_unenforced_rules.md として codify 済)、T3-3 (PARK signal 設計 ADR) は premature で 🤔 様子見保留。**本 PR 含意**: Bb-1 の sibling parity invariant (`finalize_*` 群の error path 対称性) は Bb-2 / Bb-3 で同種関数を追加する際に再発確度が高いため、**test レベルで machine-enforceable に保護** することを Bb-2 着手前の前提条件とする。 **PR #114 (Bb-2 + 順位 75 = Bundle b PR-2 + T2-2) post-merge-feedback (2026-05-05)** ✅ 完了: 9 findings に対して **2 件採用 / 5 件様子見 / 3 件却下**。**Bb-3 (順位 55) で fold-in する採用提案**: T2-2 (Parity test coverage 拡張 = `finalize_park_siblings_have_symmetric_write_state_handling` テストに `finalize_initial_review_park` を追加、self-violation 解消、Effort S)。T2-1 (Legacy JSON deserialize test) は **PR #114 で既に実装済** (`state_legacy_json_without_new_fields_deserializes_with_defaults`、Bb-3 以降の新フィールド追加時に同 pattern を継続するための reference として保存)。**様子見 (5 件)**: T1-1 (finalize_* parity lint、Effort M + NLP 必要、簡易プロキシで再評価) / T1-2 (polling block lint、FP リスクで dogfood 後判断) / T2-3 (env override コメント強化、XS Low) / T2-4 (CI parallel race 確認、preventive only) / T3-1 (Wakeup Resume Invariant ADR) / T3-2 (DI 戦略 ADR、Bb-3 着手時に再検討)。**却下 (3 件)**: T1-3 (Serde schema lint、ROI 低、T2-1 で代替) / T3-3 (parity invariant の global rules 追加) / T3-4 (test-only env var prefix rule) — 後 2 件は **memory: feedback_no_unenforced_rules.md** を直接引用してアナライザが正しく即却下判定。Bb-2 land 時点で Bundle b の核 (CronCreate park モデル) 完成、残る Bb-3 は config 整理 + SessionStart catch-up + T2-2 follow-up を bundled。 + +**Bundle j (PR #133 post-merge-feedback、docs/ 整合性多層検証、2026-05-09)**: PR #133 (todo.md / todo5.md 50KB 分割) merge 後の post-merge-feedback で 9 findings 中 **3 件採用** (Tier 1 #1 / Tier 2 #3, #4) で **3 層対策**: (1) **規約層** = 順位 94 (`(?i)\]\(\.\./docs/` regex 1 行で `docs/` 配下からの逆戻り参照を block) は CodeRabbit が PR #133 で実検出した broken link を決定論的に防止、(2) **CI 検証層** = 順位 95 (preamble file count 自動照合) は todo*.md 分割が今後反復する pattern (todo3 → 4 → 5 → 6 → 7) のため Frequency Medium で採用、(3) **包括的 link 検証層** = 順位 96 (Markdown cross-reference validator、directory-aware resolution) は順位 10 (ADR-032 PR-broken-link) と方向性近接で fold-in 検討余地あり。**Sub-PR 分割推奨**: j-1 (順位 94、`.claude/custom-lint-rules.toml` 規約追加、Effort S、独立) / j-2 (順位 95 + 96、`.github/workflows/lint.yml` 新設 = workflows 未存在 repo の最初の workflow 整備、Effort S+M、まとめて land が効率的)。**却下** (2 件): T1 #2 (prose 数詞 lint、NLP 必要 + FP 確実) / T3 #5/#6 (機械検知不可ルール追加、`feedback_no_unenforced_rules.md` 適用)。**様子見** (3 件): T3 #7 (ADR-035 not_applicable と GitHub thread state の乖離明文化、1 観測のみ) / T3 #8 (ADR-030 AFK wakeup 時 PR body intent ルール化、1 観測のみ) / T3 #9 (50KB 分割原則 CLAUDE.md 明文化、機械検知不可)。**本 PR 含意**: 順位 94 = 「決定論的防止層」哲学 (Bundle Z #B-α 系譜)、順位 95-96 = 「規約だけでは塞げない構造的検証は CI で」(ADR-031 週次レビューと相補)。`.github/workflows/` 未存在 repo に最初の workflow を追加する転換点でもあり、scope 慎重判断が必要。 diff --git a/docs/todo6.md b/docs/todo6.md index 3e912bd..f572e93 100644 --- a/docs/todo6.md +++ b/docs/todo6.md @@ -208,3 +208,133 @@ config.rs + push-runner-config.toml + review-simplicity.md + ADR で family_tag - coding-style.md に「変更差分外への partial fix 再発」例が codify される - 既存 lint rule⑥ (`no-ephemeral-todo-reference` 系) と組み合わせで教育効果が強化される + +--- + +### `docs/` 内 Markdown の `../docs/` 相対パストラップ検出 lint rule (PR #133 T1-1 採用) ★ Bundle j + +> **動機**: PR #133 (todo5.md 分割) で `docs/todo7.md` L103 に `[ADR-036](../docs/adr/adr-036-...)` 形式の壊れ link が混入。`docs/` 配下のファイルから `../docs/` を辿ると `docs/docs/` を指すため directory nesting mismatch で必ず broken link になる。todo5.md 時代から存在した pre-existing bug が分割で表面化した経緯で、CodeRabbit Minor finding として検出。custom lint rule で書いた瞬間に block すれば bug class が排除される。 +> +> **本タスクの位置づけ**: PR #133 post-merge-feedback Tier 1 #1 採用 (Severity Medium / Frequency Low / Effort S / Adoption Risk None)。Bundle Z #B-α と同じ「決定論的防止層」哲学。AST 解析ではなく正規表現層 (ADR-007) で対応可能。 +> +> **参照**: `.claude/feedback-reports/133.md` Tier 1 #1、ADR-007 (custom lint rule の正規表現 / AST 層線引き)、CodeRabbit PR #133 review #3 +> +> **実行優先度**: 🚀 **Tier 1** — Effort S。`.claude/custom-lint-rules.toml` への regex rule 追加。 + +#### 設計決定 (案) + +- **配置先**: `.claude/custom-lint-rules.toml` に新規 rule entry +- **検出パターン (正規表現案)**: `(?i)\]\(\.\./docs/` + - case-insensitive flag は `.claude/rules/common/code-review.md` の Custom lint rule patterns 規約に従う (PowerShell 等向けだが安全側に倒す) +- **適用対象**: `docs/**/*.md` (rule の `paths` filter で限定。他 path 配下からは正当な `../docs/` 参照があり得るため) +- **rule 名 (案)**: `no-docs-relative-back-to-docs` +- **suppress マーカー**: 該当行末に `` 等 + +#### 作業計画 + +- [ ] 既存 `.claude/custom-lint-rules.toml` の rule 構造を確認 +- [ ] regex + path filter を新 rule として記述 +- [ ] PostToolUse hook の lint runner で synthetic test (PR #133 で混入した `../docs/adr/...` パターンを再現してマッチ確認) +- [ ] 既存 `docs/` 配下を grep して false positive 影響範囲を確認 (`grep -rn '\]\(\.\./docs/' docs/`) +- [ ] 派生プロジェクト (techbook-ledger / auto-review-fix-vc) への deploy 確認 +- [ ] 本 todo6.md エントリを削除 + +#### 完了基準 + +- `.claude/custom-lint-rules.toml` に新 rule が追加され `docs/**/*.md` 内の `\]\(\.\./docs/` を検出 +- 1〜2 PR で dogfood し false positive がないこと +- PR #133 と同型の broken link 混入が新 PR で構造的に防止される + +#### 詰まっている箇所 + +- 派生プロジェクト (techbook-ledger 等) で同 rule が適用された際、各 repo の `docs/` 構造が異なる可能性 — 着手時に各派生 repo の `docs/` レイアウトを確認 + +--- + +### `docs/todo*.md` preamble file count 自動照合スクリプト (PR #133 T2-#4 採用) ★ Bundle j + +> **動機**: PR #133 で `docs/todo6.md` L5 (「六つすべてを確認すること」) と `docs/todo7.md` L5 (「七つすべて」) が実 8 ファイル (todo.md / todo2-7.md / todo-summary.md) と乖離。CodeRabbit Minor finding として 2 件検出され、fix commit (`4889413`) で修正したが、`todo*.md` 分割が今後も繰り返される pattern (todo3 → 4 → 5 → 6 → 7) のため CI 層で自動検証する価値がある。Tier 1 #1 (custom lint) と相補で防御層を構築。 +> +> **本タスクの位置づけ**: PR #133 post-merge-feedback Tier 2 #4 採用 (Severity Low / Frequency Medium / Effort S / Adoption Risk None)。shell script のみで実装可能、機械検知が容易な低リスク CI step。 +> +> **参照**: `.claude/feedback-reports/133.md` Tier 2 #4、PR #133 fix commit `4889413`、CodeRabbit PR #133 review #1/#2 +> +> **実行優先度**: 🔧 **Tier 2** — Effort S。`.github/workflows/lint.yml` (現状未存在のため新規作成も視野) または PostToolUse hook + Stop hook での実装も検討可能。 + +#### 設計決定 (案) + +- **配置先**: `.github/workflows/lint.yml` の docs check job に追加 (本リポジトリは現状 GitHub Actions 未設定なので、最初の workflow 作成を含む)。代替案として PostToolUse / Stop hook で local 段階で検出も可 +- **検出ロジック (shell)**: + ```bash + EXPECTED=$(find docs -maxdepth 1 -name "todo*.md" | wc -l) + for f in docs/todo*.md; do + # preamble 内の "X つ" 数詞を抽出、期待値と照合 + PREAMBLE=$(sed -n '5p' "$f") + # 「八つ」(8) / 「七つ」(7) 等の漢数字 → 数値変換で照合 + ... + done + ``` +- **数詞 → 数値マッピング**: 一/二/三/四/五/六/七/八/九/十 を hash で持つ +- **対象範囲**: `docs/todo*.md` のみ (todo-summary.md の preamble 別仕様は scope 外) + +#### 作業計画 + +- [ ] 現状 `.github/workflows/` が無いことを確認 (PR #133 で確認済) し、新規 lint.yml の足場を作るか PostToolUse hook 拡張で代替するか判定 +- [ ] shell script (or Rust hook) で count 検証ロジックを実装 +- [ ] 漢数字 → 数値マッピングと preamble grep の正規表現を定義 +- [ ] PR #133 の修正前状態 (todo6.md「六つ」/ todo7.md「七つ」) を re-introduce した synthetic test で fail することを確認 +- [ ] 採用後の dogfood で false positive がないことを 2-3 PR で確認 +- [ ] 本 todo6.md エントリを削除 + +#### 完了基準 + +- preamble count と実 file 数の乖離が CI / hook で検出される +- PR #133 fix commit で修正した同型問題が機械的に再発防止される + +#### 詰まっている箇所 + +- **GitHub Actions 未設定 repo であること**: workflows 新設は本タスク scope を超える可能性。代替として PostToolUse hook (Rust) での検証が低コスト。Tier 2 #3 (Markdown cross-reference validator) と同 PR で `.github/workflows/lint.yml` 新設を検討する形がまとまりよい +- **数詞表記の揺れ**: 「八つ」「8 つ」「8つ」等の異表記許容範囲を着手時に確定する必要 + +--- + +### Markdown cross-reference validator CI step (PR #133 T2-#3 採用) ★ Bundle j + +> **動機**: PR #133 で `docs/todo7.md` L103 の壊れ ADR link (`../docs/adr/...`) が pre-push lint で早期検知できなかった (CodeRabbit Minor finding で post-PR 検出)。既存 `markdown-link-check` 系 tool は `docs/` 内 relative path を起点 file の directory レベルで正規化しないため broken link を見逃す。custom validator で directory-aware に解決する CI step が必要。Tier 1 #1 (custom lint で `../docs/` パターンを規約レベルで block) と Tier 2 #4 (preamble count 照合) と組み合わせて、docs/ 全体の構造的一貫性を多層検証する。 +> +> **本タスクの位置づけ**: PR #133 post-merge-feedback Tier 2 #3 採用 (Severity Medium / Frequency Medium / Effort M / Adoption Risk: 実装工数中)。 +> +> **参照**: `.claude/feedback-reports/133.md` Tier 2 #3、PR #133 fix commit `4889413` (todo7.md L103 修正)、関連 task: 順位 10 (ADR-032 PR-broken-link) +> +> **実行優先度**: 🔧 **Tier 2** — Effort M。validator 実装 + CI 統合。 + +#### 設計決定 (案) + +- **配置先**: `.github/workflows/lint.yml` に validator step 追加 (順位 95 と同 PR で workflows 新設するのが効率的) +- **実装方針候補**: + - **A**: 既存 `markdown-link-check` を fork or wrapper で directory-aware 化 + - **B**: custom Rust binary (cli-markdown-link-validator 等、既存 cli-* と同 workspace) で書き起こし + - **C**: 軽量 shell + ripgrep ベースの解析 (`rg '\]\([^http][^\)]*\)' docs/` → 各 link を file path 起点で resolve) +- **検証範囲**: `docs/**/*.md` 内の relative link (`./`, `../`, または anchor 付きの内部 link) すべて +- **既存タスクとの関係**: 順位 10 (ADR-032 PR-broken-link) と方向性が近接。同タスクとして fold-in 検討の余地あり + +#### 作業計画 + +- [ ] 既存 `markdown-link-check` 系 tool の機能調査 (directory-aware resolution の有無) +- [ ] 順位 10 (ADR-032 PR-broken-link) との重複排除判定: 同タスクで包含するか、独立 task として残すか +- [ ] 実装方針 A/B/C の比較評価 (Effort vs maintainability) +- [ ] PR #133 で混入した `../docs/adr/...` パターンを synthetic test で検出 +- [ ] PR #133 で正常な相対 link (例: `[docs/todo-summary.md](todo-summary.md)`) を false positive 検出しないことを確認 +- [ ] 採用後の dogfood で 3-5 PR の false positive 率測定 +- [ ] 本 todo6.md エントリを削除 + +#### 完了基準 + +- `docs/` 内 broken relative link が CI で検出される +- PR #133 と同型の `../docs/` トラップを Tier 1 #1 と Tier 2 #3 の二重防御で抑止 +- 既存正常 link で false positive 率 < 5% + +#### 詰まっている箇所 + +- **順位 10 (ADR-032 PR-broken-link) との関係整理**: 設計上 fold-in が妥当か、独立 task が妥当か着手時に判断必要 +- **GitHub Actions 未設定**: 順位 95 (Tier 2 #4) と同様、workflows 新設の判断を含む。この場合 95 + 96 + (将来の lint workflow 整備) を 1 PR の Bundle として land する案も検討余地