diff --git a/docs/todo-summary.md b/docs/todo-summary.md index 1202302e..03e287cf 100644 --- a/docs/todo-summary.md +++ b/docs/todo-summary.md @@ -2,7 +2,7 @@ > **本ファイルの位置付け**: `docs/todo.md` から「推奨実行順序サマリー」section を切り出した index 専用ファイル。各タスクの詳細は「ファイル」列に示された `docs/todoN.md` を参照する。`docs/todo.md` のサイズが 50KB を超え Claude Code 読み取り安定性に影響したため分離 (2026-05-09)。 > -> **更新方針**: table への新規行追加・既存行の削除・順位の再採番は本 index (todo-summary.md + [docs/todo-summary2.md](todo-summary2.md)) で実施する (2026-07-20 に順位 220 以降を todo-summary2.md へ物理分割、docs 50KB 超過解消。新規行は末尾 = todo-summary2.md 側に追加)。詳細エントリは現行の追加先ファイル (= **`docs/todo22.md`**、2026-08-11 の post-merge feedback 採否バッチで新設。直前の追加先 `docs/todo21.md` が約 57KB = 50KB 安定読み取り閾値超過に達したため移行) に記録する。追加先は 50KB 到達のたびに移っており、`docs/todo13.md` → `todo14.md` (2026-07-19、WR-2026-07-19-T02) → `todo20.md` → `todo21.md` (2026-08-08) → `todo22.md` (2026-08-11) と辿ってきた。**移行済みの旧ファイルは既存エントリの編集・完了削除専用**で、新規追加先ではない。なお `docs/todo10.md` は 2026-06-29 PR #224 セッションで todo13.md へ追加先が移行するまでの旧追加先 (以降 既存エントリの編集・完了削除専用)、`docs/todo11.md` は 2026-06-06 todo9.md 分割で新設された専用ファイル (順位 157, 160-173 を収容)、`docs/todo12.md` は 2026-06-12 PR #204 で todo10.md 分割により新設された専用ファイル (順位 176/178/179/180/181/182/193/194 = PR #185 〜 PR #196 era を収容) で、いずれも新規追加先ではない。 +> **更新方針**: table への新規行追加・既存行の削除・順位の再採番は本 index (todo-summary.md + [docs/todo-summary2.md](todo-summary2.md)) で実施する (2026-07-20 に順位 220 以降を todo-summary2.md へ物理分割、docs 50KB 超過解消。新規行は末尾 = todo-summary2.md 側に追加)。詳細エントリは現行の追加先ファイル (= **`docs/todo23.md`**、2026-08-13 に週次レビュー WR-2026-08-13-M01 採用で新設。直前の追加先 `docs/todo22.md` が約 66KB = 50KB 安定読み取り閾値超過に達したため移行) に記録する。追加先は 50KB 到達のたびに移っており、`docs/todo13.md` → `todo14.md` (2026-07-19、WR-2026-07-19-T02) → `todo20.md` → `todo21.md` (2026-08-08) → `todo22.md` (2026-08-11) → `todo23.md` (2026-08-13) と辿ってきた。**移行済みの旧ファイルは既存エントリの編集・完了削除専用**で、新規追加先ではない。なお `docs/todo10.md` は 2026-06-29 PR #224 セッションで todo13.md へ追加先が移行するまでの旧追加先 (以降 既存エントリの編集・完了削除専用)、`docs/todo11.md` は 2026-06-06 todo9.md 分割で新設された専用ファイル (順位 157, 160-173 を収容)、`docs/todo12.md` は 2026-06-12 PR #204 で todo10.md 分割により新設された専用ファイル (順位 176/178/179/180/181/182/193/194 = PR #185 〜 PR #196 era を収容) で、いずれも新規追加先ではない。 diff --git a/docs/todo.md b/docs/todo.md index c9c9f214..17aeb559 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -2,7 +2,7 @@ > **運用ルール**: 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイル + [docs/todo3.md](todo3.md) 〜 [docs/todo22.md](todo22.md) + [docs/todo-summary.md](todo-summary.md) + [docs/todo-summary2.md](todo-summary2.md) の使い分け** (todo2.md は 2026-08-12 退役) (PR #83 T3-2 で恒久化、2026-04-28 強化、PR #88 で todo3.md 追加、PR #96 セッションで todo4.md 追加、PR #101 セッションで todo5.md 追加、PR #123 セッションで todo6.md 追加、2026-05-09 に todo-summary.md 切り出し + todo5.md 分割で todo7.md 追加、PR #143 = 2026-05-11 で todo8.md 追加、PR #172 仕組み化方針切替 = 2026-05-25 で todo9.md 追加、PR #185 land 後 2026-05-29 で todo10.md 追加、2026-06-06 todo9.md 分割で todo11.md 追加、2026-06-12 PR #204 で todo10.md 分割により todo12.md 追加、2026-06-29 PR #224 セッションで todo13.md 追加、2026-07-19 週次レビュー WR-2026-07-19-T02 採用で todo14.md 追加、2026-07-20 docs 50KB 超過解消で todo13.md を todo15/16/17・todo10.md を todo18/19 へ物理分割、2026-08-04 todo14.md の 50KB 超過で todo20.md 追加、2026-08-08 todo20.md の 50KB 超過で todo21.md 追加、2026-08-11 todo21.md の 50KB 超過で todo22.md 追加): +> **本ファイル + [docs/todo3.md](todo3.md) 〜 [docs/todo23.md](todo23.md) + [docs/todo-summary.md](todo-summary.md) + [docs/todo-summary2.md](todo-summary2.md) の使い分け** (todo2.md は 2026-08-12 退役) (PR #83 T3-2 で恒久化、2026-04-28 強化、PR #88 で todo3.md 追加、PR #96 セッションで todo4.md 追加、PR #101 セッションで todo5.md 追加、PR #123 セッションで todo6.md 追加、2026-05-09 に todo-summary.md 切り出し + todo5.md 分割で todo7.md 追加、PR #143 = 2026-05-11 で todo8.md 追加、PR #172 仕組み化方針切替 = 2026-05-25 で todo9.md 追加、PR #185 land 後 2026-05-29 で todo10.md 追加、2026-06-06 todo9.md 分割で todo11.md 追加、2026-06-12 PR #204 で todo10.md 分割により todo12.md 追加、2026-06-29 PR #224 セッションで todo13.md 追加、2026-07-19 週次レビュー WR-2026-07-19-T02 採用で todo14.md 追加、2026-07-20 docs 50KB 超過解消で todo13.md を todo15/16/17・todo10.md を todo18/19 へ物理分割、2026-08-04 todo14.md の 50KB 超過で todo20.md 追加、2026-08-08 todo20.md の 50KB 超過で todo21.md 追加、2026-08-11 todo21.md の 50KB 超過で todo22.md 追加、2026-08-13 todo22.md の 50KB 超過で todo23.md 追加): > > - **docs/todo-summary.md**: 推奨実行順序サマリー table 専用 (旧 todo.md から切り出し)、順位 6-219 を収容。既存行編集・順位再採番はここで行う。 > - **docs/todo-summary2.md**: todo-summary.md の table を 2026-07-20 に docs 50KB 超過解消で分割した後半 (順位 220 以降を収容)。新規行追加は末尾 = 本ファイルで行う。cli-docs-lint の priority-inversion / preamble は両 summary を統合検査。 @@ -27,9 +27,10 @@ > - **docs/todo19.md**: 既存タスクの編集・完了削除専用 (2026-07-20 todo10.md 分割で新設、順位 220-224 収容)。**新規タスクは追加しない** > - **docs/todo20.md**: 既存タスクの編集・完了削除専用。**新規タスクは追加しない** (2026-08-04 todo14.md の 50KB 超過で新設・順位 365-388 を収容、2026-08-08 に本ファイルも 50KB 超過で新規追加先は todo21.md へ移行) > - **docs/todo21.md**: 既存タスクの編集・完了削除専用。**新規タスクは追加しない** (約57KB に到達したため、2026-08-11 以降の新規エントリは todo22.md へ。2026-08-08 todo20.md の 50KB 超過で新設、順位 385 以降を収容) -> - **docs/todo22.md**: 新規タスクの追加先。50KB に到達するまでは本ファイルへ追加 (2026-08-11 todo21.md の 50KB 超過で新設) -> - 例外: 既存 todo.md / todo3.md 〜 todo22.md タスクと **同一ファイル / 同一コンポーネント** を編集する密結合タスクは該当ファイルに追加可 (例: `~/.claude/rules/common/git-workflow.md` 配下のグローバルルール群) -> - **新セッションでは全 todo ファイルを確認すること** (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役) +> - **docs/todo22.md**: 既存タスクの編集・完了削除専用。**新規タスクは追加しない** (約 66KB に到達したため、2026-08-13 以降の新規エントリは todo23.md へ。2026-08-11 todo21.md の 50KB 超過で新設) +> - **docs/todo23.md**: 新規タスクの追加先。50KB に到達するまでは本ファイルへ追加 (2026-08-13 todo22.md の 50KB 超過で新設、週次レビュー WR-2026-08-13-M01 採用) +> - 例外: 既存 todo.md / todo3.md 〜 todo23.md タスクと **同一ファイル / 同一コンポーネント** を編集する密結合タスクは該当ファイルに追加可 (例: `~/.claude/rules/common/git-workflow.md` 配下のグローバルルール群) +> - **新セッションでは全 todo ファイルを確認すること** (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役) --- diff --git a/docs/todo10.md b/docs/todo10.md index 51fe7a5d..e04a6dcf 100644 --- a/docs/todo10.md +++ b/docs/todo10.md @@ -2,7 +2,7 @@ > **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイルの位置付け**: docs/todo9.md がファイルサイズ 50KB を超え行数 1100+ 行に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して新規エントリは本ファイルに記録する (PR #185 = Bundle CR-RL land 後、2026-05-29 ユーザー判断)。**本ファイルは既存タスクの編集・完了削除専用** (新規エントリの追加先は PR #224 セッション = 2026-06-29 で [docs/todo13.md](todo13.md) へ移行し、その後 todo14.md → todo20.md → todo21.md を経て、**現在は [docs/todo22.md](todo22.md)** (2026-08-11 に todo21.md が 50KB 超過で移行)。2026-06-12 PR #204 で PR #185 〜 PR #196 era の 8 エントリを [docs/todo12.md](todo12.md) に分離して file_size_check 50KB threshold 内に収めた、todo12.md は新規追加先ではない)。todo.md / todo3.md 〜 todo9.md / todo11.md / todo12.md の既存エントリ (todo2.md は 2026-08-12 退役)は引き続き有効、相互に独立。**2026-07-20 に順位 215-224 を todo18.md/todo19.md へ物理分割し、本ファイルは順位 198-214 のみ収容 (docs 50KB 超過解消、39KB 台に縮小)。**新セッションでは23つすべてを確認すること (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 +> **本ファイルの位置付け**: docs/todo9.md がファイルサイズ 50KB を超え行数 1100+ 行に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して新規エントリは本ファイルに記録する (PR #185 = Bundle CR-RL land 後、2026-05-29 ユーザー判断)。**本ファイルは既存タスクの編集・完了削除専用** (新規エントリの追加先は PR #224 セッション = 2026-06-29 で [docs/todo13.md](todo13.md) へ移行し、その後 todo14.md → todo20.md → todo21.md を経て、**現在は [docs/todo23.md](todo23.md)** (2026-08-13 に todo22.md が 50KB 超過で移行)。2026-06-12 PR #204 で PR #185 〜 PR #196 era の 8 エントリを [docs/todo12.md](todo12.md) に分離して file_size_check 50KB threshold 内に収めた、todo12.md は新規追加先ではない)。todo.md / todo3.md 〜 todo9.md / todo11.md / todo12.md の既存エントリ (todo2.md は 2026-08-12 退役)は引き続き有効、相互に独立。**2026-07-20 に順位 215-224 を todo18.md/todo19.md へ物理分割し、本ファイルは順位 198-214 のみ収容 (docs 50KB 超過解消、39KB 台に縮小)。**新セッションでは24つすべてを確認すること (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 > > **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 diff --git a/docs/todo11.md b/docs/todo11.md index 8082a354..1ff33885 100644 --- a/docs/todo11.md +++ b/docs/todo11.md @@ -2,7 +2,7 @@ > **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイルの位置付け**: docs/todo9.md がファイルサイズ 75KB 超 (890 行) に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して、PR-specific follow-up entries (PR #174 以降の post-merge-feedback 採用 entry) を本ファイルに分離 (2026-06-06)。todo9.md には「既存ルール仕組み化バンドル + 週次レビュー拡張」themed entries が残る。todo.md / todo3.md 〜 todo10.md の既存エントリ (todo2.md は 2026-08-12 退役)は引き続き有効、相互に独立。新セッションでは23つすべてを確認すること (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 +> **本ファイルの位置付け**: docs/todo9.md がファイルサイズ 75KB 超 (890 行) に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して、PR-specific follow-up entries (PR #174 以降の post-merge-feedback 採用 entry) を本ファイルに分離 (2026-06-06)。todo9.md には「既存ルール仕組み化バンドル + 週次レビュー拡張」themed entries が残る。todo.md / todo3.md 〜 todo10.md の既存エントリ (todo2.md は 2026-08-12 退役)は引き続き有効、相互に独立。新セッションでは24つすべてを確認すること (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 > > **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 diff --git a/docs/todo23.md b/docs/todo23.md new file mode 100644 index 00000000..833e5853 --- /dev/null +++ b/docs/todo23.md @@ -0,0 +1,13 @@ +# TODO (Part 23) + +> **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 +> +> **本ファイルの位置付け**: docs/todo22.md がファイルサイズ 66528 B (2026-08-13 時点、50KB = 51200 B の安定読み取り閾値超過) に到達したため、新規エントリは本ファイルに記録する (2026-08-13 新設、週次レビュー WR-2026-08-13-M01 採用)。**新規エントリの追加先は本ファイル**。todo.md / todo3.md 〜 todo22.md の既存エントリは引き続き有効、相互に独立。 +> +> **サイズ表記について**: todo22.md のサイズは記録時点で異なる (週次レビュー検出時 54203 B → 本ファイル新設時 66528 B → その後の追記でさらに増加)。各記載は**その時点の計測値**であり、現在値と一致しないことがある。現在値が必要なら計測すること。 +> +> **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 + +--- + +(新規エントリはここに追加する) diff --git a/docs/todo3.md b/docs/todo3.md index f66ea129..d227e2d4 100644 --- a/docs/todo3.md +++ b/docs/todo3.md @@ -2,7 +2,7 @@ > **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイルの位置付け**: docs/todo2.md がファイルサイズ約 50KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して PR #88 以降の新規エントリは本ファイルに記録した。本ファイルも PR #96 セッションで 50KB 接近のため、それ以降の新規エントリは [docs/todo4.md](todo4.md) へ。todo.md / todo3-22.md の既存エントリは引き続き有効、相互に独立。新セッションでは23つすべてを確認すること (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 +> **本ファイルの位置付け**: docs/todo2.md がファイルサイズ約 50KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して PR #88 以降の新規エントリは本ファイルに記録した。本ファイルも PR #96 セッションで 50KB 接近のため、それ以降の新規エントリは [docs/todo4.md](todo4.md) へ。todo.md / todo3-23.md の既存エントリは引き続き有効、相互に独立。新セッションでは24つすべてを確認すること (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 > > **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 diff --git a/docs/todo4.md b/docs/todo4.md index 0c8845ec..3d102d5e 100644 --- a/docs/todo4.md +++ b/docs/todo4.md @@ -2,7 +2,7 @@ > **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイルの位置付け**: docs/todo3.md がファイルサイズ約 50KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して新規エントリは本ファイルに記録していた。**本ファイルも 50KB に到達したため、PR #101 セッション以降の新規エントリは [docs/todo5.md](todo5.md) へ**。本ファイルは既存タスクの編集・完了削除専用。todo.md / todo3-22.md の既存エントリは引き続き有効、相互に独立。新セッションでは23つすべてを確認すること (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 +> **本ファイルの位置付け**: docs/todo3.md がファイルサイズ約 50KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して新規エントリは本ファイルに記録していた。**本ファイルも 50KB に到達したため、PR #101 セッション以降の新規エントリは [docs/todo5.md](todo5.md) へ**。本ファイルは既存タスクの編集・完了削除専用。todo.md / todo3-23.md の既存エントリは引き続き有効、相互に独立。新セッションでは24つすべてを確認すること (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 > > **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 diff --git a/docs/todo5.md b/docs/todo5.md index ce9871eb..cd926b3e 100644 --- a/docs/todo5.md +++ b/docs/todo5.md @@ -2,7 +2,7 @@ > **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイルの位置付け**: docs/todo4.md がファイルサイズ約 50KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して PR #101 セッション以降の新規エントリは本ファイルに記録していた。**本ファイルも 67KB に到達したため、2026-05-09 に PR #101〜#109 由来の古い半分を [docs/todo7.md](todo7.md) へ分離した**。本ファイル残存は PR #110 以降のエントリのみ。新規エントリは [docs/todo6.md](todo6.md) へ。todo.md / todo3-22.md の既存エントリは引き続き有効、相互に独立。新セッションでは23つすべてを確認すること (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 +> **本ファイルの位置付け**: docs/todo4.md がファイルサイズ約 50KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して PR #101 セッション以降の新規エントリは本ファイルに記録していた。**本ファイルも 67KB に到達したため、2026-05-09 に PR #101〜#109 由来の古い半分を [docs/todo7.md](todo7.md) へ分離した**。本ファイル残存は PR #110 以降のエントリのみ。新規エントリは [docs/todo6.md](todo6.md) へ。todo.md / todo3-23.md の既存エントリは引き続き有効、相互に独立。新セッションでは24つすべてを確認すること (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 > > **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 diff --git a/docs/todo6.md b/docs/todo6.md index 055e5bce..c5e3d98e 100644 --- a/docs/todo6.md +++ b/docs/todo6.md @@ -2,7 +2,7 @@ > **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイルの位置付け**: docs/todo5.md / 本ファイルが 50KB に到達 (PR #143 T3-#1) のため **新規エントリは [docs/todo8.md](todo8.md) へ移行**。本ファイルは既存タスクの編集・完了削除専用。todo.md / todo3-22.md の既存エントリは引き続き有効、相互に独立。新セッションでは23つすべてを確認すること (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 +> **本ファイルの位置付け**: docs/todo5.md / 本ファイルが 50KB に到達 (PR #143 T3-#1) のため **新規エントリは [docs/todo8.md](todo8.md) へ移行**。本ファイルは既存タスクの編集・完了削除専用。todo.md / todo3-23.md の既存エントリは引き続き有効、相互に独立。新セッションでは24つすべてを確認すること (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 > > **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 diff --git a/docs/todo7.md b/docs/todo7.md index 34190622..18771e7f 100644 --- a/docs/todo7.md +++ b/docs/todo7.md @@ -2,7 +2,7 @@ > **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイルの位置付け**: docs/todo5.md がファイルサイズ 67KB に到達して Claude Code の読み取り安定性 (50KB 超で不安定化) を損なったため、2026-05-09 に **PR #101〜#109 由来の古い半分のタスクを本ファイルへ分離** した。todo5.md には PR #110 以降のタスクが残存。本ファイルは既存タスクの編集・完了削除専用、新規タスクは追加しない (新規エントリは [docs/todo6.md](todo6.md) へ)。todo.md / todo3-22.md の既存エントリは引き続き有効、相互に独立。新セッションでは23つすべてを確認すること (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 +> **本ファイルの位置付け**: docs/todo5.md がファイルサイズ 67KB に到達して Claude Code の読み取り安定性 (50KB 超で不安定化) を損なったため、2026-05-09 に **PR #101〜#109 由来の古い半分のタスクを本ファイルへ分離** した。todo5.md には PR #110 以降のタスクが残存。本ファイルは既存タスクの編集・完了削除専用、新規タスクは追加しない (新規エントリは [docs/todo6.md](todo6.md) へ)。todo.md / todo3-23.md の既存エントリは引き続き有効、相互に独立。新セッションでは24つすべてを確認すること (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 > > **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 diff --git a/docs/todo8.md b/docs/todo8.md index c066aeec..26366d83 100644 --- a/docs/todo8.md +++ b/docs/todo8.md @@ -2,7 +2,7 @@ > **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイルの位置付け**: docs/todo6.md がファイルサイズ 50KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して PR #143 T3-#1 採用時 = 2026-05-11 から新規エントリは本ファイルに記録していた。**本ファイルも 60KB に到達したため、PR #172 仕組み化方針切替セッション = 2026-05-25 以降の新規エントリは [docs/todo9.md](todo9.md) へ移行**。本ファイルは既存タスクの編集・完了削除専用。**新規エントリの現在の追加先は [docs/todo22.md](todo22.md)** (todo9 → todo10 → todo13 → todo14 → todo20 → todo21 → todo22 と移動してきた)。todo.md / todo3.md 〜 todo7.md / todo9.md 〜 todo22.md の既存エントリは引き続き有効、相互に独立。新セッションでは23つすべてを確認すること (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 +> **本ファイルの位置付け**: docs/todo6.md がファイルサイズ 50KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して PR #143 T3-#1 採用時 = 2026-05-11 から新規エントリは本ファイルに記録していた。**本ファイルも 60KB に到達したため、PR #172 仕組み化方針切替セッション = 2026-05-25 以降の新規エントリは [docs/todo9.md](todo9.md) へ移行**。本ファイルは既存タスクの編集・完了削除専用。**新規エントリの現在の追加先は [docs/todo23.md](todo23.md)** (todo9 → todo10 → todo13 → todo14 → todo20 → todo21 → todo22 と移動してきた)。todo.md / todo3.md 〜 todo7.md / todo9.md 〜 todo23.md の既存エントリは引き続き有効、相互に独立。新セッションでは24つすべてを確認すること (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 > > **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 diff --git a/docs/todo9.md b/docs/todo9.md index c4153875..cea8dea8 100644 --- a/docs/todo9.md +++ b/docs/todo9.md @@ -2,7 +2,7 @@ > **運用ルール** ([docs/todo.md](todo.md) と同一): 各タスクには **やろうとしたこと / 現在地 / 詰まっている箇所** を必ず書く。完了タスクは ADR か仕組みに反映後、このファイルから削除する。過去の経緯は git log で追跡可能。 > -> **本ファイルの位置付け**: docs/todo8.md がファイルサイズ 60KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して新規エントリは本ファイルに記録する (PR #172 仕組み化方針切替セッション = 2026-05-25)。todo.md / todo2.md 〜 todo8.md の既存エントリは引き続き有効、相互に独立。**2026-06-06 分割**: 本ファイルが 75KB / 890 行に到達したため、PR-specific follow-up entries (順位 157, 160-173) を [docs/todo11.md](todo11.md) に分離。残置: 既存ルール仕組み化バンドル (順位 146-151) + 週次レビュー拡張 (順位 152-154)。新セッションでは23つすべてを確認すること (todo.md / todo3-22.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 +> **本ファイルの位置付け**: docs/todo8.md がファイルサイズ 60KB に到達したため、Claude Code の読み取り安定性 (50KB 超で不安定化) を考慮して新規エントリは本ファイルに記録する (PR #172 仕組み化方針切替セッション = 2026-05-25)。todo.md / todo2.md 〜 todo8.md の既存エントリは引き続き有効、相互に独立。**2026-06-06 分割**: 本ファイルが 75KB / 890 行に到達したため、PR-specific follow-up entries (順位 157, 160-173) を [docs/todo11.md](todo11.md) に分離。残置: 既存ルール仕組み化バンドル (順位 146-151) + 週次レビュー拡張 (順位 152-154)。新セッションでは24つすべてを確認すること (todo.md / todo3-23.md / todo-summary.md / todo-summary2.md。todo2.md は 2026-08-12 退役)。 > > **推奨実行順序**: 全タスク横断のサマリーは [docs/todo-summary.md](todo-summary.md#recommended-order-summary) を参照。 diff --git a/src/hooks-post-tool-linter/src/custom_rules/engine.rs b/src/hooks-post-tool-linter/src/custom_rules/engine.rs index f3e40779..54308284 100644 --- a/src/hooks-post-tool-linter/src/custom_rules/engine.rs +++ b/src/hooks-post-tool-linter/src/custom_rules/engine.rs @@ -9,6 +9,7 @@ use crate::violation::{ emit_feedback, LintViolation, ViolationExample, ViolationFix, ViolationLocation, MAX_CUSTOM_VIOLATIONS, }; +use crate::repo_path::to_repo_relative; use globset::{Glob, GlobSet, GlobSetBuilder}; use regex::Regex; use std::path::{Path, PathBuf}; @@ -127,12 +128,15 @@ pub(crate) fn rule_matches_ext(rule: &CustomRule, file: &str) -> bool { } /// `compiled.paths_glob` が `None` (filter なし) または `Some(GlobSet)` で file path がマッチする場合 true。 +/// +/// 照合前に [`to_repo_relative`] を通すこと。rule の `paths` はリポジトリ相対 glob で書かれる +/// のに hook 入力は絶対パスなので、素の文字列で照合すると**常に不一致 = rule が無言で +/// 死ぬ** (2026-08-13 に `takt-workflow-persona-without-model` で実測)。 pub(crate) fn rule_matches_path(compiled: &CompiledRule, file: &str) -> bool { let Some(globset) = compiled.paths_glob.as_ref() else { return true; }; - let normalized = file.replace('\\', "/"); - globset.is_match(&normalized) + globset.is_match(to_repo_relative(file)) } /// 1 件の regex match と rule 定義から `LintViolation` の JSON 文字列を構築する。 diff --git a/src/hooks-post-tool-linter/src/custom_rules/engine_tests.rs b/src/hooks-post-tool-linter/src/custom_rules/engine_tests.rs index 044997c8..3372bdf3 100644 --- a/src/hooks-post-tool-linter/src/custom_rules/engine_tests.rs +++ b/src/hooks-post-tool-linter/src/custom_rules/engine_tests.rs @@ -517,3 +517,36 @@ fn powershell_validation_returns_multiple_violators() { let missing = find_powershell_rules_missing_case_insensitive_flag(&rules); assert_eq!(missing, vec!["ps-a".to_string(), "ps-b".to_string()]); } + +/// **hook が実際に渡すのは絶対パス**なので、`paths` 付き rule がその形で一致することを固定する。 +/// +/// 既存テストは相対パスのみを渡しており、`paths` を持つ rule が実運用で一度も発火しない +/// 状態を通していた (2026-08-13 に `takt-workflow-persona-without-model` で実測確認)。 +#[test] +fn paths_filter_matches_absolute_path_as_delivered_by_the_hook() { + let rule = make_test_rule_with_paths("test", "x", &["md"], &["docs/**/*.md"]); + let compiled = compile_rule(rule).expect("rule must compile"); + let cwd = std::env::current_dir().expect("cwd"); + let abs = format!("{}/docs/spec.md", cwd.to_string_lossy().replace('\\', "/")); + assert!( + rule_matches_path(&compiled, &abs), + "絶対パスで一致しないと paths 付き rule は無言で死ぬ: {}", + abs + ); +} + +/// リポジトリ外の絶対パスは `paths` に一致させない。 +/// +/// 固定パス (`/other-repo` 等) は実行環境の cwd とたまたま一致すると正しい実装でも落ちる。 +/// cwd 由来の sibling path なら cwd 自身とは必ず別ディレクトリになる。 +#[test] +fn paths_filter_rejects_absolute_path_outside_repo() { + let rule = make_test_rule_with_paths("test", "x", &["md"], &["docs/**/*.md"]); + let compiled = compile_rule(rule).expect("rule must compile"); + let cwd = std::env::current_dir().expect("cwd"); + let outside = format!( + "{}-outside/docs/spec.md", + cwd.to_string_lossy().replace('\\', "/") + ); + assert!(!rule_matches_path(&compiled, &outside)); +} diff --git a/src/hooks-post-tool-linter/src/file_size_check.rs b/src/hooks-post-tool-linter/src/file_size_check.rs index 59636b0c..8d2d33c0 100644 --- a/src/hooks-post-tool-linter/src/file_size_check.rs +++ b/src/hooks-post-tool-linter/src/file_size_check.rs @@ -7,6 +7,7 @@ //! ADR-039 § 3 Bounded lifetime: 3-5 PR の dogfood 後に default-ON 昇格 or 却下を判定。 use crate::config::{Config, FileSizeCheckConfig}; +use crate::repo_path::to_repo_relative; use crate::violation::emit_feedback; use globset::{Glob, GlobSet, GlobSetBuilder}; @@ -57,7 +58,7 @@ pub(crate) fn check_file_size_threshold( return None; } }; - let normalized = file.replace('\\', "/"); + let normalized = to_repo_relative(file); if !glob_set.is_match(&normalized) { return None; } @@ -120,6 +121,51 @@ mod tests { ); } + /// **hook が実際に渡すのは絶対パス**なので、その形で glob に一致することを固定する。 + /// + /// 既存テストは相対パスしか渡しておらず、`paths` が相対 glob であるために実運用では + /// 常に不一致 = 本検査が一度も発火しない状態を通してしまった (2026-08-13 に docs 配下の + /// 50KB 超 6 件が無警告で蓄積していたことで発覚)。入力の形まで再現しないテストは + /// 「動いているつもり」を固定する。 + #[test] + fn file_size_check_matches_absolute_path_as_delivered_by_the_hook() { + let config = FileSizeCheckConfig { + enabled: true, + threshold_bytes: 51_200, + paths: vec!["docs/**/*.md".to_string()], + touch_trigger: true, + }; + let cwd = std::env::current_dir().expect("cwd"); + let abs = format!("{}/docs/oversized.md", cwd.to_string_lossy().replace('\\', "/")); + let result = check_file_size_threshold(&abs, 60_000, &config); + assert!( + result.is_some(), + "絶対パス入力で発火しないと実運用では無言の no-op になる: {}", + abs + ); + } + + /// リポジトリ外の絶対パスは対象外 (誤って検査しない)。 + /// + /// 固定パス (`/other-repo` 等) を使うと、実行環境の cwd がたまたま一致した場合に + /// 正しい実装でも落ちる。cwd から派生させた sibling path なら、cwd 自身とは必ず + /// 別ディレクトリであることが構造的に保証される。 + #[test] + fn file_size_check_skips_absolute_path_outside_repo() { + let config = FileSizeCheckConfig { + enabled: true, + threshold_bytes: 51_200, + paths: vec!["docs/**/*.md".to_string()], + touch_trigger: true, + }; + let cwd = std::env::current_dir().expect("cwd"); + let outside = format!( + "{}-outside/docs/x.md", + cwd.to_string_lossy().replace('\\', "/") + ); + assert!(check_file_size_threshold(&outside, 60_000, &config).is_none()); + } + #[test] fn file_size_check_skips_when_path_does_not_match_glob() { let config = FileSizeCheckConfig { diff --git a/src/hooks-post-tool-linter/src/main.rs b/src/hooks-post-tool-linter/src/main.rs index 6dd7784e..fd77ee19 100644 --- a/src/hooks-post-tool-linter/src/main.rs +++ b/src/hooks-post-tool-linter/src/main.rs @@ -17,6 +17,7 @@ mod config; mod custom_rules; mod file_size_check; mod pipeline_runner; +mod repo_path; mod utf8_integrity; mod violation; diff --git a/src/hooks-post-tool-linter/src/repo_path.rs b/src/hooks-post-tool-linter/src/repo_path.rs new file mode 100644 index 00000000..78e644fb --- /dev/null +++ b/src/hooks-post-tool-linter/src/repo_path.rs @@ -0,0 +1,112 @@ +//! hook が受け取るファイルパスを、config の glob と同じ土俵 (リポジトリ相対) へ揃える層。 +//! +//! # なぜ必要か +//! +//! `.claude/hooks-config.toml` の `paths` や `.claude/custom-lint-rules.toml` の `paths` は +//! **リポジトリ相対の glob** (`docs/**/*.md` / `.takt/workflows/*.yaml`) で書く。一方 +//! Claude Code が PostToolUse hook に渡す `tool_input.file_path` は **絶対パス** +//! (`C:/Users/.../repo/docs/guide.md`) である。 +//! +//! 両者をそのまま照合すると `docs/` 始まりの glob は `C:/` 始まりの文字列に一致せず、 +//! **フィルタが常に不一致 = 検査が無言で no-op になる**。2026-08-13 の調査で、 +//! `file_size_check` (50KB 閾値) と `paths` 付き custom rule の両方がこの理由で一度も +//! 発火していなかったことが実測で判明した (docs 配下に 50KB 超が 6 件蓄積していた)。 +//! +//! # 正規化の方針 +//! +//! 現在の作業ディレクトリ (hook はリポジトリ root で起動される) を prefix として剥がす。 +//! 剥がせない場合は**元の文字列をそのまま返す** — 判定を「マッチしない」側へ倒すことで、 +//! リポジトリ外のファイルを誤って検査対象に含めない (fail-safe)。 + +/// 区切りを `/` に揃え、可能なら現在の作業ディレクトリからの相対パスへ変換する。 +/// +/// Windows ではドライブレターの大小が経路によって揺れる (`C:` / `c:`) ため、prefix 比較は +/// 大小無視で行う。返す値は元の文字列から切り出すので、パス自体の大小は保たれる。 +pub(crate) fn to_repo_relative(file: &str) -> String { + let normalized = file.replace('\\', "/"); + let Ok(cwd) = std::env::current_dir() else { + return normalized; + }; + let root = cwd.to_string_lossy().replace('\\', "/"); + let root = root.strip_suffix('/').unwrap_or(&root); + if root.is_empty() { + return normalized; + } + strip_root_prefix(&normalized, root).unwrap_or(normalized) +} + +/// `normalized` が `root` 配下なら、root を剥がした相対パスを返す。 +/// +/// `root` の直後が `/` であることまで確認する。これが無いと `/repo` と `/repo-backup` の +/// ように prefix を共有する別ディレクトリを同一視してしまう。 +fn strip_root_prefix(normalized: &str, root: &str) -> Option { + let head = normalized.get(..root.len())?; + if !head.eq_ignore_ascii_case(root) { + return None; + } + let rest = normalized.get(root.len()..)?; + let rest = rest.strip_prefix('/')?; + if rest.is_empty() { + return None; + } + Some(rest.to_string()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn backslashes_become_forward_slashes() { + assert_eq!( + to_repo_relative("docs\\adr\\adr-001.md"), + "docs/adr/adr-001.md" + ); + } + + /// リポジトリ外のパスは相対化できないのでそのまま返る (= glob に一致せず対象外)。 + #[test] + fn path_outside_repo_is_returned_as_is() { + let outside = if cfg!(windows) { + "D:/elsewhere/docs/x.md" + } else { + "/elsewhere/docs/x.md" + }; + assert_eq!(to_repo_relative(outside), outside); + } + + /// 実際の hook 入力形式 (cwd 配下の絶対パス) が相対へ落ちること。 + /// + /// **本 crate の検査層はすべてこの形の入力を受け取る。** 相対パスだけを渡すテストでは + /// 正規化の欠落を検出できず、実際に `file_size_check` と `paths` 付き custom rule が + /// 無言で no-op になっていた (2026-08-13)。 + #[test] + fn absolute_path_under_cwd_becomes_repo_relative() { + let cwd = std::env::current_dir().expect("cwd"); + let abs = format!("{}/docs/guide.md", cwd.to_string_lossy().replace('\\', "/")); + assert_eq!(to_repo_relative(&abs), "docs/guide.md"); + } + + #[test] + fn absolute_path_with_backslashes_becomes_repo_relative() { + let cwd = std::env::current_dir().expect("cwd"); + let abs = format!("{}\\src\\main.rs", cwd.to_string_lossy()); + assert_eq!(to_repo_relative(&abs), "src/main.rs"); + } + + /// prefix を共有する別ディレクトリ (`-backup`) を repo 配下と誤認しない。 + #[test] + fn sibling_directory_sharing_the_prefix_is_not_stripped() { + let cwd = std::env::current_dir().expect("cwd"); + let sibling = format!("{}-backup/docs/x.md", cwd.to_string_lossy().replace('\\', "/")); + assert_eq!(to_repo_relative(&sibling), sibling); + } + + /// cwd 自身 (末尾にファイル名が無い) は相対化しない。 + #[test] + fn cwd_itself_is_returned_as_is() { + let cwd = std::env::current_dir().expect("cwd"); + let root = cwd.to_string_lossy().replace('\\', "/"); + assert_eq!(to_repo_relative(&root), root); + } +}