fix(hooks-stop-quality): 品質ゲートの cwd 依存を修正 (push パイプライン改善 T7) - #284
Conversation
T6 の作業コミット時点では PR が未採番だったため、計画書の §4 実施結果と §8 判定記録に「PR 未採番 — 採番後に backfill」と書いて負債を明示していた。PR #283 がマージされたため採番情報のみを更新する。 変更 (3 箇所、いずれも採番情報のみ): - §4 T6 実施結果の見出し: PR 未採番 → PR #283 - §4 T6 の backlog 10 への申し送り: 「本 PR では触れず」→「PR #283 では触れず」 (T5 が §4/§8 の「本 PR」を番号へ解決した慣習に揃える) - §8 判定記録の T6 行: PR 未採番 → PR #283 由来: PR #282 (T5) の post-PR レビューで「T4 行が『本 PR』のまま放置され PR #282 で backfill する羽目になった」負債が指摘され、同じ形を繰り返さないために T6 では 未採番であることを明示していた。本コミットでその明示を回収する。 Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stop hook はセッションの cwd を継承して起動されるため、cwd がリポジトリルート 以外 (例: .takt/runs に cd したまま Stop) だと 2 つの症状が黙って出ていた: 1. hooks-config.toml のルート相対 step (file-length) が「指定されたパスが 見つかりません」で失敗し、品質ゲートが誤 block する (2026-07-16 に実発火)。 pnpm / cargo 系 step は設定ファイルを上方探索するため偶然通っており、 ルート相対パスを書いた step だけが壊れる非対称が発見を遅らせていた。 2. takt subsession 判定が <cwd>/.takt/runs を探して空振りし、active run を 検出できない。ADR-004 の edit:false subsession skip が効かなくなる。 同一の根本原因なので main 冒頭で cwd を 1 度だけプロジェクトルートへ正規化する。 ルートは exe パス (<root>/.claude/<hook>.exe) から導出する — CLAUDE_PROJECT_DIR env は VSCode 拡張環境で空になることを実測確認した (ADR-005 の不安定性が現存)。 config / pipeline lock / telemetry が既に採る exe-relative 規約と同形。 ルート特定不能時は警告のみで継続 (fail-open、pipeline_is_running と同じ線引き)。 main.rs が 800 行上限に触れたため takt 判定を takt_subsession.rs へ分離した。 回帰テスト: tests/t7_cwd_independence.rs に E2E 5 本 + unit 2 本 (26 → 33)。 exe を <root>/.claude/ に staging して spawn し、exe-relative 解決を実配置で 検証する。正規化の呼び出しを外すと bad 2 本が失敗し good 3 本は通ることを確認済み。
|
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 Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughStop hook の cwd を実行ファイル配置から導出したプロジェクトルートへ正規化し、takt subsession 判定を専用モジュールへ分離しました。Windows の cwd 独立性回帰テストと、T6/T7 の実装記録・ADR 更新も追加されています。 ChangesStop hook の cwd 独立化
実装記録と設計文書
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant StopHookMain
participant ProjectRootResolver
participant CwdNormalizer
participant QualityGate
participant TaktSubsession
StopHookMain->>ProjectRootResolver: exe パスからプロジェクトルートを導出
StopHookMain->>CwdNormalizer: 起動時に cwd を正規化
StopHookMain->>QualityGate: Stop 品質ゲートを実行
QualityGate->>TaktSubsession: active takt run を判定
TaktSubsession-->>QualityGate: skip 判定を返却
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 概要 (レビュー指摘が無いため軽量サマリー)T7 (Stop hook 品質ゲートの cwd 依存修正、
変更はテスト・ADR裏付けとも充実しており、CLAUDE.md 記載の ADR-005/ADR-010/ADR-043/ADR-049 の規約に沿った設計。 次のアクション
|
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 `@src/hooks-stop-quality/tests/t7_cwd_independence.rs`:
- Around line 91-96: In the t7 hook test around wait_with_timeout_safe, retain
the returned process status and assert status.success() instead of discarding
it. Join and preserve stderr before the assertion so failed hooks include stderr
diagnostics, while keeping the existing stdout-based block_reason flow for
successful exits.
🪄 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
Run ID: 0fb8e04a-732e-40d9-a86d-589f3394895a
📒 Files selected for processing (5)
docs/adr/adr-005-hooks-path-resolution-with-template.mddocs/push-pipeline-fix-plan.mdsrc/hooks-stop-quality/src/main.rssrc/hooks-stop-quality/src/takt_subsession.rssrc/hooks-stop-quality/tests/t7_cwd_independence.rs
🤖 PR Monitor 分析 (GitHub Actions バックストップ)
Applicable Findings (Critical / High / Major)
Applicable Findings (Medium 以下)(該当なし) Filtered (not applicable)(該当なし) 次のアクション
|
Resolved findings: - [Major] src/hooks-stop-quality/tests/t7_cwd_independence.rs:96 hook の終了ステータスを確認してください
auto-fix が追加した assert_hook_success は exit code assert 自体は入れたが、 指摘の「失敗時は stderr を出す」部分が未達だった: メッセージに stdout を渡しており、 かつ stderr.join() より前に呼ばれるため構造上 stderr を出せない。 本 hook の診断 (cwd 正規化の警告等) は eprintln! = stderr にしか出ないため、 指摘が想定する「非 0 exit かつ stdout が空」の失敗では stderr だけが手掛かりになる。 stderr を join してから assert に渡す形へ補正した。 guard が空振りでないことを実証済み: staged exe を where.exe (非 0 exit・stdout 空) に 差し替えると 5 本すべてが exit code Some(2) で失敗する (guard 導入前なら None を 期待する 3 本が false green で素通りしていた)。
🤖 PR Monitor 分析 (GitHub Actions バックストップ)
Applicable Findings (Critical / High / Major)(該当なし — 唯一の Major finding は解決済み。下記参照) Applicable Findings (Medium 以下)(該当なし) Filtered (not applicable)(該当なし) 参考: 解決済み指摘
次のアクション
|
Summary
main冒頭で cwd をプロジェクトルートへ正規化する(
normalize_cwd_to_project_root)。ルートは exe パス (<root>/.claude/<hook>.exe)から導出し、
CLAUDE_PROJECT_DIRenv には依存しない(file-length) の誤失敗 = 由来 incident、(2) takt subsession 判定の空振り
tests/t7_cwd_independence.rsを追加 (E2E 5 本 + unit 2 本、26 → 33 pass)。exe を
<root>/.claude/に staging して spawn し、exe-relative 解決を実配置で検証するCLAUDE_PROJECT_DIRが現在も空になることを実測で確認した記録を残す
main.rsが 800 行上限に触れたため takt 判定をtakt_subsession.rsへ分離Context
Why: Stop hook はセッションの cwd を継承して起動されるため、cwd がリポジトリルート
以外 (例:
.takt/runsにcdしたまま Stop) だとhooks-config.tomlのルート相対 stepが「指定されたパスが見つかりません」で失敗し、品質ゲートが誤 block していた
(2026-07-16 に実発火)。
pnpm/cargo系 step は設定ファイルを上方探索するため偶然通っており、ルート相対パスを書いた step だけが壊れる非対称が症状をまだらにして
発見を遅らせていた。
Trigger:
docs/push-pipeline-fix-plan.md§4 T7 (push パイプライン改善計画)。方針からの逸脱 (ユーザー承認済み): 計画は「正規化は step 実行の子プロセスにのみ適用し、
takt subsession 判定は元 cwd を使う形が安全」としていたが、調査の結果その判定も同じ
根本原因で既に壊れていた (cwd =
.takt/runsだと.takt/runs/.takt/runsを探して空振り→ active run 未検出 → ADR-004 の edit:false subsession skip が効かず、PR #221 の事故が
再発しうる)。元 cwd の維持は「安全」ではなく既知不具合の温存にあたるため、両症状に効く
main冒頭 1 回の正規化を採用した。回帰テストで修正前に実際に失敗することを確認済み。ルート導出手段: 計画は (a)
CLAUDE_PROJECT_DIRenv と (b) exe パスを両論併記し「実装時にどちらが確実か確認して選ぶ」としていた。実測すると VSCode 拡張環境
(Claude Code 2.1.212) で
CLAUDE_PROJECT_DIRは空で、ADR-005 が 2026-03-17 に記録した不安定性が現存する。よって (b) を採用 — 既存規約 (順位 287 / ADR-010、
config_path()/pipeline_lock::exe_claude_dir()/lib_telemetry::exe_dir()) と同形。Scope decision: 方針 2 の CP932 デコードフォールバックは本 PR に含めず
§6 backlog 11 へ分離した (ユーザー承認済み)。影響先が共有
lib-subprocess(push-runner / merge-pipeline) に及び、§2 原則 4「1 PR 1 変更」から外れるため。
cwd 修正で incident の文字化けは消えるが、exe 欠落時等で経路自体は残るため却下ではない。
Validation
pnpm pushquality_gate: 全 4 グループ PASS (47.3s) — lint / test / build /rust-lint-test (clippy +
cargo test+--ignored)cargo test -p hooks-stop-quality: 33 pass (unit 28 + E2E 5)、cargo test --workspace全 passpre-push-review-refute, 3 iterations / 9m59s):convergence_verdict: fully_resolvednormalize_cwd_to_project_root()の呼び出しを外すと bad 2 本がちょうど失敗し good 3 本は通る。失敗内容は由来 incident の逐語再現
.takt/runsでbefore =
{"decision":"block"...}+**file-length** failed/ after = 出力なし (通過)。cwd = repo root と深い cwd (
src/lib-subprocess/src) も通過References
docs/push-pipeline-fix-plan.md§4 T7 / §8 判定記録 / §6 backlog 11@時の bookmark_check 誤誘導を修正 (push T8) #280 (T8)Summary by CodeRabbit
改善
テスト
ドキュメント