Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
36 changes: 35 additions & 1 deletion .github/workflows/nightly-todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,35 @@ jobs:
--title "feat: 順位 ${RANK} の無人実装 (nightly-todo)" \
--body-file "$RUNNER_TEMP/pr-body.md"

# CodeRabbit の自動レビューは draft PR を対象外にしている
# (.coderabbit.yaml の reviews.auto_review.drafts: false = ADR-019 のクォータ設計)。
# 一方 ADR-052 / 本 ADR は夜間ループを **draft PR で止める**。この 2 つを素直に
# 組み合わせると「夜間 PR は永久にレビューされない」状態になる (2026-08-08 に PR #365 で
# 実測)。両立のため、draft PR 作成後に**明示トリガーを 1 回だけ**投げる。
# ADR-019 が fix push で採っている「自動増分レビューを止め、明示 `@coderabbitai review` を
# 1 回投稿する」と同じ形で、レート消費は 1 PR あたり 1 回に留まる。
#
# **token は App のものを使う。** job の GITHUB_TOKEN は pull-requests: read しか
# 持たず、書き込み権限を戻すと決定 8 § 副次効果 (agent が触れる唯一の資格情報を
# read-only にした) を巻き戻してしまう。
#
# **本 step は continue-on-error で受ける。** 決定 10 は gh / network の失敗を red と
# 分類するが、それは無人ループの本体経路 (実装 → ゲート → push → PR 作成) の話であり、
# レビュー起動は成果物が出来た**後**に走る助言層にあたる。[ADR-043] が「fail-closed は
# ゲート関数のみ。助言層は fail-open が正しい」と定めているため、ここで run を red に
# すると「draft PR は正しく出来たのにレビュー起動だけ失敗した夜」が「本当に壊れた夜」と
# 同じ色になる。代わりに outcome を Report outcome へ出して可視化する。
- name: Request a CodeRabbit review (drafts are excluded from auto review)
id: request-review
continue-on-error: true
if: steps.publish.outcome == 'success'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
BRANCH: ${{ steps.select.outputs.branch }}
run: |
set -euo pipefail
gh pr comment --repo "${{ github.repository }}" "$BRANCH" --body "@coderabbitai review"

# 無音で終わらせない (ADR-064 と同じ論理)。どの段で止まったかを 1 行で出す。
- name: Report outcome
if: '!cancelled()'
Expand All @@ -468,10 +497,15 @@ jobs:
GATE_OUTCOME: ${{ steps.gate.outcome }}
APP_TOKEN_OUTCOME: ${{ steps.app-token.outcome }}
PUBLISH_OUTCOME: ${{ steps.publish.outcome }}
REQUEST_REVIEW_OUTCOME: ${{ steps.request-review.outcome }}
run: |
echo "[NIGHTLY] preflight=${PREFLIGHT_OUTCOME:-<未実行>} select=${SELECT_OUTCOME:-<未実行>} implement=${IMPLEMENT_OUTCOME:-<未実行>} verify=${VERIFY_OUTCOME:-<未実行>} publish_tree=${PUBLISH_TREE_OUTCOME:-<未実行>} guard=${GUARD_OUTCOME:-<未実行>} integrity=${INTEGRITY_OUTCOME:-<未実行>} gate=${GATE_OUTCOME:-<未実行>} app_token=${APP_TOKEN_OUTCOME:-<未実行>} publish=${PUBLISH_OUTCOME:-<未実行>}"
echo "[NIGHTLY] preflight=${PREFLIGHT_OUTCOME:-<未実行>} select=${SELECT_OUTCOME:-<未実行>} implement=${IMPLEMENT_OUTCOME:-<未実行>} verify=${VERIFY_OUTCOME:-<未実行>} publish_tree=${PUBLISH_TREE_OUTCOME:-<未実行>} guard=${GUARD_OUTCOME:-<未実行>} integrity=${INTEGRITY_OUTCOME:-<未実行>} gate=${GATE_OUTCOME:-<未実行>} app_token=${APP_TOKEN_OUTCOME:-<未実行>} publish=${PUBLISH_OUTCOME:-<未実行>} request_review=${REQUEST_REVIEW_OUTCOME:-<未実行>}"
if [ "${PUBLISH_OUTCOME:-}" = "success" ]; then
echo "[NIGHTLY] draft PR を作成しました。"
# 助言層の失敗は run を red にしないが、無音にもしない (ADR-043)。
if [ "${REQUEST_REVIEW_OUTCOME:-}" != "success" ]; then
echo "[NIGHTLY_WARN] CodeRabbit レビューの明示トリガー投稿に失敗しました (request_review=${REQUEST_REVIEW_OUTCOME:-<未実行>})。draft PR は作成済みなので、必要なら PR へ手で '@coderabbitai review' を投稿してください。"
fi
exit 0
fi
echo "[NIGHTLY_SKIP] 本 run は draft PR を作りませんでした。上の 1 行で停止段を特定してください。"
53 changes: 37 additions & 16 deletions docs/adr/adr-072-nightly-todo-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,24 @@ clone は shallow にしない。新規ブランチの push で shallow update

