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
5 changes: 5 additions & 0 deletions .claude/hooks-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ failed_marker_check_enabled = true # 前回失敗 marker 検出 → resume promo
# Bash command + Edit/Write content 双方で検出してブロック
# (~/.claude/rules/common/security.md § Secret Management 移管、
# 順位 146 / PR #200 follow-up 採用、Tier 1 default-on)
# "gh-repo-env-guard" — GH_REPO 環境変数の場当たり使用をブロックし GIT_DIR /
# 自動注入 / --repo フラグに誘導 (GH_REPO は引数なし
# gh repo view に効かず非 colocated jj workspace で
# silent 部分故障を招く、PR #238 実例 / ADR-045)
# プリセット名以外の文字列は正規表現としてカスタムパターン扱い
blocked_patterns = [
"default",
Expand All @@ -79,6 +83,7 @@ blocked_patterns = [
"electron",
"jj-message-required",
"secret-detection",
"gh-repo-env-guard",
]

# 追加の保護ファイル (デフォルトリストに追加)
Expand Down
4 changes: 4 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 13 additions & 9 deletions docs/adr/adr-045-jj-workspace-parallel-sessions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## ステータス

試験運用 (2026-06-29) / 改訂 (2026-06-30: 初 PR 運用ケースで判明した secondary workspace の `.git` 不在 → gh ベースコマンドの `GIT_DIR` 必須、および merge-pipeline の bookmark 誤検出を「§ PR 運用時の追加設定」として追記)
試験運用 (2026-06-29) / 改訂 (2026-06-30: 初 PR 運用ケースで判明した secondary workspace の `.git` 不在 → gh ベースコマンドの `GIT_DIR` 必須、および merge-pipeline の bookmark 誤検出を「§ PR 運用時の追加設定」として追記) / 改訂 (2026-07-03: 恒久対策候補 1 = `GIT_DIR` 自動注入を実装。cli-* exe は手動 `GIT_DIR` 前置なしで動作するようになり、手動前置は直接 gh 呼び出し時の fallback に格下げ。PR #238 で `GH_REPO` による場当たり対処が部分故障を招いた実観測を受け `gh-repo-env-guard` preset も追加)

> ADR-039 (Experimental feature 標準パターン) に準拠: config opt-in なし (本 ADR は workflow 運用ポリシーであり実装機構ではないため該当しない) / kill-switch = 本 ADR を supersede する後続 ADR で停止可能、運用上は単一 workspace へ戻すだけで無効化 / bounded lifetime = 採用判定 3 ヶ月 (2026-09-29) を目安に dogfood 結果から本採用 / 修正 / 却下を判定。

Expand Down Expand Up @@ -112,13 +112,17 @@ src の大規模分割 (メイン) と lint/facet/docs (改善) は編集領域
| コマンド | 内部実装 | secondary workspace 単独 |
|---|---|:---:|
| `pnpm push` / `jj` 系すべて | jj backend (`.jj/repo/store/git`) | ✅ 動く |
| `pnpm create-pr` / `pnpm merge-pr` | `gh pr create` / `gh pr merge` | ❌ 要 `GIT_DIR` |
| `cli-pr-monitor --monitor-only` | `gh api` / `gh pr checks` | ❌ 要 `GIT_DIR` |
| `gh api` / `gh pr checks` 直接呼び出し | gh | ❌ 要 `GIT_DIR` |
| `pnpm create-pr` / `pnpm merge-pr` | `gh pr create` / `gh pr merge` | ✅ 動く (2026-07-03〜、exe が `GIT_DIR` 自動注入) |
| `cli-pr-monitor --monitor-only` / `check-ci-coderabbit` | `gh api` / `gh pr checks` / `gh repo view` | ✅ 動く (2026-07-03〜、同上) |
| `gh api` / `gh pr checks` 直接呼び出し | gh | ❌ 要 `GIT_DIR` 前置 (fallback、後述) |

#### 解決: `GIT_DIR` でメインリポジトリの `.git` を参照
#### 解決 (2026-07-03 改訂): cli-* exe が `GIT_DIR` を自動注入

gh ベースのコマンド実行時に環境変数 `GIT_DIR` でメインリポジトリ (`.jj/repo` が指す先、本プロジェクトでは `~/work/claude-code-hook-test`) の `.git` を指す。**jj は `GIT_DIR` を無視する** (独自に `.jj/repo` を解決) ため、`GIT_DIR` は gh だけを制御し jj 操作 (bookmark 自動補完 / push / rebase) には影響しない。monitor state は `<exe>` パス基準で解決されるため、`GIT_DIR` 設定下でもこの workspace に保たれる (並列 monitor の分離を壊さない)。
**恒久対策候補 1 を実装済み**: `cli-pr-monitor` / `cli-merge-pipeline` / `check-ci-coderabbit` は main() 冒頭で `lib_jj_helpers::inject_git_dir_for_gh()` を呼び、`.git` 不在 + `GIT_DIR` 未設定のとき `.jj/repo` (secondary では main store への相対パスを格納したファイル) → `store/git_target` の順に辿って main の `.git` を導出し、プロセス env に `GIT_DIR` を設定する (子プロセスの gh 全体へ伝播)。**これにより `pnpm create-pr` / `pnpm merge-pr` / `cli-pr-monitor --monitor-only` は secondary workspace でも素のコマンドで動作する**。注入時は `[env] GIT_DIR 自動注入: <path>` ログが出る。既存の `GIT_DIR` env は尊重、導出失敗は warning + 続行 (fail-soft)。

以下の手動 `GIT_DIR` 前置は、**exe を経由しない直接の gh 呼び出し時の fallback** として残す。**jj は `GIT_DIR` を無視する** (独自に `.jj/repo` を解決) ため、`GIT_DIR` は gh だけを制御し jj 操作 (bookmark 自動補完 / push / rebase) には影響しない。monitor state は `<exe>` パス基準で解決されるため、`GIT_DIR` 設定下でもこの workspace に保たれる (並列 monitor の分離を壊さない)。

なお **`GH_REPO` 環境変数による代替は不可**: `GH_REPO` は gh の pr / issue / api 系にしか効かず、引数なし `gh repo view` (exe 群の repo 検出) には無効なため、「PR 作成・マージは成功するが repo 検出依存の機能 (監視 checker / post-merge feedback) だけ silent に失敗する」部分故障を招く (PR #238 実観測)。`gh-repo-env-guard` preset (hooks-pre-tool-validate) が `GH_REPO=` の使用を block して本節へ誘導する。

```sh
# Bash — $HOME=/c/Users/<user> (Unix 形式) なのでフォワードスラッシュ。フルパスは $HOME で隠蔽
Expand Down Expand Up @@ -154,9 +158,9 @@ PR head 以外の non-trunk bookmark が `@` / `@-` / `@--` の近接 3 世代

`GIT_DIR` の手動前置は忘れると失敗するため、構造的解決を推奨 (投資対効果順):

1. **cli-* exe 側で `GIT_DIR` 自動注入** — `cli-pr-monitor` / `cli-merge-pipeline` が `.git` 不在を検出したら `.jj/repo` からメインリポジトリを導出し、子プロセスの gh に `GIT_DIR` を自動設定する。ユーザーが `GIT_DIR` を意識せず `pnpm create-pr` がそのまま動く。最も投資対効果が高い
2. **direnv `.envrc`** — workspace ルートで `GIT_DIR` を自動エクスポート (direnv 導入が前提)
3. **workspace の colocated 化** — `jj workspace add` 後に当該 workspace を `.git` 付きにできるか jj の機能を調査。可能なら `GIT_DIR` 自体が不要
1. **cli-* exe 側で `GIT_DIR` 自動注入** — ✅ **実装済み (2026-07-03)**: `lib_jj_helpers::inject_git_dir_for_gh()` を `cli-pr-monitor` / `cli-merge-pipeline` / `check-ci-coderabbit` の main() で呼ぶ。導出ロジックと fail-soft 方針は上記「§ 解決」参照
2. **direnv `.envrc`** — workspace ルートで `GIT_DIR` を自動エクスポート (direnv 導入が前提)。候補 1 実装により優先度低下
3. **workspace の colocated 化** — `jj workspace add` 後に当該 workspace を `.git` 付きにできるか jj の機能を調査。候補 1 実装により優先度低下

## 影響

Expand Down
2 changes: 1 addition & 1 deletion docs/auto-push-gate-dogfood.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ B1 は **即 escalation 方式** (ループなし)。gate FAIL 時は人間が `

## 3. dogfood 運用

- **観測開始日 (PR-1 merge 日)**: (merge 時に記入)
- **観測開始日 (PR-1 merge 日)**: 2026-07-03 (PR #238 squash merge)
- **観測対象イベント**: auto-push 発火 (cli-pr-monitor の `[decision] gate:` ログが出た監視ターン)。
- **記録方法**: イベント発生ごとに下表へ 1 行追記する。gate の実行経路・結果は `[gate]` プレフィックスの stdout ログから転記できる。

Expand Down
1 change: 1 addition & 0 deletions docs/todo-summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
| 248 | 💎 Tier 3 | **Gate Function Design Checklist を新規 guide として追加 (fail-closed パターン集) (PR #234 post-merge-feedback T3-1 採用)** | todo13.md | S | なし (却下した linter 化 T1-1/T1-2 の補完。fail-closed 実装の失敗/推奨パターンを 1 箇所に集約。PR #234 で collect_oversize_files 初版の `.ok()?` が fail-open bug → CodeRabbit Major #234-1。Severity Medium + Frequency Medium + Effort S + Adoption Risk None、順位 249 と相補) |
| 249 | 💎 Tier 3 | **ADR-043 に fail-open vs fail-closed の具体コード例を追記 (PR #234 post-merge-feedback T3-2 採用)** | todo13.md | S | なし (ADR-043 は security-critical だが具体コード例が未記載で解釈分散が今回の bug を生んだ。`.ok()?` anti-pattern / single-read + ErrorKind idiom / multi-step vs 単一操作の比較を ADR 本文に追記。Severity Medium + Frequency Medium + Effort S + Adoption Risk None、順位 248 と相補) |
| 250 | 💎 Tier 3 | **ADR-021 に「jj revset の base branch は config/arg 化 (hardcode 禁止)」を明文化 (PR #234 post-merge-feedback T3-3 採用)** | todo13.md | XS | なし (PR #234 で `[file_length_gate] base` を config 引数化 = ADR-021 準拠。custom lint ⑫ `no-hardcoded-jj-revset-range` は `.rs` の `master..@` literal を捕捉するが、TOML config / docs / 他ツールへの原則適用は未明文化。Severity Low + Frequency Medium + Effort XS + Adoption Risk None) |
| 251 | 🔧 Tier 2 | **cli-pr-monitor / cli-merge-pipeline の非 colocated jj workspace 対応 — repo 解決 fallback + checker 出力の stdout/stderr 分離 (PR #238 監視・マージで実観測)** | todo13.md | M | なし (順位 247 bug class「`--repo` 無し gh」の実例 3 件 = (a) `get_pr_info` の引数なし `gh repo view` が非 colocated で常に失敗 (b) `invoke_checker` が stdout+stderr 結合テキストを JSON parse し stderr ノイズで「trailing characters」error → 監視停止 (c) cli-merge-pipeline も owner_repo 検出失敗で post-merge feedback (ADR-030) が skip。(a) jj git remote list fallback 共通 helper + (b) stdout 限定パース + regression test、ADR-045 並列 workspace で自動化全損のため要修正、1 PR bundle 推奨) |

**戦略**: Tier 1 を 2〜3 セッションで片付け → Tier 2 で ADR-032 の前提 + rate-limit + convergence cost 削減を進める → Tier 3 で ADR-032 を land + ドキュメント整備。Tier 4-5 は cleanup / 外部展開で daily efficiency への直接効果は小さい。

Expand Down
38 changes: 38 additions & 0 deletions docs/todo13.md
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,44 @@

---

### cli-pr-monitor / cli-merge-pipeline の非 colocated jj workspace 対応 — repo 解決 fallback + checker 出力の stdout/stderr 分離 (PR #238 監視・マージで実観測)

> **動機**: PR #238 (auto-push gate PR-1) の監視とマージで 3 箇所の欠陥が連鎖して観測された (2026-07-03)。(a) `get_pr_info` の repo 解決が引数なし `gh repo view` 依存で、非 colocated jj workspace (.git なし) では GH_REPO 環境変数を設定しても "failed to run git" で常に失敗し `PrInfo.repo = None` になる (gh は pr サブコマンドでは GH_REPO を尊重するが、引数なし repo view では git remote を直接参照する)。(b) repo が None のため checker (`check-ci-coderabbit`) に `--repo` が渡らず、checker 自身の repo 検出も同様に失敗して stderr に初期化エラーを出力する (exit 0 の fail-soft)。`invoke_checker` は `run_cmd_direct` の stdout+stderr **結合**テキストを `serde_json::from_str` にかけるため、正常な JSON の後ろに stderr が連結され「trailing characters」で parse 失敗 → `action=error` で監視停止 (park も wakeup 予約もされない)。(c) `cli-merge-pipeline` も同型の `gh repo view` 失敗で owner_repo を検出できず、**post_steps の post-merge feedback (ADR-030) が pending file 未書込のまま skip** された (マージ自体は bookmark fallback で成功)。
>
> **参照**: `src/cli-pr-monitor/src/util.rs` `get_pr_info` / `src/cli-pr-monitor/src/stages/poll/iteration.rs` `invoke_checker` / `src/cli-pr-monitor/src/runner.rs` `run_cmd_direct` (combined 出力仕様) / `src/cli-merge-pipeline/src/github.rs` `detect_owner_repo` (ADR-029 由来、PR #230 の module 分割は移動のみで挙動不変)。順位 247 (観点⑧ jj-workspace robustness) の既知 bug class「`--repo` 無し gh」の新実例 3 件 + parse 層の新規欠陥。
>
> **原因の切り分け (2026-07-03 調査確定)**: コード回帰でも flaky でもなく決定論的。ADR-045 § PR 運用時の追加設定 (2026-06-30、PR #228) が本問題と回避策 `GIT_DIR="$HOME/work/claude-code-hook-test/.git"` 前置を既に文書化しており、PR #227/#228 は本 workspace から `GIT_DIR` 付きで成功していた (`.takt/runs/2026063*-post-merge-feedback-for-227/228` が本 workspace に存在)。PR #238 セッションでは文書化された `GIT_DIR` でなく `GH_REPO` を使ったため、`gh pr create/merge/view` (GH_REPO を尊重) は成功し、引数なし `gh repo view` (git remote 直接参照、GH_REPO 無視) に依存する repo 検出だけが失敗する**部分故障**になった。`GIT_DIR` 併用で全 gh 呼び出しが成功することを実証済み。
>
> **実行優先度**: 🔧 Tier 2 — Effort M。ADR-045 並列 workspace 運用では手動 `GIT_DIR` 前置忘れで PR 監視自動化と post-merge feedback が silent に全損するため、ADR-045 §恒久対策の候補 1 の実装を優先。

#### 設計決定 (ユーザー合意 2026-07-03: (a) GIT_DIR 自動注入を本命 + (d) GH_REPO guard preset を恒久追加、同一 PR。「PR 操作コマンド + .git 不在 + GIT_DIR なしを block する案」は不採用 = (a) land 後に前提が崩れるため)

- **(a) GIT_DIR 自動注入** (ADR-045 §恒久対策の候補 1 の実装): lib-jj-helpers に共通 helper を追加し、cli-pr-monitor / cli-merge-pipeline / check-ci-coderabbit の main() 冒頭で 1 回呼ぶ。`.git` 不在 + `GIT_DIR` 未設定のとき、`.jj/repo` (secondary workspace ではファイル = main store への相対パス、実測 `../../claude-code-hook-test/.jj/repo`) → `store/git_target` (実測 `../../../.git`) の順に解決して `std::env::set_var("GIT_DIR", ...)` = 子プロセス gh 全体に伝播。既存 env 尊重・導出失敗は warning + 続行 (colocated では no-op の fail-soft)。check-ci-coderabbit に lib-jj-helpers dep 追加。
- **(b) stdout/stderr 分離パース**: `invoke_checker` は stdout のみを JSON パース対象にする (結合出力の `run_cmd_direct` をやめ、分離キャプチャ版 helper を追加)。stderr は非空なら log 転送。
- **(c) skip 時の marker 書込**: owner_repo 検出失敗の skip path は `.failed` marker を書かずに抜けるため L2 recovery (ADR-030) が発火しない (PR #238 の feedback は silent 消失、marker 無しを実確認)。skip でも marker を書き、(a) 修正後の recovery 再実行を可能にする。
- **(d) `gh-repo-env-guard` preset (恒久)**: hooks-pre-tool-validate に `GH_REPO=` (Bash) / `$env:GH_REPO` (PowerShell) 検出 preset を追加。GH_REPO は公式 env だが本リポジトリでは部分カバー (引数なし `gh repo view` に効かない) で silent 部分故障を招くため、GIT_DIR / 自動注入 / `--repo` フラグへ誘導する block メッセージ。hooks-config.toml の blocked_patterns + preset 一覧コメント更新、positive/negative test (既存 preset と同型)。
- **regression test**: stderr にノイズを含む fail-soft checker 出力で parse が成功することを検証 (a が直っても b は独立の防御層として必要)。

#### 作業計画 (1 PR、push 時に squash)

- [x] (a) lib-jj-helpers に GIT_DIR 導出 helper (純関数 + unit test + jj workspace 実組みの #[ignore] 統合テスト) + 3 exe main() へ注入 + `[env]` ログ
- [x] (d) `gh-repo-env-guard` preset + hooks-config.toml 更新 + positive/negative test (templates 展開は見送り = 派生プロジェクトの gh 運用は別途判断)
- [x] (b) `invoke_checker` の stdout 限定パース + stderr ノイズ regression test (`run_cmd_capture` 分離キャプチャ新設)
- [x] (c) owner_repo 失敗 path の `.failed` marker 書込 + unit test (`AiStepContext::SkipWithMarker`)
- [x] docs: ADR-045 改訂 (恒久対策候補 1 実装済み化、手動 GIT_DIR 前置を fallback に格下げ、preset 追記)
- [ ] dogfood: 本 PR 自体を **env 前置なしの素のコマンド**で本 workspace から push → create-pr → monitor → merge し、repo 検出成功 / checker parse 成功 / post-merge feedback 発火を確認。GH_REPO guard は意図的 `GH_REPO=x` 実行で block 確認 (PR body に記録)
- [ ] 本 entry 削除 + todo-summary.md 行削除 (dogfood 確認後の後続 docs PR で実施)

#### 完了基準

- 非 colocated jj workspace から `cli-pr-monitor.exe --monitor-only` と `pnpm merge-pr` を実行して、gh 系呼び出しが repo 解決に成功し、監視 (park / findings 対応 / merge-ready 判定) と post-merge feedback が自動で完走すること。

#### 詰まっている箇所

- なし (3 観測とも根因特定済み、再現手順あり)。PR #238 の post-merge feedback が skip されたため、本 PR 分の feedback 分析は修正後に手動 or 次 PR 分から再開。

---

## 既知課題 (記録のみ、本セッションで未対応)

(現時点で本ファイルへの既知課題は無し。docs/todo10.md / todo9.md 末尾を参照。)
1 change: 1 addition & 0 deletions src/check-ci-coderabbit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2021"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
regex = "1"
lib-jj-helpers = { path = "../lib-jj-helpers" }
lib-report-formatter = { path = "../lib-report-formatter" }

# [profile.release] は workspace root (Cargo.toml) に集約 (ADR-026)
7 changes: 7 additions & 0 deletions src/check-ci-coderabbit/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,14 @@ fn print_json<T: serde::Serialize>(value: &T) {
println!("{}", json);
}

/// GIT_DIR 注入時のログ adapter。stdout は機械可読 JSON 専用のため必ず stderr へ出す。
fn log_env_to_stderr(msg: &str) {
eprintln!("[check-ci-coderabbit] {}", msg);
}

fn main() {
lib_jj_helpers::inject_git_dir_for_gh(log_env_to_stderr);

let args = match parse_args() {
Ok(a) => a,
Err(e) => {
Expand Down
1 change: 1 addition & 0 deletions src/cli-merge-pipeline/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ mod github;
mod pipeline;

fn main() {
lib_jj_helpers::inject_git_dir_for_gh(pipeline::log_info);
std::process::exit(pipeline::run_pipeline());
}
Loading