feat(cloud-harness): ADR-060 Cloud ハーネス有効化 — tracked dispatcher 登録 + SessionStart 実体確保の 2 層分離 - #319
Conversation
run_quality_steps の steps.iter().cloned() が QualityStepConfig 全体を clone して いたが、実際に使うのは name / cmd の 2 field のみ。rust 1.94 の clippy が redundant_iter_cloned として検出し -D warnings で fail する。 CI (release-binaries.yml) は build 時点の stable で green だったが、rust-toolchain pin が無いため cloud セッションの新しい stable では Stop gate の lint:rust step が この債務で fail する (ADR-060 の dogfood 前提を壊す)。必要 field のみ clone する形 に変更して解消。 検証: cargo clippy --workspace --all-targets -- -D warnings green / cargo test --workspace green (Linux, rust 1.94.1) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FqB6tSGZsEjT3VuydstnoG
…保の 2 層分離 Claude Code Web で hooks が半整備になる構造 (WP-15 注意 B) の根本対応。実測で確定 した 3 制約 — (1) セットアップスクリプトはキャッシュ構築時のみ実行、(2) リポ内 生成物は毎セッション fresh clone で消滅、(3) hooks は起動時 snapshot されセッション 中の settings 生成は登録に間に合わない — により、生成物ベースの hook 登録は クラウドでは原理的に機能しない。登録と実体確保をライフサイクル分離する: - scripts/cloud-hook-dispatch.mjs (新規): tracked settings から起動される cross-platform dispatcher。import.meta.url 自己位置解決 (ADR-005 の .mjs 適用、 CLAUDE_PROJECT_DIR 非依存)。CLAUDE_CODE_REMOTE + CLOUD_HARNESS opt-in の 2 段ゲートでローカルでは完全不活性。バイナリ不在は warn + exit 0 (ADR-043 から の意図的逸脱、復旧コマンド自体が block されるデッドロック回避。ADR-060 § 決定 5) - scripts/cloud-setup.sh: --session-phase (SessionStart hook から毎セッション。 バイナリ配置 + jj 導入/init + pnpm install、generate_settings は skip) と --cache-phase (UI セットアップスクリプト欄。pnpm store + cargo warmup 暖機、 要 CARGO_TARGET_DIR=リポ外) を追加。引数なしは旧来動作で後方互換 - RETURN trap の残留バグ修正: 関数返却後も trap がシェルに残り、後続関数の return で消滅済み local tmp_dir を set -u が捕捉して --session-phase 再実行が exit 1 になっていた (リハーサルで実測)。trap 発火時に自己解除する形へ - docs/adr/adr-060 + CLAUDE.md 索引: 設計根拠・ADR-039 3 点セット (opt-in env CLOUD_HARNESS / kill-switch = env 削除 / dogfood 5 セッション or 2026-09-30 で 採否判定)・ユーザー側 Web UI 設定手順を記録 .claude/settings.json への hooks 登録は別 commit (要ユーザー承認の設定変更)。 登録が入るまで dispatcher は完全 dead code ではなく不活性 (opt-in 前と同状態)。 検証 (Linux 実機リハーサル): --session-phase 実行で 9 hook バイナリ + jj 0.42 + node_modules 配置 / 冪等再実行 exit 0 / --setup E2E で hooks-session-start の additionalContext 実出力 / dispatcher 経由で hooks-pre-tool-validate が jj-push-guard を exit 2 block (安全コマンドは exit 0) / 残り 5 hook バイナリも 合成 stdin JSON で exit 0 / Stop gate 全 step (lint / lint:md / lint:docs / test / build) green / cargo clippy + cargo test --workspace green Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FqB6tSGZsEjT3VuydstnoG
jj git init --colocate は git HEAD を detach し、環境によってはローカルブランチ ref も残らない (ADR-060 リハーサルで実測: push が src refspec does not match any で失敗)。jj 中心のローカル flow は影響しないが、クラウドセッションの Claude は git で commit/push するため、init 前に取得した現ブランチへ HEAD を戻す。 開始時点で既に detached だった run は戻し先が不明なので warn で明示する (無言 skip だと push 失敗まで露見しない)。 検証: attached → no-op / detached + ブランチ名不明 → warn の両経路を実機確認。 bash -n green。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FqB6tSGZsEjT3VuydstnoG
…0 登録層) tracked な settings.json への登録により、クラウドセッションの起動時 snapshot に hooks が確実に載る (ADR-060 § 決定 1)。全 command は cross-platform dispatcher (scripts/cloud-hook-dispatch.mjs) 経由で、CLAUDE_CODE_REMOTE + CLOUD_HARNESS の 2 段ゲートによりローカルでは不活性、クラウドでも opt-in env 設定までは不活性。 構成・timeout はテンプレート (settings.local.json.template) と同一。 検証: JSON parse green / 全 hook 名が配置済みバイナリ 9 個と一致。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FqB6tSGZsEjT3VuydstnoG
|
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クラウド用フック登録、環境ゲート付きディスパッチャ、SessionStart/キャッシュの二段階セットアップを追加した。セットアップ時の一時ディレクトリ処理と jj 初期化を修正し、品質ステップの並列実行引数の所有方法も整理した。 Changesクラウドハーネスのフック登録
品質ステップ並列実行整理
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant SessionStart
participant cloud-hook-dispatch.mjs
participant cloud-setup.sh
participant hooks-session-start
SessionStart->>cloud-hook-dispatch.mjs: --setup と stdin JSON を送信
cloud-hook-dispatch.mjs->>cloud-setup.sh: --session-phase を実行
cloud-setup.sh-->>cloud-hook-dispatch.mjs: セットアップ結果を返却
cloud-hook-dispatch.mjs->>hooks-session-start: stdin JSON を渡して起動
hooks-session-start-->>SessionStart: 終了コードを返却
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)該当なし 次のアクション
|
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 `@scripts/cloud-setup.sh`:
- Around line 103-106: Update the temporary-directory cleanup traps in both
install_harness_binaries and install_jj at scripts/cloud-setup.sh lines 103-106
and 206-207: use a cleanup trap covering both RETURN and EXIT so die() paths
remove the directory, then explicitly disable both traps after successful
cleanup to prevent later function returns from referencing the local tmp_dir.
🪄 Autofix (Beta)
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: 3575b1a5-8d8c-4dce-bc8a-c0bf915f8aa2
📒 Files selected for processing (6)
.claude/settings.jsonCLAUDE.mddocs/adr/adr-060-cloud-harness-sessionstart-dispatcher.mdscripts/cloud-hook-dispatch.mjsscripts/cloud-setup.shsrc/hooks-stop-quality/src/main.rs
| # 途中で失敗しても一時ディレクトリを残さない。RETURN trap は関数返却後もシェルに残留し、 | ||
| # 後続関数の return で消滅済み local tmp_dir を参照して set -u で落ちるため | ||
| # (--session-phase 再実行が exit 1 になる実測バグ)、発火時に自己解除する。 | ||
| trap 'rm -rf "${tmp_dir}"; trap - RETURN' RETURN |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# die が exit する実装か、既存 EXIT trap を上書きしないかを確認する。
rg -n -A5 -B2 '^(die\(\)|trap )' scripts/cloud-setup.shRepository: aloekun/claude-code-hook-test
Length of output: 496
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "== trap occurrences =="
rg -n '^[[:space:]]*trap ' scripts/cloud-setup.sh
echo
echo "== die definition and callers around install functions =="
sed -n '60,120p' scripts/cloud-setup.sh
echo
sed -n '180,225p' scripts/cloud-setup.sh
echo
echo "== structural probe: RETURN vs EXIT trap semantics in this script pattern =="
python3 - <<'PY'
from pathlib import Path
text = Path('scripts/cloud-setup.sh').read_text()
# Lightweight semantic check: RETURN traps do not fire on top-level EXIT from a sourced script;
# functions returning normally do, but functions that call exit do not continue to return.
print('has only RETURN trap for tmp_dir cleanup:', text.count('trap - RETURN') == text.count('rm -rf "${tmp_dir}"; trap - RETURN') and 'EXIT' not in text[
text.find('trap - RETURN'):
text.find('trap - RETURN') + 256
])
PYRepository: aloekun/claude-code-hook-test
Length of output: 4111
死んだプロセスが残った一時ディレクトリをCleanupしてください。
die() が exit 1 するため、RETURN trap は呼ばれません。install_harness_binaries() と install_jj() では curl/node/tar などの失敗経路で一時ディレクトリが残りうるため、trap - RETURN EXIT で cleanup を実行し、成功時に両方の trap を解除してください。
修正案
- trap 'rm -rf "${tmp_dir}"; trap - RETURN' RETURN
+ trap 'rm -rf "${tmp_dir}"; trap - RETURN EXIT' RETURN EXIT📍 Affects 1 file
scripts/cloud-setup.sh#L103-L106(this comment)scripts/cloud-setup.sh#L206-L207
🤖 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 `@scripts/cloud-setup.sh` around lines 103 - 106, Update the
temporary-directory cleanup traps in both install_harness_binaries and
install_jj at scripts/cloud-setup.sh lines 103-106 and 206-207: use a cleanup
trap covering both RETURN and EXIT so die() paths remove the directory, then
explicitly disable both traps after successful cleanup to prevent later function
returns from referencing the local tmp_dir.
🤖 PR Monitor 分析 (GitHub Actions バックストップ)
Applicable Findings (Critical / High / Major)該当なし Applicable Findings (Medium 以下)
Filtered (not applicable)該当なし 次のアクション
|
die() は exit 1 するため RETURN trap では curl 失敗・checksum 不一致等の失敗 経路で一時ディレクトリが残る (CodeRabbit 指摘、検証の上正当と判断)。EXIT にも 掛け、発火時に両方を自己解除する。 検証: 存在しない release tag で die 経路を実走し tmp dir 残留ゼロ / 正常経路の冪等再実行 exit 0 維持 / bash -n green。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FqB6tSGZsEjT3VuydstnoG
概要
Claude Code Web で hooks が「半整備」になる構造(WP-15 注意 B)の根本対応。実測で確定した 3 つのプラットフォーム制約により、従来の生成物ベース(
settings.local.json)の hook 登録はクラウドでは原理的に機能しない:対応として 登録層(tracked)と実体確保層(毎セッション再構築)のライフサイクル分離 を導入する。詳細は ADR-060。
変更内容
scripts/cloud-hook-dispatch.mjs(新規): tracked settings から起動される cross-platform dispatcher。import.meta.url自己位置解決(ADR-005 の .mjs 適用)。CLAUDE_CODE_REMOTE+CLOUD_HARNESSopt-in の 2 段ゲートでローカル/未 opt-in 環境では完全不活性。バイナリ不在時は warn + exit 0(ADR-043 からの意図的逸脱 — 復旧コマンド自体が block されるデッドロック回避。ADR-060 § 決定 5).claude/settings.json: dispatcher 経由の hooks 登録を追加(SessionStart / UserPromptSubmit / PreToolUse / PostToolUse×3 / Stop×3、構成・timeout はテンプレートと同一)scripts/cloud-setup.sh:--session-phase(SessionStart hook から毎セッション: バイナリ + jj + pnpm install)/--cache-phase(UI セットアップスクリプト欄: pnpm store + cargo warmup 暖機)を追加。引数なしは後方互換local tmp_dirをset -uが捕捉)を自己解除型 trap で解消jj git init --colocateの HEAD detach により git push がsrc refspec does not match anyで失敗する問題(本 PR 作業中に実際に遭遇)を機構化(ADR-042)src/hooks-stop-quality/main.rs: rust 1.94 新 lintredundant_iter_clonedの債務解消(toolchain pin が無いためクラウド Stop gate のlint:rustが fail する dogfood 阻害要因)docs/adr/adr-060+ CLAUDE.md 索引: 設計根拠と ADR-039 3 点セットADR-039 kill-switch table
CLOUD_HARNESS=1(またはtrue)+ settings.json hooks(merge 済みが前提)CLOUD_HARNESSを削除(次セッションから全 hook が exit 0 no-op)CLAUDE_CODE_REMOTEゲートで恒久不活性(従来の settings.local.json 経路が継続)DoD / 検証(Linux 実機リハーサル)
cargo test --workspacegreen(1720 passed / 0 failed)+cargo clippy --workspace --all-targets -- -D warningsgreen(rust 1.94.1)pnpm lint/lint:md/lint:docs/test/build--session-phase実機実行: 9 hook バイナリ + jj 0.42 + node_modules 配置、冪等再実行 exit 0--setup→hooks-session-startの additionalContext 実出力まで貫通jj git push直叩きが dispatcher 経由で exit 2 block(jj-push-guard)、安全コマンドは exit 0 通過。残り 5 hook バイナリも合成 stdin JSON で正常動作マージ後の有効化手順(ユーザー操作)
CLOUD_HARNESS=1とCARGO_TARGET_DIR=/opt/cargo-targetを追加bash scripts/cloud-setup.sh --cache-phaseへ変更(欄の変更がキャッシュ再構築を兼ねる)🤖 Generated with Claude Code
https://claude.ai/code/session_01FqB6tSGZsEjT3VuydstnoG
Generated by Claude Code
Summary by CodeRabbit
新機能
CLOUD_HARNESSによる明示的な有効化に対応し、通常のローカル環境への影響を抑えました。ドキュメント