feat(nightly-todo): 改ざん検知を red 化し決定 10 の色分けと決定 6 の列挙基準を明文化する (ADR-072) - #366
Conversation
#363 の最終 push が pre-push security review の REJECT で止まったため master に 載らなかった 3 点を、master 上に載せ直す。いずれも可観測性と文書の改善で、 fail-closed 自体は master 版でも成立している。 ## 改ざん検知を green から red へ (workflow) ゲート資産の改ざん検知 step から continue-on-error を除去する。 fail-closed は元から成立していた — continue-on-error: true でも下流の `if: steps.integrity.outcome == 'success'` で push は止まる。問題は**色**で、 green で終わるため run 一覧上「何もすることが無かった夜」と区別が付かなかった。 毎晩回る無人ループでは、この 2 つが混ざった時点で run 一覧が読まれなくなる。 改ざん検知は「何かがゲートを無効化しようとした」という、この系が出しうる最も 大きい信号である。red で落ちても後続 step は if: の評価前に skip されるため push には到達せず、Report outcome は if: '!cancelled()' なので診断行は出る。 ## 決定 10 に色分け表を追加 (ADR-072) 「設計された停止」と「インフラ障害」の 2 分類を表にしたところ、**改ざん検知が どちらにも入っていない**ことが露出した。分類を明文化すると分類に入らない結末が 可視になる、の実例として § 静的レビューが捕捉した件 の #10 に記録した。 見落としていたのは安全性ではなく可観測性の側だった。 ## 決定 6 に列挙基準を追加 (ADR-072) 禁止リストの基準は「危険か」ではなく「**将来の無人 run のゲートを緩めるか**」で ある。security review が挙げた Cargo.toml / Cargo.lock の欠落を採らない根拠が これで、通常の diff は人間の PR レビューとマージという既存の防衛線が効く。 基準を持たないと禁止リストは「怪しいもの全部」へ膨らみ正当なタスクを弾き始める。 ## 適用方法 保持していたローカル bookmark (wp18/unpushed-improvements) は #363 マージ前の スタックのため、そのまま復元すると **#364 で入れた ADR-072 § 残課題 の追記 (外部設定の実体が未記録 / 秘密値は記録しない) を巻き戻す**。したがって workflow は ファイル単位で restore し、ADR-072 は追加分 4 箇所のみ手で適用した。適用後に lpzvttwu との差分が #364 の 1 行だけであることを実測確認している。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthrough夜間Todoワークフローのゲート完全性検証を fail-closed に変更しました。検証失敗時はジョブが失敗し、権限付きゲートと push 処理へ進みません。ADR-072に判定基準とレビュー記録を追加しました。 Changes夜間ゲート完全性検証
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🤖 PR Monitor 分析 (GitHub Actions バックストップ)
Applicable Findings (Critical / High / Major)該当なし Applicable Findings (Medium 以下)該当なし Filtered (not applicable)該当なし diff 概要 (軽量サマリー)
次のアクション
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/adr/adr-072-nightly-todo-loop.md`:
- Around line 213-220: Decision 10 の red 分類を workflow に反映するため、Prepare a clean
publish tree、Mint App token、Push branch and open draft PR の各ステップから
continue-on-error: true を削除してください。Report outcome の成功時処理は維持し、これらの
gh/network/clone 失敗時にジョブが失敗扱いになるようにします。
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 6a7c5af7-31e0-4706-8abd-69c16d65c3e8
📒 Files selected for processing (2)
.github/workflows/nightly-todo.ymldocs/adr/adr-072-nightly-todo-loop.md
| | 結末 | 色 | 根拠 | | ||
| |---|---|---| | ||
| | 背圧 deny / タスク無し / guard deny / 空 diff | green + `[NIGHTLY_SKIP]` | 設計された結末。毎晩起こりうる | | ||
| | `gh` / network / clone の失敗 | **red** | インフラ障害。設計された結末ではない | | ||
| | **ゲート資産の改ざん検知 (決定 7)** | **red** | 「何かがゲートを無効化しようとした」— この系が出しうる最も大きい信号 | | ||
|
|
||
| 改ざん検知を red にするのは初版で落としていた。`continue-on-error: true` + 下流の `if: steps.integrity.outcome == 'success'` で push は止まる (fail-closed は成立している) が、**green で終わるため run 一覧上は「何もすることが無かった夜」と区別が付かない**。決定 10 を書いたことで、その分類にこの結末が入っていないことが露出した (§ 静的レビューが捕捉した件 #10)。 | ||
|
|
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Decision 10 の赤分類を workflow に反映してください。
表は gh / network / clone の失敗を red と定義しています。しかし、.github/workflows/nightly-todo.yml の Prepare a clean publish tree(Line 290)、Mint App token(Line 385)、Push branch and open draft PR(Line 396)は continue-on-error: true のままです。
これらの失敗後は Report outcome が exit 0 するため、job は green になります。ADR の分類と実装が不一致です。該当する continue-on-error を削除してください。
修正案
- name: Prepare a clean publish tree (agent never touched its .git)
id: publish-tree
- continue-on-error: true
- name: Mint App token (so ci.yml attaches to the draft PR)
id: app-token
- continue-on-error: true
- name: Push branch and open draft PR (workflow-authored)
id: publish
- continue-on-error: true🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/adr/adr-072-nightly-todo-loop.md` around lines 213 - 220, Decision 10 の
red 分類を workflow に反映するため、Prepare a clean publish tree、Mint App token、Push branch
and open draft PR の各ステップから continue-on-error: true を削除してください。Report outcome
の成功時処理は維持し、これらの gh/network/clone 失敗時にジョブが失敗扱いになるようにします。
🤖 PR Monitor 分析 (GitHub Actions バックストップ)
Applicable Findings (Critical / High / Major)
Applicable Findings (Medium 以下)該当なし Filtered (not applicable)該当なし(対象 ADR (docs/adr/adr-072-nightly-todo-loop.md L209 「インフラ障害は continue-on-error を付けず red のまま落とす」) の記述と指摘は整合しており、意図的設計との矛盾なし。read-only zone / sensitive-file / platform-scope のいずれにも該当しない) 次のアクション
|
自動 fix 経路が作った commit を、内容を実測検証したうえで採用したもの。 **push 自体は scope guard (ADR-054) が BLOCK した** — finding の anchor が docs/adr/adr-072 なのに fix が .github/workflows/ を触ったため。指摘の remedy が anchor と別ファイルにある典型で、guard の設計どおりの挙動だが本件は injection では ないため誤検知にあたる (WP-11 の enforce 期間の観測データとして計上すべき)。 ## 指摘の妥当性 同 PR で追加した決定 10 の色分け表は「gh / network / clone の失敗 → red」と 定めているのに、その 3 経路が continue-on-error: true で green に落ちていた。 表を追加した PR 自身が作った不整合であり、妥当と判断して採用する。 - Prepare a clean publish tree — git clone (ネットワーク I/O) - Mint App token — GitHub API 呼び出し (secret 誤設定・GitHub 障害) - Push branch and open draft PR — git push / gh pr create ## 実測検証 (fix の出力を鵜呑みにしない) - 下流の if: はいずれも `steps.<id>.outcome == 'success'` 形式のため、失敗時は 後続が skip され push へ到達しない (fail-closed は維持) - Report outcome は `if: '!cancelled()'` なので red でも診断行は出る - dry_run=true では app-token / publish は if: により **skipped** (failed ではない) ため、dry_run の run は green のまま ## ADR への記帳 表を書いた著者自身は 1 件 (改ざん検知) しか見つけられず、残り 3 件は他者の レビューで出た。**分類の明文化は露出の必要条件であって十分条件ではない**ことの 実例として決定 10 へ追記した。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
いずれも「実コードを確認せず断定していた」箇所で、実装を verify して直した。 ## #1 (harness-plan) WP-11 の「誤検知」→「設計どおりの保守的 deny」 evaluate_scope_guard の allowlist は allowlist_from_paths(findings.map(f.file)) = finding の anchor 位置だけで、remedy が別ファイルなら含まない (ADR-054 も欠点として 明記)。#366 の BLOCK は誤検知ではなく設計どおりの保守的 deny。本採用の判定基準を 「この保守的 deny を誤検知に数えない」よう明確化する、と修正。 ## #2 (todo.md/todo3-7) breadcrumb の todo20/todo2-20 残存 docs バッチで更新し漏れた参照を補完。todo.md 冒頭の使い分けを todo21 + summary2 まで、 todo3-7 の「todo2-20」を todo2-21 へ。全 docs で todo2-20 残存ゼロを確認。 ## #3 (todo21:58) heads(::@ & bookmarks()) の複数返り @ に複数 bookmark が付くと複数コミットを返し clone --head / PR 選択が多対象になる。 trunk 除外 + 単一 bookmark へ絞る (現行 is_trunk_bookmark 除外と同規律) 必要を追記。 ## #4 (todo21:102) 388 の「race」断定を撤回 reconcile_takt_output → copy_feedback_report は find_latest_run_dir で run dir を 選ぶ (mod.rs:147 / takt.rs:84)。単純な write race と断定せず、latest 特定のずれ / パス不一致 / 前後関係を「まず特定する」形へ。#367 では実体が run dir に存在した。 ## 検証 pnpm lint:docs OK / markdownlint 0 error。scope guard・feedback reconcile の実装を 実際に読んで記述と一致させた。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* docs(todo): WP-18 セッションの観測を順位 385-388 へ登録し todo21.md を新設 (Phase 2) WP-18 の PR 作業 (#364〜#370) で実測した自動化経路の運用問題を todo へ登録し、 384 完了削除・todo ローテーション・WP-11 記録を 1 バッチにまとめる。 ## todo21.md 新設 (todo20.md が 56KB = 50KB 閾値超過) 新規追加先を todo20.md → todo21.md へ移行。breadcrumb を持つ 5 ファイル (todo.md / todo8 / todo10 / todo13 / todo14) の「現在の追加先」ポインタと、 数詞「22つ/todo2-20」を持つ 8 ファイル (todo3-11) を 23つ/todo2-21 へ更新。 ## 順位 385-388 (2026-08-08 実測、todo21.md) - 385 (T3): cli-pr-monitor lock の liveness check 欠落 (復帰窓 30 分) - 386 (T2): 監視・自動 fix 経路の空コミットで bookmark ずれ → merge/push 失敗。 **本セッションで 7 回観測**、生成元確定、深さ非依存 revset が本命の対処 - 387 (T2): 自動 fix は push が BLOCK されてもローカル作業コピーを書き換える - 388 (T3): post-merge-feedback の完了判定が書き込みと race し誤 failed marker いずれも post-merge feedback には構造的に入らない (feedback の入力は PR diff と レビュー指摘で、ツール自身の運用中の事象は拾わない)。 ## 順位 384 完了・削除 外部設定の実体は ADR-072 § 外部設定の実体 に記録済み (#369/#370)。todo20.md の full エントリと summary2 の行を削除し、完了記録の 1 行に置換。 ## WP-11 記録 (harness-improvement-plan) #366 で enforce 下の scope guard 誤検知を 1 件観測。anchor と remedy が別ファイルの 指摘は構造的に必ず BLOCK される。本採用判定の前に判定基準の再定義が要ることを記録。 ## 検証 pnpm lint:docs OK (preamble + cross-ref + priority-inversion — 数詞 23 整合を含む) / markdownlint 127 files 0 error。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: CodeRabbit 指摘 4 件に対応 — 実装確認のうえ断定を訂正 (#371) いずれも「実コードを確認せず断定していた」箇所で、実装を verify して直した。 ## #1 (harness-plan) WP-11 の「誤検知」→「設計どおりの保守的 deny」 evaluate_scope_guard の allowlist は allowlist_from_paths(findings.map(f.file)) = finding の anchor 位置だけで、remedy が別ファイルなら含まない (ADR-054 も欠点として 明記)。#366 の BLOCK は誤検知ではなく設計どおりの保守的 deny。本採用の判定基準を 「この保守的 deny を誤検知に数えない」よう明確化する、と修正。 ## #2 (todo.md/todo3-7) breadcrumb の todo20/todo2-20 残存 docs バッチで更新し漏れた参照を補完。todo.md 冒頭の使い分けを todo21 + summary2 まで、 todo3-7 の「todo2-20」を todo2-21 へ。全 docs で todo2-20 残存ゼロを確認。 ## #3 (todo21:58) heads(::@ & bookmarks()) の複数返り @ に複数 bookmark が付くと複数コミットを返し clone --head / PR 選択が多対象になる。 trunk 除外 + 単一 bookmark へ絞る (現行 is_trunk_bookmark 除外と同規律) 必要を追記。 ## #4 (todo21:102) 388 の「race」断定を撤回 reconcile_takt_output → copy_feedback_report は find_latest_run_dir で run dir を 選ぶ (mod.rs:147 / takt.rs:84)。単純な write race と断定せず、latest 特定のずれ / パス不一致 / 前後関係を「まず特定する」形へ。#367 では実体が run dir に存在した。 ## 検証 pnpm lint:docs OK / markdownlint 0 error。scope guard・feedback reconcile の実装を 実際に読んで記述と一致させた。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
continue-on-errorを除去し、検知時に run を red で落とすContext
Why: いずれも #363 の最終 push が pre-push security review の REJECT で止まったため master に載らなかった 3 点で、ローカル bookmark に保持していた。fail-closed 自体は master 版でも成立している —
continue-on-error: trueでも下流のif: steps.integrity.outcome == 'success'で push は止まる。今回直すのは可観測性であって安全性ではない。問題は run の色だった。改ざん検知が green で終わると、run 一覧上「何もすることが無かった夜」と区別が付かない。毎晩回る無人ループでは、この 2 つが混ざった時点で run 一覧が読まれなくなる。改ざん検知は「何かがゲートを無効化しようとした」という、この系が出しうる最も大きい信号である。
Trigger: WP-18(#361 / #362 / #363)の積み残し。順位 374 の実走スモークを最終形の workflow に対して実施するため、スモーク前に land させる(2026-08-08 ユーザー判断)。
Scope decision: 保持していた bookmark(
wp18/unpushed-improvements)は #363 マージ前のスタックのため、ファイル単位で復元すると #364 で入れた ADR-072 § 残課題 の追記(外部設定の実体が未記録 / 秘密値は記録しない)を巻き戻す。したがって workflow のみjj restoreでファイル復元し、ADR-072 は追加分 4 箇所を手で適用した。適用後に元 bookmark との差分が #364 の 1 行だけであることを実測確認している。todo 系列(順位 385/386 の登録)は本 PR に含めない — 追ってドキュメント PR にまとめる方針のため。
Validation
pnpm pushpre-push review: verdict=APPROVE(simplicity / security 両 facet、1 iteration、62s)lintPASS (2.0s) /testPASS (3.5s) /buildPASS (1.1s) /rust-lint-testPASS (61.8s)fc22403cとの差分が docs(todo): WP-18 の残作業 11 件を登録し計画書を 3 PR マージ済へ更新 (順位 374-384) #364 の 残課題 1 行のみであることをjj diffで確認References
Summary by CodeRabbit
バグ修正
ドキュメント