pre-push simplicity review はここを「他の停止点と同様に graceful degradation すべき」と指摘したが、上記の理由で**現状を維持する**。指摘が再発しないよう決定として記録しておく。

### 11. draft PR 作成後に CodeRabbit レビューを明示トリガーする

**夜間 draft PR は、放っておくと永久にレビューされない。** 初回の実走 (2026-08-08、PR #365) で確定した:

- [`.coderabbit.yaml`](../../.coderabbit.yaml) は `reviews.auto_review.drafts: false` を設定している ([ADR-019](adr-019-coderabbit-review-hybrid-policy.md) の無料枠クォータ設計)
- 一方 [ADR-052](adr-052-autonomy-execution-boundary-classes.md) と本 ADR は、夜間ループを **draft PR で止める**と決めている (commitment 点の手前)
- 両者を素直に組み合わせると、夜間 PR にはレビューが付かない。さらに [ADR-067](adr-067-phase-b-unattended-fix-push.md) の Phase B は `issue_comment` / `pull_request_review` で起動するため、**Phase B も夜間 PR では永久に発火しない**

**どちらの設定も単体では正しく、衝突は 2 つを繋いだときにだけ現れる。** 実際、本 ADR § 欠点 は「Phase A が夜間 draft PR で自動起動しない可能性がある」と書きながら、原因を CodeRabbit の起動条件ではなく**自リポジトリの設定**に求めていなかった。設定ファイル 1 行と ADR の決定が論理結合している型で、[ADR-051](adr-051-cross-system-config-coupling.md) が扱う coupling の内部版にあたる。

**解き方は `drafts: true` ではなく明示トリガーを採る。** `drafts: true` は ADR-019 が解いたレート消費の問題を戻す。ready 化は ADR-052 の commitment 点を侵す。採ったのは **draft PR 作成後に `@coderabbitai review` を 1 回だけ投稿する**方法で、これは ADR-019 が fix push に対して既に採っている形 (`auto_incremental_review: false` + 監視が明示トリガーを 1 回投稿) と同型である。レート消費は 1 PR あたり 1 回に留まる。

**token は App のものを使う。** job の `GITHUB_TOKEN` は `pull-requests: read` しか持たない。書き込みを戻すと決定 8 § 副次効果 (agent が触れる唯一の GitHub 資格情報を read-only にした) を巻き戻すため、App installation token を使う。

**この step は決定 10 の red 分類の例外で、`continue-on-error` を付ける。** 決定 10 が red と定めるのは無人ループの**本体経路** (実装 → ゲート → push → PR 作成) の失敗であり、レビュー起動は成果物が出来た**後**に走る助言層にあたる。[ADR-043](adr-043-security-gates-fail-closed.md) が「fail-closed はゲート関数のみに適用。助言層は fail-open が正しい」と定めているため、ここで run を red にすると「draft PR は正しく出来たのにレビュー起動だけ失敗した夜」が「本当に壊れた夜」と同じ色になる。**無音にはしない** — `Report outcome` が `request_review` の outcome を出し、失敗時は `[NIGHTLY_WARN]` で手動投稿を促す。

**未検証**: **CodeRabbit が bot (App) の投稿した `@coderabbitai review` に反応するか**は未確認である。bot 同士のループを避けるため他 bot のコメントを無視する実装は珍しくない。次回の夜間 run で反応の有無を実測し、無反応なら (a) PAT 経由の投稿 (ADR-067 の ruleset backstop を bypass するため不可)、(b) `drafts: true` への方針転換とレート影響の再評価、(c) 人手で投げる運用、の 3 択で再判断する (§ 残課題)。

## 試験運用判断基準 (ADR-039)

| 項目 | 内容 |
Expand Down Expand Up @@ -299,24 +317,25 @@ pre-push review を 12 サイクル通す過程で、blocking な欠陥 10 件

#4 は `sha256sum -c` が基準値ファイルを読めない時点で失敗するため、fail-closed が自然に成立する。加えて基準値は `$RUNNER_TEMP` = ワークスペース外にあり agent のサンドボックスが届かないため、防御は 2 層になっている。

### 実走スモーク — **未実施**

**本 ADR の受け入れ基準のうち実走スモークは、この PR の時点では満たしていない。** 実行には (a) 本 workflow が master に存在するか対象ブランチ ref へ `workflow_dispatch` できること、(b) 台帳に無人可マークがあること (= WP-18 PR 2 のマージ) の両方が要る。
### 実走スモーク — allow 経路は **schedule の初回実走で成立** (2026-08-08)

反復は [ADR-067](adr-067-phase-b-unattended-fix-push.md) § 段 2 の知見 2 に従い、**マージせずブランチ ref への `workflow_dispatch`** で行う。`dry_run` 入力でゲート通過まで走らせて push を止められるようにしてある。
**スモークは `workflow_dispatch` で意図的に始める前に、schedule (03:00 JST) の初回実走が先に成立した。** 2026-08-07 18:19 UTC の run が台帳の順位 203 を選び、draft PR [#365](https://github.com/aloekun/claude-code-hook-test/pull/365) (`claude/nightly-203`) の作成まで完走した。

スモークで同梱観測する項目:
**この順序は褒められたものではない。** 受け入れ基準の中核である実走検証を、人間が観測装置を用意した dispatch ではなく**本番の無人 run が先に消化した**形になっている。結果的に成功したが、失敗していれば観測の準備が無いまま夜間に壊れた成果物が出ていた。ここでの教訓は、`AUTONOMY_ENABLED` を立てた時点で schedule も同時に有効になるという事実が、スモーク計画に織り込まれていなかったこと (§ 残課題)。

| 観測項目 | 出所 |
|---|---|
| WP-17 残課題: Phase B の自動起動経路が成立するか | [ADR-067](adr-067-phase-b-unattended-fix-push.md) § 検証記録 |
| WP-17 残課題: `coderabbitai[bot]` allowlist の要否 | 同上 |
| **`cargo` サブプロセスから `CLAUDE_CODE_OAUTH_TOKEN` / `GITHUB_TOKEN` が見えるか** | pre-push security review の warning |
| 決定 7 の照合が実 runner 上でも通ること (誤検知で毎晩止まらないこと) | 本 ADR § integrity 機構の drill |
| **App token で作った draft PR に `ci.yml` の 2 OS run が紐づくこと** | 決定 8 (仕様は公式で確認済み、実環境での成立は未観測) |
| Actions variable `AUTONOMY_ENABLED` が `true` ちょうどで設定されており job が起動すること | ADR-066 § 決定 2 (完全一致要件) |
| `claude/nightly-*` の **ref 作成**が App token で通ること (ruleset の除外が creation にも効くこと) | ADR-067 段 0 の ruleset。Phase B が観測したのは既存ブランチへの update のみ |
| `publish/` の clone + rsync が実 runner で成立し、`work/` の変更が過不足なく運ばれること | 決定 9 (`--delete` による削除の反映を含む) |
| 観測項目 | 出所 | 結果 (2026-08-08) |
|---|---|---|
| Actions variable `AUTONOMY_ENABLED` が `true` ちょうどで設定されており job が起動すること | ADR-066 § 決定 2 (完全一致要件) | **充足** — job が起動し完走 |
| `claude/nightly-*` の **ref 作成**が App token で通ること (ruleset の除外が creation にも効くこと) | ADR-067 段 0 の ruleset。Phase B が観測したのは既存ブランチへの update のみ | **充足** — `claude/nightly-203` が新規作成された |
| **App token で作った draft PR に `ci.yml` の 2 OS run が紐づくこと** | 決定 8 (仕様は公式で確認済み、実環境での成立は未観測) | **充足** — PR の author は `nightly-todo-aloekun[bot]`、`rust (ubuntu-latest)` / `rust (windows-latest)` がいずれも success。承認待ちにならなかった |
| 決定 7 の照合が実 runner 上でも通ること (誤検知で毎晩止まらないこと) | 本 ADR § integrity 機構の drill | **充足 (1 run)** — 誤検知せず publish へ到達。毎晩の安定性は継続観測 |
| `publish/` の clone + rsync が実 runner で成立し、`work/` の変更が過不足なく運ばれること | 決定 9 (`--delete` による削除の反映を含む) | **充足** — commit は 1 ファイル 18 行追加・削除ゼロで、順位 203 の指定範囲と完全に一致 |
| WP-17 残課題: Phase B の自動起動経路が成立するか | [ADR-067](adr-067-phase-b-unattended-fix-push.md) § 検証記録 | **不成立と判明** — CodeRabbit が draft を自動レビューしないため起動契機のコメント自体が発生しない (決定 11 で対処) |
| WP-17 残課題: `coderabbitai[bot]` allowlist の要否 | 同上 | **判定不能** — 上記より CodeRabbit のイベントが発生していない。決定 11 の明示トリガーが効いてから再判定 |
| **`cargo` サブプロセスから `CLAUDE_CODE_OAUTH_TOKEN` / `GITHUB_TOKEN` が見えるか** | pre-push security review の warning | **未観測** — 使い捨ての `build.rs` を仕込む専用 run が要る (§ 残課題) |
| **停止側: `AUTONOMY_ENABLED` が `'false'` / 未設定で何も作られないこと** | ADR-066 の 3 状態。#364 で受け入れ基準へ追加 | **未観測** — allow 経路しか走っていない |

**`workflow_dispatch` + `dry_run` は依然として必要である。** 残る 2 項目 (トークン露出・停止側) は本番 schedule では観測できない。反復は [ADR-067](adr-067-phase-b-unattended-fix-push.md) § 段 2 の知見 2 に従い、**マージせずブランチ ref への `workflow_dispatch`** で行う。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

実走スモークの項目数を両文書で同じ定義にしてください。

5 項目充足 / 1 項目不成立 / 2 項目未観測 は 8 項目の集計です。
一方、docs/adr/adr-072-nightly-todo-loop.md の観測表には 9 行あります。
allowlist 行を補助記録として除外するなら、その扱いを表と集計に明記してください。除外しないなら集計値を更新してください。

  • docs/adr/adr-072-nightly-todo-loop.md#L320-L338: 9 行の観測表と「8 項目」の定義を一致させる。
  • docs/harness-improvement-plan.md#L223-L225: 5/1/2 の acceptance summary を修正するか、補助行の除外を明記する。

この指摘は両文書の観測表と acceptance summary の突合に基づきます。

📍 Affects 2 files
  • docs/adr/adr-072-nightly-todo-loop.md#L320-L338 (this comment)
  • docs/harness-improvement-plan.md#L223-L225
🤖 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 320 - 338, Align the
smoke-test item count across the observation table in
docs/adr/adr-072-nightly-todo-loop.md:320-338 and the acceptance summary in
docs/harness-improvement-plan.md:223-225. Either count all 9 table rows and
update the 5/1/2 totals accordingly, or explicitly mark the coderabbitai[bot]
allowlist row as an excluded supplementary record and make both documents state
that exclusion consistently.


3 行目は決定 5 で Bash を落とした後も残る経路の確認である。agent は `cargo` を直接叩けないが、`work/` へ書いた `build.rs` は `Verify deterministically` step の `cargo test` が実行する。同 step に `env:` を置いていないことがトークン非露出の根拠なので、**その前提が実 runner で成立するか**を使い捨ての `build.rs` から `env | grep -i token` を出して実測する。

Expand Down Expand Up @@ -344,7 +363,9 @@ pre-push review を 12 サイクル通す過程で、blocking な欠陥 10 件

### 残課題

- **実走スモークの完走** (§ 検証記録)。本 ADR の受け入れ基準の中核であり、未実施。
- **実走スモークの残り 2 項目** (§ 実走スモーク)。allow 経路は 2026-08-08 の schedule 初回実走で成立したが、**(a) `cargo` サブプロセスへのトークン露出**と**(b) 停止側 (`AUTONOMY_ENABLED` = `'false'` / 未設定)** はいずれも本番 schedule では観測できず、`workflow_dispatch` の専用 run が要る。
- **`AUTONOMY_ENABLED` を立てると schedule も同時に有効になる**。スモークを「まず dry_run で」と計画していたのに、変数を立てた時点で本番の夜間 run が先に走った (§ 実走スモーク)。**観測装置の準備前に無人 run が始まる**構造なので、次に同種の自律機能を足すときは「有効化の粒度」を dispatch 限定と schedule 込みで分けられるか検討する。
- **CodeRabbit が bot 投稿の `@coderabbitai review` に反応するか** (決定 11)。無反応なら明示トリガーの設計自体が成立しないため、次回の夜間 run で最優先に確認する。
- **外部設定 (GitHub App / repository variables・secrets) の実体が未記録**。決定 8 は「なぜ App token か」を厚く残す一方、App 名・インストール範囲・付与権限の実際・`NIGHTLY_APP_ID` (variable) / `NIGHTLY_APP_PRIVATE_KEY` (secret) / `AUTONOMY_ENABLED` (variable) の登録先と欠落時の倒れ方を 1 行も書いていない。[ADR-051](adr-051-cross-system-config-coupling.md) が内部設定と外部 SaaS 設定の論理結合に課す 3 点 (相互参照コメント / 期待値の組み合わせ表 / 両側同一 PR) が未実施の状態にあたる。実走スモークで GitHub UI を触る際に**設定メタデータ** (名前・登録先の別・付与権限のスコープ・所有者・ローテーション方針・欠落時の挙動) を確認し、§ 外部設定の実体 として本 ADR へ追記する。**秘密値そのもの (`NIGHTLY_APP_PRIVATE_KEY` の鍵本文や発行済み token) は ADR にも git 履歴にも残さない** — ADR-051 が記録を課すのは「結合の存在」と「期待値の組み合わせ」であって、秘密の実値ではない。
- **`master-ref/` を agent のファイルシステムから外す**。決定 7 は検知どまりで、防止には別 job + artifact 受け渡しへの構造変更が要る。実走スモークで agent が実際にワークスペース外へ手を伸ばすか観測してから判断する。
- **authority gate の直前で draft 数を再計数するか**。現状は job 冒頭のスナップショットを使い回す (§ 決定 4)。閾値を 1 件超えて push される事象が実運用で観測されたら入れる。
Expand Down
Loading
Loading