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
15 changes: 11 additions & 4 deletions docs/bugfix-batch-plan.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 不具合修正バックログ消化計画 — 第 2 バッチ

> **状態**: 第 1 バッチ (PR A〜L、12 本) はすべてマージ済み。**第 2 バッチは優先枠 PR T〜W (4 本) + 通常枠 PR M〜S (7 本) の計 11 本。うち PR T が実装済み (未マージ)、残り 10 本は未着手**。加えて第 1 バッチの実走観測が 2 件残っている。**優先枠を先に消化する** (→ [§ 優先枠](#優先枠-pr-tw--他の不具合の発見を遅らせる層))。
> **状態**: 第 1 バッチ (PR A〜L、12 本) はすべてマージ済み。**第 2 バッチは優先枠 PR T〜W (4 本) + 通常枠 PR M〜S (7 本) の計 11 本。うち PR T がマージ済み、PR V が実装済み (未マージ)、残り 9 本は未着手**。加えて第 1 バッチの実走観測が 2 件残っている。**優先枠を先に消化する** (→ [§ 優先枠](#優先枠-pr-tw--他の不具合の発見を遅らせる層))。
>
> **本ファイルは ephemeral な作業計画書**である。第 2 バッチのマージと後始末が済み、下記の観測も済んだら**本ファイル自身を削除する** (→ [§ 退役手順](#退役手順))。
>
Expand Down Expand Up @@ -38,8 +38,8 @@

| # | PR | 対象順位 | 状態 |
|---|---|---|---|
| T | `fix(nightly-todo): 着手して失敗した夜を red にする` | 488 | **実装済み (未マージ)** — 実走確認はマージ後の dry_run dispatch |
| V | `fix(pr-monitor): takt 前後の比較で作業ツリー変更を判定する` | 490 | 未着手 |
| T | `fix(nightly-todo): 着手して失敗した夜を red にする` | 488 | **マージ済み ([#445](https://github.com/aloekun/claude-code-hook-test/pull/445))** — 実走確認のみ残 |
| V | `fix(pr-monitor): takt 前後の比較で作業ツリー変更を判定する` | 490 | **実装済み (未マージ)** |
| W | `test(ledger): 台帳の実体整合を cargo test で検査する` | 491 | 未着手 |
| U | `fix(jj-op-verify): 付随 op を読み飛ばして照合する` | 489 | 未着手 |

Expand Down Expand Up @@ -78,7 +78,14 @@
中身を失う**。比較材料 `pre_takt_cid` は既に捕捉されており、同一 crate の `scope_guard.rs` に
正しい実装例がある。

**後始末**: todo25.md の 490 節 + todo-summary2.md の 490 行を削除。
**実装済み (2026-08-25)**: `diff_at_is_empty()` を I/O 層 (`query_at_emptiness`) と判定層
(`interpret_at_emptiness`) に分離し、警告経路は `pre_takt_cid` を基準にした pure function
`judge_tree_change` へ差し替えた。**`pre_takt_cid` が `None` のときは第 3 の状態
`Undeterminable`** — 「判定不能」を専用文言で出し、片付けコマンドは案内しない (2026-08-25
ユーザー決定。fail-open では本当の変更を見逃し、fail-closed では本 PR が直す実害が残るため)。
浮上した設計の問い 2 件は defect-convergence-plan.md § Phase 2 に機2 の入力として記録済み。

**後始末**: todo25.md の 490 節 + todo-summary2.md の 490 行を削除 — **実施済み (2026-08-25)**。

#### PR W — 台帳の実体整合を cargo test で検査する (順位 491)

Expand Down
21 changes: 19 additions & 2 deletions docs/defect-convergence-plan.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 不具合収束計画 — 後追い発覚ループの根治

> **状態**: Phase 0 が進行中 (PR T = 実装済み・未マージ / V・W・U = 未着手)、Phase 1 以降は未着手。**PR 総数は新規 7 本 (機構 4 + ルール撤廃 3)**。既存の第 2 バッチ 11 本 ([bugfix-batch-plan.md](bugfix-batch-plan.md)) と交錯して進める (→ [§ 全体順序](#全体順序))。
> **状態**: Phase 0 が進行中 (PR T = マージ済み / V = 実装済み・未マージ / W・U = 未着手)、Phase 1 以降は未着手。**PR 総数は新規 7 本 (機構 4 + ルール撤廃 3)**。既存の第 2 バッチ 11 本 ([bugfix-batch-plan.md](bugfix-batch-plan.md)) と交錯して進める (→ [§ 全体順序](#全体順序))。
>
> **本ファイルは ephemeral な作業計画書**であり、**本ファイルと参照先の repo 内ドキュメントだけで作業に着手できる**ことを編集方針とする (実装セッションは本計画の策定会話を参照できない)。退役条件は [§ 退役手順](#退役手順)。
>
Expand Down Expand Up @@ -66,7 +66,7 @@

## Phase 0 — 優先枠 T〜W (既存 4 本)

**進捗 (2026-08-25)**: **T = 実装済み (未マージ)**、V / W / U = 未着手。T は緑/赤分類を新 crate `cli-nightly-outcome` へ移し、`Report outcome` step を exe 呼び出しへ縮退させた。
**進捗 (2026-08-25)**: **T = マージ済み ([#445](https://github.com/aloekun/claude-code-hook-test/pull/445))**、**V = 実装済み (未マージ)**、W / U = 未着手。T は緑/赤分類を新 crate `cli-nightly-outcome` へ移し `Report outcome` step を exe 呼び出しへ縮退させた。V は `diff_at_is_empty()` を I/O 層と判定層に分け、takt 前後の比較を `pre_takt_cid` 基準の pure function にした。

実施内容・完了基準・後始末は bugfix-batch-plan.md § 優先枠を正とする。ただし**以下の実装方針変更が同計画の記載に優先する**:

Expand Down Expand Up @@ -136,6 +136,23 @@

**境界 (doc コメントに書く)**: 「問うべきなのに書かなかった」は検出不能。本機構の保証は「**書かれた問いは必ず push 前にユーザーへ届く**」まで。問いが浮上すること自体は機1 の pure 化作業に依存する (Phase 0 PR V で実地検証済みであること)。

### Phase 0 PR V で実地に浮上した問い (2026-08-25、エントリ形式の検証材料)

**新規ファイルは作らない** (ユーザー決定)。`docs/open-questions.md` は機2 の実装 PR で新規作成し、本節はその**最初の入力**として使う。

PR V の pure 化作業で実際に浮上した問いは次の 2 件で、いずれも**その場でユーザーに確認して解消済み**である。エントリ形式 (`## Q-<連番>` + `関連:` + `仮定:`) がこの 2 件を表現できるかが、機2 実装時の受け入れ確認になる。

| 問い | 関連 | 当時置いた仮定 | 得た回答 (2026-08-25) |
|---|---|---|---|
| **比較材料 (`pre_takt_cid`) が `None` のとき、警告を出すか出さないか** | [monitor.rs](../src/cli-pr-monitor/src/stages/monitor.rs) `judge_tree_change` | ADR-043 に従い助言層なので fail-open | **どちらでもない第 3 の状態**を持つ。「判定不能」を専用文言で出し、`jj abandon` / `jj restore` は案内しない (fail-open だと本当の変更を見逃し、fail-closed だと順位 490 の実害が残るため) |
| **`diff_at_is_empty()` の pure 化はどこまでやるか** (判定層だけか、関数ごと I/O と分離するか) | [runner.rs](../src/cli-pr-monitor/src/runner.rs) | 呼び出し元が 2 系統あるため warning 経路だけ切り出す | **関数ごと I/O と判定を分離する**。機1 の allowlist 初期登録から `diff_at_is_empty` が 1 件減る |

**この 2 件から分かったこと (機2 の設計に反映すること)**:

1. **問いには「回答」だけでなく「置いた仮定」が要る** — どちらの問いも、答えを待たずに実装を進めるための仮定を置いていた。仮定を書かないと、回答が来たときにどのコードを直すべきか分からない。現行のエントリ形式 (`仮定:` を必須要素にしている) はこの点を満たしている
2. **二択に見えて三択のことがある** — 1 件目は「fail-closed か fail-open か」の二択として起票されていた (todo25.md の 490 節) が、実際の答えはどちらでもなかった。**エントリ形式に選択肢を書く欄を設けない**のは正しい (選択肢を書くと答えがその中にあると誤読させる)
3. **`関連:` はファイルパスだけで足りた** — 行番号を書くと実装中にずれる

## Phase 3 — 機3: shell 判定の exe 移送 (新規 1 本)

**何を止めるか**: `.github/workflows/nightly-todo.yml` の掃除ループ (`Clean up branches of settled PRs` step) に shell 判定として実装された 3 分岐が、テスト不能なまま残ること。
Expand Down
1 change: 0 additions & 1 deletion docs/todo-summary2.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@
| 486 | 🚀 Tier 1 | **auto lane の対象ファイルが Guard 禁止パスに当たる行を決定論的に弾く (夜間ループ停止調査 2026-08-22 由来)** | todo25.md | S | なし (2026-08-20 の run が順位 383 を選び `src/lib-ledger/src/lib.rs` の変更で `[NIGHTLY_DENY]` 停止。auto lane 22 行の全件照合で 5 行が deny リスト該当 (383 / 454 / 368 / 360 / 361)。ADR-074 決定 2 クラス 3 の判定を決定論化する — 同 ADR 決定 6 が「決定論だが未実装」と自認している穴。**実装先が deny リスト配下のため auto lane に載せない**) |
| 487 | 🚀 Tier 1 | **nightly-todo の master 参照を SHA で pin する (夜間ループ停止調査 2026-08-22 由来)** | todo25.md | S | なし (2026-08-21 の run で master-ref=`7539551f` / work=`868c9316` と 31 秒差の別コミットを読み、その間に順位 228 の実装 PR #422 がマージされて変更 0 件で停止。master を 3 回別々に読むのに pin が無い。**`.github/workflows/` が deny リスト該当のため auto lane に載せない**) |
| 489 | 🔧 Tier 2 | **jj-op-verify の照合窓が付随 op に押し下げられて誤警告する (優先枠 PR U)** | todo25.md | S | なし (`jj op log --limit 1` の先頭を付随 op (snapshot / fetch / push / import git refs) が占めると誤警告。直近 40 op のうち 28 件 (70%) が付随 op、本セッションの誤警告率 50% (4 回中 2 回)。**順位 476 とは根本原因が別**で 476 を実装しても塞がらない。案 B (付随 op の skip) 起点。チェーン内最後の 1 件しか追跡しない点とサブプロセスの op を予見できない点は本案の範囲外) |
| 490 | 🚀 Tier 1 | **post-pr-monitor が「takt が作業ツリーを変更した」と誤警告する (優先枠 PR V)** | todo25.md | S | なし (`diff_at_is_empty()` が「takt の前後で変化したか」ではなく「`@` が空コミットか」を聞いている。feature ブランチでは `@` が PR の中身そのものなので必ず false になり、takt が何もしなくても警告が出る。**文言が `jj abandon` / `jj restore` を案内するため額面どおり実行すると PR の中身を失う**。比較材料 `pre_takt_cid` は既に捕捉済みで scope_guard に正しい実装例がある) |
| 491 | 🚀 Tier 1 | **台帳の実体整合を毎 cargo test で検査する (優先枠 PR W)** | todo26.md | M | なし (2 クラスとも既存の決定論検査の射程外だった — A: lane と § 対象外 の矛盾 (162/199、台帳の編集時に発生するが `cli-ledger-candidates` は未掲載しか見ない)、B: 宣言パスの漂流 (162/143/176/145、**台帳を編集していないのに壊れる**ためADR-074 決定 4 の登録時 1 回きりの存在確認では捕まらない)。順位 486 と同じ層で統合検討。`src/lib-ledger/` が Guard 禁止パスのため auto lane 不可) |

**戦略**: Tier 1 を 2〜3 セッションで片付け → Tier 2 で計測基盤 (gate telemetry / weekly-review 保存) + rate-limit + convergence cost 削減を進める → Tier 3 でドキュメント整備。Tier 4-5 は cleanup / 外部展開で daily efficiency への直接効果は小さい。(2026-08-12 更新: 旧記述の ADR-032 は ADR-057 置換で欠番)
Expand Down
61 changes: 0 additions & 61 deletions docs/todo25.md
Original file line number Diff line number Diff line change
Expand Up @@ -607,64 +607,3 @@ green になること。検査を外す変異で落ちること。

付随 op が head を占めても誤警告が出ないこと。本物の未記録は従来どおり警告されること。
両方向が unit test で固定され、**本案で塞がらない限界が doc から追えること**。

---

### post-pr-monitor が「takt が作業ツリーを変更した」と誤警告する (順位 490)

> **動機**: findings 0 件の再 push のたびに次の警告が出る。本セッションで **2 回**発生した。
>
> ```text
> [warn] findings 0 件なのに takt が作業ツリーを変更しました。push せず残します —
> jj diff で内容を確認し、不要なら jj abandon / jj restore で片付けてください
> ```
>
> **実際には takt は何も変更していない** (ローカル @ と origin が同一コミット、差分 0 件で確認)。
>
> **根本原因**: 判定が**別の問いを聞いている**。コメントは「takt が作業ツリーを変更したか」
> = before/after の比較を意図しているが、実装は
> [`diff_at_is_empty()`](../src/cli-pr-monitor/src/runner.rs) が
> jj log -r @ のテンプレート empty 判定で「**@ が空コミットか**」を聞いている。
> feature ブランチでは @ が PR の中身そのものなので empty は常に false になり、
> **takt が何もしなくても必ず「変更した」と判定される**。
>
> 前提が成り立つのは「takt 実行前の @ が空」の文脈だけ。`pnpm push` 経路では
> push-runner が bookmark を @ に進めるため @ = push したコミット本体になり、前提が崩れる。
>
> **実害**: log_info で出るだけで push は止めないが、**文言が jj abandon / jj restore を
> 案内している**。額面どおり実行すると **PR の中身を失う**。助言層だが誤誘導の実害がある。
>
> **材料は既にある**: TaktOutcome に pre_takt_cid が捕捉されており
> ([monitor.rs](../src/cli-pr-monitor/src/stages/monitor.rs))、execute_repush_flow には
> 渡されている。warn_if_takt_changed_the_tree_without_findings が引数を受け取っていない
> ため使えていないだけ。同種の正しい比較は **同一 crate 内の
> [scope_guard.rs](../src/cli-pr-monitor/src/stages/scope_guard.rs)** が
> jj diff --from pre_takt_cid --to @ --summary で実装済み。
>
> **参照**: [`src/cli-pr-monitor/src/stages/monitor.rs`](../src/cli-pr-monitor/src/stages/monitor.rs)、
> [`src/cli-pr-monitor/src/runner.rs`](../src/cli-pr-monitor/src/runner.rs)
>
> **実行優先度**: 🚀 **Tier 1** — Severity **High** (案内どおり操作すると作業を失う) /
> Frequency High (findings 0 件の再 push ごと。実測 2/2) / Effort S / Adoption Risk Low。

#### 設計決定 (案)

- warn_if_takt_changed_the_tree_without_findings に pre_takt_cid を渡し、
jj diff --from pre_takt_cid --to @ が空かで判定する (scope_guard と同じ呼び方)
- **pre_takt_cid が None (捕捉失敗) のときの扱いを決める** — fail-closed (警告を出す) と
fail-open (出さない) のどちらが正しいかは、誤誘導の実害を踏まえて判断する
- diff_at_is_empty の他の呼び出し元が同じ誤解をしていないか確認する

- [ ] pre_takt_cid ベースの比較へ差し替える
- [ ] pre_takt_cid が None のときの方針を決めて doc に残す
- [ ] diff_at_is_empty の全呼び出し元を確認する
- [ ] 「takt が変更した / していない」の両方向を回帰テストで固定する

#### 完了基準

takt が作業ツリーを変更していない再 push で警告が出ないこと。実際に変更した場合は従来どおり
警告されること。両方向がテストで固定されていること。

**`pre_takt_cid` が `None` の経路もテスト対象に含める** — 基準コミットが取れないときに
fail-closed (警告を出す) か fail-open (出さない) かを決め、**決めた方の挙動をテストで固定する**。
ここを未定義のまま残すと、比較材料が無い状況で従来と同じ誤警告に戻りうる。
Loading
Loading