Skip to content

feat: pipeline lock + Stop hook 品質ゲート skip — Concurrent checkout 事故の根本解決 (順位280/289/290/291消化) - #271

Merged
aloekun merged 8 commits into
masterfrom
pipeline-lock-stop-skip
Jul 14, 2026
Merged

feat: pipeline lock + Stop hook 品質ゲート skip — Concurrent checkout 事故の根本解決 (順位280/289/290/291消化)#271
aloekun merged 8 commits into
masterfrom
pipeline-lock-stop-skip

Conversation

@aloekun

@aloekun aloekun commented Jul 13, 2026

Copy link
Copy Markdown
Owner

概要

順位 280 (pipeline lock + Stop hook 品質ゲート skip) を実装し、順位 289/290/291 を同乗消化する。PR #267 マージで実発生した「background merge pipeline のローカル同期 checkout と、ターン終了で発火する Stop hook 品質ゲート (cargo/jj) の Concurrent checkout 競合」の根本解決。

変更内容 (コミット単位)

  1. feat(lib-jj-helpers): pipeline_lock モジュール新設。cli-pr-monitor/src/lock.rs の実績パターン (atomic create_new / age ベース stale takeover / RAII Drop) を踏襲し、timestamp は epoch 秒直記録に簡素化 (future-dated lock は stale 扱い = 永続 fresh 化 bug class の防止)。テスト 7 件
  2. feat(pipeline): merge-pipeline / push-runner が実行区間で .claude/pipeline.lock を保持 (advisory、Busy/Unavailable は警告のみで pipeline 続行)
  3. feat(hooks-stop-quality): fresh な lock 検知で品質ゲートを skip (fail-open — Stop 時点のゲートは助言層、本物のゲートは push pipeline 側 = ADR-043 の線引き)。lock パスは exe-relative 解決 (順位 287 規約)。stale threshold 30 分でクラッシュ pipeline の lock は自動失効
  4. feat(push-runner) (順位 290 消化): bookmark 検出を jj bookmark list -r "::@ ~ ::trunk()" で自 workspace のブランチ線上に限定。::@ 単独では共有祖先上の他 workspace bookmark を含みうる (CodeRabbit 指摘) ため ~ ::trunk() で共有履歴を除外
  5. fix(merge-pipeline) (順位 289/291 消化): run_feedback_only の docstring を実装に合わせ修正 (owner_repo 検出失敗パスは marker を書かない = 意図的)。exit code 導出を純関数 feedback_only_outcome に抽出し、「stale report 存在下でも Err は exit 1」の regression test を追加 (SIM-NEW-pipeline-L224 の再発防止)
  6. docs: ADR-045 の運用ルールに lock 機構の補足を追記 (「merge をターン保持で実行する」暫定運用の撤去)、Operation Verification Checklist を hook 実装済みの現状に更新 (background 実行時の誤警告の注意も記載)、消化済み todo エントリ削除

実地検証 (本 PR の push 自体が dogfood)

  • push はリビルド済み exe で実行され pipeline lock を保持。push 中のターン終了で Stop hook の品質ゲートブロックは発生せず、pipeline 完了後に .claude/pipeline.lock が RAII cleanup で消滅していることを確認
  • push コマンドは jj git push -b pipeline-lock-stop-skip の単一 bookmark 指定 — 順位 290 の revset 限定が機能
  • cargo clippy --workspace --all-targets -- -D warnings clean / cargo test --workspace 全 33 suite ok / pnpm lint:docs OK

設計判断・注意点

  • lock は advisory: pipeline の実行可否を左右せず、Stop hook への信号に限定 (jj 公式の lock-free 設計と衝突しない)
  • 順位 290 の完了基準について: PR docs(todo): PR #268/#269 post-merge feedback 採用 4 件を順位 288-291 に登録 #270 の CodeRabbit fix で完了基準が「::@ のみに依存しない追加の所有権検証 (workspace root commit の照合等) を伴うこと」に強化されていた。本実装の ~ ::trunk() (共有履歴の除外) はこの「追加の検証」を trunk 除外方式で満たすという解釈。より厳密な workspace root 照合が必要と判断される場合はレビューで指摘いただきたい
  • kill-switch: lock ファイル削除 (stop-quality 側) / lock は 30 分で自動失効

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 改善
    • merge/push の並列実行を抑制するロック機構を導入しました。
    • 実行中パイプラインを検知すると、Stop hook の品質ゲートを自動スキップします(競合の予防)。
    • ブックマーク確認は現在の workspace に紐づく対象へ限定し、検査の運用を整理しました。
  • 不具合修正
    • フィードバック専用実行の終了コード判定を、古いレポートの影響を受けない形に調整しました。
  • ドキュメント
    • 並列セッション時の停止フック競合回避と検証手順(自動化前提)を更新し、完了した TODO を整理しました。

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 44fe01e7-f545-4b19-b69a-f3c7e1b79e77

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

merge/push パイプラインに pipeline.lock を導入し、Stop hook の品質ゲートを競合時に skip する仕組みを追加しました。feedback-only の結果判定、bookmark 検出範囲、関連文書とTODOも更新しています。

Changes

パイプライン競合回避

Layer / File(s) Summary
パイプラインロック基盤
src/lib-jj-helpers/src/lib.rs, src/lib-jj-helpers/src/pipeline_lock.rs
RAII ロック、原子的な取得、stale takeover、holder 検出、fail-open 動作、各種テストを追加しました。
パイプラインとStop hookの統合
src/cli-merge-pipeline/..., src/cli-push-runner/..., src/hooks-stop-quality/..., src/*/Cargo.toml
merge/push がロックを保持し、Stop hook が fresh lock 検知時に品質ゲートを skip する経路を追加しました。
並列運用の文書と追跡更新
.gitignore, docs/adr/..., docs/todo13.md
pipeline.lock の追跡除外、並列運用と自動検証のADR記載、完了済みTODOの削除を行いました。

関連するパイプライン判定修正

Layer / File(s) Summary
結果判定とbookmark検出の修正
src/cli-merge-pipeline/src/pipeline.rs, src/cli-push-runner/src/stages/bookmark_check.rs
feedback-only の終了コードを Result から決定し、stale report の回帰テストを追加しました。bookmark 検出対象は現在 workspace の @ に限定されます。
完了済みTODOの整理
docs/todo-summary.md
完了済みの関連タスクを推奨実行順序から削除しました。

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MergePushPipeline
  participant PipelineLock
  participant StopQualityHook
  MergePushPipeline->>PipelineLock: merge/push ロックを取得
  PipelineLock-->>MergePushPipeline: Acquired または Busy/Unavailable
  StopQualityHook->>PipelineLock: fresh lock を確認
  PipelineLock-->>StopQualityHook: holder 情報を返却
  StopQualityHook-->>StopQualityHook: 品質ゲートを skip
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルは pipeline lock と Stop hook の品質ゲート skip を主題としており、変更内容と一致しています。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch pipeline-lock-stop-skip

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Monitor 分析 (GitHub Actions バックストップ)

  • トリガー: issue_comment (created) / 実行 run
  • CI: CodeRabbit review が pending (in progress)。他に登録済みチェックなし。mergeStateStatus: UNSTABLE (pending checks 起因と推測)、mergeable: MERGEABLE
  • レビュー状況: レビュー・インラインコメントともに 0 件。CodeRabbit は "Currently processing new changes..." のプレースホルダーコメントのみで、レビュー内容は未着 (待機はしない)
  • Verdict: user_decision (レビュー未完了のため fix/approve いずれの判定材料も無い)

Applicable Findings (Critical / High / Major)

(該当なし — レビュー未着)

Applicable Findings (Medium 以下)

(該当なし — レビュー未着)

Filtered (not applicable)

(該当なし)

差分概要 (軽量サマリー)

12 ファイル変更、todo 順位 280/289/290/291 の実装消化 PR。

ファイル 変更内容
src/lib-jj-helpers/src/pipeline_lock.rs (新規, 285行) pipeline lock 機構本体。PID+timestamp の atomic create、stale takeover (30分)、RAII guard、7 ユニットテスト付き。cli-pr-monitor/src/lock.rs パターンの lib 化
src/hooks-stop-quality/src/main.rs fresh lock 検知時に品質ゲートを skip (fail-open) する pipeline_is_running() を追加
src/cli-merge-pipeline/src/pipeline.rs run_pipeline() で lock 保持を追加。run_feedback_onlyfeedback_only_outcome に分離し、stale report 存在下でも Err→exit 1 を保証する regression test を追加 (順位291)
src/cli-push-runner/src/main.rs run_pipeline() で lock 保持を追加
src/cli-push-runner/src/stages/bookmark_check.rs bookmark 検出 revset を ::@ ~ ::trunk() に限定し並行 workspace の bookmark 混入を防止 (順位290)
docs/adr/adr-045-*.md lock 機構の運用注記追加、hook 誤報についての補足追加
docs/todo13.md / docs/todo-summary.md 実装完了に伴い順位 280/289/290/291 のエントリ削除
.gitignore, Cargo.lock, Cargo.toml x2 付随する依存関係・除外設定の更新

実装は CLAUDE.md 記載の ADR-045 (jj workspace 並列運用) の既知リスク対策および該当 todo エントリの設計内容と一致しており、意図的設計からの逸脱は確認されない。

次のアクション

  • CodeRabbit のレビュー完了を待ち、指摘が投稿された時点で本 workflow (または次回起動) が再分析する
  • 他の CI チェックが未登録に見えるため、人間側でこの PR に必要な CI ワークフローが正しくトリガーされているか確認を推奨

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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/cli-push-runner/src/stages/bookmark_check.rs`:
- Around line 28-37: Update OWN_BRANCH_BOOKMARKS_REVSET to use
first_ancestors(@) ~ ::trunk() so bookmark detection follows only the
workspace’s first-parent branch line and excludes merge side branches. Add
coverage for histories containing merges and side branches, verifying unintended
bookmarks are not selected.

In `@src/lib-jj-helpers/src/pipeline_lock.rs`:
- Around line 36-44: Update PipelineLock to retain its ownership identity,
including pid and start_unix, and initialize those fields wherever PipelineLock
is constructed, including the takeover path. In Drop::drop, read and parse the
current lock contents and remove the file only when they match the guard’s
stored ownership values; otherwise leave the newer owner’s lock intact.
🪄 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: 113c4725-19aa-40ce-be0f-8f7795f175a9

📥 Commits

Reviewing files that changed from the base of the PR and between 56bd745 and 054adfc.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (12)
  • .gitignore
  • docs/adr/adr-045-jj-workspace-parallel-sessions.md
  • docs/todo-summary.md
  • docs/todo13.md
  • src/cli-merge-pipeline/Cargo.toml
  • src/cli-merge-pipeline/src/pipeline.rs
  • src/cli-push-runner/src/main.rs
  • src/cli-push-runner/src/stages/bookmark_check.rs
  • src/hooks-stop-quality/Cargo.toml
  • src/hooks-stop-quality/src/main.rs
  • src/lib-jj-helpers/src/lib.rs
  • src/lib-jj-helpers/src/pipeline_lock.rs
💤 Files with no reviewable changes (2)
  • docs/todo13.md
  • docs/todo-summary.md

Comment thread src/cli-push-runner/src/stages/bookmark_check.rs Outdated
Comment thread src/lib-jj-helpers/src/pipeline_lock.rs
@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Monitor 分析 (GitHub Actions バックストップ)

  • トリガー: pull_request_review (submitted) / 実行 run
  • CI: 登録済みチェックは本 workflow 自身 (analyze, pending — 自己参照的に実行中) と CodeRabbit (pass, Review completed) のみ。他の CI (build/test) は未登録。mergeStateStatus: UNSTABLE (pending own check 起因と推測)、mergeable: MERGEABLE
  • レビュー状況: CodeRabbit が 2026-07-13T13:55:55Z にレビュー (COMMENTED, actionable 2件) を投稿。人間レビューは無し (reviewDecision 未設定)。前回の分析コメント (issue_comment, 13:51:07Z) はこのレビュー投稿より前の時点のものなので、重複ガードは不成立 (新規情報あり)
  • Verdict: needs_fix

Applicable Findings (Critical / High / Major)

# File (Line) Reviewer Issue Recommended Action
1 src/lib-jj-helpers/src/pipeline_lock.rs:36-44 CodeRabbit PipelineLock::drop は所有権を確認せず無条件に remove_file する。stale threshold (30分) 超過だが未クラッシュのプロセス A の lock を B が takeover 後、A の guard が drop されると B の最新 lock ファイルまで削除され、本 PR が防止対象とする Concurrent checkout 事故を stale 境界で再発させ得る。参照実装 src/cli-pr-monitor/src/lock.rsMonitorLock::drop (41-50行目) にも同じ無条件 remove パターンがあり、既存踏襲元にも同型の潜在バグがある guard に pid/start_unix を保持し、Drop::drop で現在のファイル内容と一致する場合のみ削除する (CodeRabbit 提案の diff を適用)。takeover→drop 衝突を再現する regression test も追加
2 src/cli-push-runner/src/stages/bookmark_check.rs:28-37 CodeRabbit OWN_BRANCH_BOOKMARKS_REVSET = "::@ ~ ::trunk()" は @ が merge commit で side branch (他 workspace の未マージ commit 等) を親に持つ場合、その側の祖先が ::@ ~ ::trunk() に残り「自分のブランチ線上のみ」という設計意図 (コメント記載の意図) を満たさない。ADR-045 の並行 workspace 運用リスクに直接関わる論理的な穴 first_ancestors(@) ~ ::trunk() へ切り替える前に、この revset 関数が実際の jj バージョンで有効か (jj bookmark list -r ... で動作確認) を検証し、merge/side-branch を含む履歴の回帰テストを追加した上で適用

Applicable Findings (Medium 以下)

(該当なし)

Filtered (not applicable)

(該当なし — 今回の CodeRabbit actionable 指摘 2 件はいずれも applicable と判定)

次のアクション

  • 上記 2 件 (いずれも Major) は次のローカルセッションでの修正を推奨。特に finding feat(hooks): 設定駆動型アーキテクチャに移行し配布自動化を実装 #1 は本 PR の目的そのもの (Concurrent checkout 事故防止) を損ないうる correctness bug のため優先度が高い
  • finding fix(hooks): stop-quality のパイプデッドロックを修正 #2 の修正時は提案 revset 関数 first_ancestors() の実在性を jj 側で確認してから適用すること (CodeRabbit の web 検索結果自体が「標準の単一組み込み関数ではない」と述べており、構文の妥当性未確認)
  • CI に build/test 系のチェックが登録されていないように見える点は、必要な workflow が正しくトリガーされているか人間側で確認を推奨 (前回分析でも同様の指摘あり、継続注視)

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Monitor 分析 (GitHub Actions バックストップ)

  • トリガー: pull_request_review (submitted) / 実行 run
  • CI: 登録済みチェックは本 workflow 自身 (analyze, pending — 自己参照的に実行中) と CodeRabbit (pass, "Review skipped: incremental reviews are disabled" 表示だが、実際の個別レビューは下記の通り既に完了・応答済み)。build/test 系の CI は引き続き未登録。mergeStateStatus: UNSTABLE (pending own check 起因と推測)、mergeable: MERGEABLE
  • レビュー状況: CodeRabbit の前回 actionable 指摘 2 件 (pipeline_lock.rs の Drop 所有権確認、bookmark_check.rs の revset) は、aloekun のコミット 913c2e05 (2026-07-14T06:44 UTC) で修正され、CodeRabbit が両方とも "Fix confirmed" / "Confirmed as addressed" と応答済み。新規の actionable 指摘は無し。人間レビューは reviewDecision 未設定 (owner 自身によるスレッド返信のみで、他レビュアーからの approve/request-changes は無し)
  • Verdict: approved

前回指摘のフォローアップ状況

# File (Line) 元指摘 (Reviewer) 対応内容 状態
1 src/lib-jj-helpers/src/pipeline_lock.rs:36-44(現行38-66) CodeRabbit — Drop が所有権を確認せず無条件 remove_file。stale takeover 後に旧 guard が新 lock を誤削除しうる pid/start_unix ではなく 128bit ランダム token を guard に保持し、Drop は読み直した lock 内容の token が一致する場合のみ削除する方式に変更。回帰テスト2件 (drop_does_not_remove_lock_after_takeover / drop_removes_lock_when_token_matches) を追加 (commit 913c2e05) CodeRabbit が "Fix confirmed" と応答。残存する read→remove 間の TOCTOU はコード内コメントで許容理由を明記済みで、CodeRabbit も "reasoning holds"(blocking ではない)と追認
2 src/cli-push-runner/src/stages/bookmark_check.rs:28-37 CodeRabbit — ::@ ~ ::trunk() は merge 経由の side branch 祖先を除外できず、first_ancestors(@) ~ ::trunk() への変更を提案 revset の絞り込みではなく方針転換し、対象 revset を @(working-copy commit の厳密一致)に変更、advance_lagging_bookmark() を追加 (commit 913c2e05)。stacked bookmark 運用時のトレードオフは todo 登録済み CodeRabbit が "structurally safer" と評価し "Confirmed as addressed" と応答

Applicable Findings (Critical / High / Major)

(該当なし — 過去の指摘2件はいずれも修正・CodeRabbit確認済み。新規 actionable 指摘なし)

Filtered (not applicable)

(該当なし)

次のアクション

  • 現時点で追加対応が必要な指摘は無い。analyze (自己参照 check) 完了後に mergeStateStatus が安定するか確認を推奨
  • build/test 系 CI チェックが引き続き未登録に見える点は、過去複数回の分析でも継続して指摘済み。必要な workflow が正しくトリガーされているか人間側での確認を推奨 (blocking ではないが繰り返し所見)
  • 人間による正式レビュー (approve) は未実施。マージ判断は人間に委ねる

@aloekun

aloekun commented Jul 14, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Monitor 分析 (GitHub Actions バックストップ)

  • トリガー: issue_comment (created) / 実行 run
  • CI: analyze (本 workflow 自身、pass、1m58s)。CodeRabbit は現在 pending ("Review in progress") — owner が 06:55:51Z に @coderabbitai review を再依頼したことによる再チェック状態で、PR の head commit (913c2e05) 自体は前回分析時点から変化なし。build/test 系 CI は引き続き未登録
  • レビュー状況: CodeRabbit の前回 actionable 指摘 2 件 (pipeline_lock.rs の Drop 所有権確認、bookmark_check.rs の revset) はいずれも commit 913c2e05 で修正済み・CodeRabbit が "Fix confirmed" / "Confirmed as addressed" 応答済み (前回分析で報告済み、変更なし)。owner の再レビュー依頼 (06:55:51Z) に対し CodeRabbit は「incremental review は既に完了しており、一時停止中でない限り再レビューしない」旨を返信 (06:55:55Z) — 新規の actionable 指摘は生成されていない。人間レビューは reviewDecision 未設定のまま
  • Verdict: approved

Applicable Findings (Critical / High / Major)

(該当なし — 過去の指摘2件は修正・CodeRabbit確認済みで、今回の再レビュー依頼からも新規指摘は発生していない)

Filtered (not applicable)

(該当なし)

次のアクション

  • 追加の code fix は不要。CodeRabbit check が pending から確定するまで待つ必要はあるが、内容は再依頼への no-op 応答のみで新規指摘は見込み薄
  • build/test 系 CI チェックが引き続き未登録に見える点は過去複数回の分析で継続指摘済み。必要な workflow が正しくトリガーされているか人間側での確認を推奨(blocking ではない)
  • 人間による正式レビュー (approve) は未実施。マージ判断は人間に委ねる

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@github-actions[bot] Thanks for the status update. Noted that both previously flagged issues (the Drop/ownership handling in pipeline_lock.rs and the revset scoping in bookmark_check.rs) are confirmed fixed as of commit 913c2e05, and no new actionable findings have surfaced from the re-review request. No further action needed from my side at this time.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib-jj-helpers/src/pipeline_lock.rs (1)

87-124: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

stale takeover も atomic にしてください

read_fresh_lock の後に std::fs::write で上書きすると、同じ stale lock を見た 2 プロセスがどちらも Acquired になり得ます。takeover も create_new(true) で行い、AlreadyExists を敗者として扱ってください。concurrent stale takeover の回帰テストも追加すると安心です。

🤖 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 `@src/lib-jj-helpers/src/pipeline_lock.rs` around lines 87 - 124, Make the
stale-lock takeover in acquire_pipeline_lock_at atomic: after read_fresh_lock
confirms the existing lock is stale, replace the direct std::fs::write overwrite
with a create_new(true)-based takeover mechanism so only one concurrent process
acquires it. Treat AlreadyExists as a losing acquisition and return the
appropriate non-acquired result, while preserving the existing stale-lock and
normal-acquisition behavior; add a regression test covering concurrent stale
takeovers.
🤖 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.

Outside diff comments:
In `@src/lib-jj-helpers/src/pipeline_lock.rs`:
- Around line 87-124: Make the stale-lock takeover in acquire_pipeline_lock_at
atomic: after read_fresh_lock confirms the existing lock is stale, replace the
direct std::fs::write overwrite with a create_new(true)-based takeover mechanism
so only one concurrent process acquires it. Treat AlreadyExists as a losing
acquisition and return the appropriate non-acquired result, while preserving the
existing stale-lock and normal-acquisition behavior; add a regression test
covering concurrent stale takeovers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3cb6093e-7f1a-4061-bfd3-87317ad9e14c

📥 Commits

Reviewing files that changed from the base of the PR and between 054adfc and 913c2e0.

📒 Files selected for processing (2)
  • src/cli-push-runner/src/stages/bookmark_check.rs
  • src/lib-jj-helpers/src/pipeline_lock.rs

@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Monitor 分析 (GitHub Actions バックストップ)

  • トリガー: pull_request_review (submitted) / 実行 run
  • CI: analyze (本 workflow 自身、pending — 自己参照的に実行中)。CodeRabbitpass (Review completed)。build/test 系 CI は引き続き未登録。mergeStateStatus: UNSTABLE (pending own check 起因と推測)、mergeable: MERGEABLE
  • レビュー状況: CodeRabbit が 2026-07-14T07:03:54Z に新規レビュー (COMMENTED) を投稿。従来の 2 件 (Drop 所有権確認、bookmark revset) は commit 913c2e05 (06:44 UTC) で修正済み・CodeRabbit 確認済み (前回分析コメント 06:58:38Z で報告済み、継続有効)。今回のレビューは同じ commit 913c2e05 に対する追加指摘で、diff 範囲外 (outside diff range) の 1 件を新規に検出。前回分析コメント (06:58:38Z、Verdict: approved) より後の新規指摘のため重複ガード不成立。人間レビューは reviewDecision 未設定のまま
  • Verdict: needs_fix

Applicable Findings (Critical / High / Major)

# File (Line) Reviewer Issue Recommended Action
1 src/lib-jj-helpers/src/pipeline_lock.rs:87-124 (acquire_pipeline_lock_at の takeover 分岐、現行543行目付近) CodeRabbit stale lock の takeover が std::fs::write による非 atomic な上書きのまま。同一の stale lock を検知した 2 プロセスがどちらも read_fresh_lock で stale 判定 → 両者とも std::fs::write で上書きし、両方が PipelineLockResult::Acquired を返し得る。現物確認済み: 前回 commit (913c2e05) で修正されたのは Drop の無条件削除問題 (token 一致確認を追加) のみで、この takeover-write 自体の race は未対応のまま残存。本 PR の目的 (Concurrent checkout 事故の根本解決) と直接矛盾する correctness gap takeover も OpenOptions::create_new(true) ベースの atomic 書き込みに変更し、AlreadyExists を敗者として扱う (Busy 相当の結果を返す)。CodeRabbit 提案通り concurrent stale takeover の回帰テストも追加

Applicable Findings (Medium 以下)

(該当なし)

Filtered (not applicable)

(該当なし — 今回の新規 outside-diff 指摘 1 件は applicable と判定。ADR-045 等の意図的設計との矛盾は無く、.claude/ 等の sensitive-file にも該当しない)

次のアクション

  • 上記 finding feat(hooks): 設定駆動型アーキテクチャに移行し配布自動化を実装 #1 (Major) の修正を次のローカルセッションで推奨。takeover 経路の atomic 化は本 PR が解決対象とする「Concurrent checkout 事故」と同種のレースであり優先度が高い
  • 修正時は Drop 側の token 検証ロジック (既存修正) との整合を確認し、takeover 敗者側の挙動 (Busy 扱いへの変更) が hold_pipeline_lock の advisory fail-open 前提と矛盾しないことを確認
  • build/test 系 CI チェックが引き続き未登録に見える点は過去複数回の分析で継続指摘済み。必要な workflow が正しくトリガーされているか人間側での確認を推奨 (blocking ではない)

…bbit re-review Major対応)

std::fs::write による無条件上書きだと、同じ stale lock を同時に見た 2 プロセス
が両方とも Acquired になり得るレースがあった。remove_file + create_new に変更し、
takeover レースに負けた側 (create_new が AlreadyExists) は Busy を返すようにした。
関数長超過回避のため takeover_stale_lock / busy_from_disk へ分割。
regression test: concurrent_stale_takeover_only_one_wins (2 スレッドで実レース)。
@aloekun
aloekun merged commit c5f7cb5 into master Jul 14, 2026
1 check passed
@aloekun
aloekun deleted the pipeline-lock-stop-skip branch July 14, 2026 10:38
aloekun added a commit that referenced this pull request Jul 14, 2026
…注記 (順位292-300) (#272)

* docs(todo): 順位292-300 登録 — jj-op-verify再分類/ADR-045注記/PR#271 post-merge-feedback採用5件

- 292: cli-pr-monitor lock.rsをtoken方式の所有権検証へ統一
- 293: push-runner stack pushモード (opt-in, YAGNI見送り継続)
- 294: jj-op-verify hookの位置づけ再整理 (並列workspace安全化→混線緩和層)
- 295: ADR-045にコミット消失事故の「並列原因」診断が未検証である旨の注記追加
- 296-300: PR #271 post-merge-feedback (271.md) T2-2/T2-3/T3-1/T3-2/T3-3 採用分

* docs(todo): 順位293の完了基準をclose判断パスも含むよう修正 (CodeRabbit Minor対応、PR #272)
aloekun added a commit that referenced this pull request Jul 16, 2026
* fix(cli-push-runner): 空 `@` 時の bookmark_check 誤誘導を修正 (push パイプライン改善 T8)

`@` が空で bookmark が `@-` にある状態 (jj new 直後の正常な再 push 状態) で、
同一 run 内の advance_jj_bookmarks が「bookmark を @- に自動更新」と報告した
直後に bookmark_check が「bookmark が見つかりません」と報告し、
`jj bookmark create <name> -r @` を案内していた。従うと空の WIP コミットに
bookmark が付く破壊的操作になる。PR #279 (T1) の dogfood push で実際に発火。

根本原因は「@ が空なら @- を対象にする」規則の二重定義。advance は
determine_target_revision() で規則を持つのに、bookmark_check は
OWN_WORKSPACE_BOOKMARKS_REVSET ("@" 厳密一致) で独自に検査していたため、
両者の判定が食い違った。

修正:
- determine_target_revision() から working_copy_is_empty() を切り出し、
  bookmark_check と共有する (規則の二重定義を解消)。
- 「@ に bookmark が無い」を 2 ケースに切り分ける判定 enum
  BookmarkCheckOutcome と pure function decide_bookmark_check() を追加。
  jj 呼び出しは closure 注入 (ADR-021 原則 3、既存 dispatch_bookmark_advance
  と同じ流儀)。
  - `@` 空 + bookmark が @-: `jj edit @-` + 空 WIP の abandon を案内
    (T1 セッションで実証済みの回避策)。
  - bookmark 皆無: 従来の作成案内が正しいので維持。
- main.rs に重複していた同じ誤案内を撤去し、ケース別案内を出す
  bookmark_check に一本化。

exit 7 による中断は維持し、案内文のみを正す方針を採った。計画の方針 2
(検査を @- 対象にして続行) は、[diff] command = "jj diff -r @" のため
`@` が空のまま続行すると diff が空になり takt レビューが無言 skip された
まま push される (誤誘導バグをレビューバイパスに置き換える) ため不採用。
方針 3 の「push すべき新変更がない」も、再現記録の事実 4 (jj edit @- 後に
push 成功 = 変更はあった) と矛盾するため不採用。

ADR-021 原則 5 との関係: bookmark_check が `@` 厳密一致に狭めているのは
PR #271 (他 workspace の bookmark 混入) の対策。本修正の @- 照会は案内文の
出し分け (診断) 専用で、push 対象の組み立ては `@` のまま維持する。

テスト: mod t8_empty_head_misdirection に 7 本追加 (186 → 193 passed)。
由来 incident と再現状態を module doc に明記 (ADR-049 の流儀)。bad =
2 ケースが潰れないこと、good = bookmark 皆無が NoBookmarks のままである
ことを固定。サンドボックス jj repo で配布 exe が記録の出力を逐語再現する
ことを確認した上で修正後 exe と before/after 比較した。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(review): CodeRabbit Major 2 件 + simplicity 警告 2 件を反映 (PR #280 / push T8)

PR #280 のレビュー指摘を反映する。いずれも「T8 が直したはずの穴が、条件違いで
残っていた」類の指摘で、本タスクの主題 (正確な案内) そのものに関わる。

## CodeRabbit Major (2 件、採用)

1. 判定順を反転し、bookmark が空の `@` にある場合も中断する

   従来は「`@` に bookmark があれば続行」を先に判定していたため、bookmark が
   空の `@` に付いていると Proceed していた。この経路は `jj diff -r @` が空に
   なり、祖先の未 push 変更が AI レビューを経ずに push される — 本タスクが
   方針 2 を却下した理由と同じ穴が、bookmark の位置違いで残っていた。
   `advance_jj_bookmarks` は非 trunk bookmark が 2 つ以上あると fallback 更新を
   skip するため、この状態は実在する (サンドボックスで再現確認済み: 修正前は
   「非 trunk bookmark 検出 (1 件): feat/b」で通過し PR diff 0 行へ進んでいた)。
   「レビュー範囲 = `@` だから `@` は非空でなければならない」という本タスクの
   不変条件に判定順を揃えた。

2. `@-` 照会の失敗を握り潰さない

   `unwrap_or_default()` が照会失敗を「親はあるが bookmark 無し」に変換して
   いたため、`@-` の存在を確認できていないのに実行不能な `jj edit @-` を
   案内し得た。ParentState::Unavailable として保持し、親を確認できない場合は
   `jj edit @-` を案内しない。

## simplicity-review 非ブロッキング警告 (2 件、採用)

3. `query_parent_state()` の jj 失敗を log する

   同ファイルの他の jj 失敗処理や push_jj_bookmark.rs は log_info する慣習が
   あり、ここだけ欠落していた。親を確認できない理由が残らないと、root commit
   なのか jj 不調なのかを切り分けられない。

4. `@-` に bookmark が無い場合の案内を分ける

   `jj edit @-` だけを案内すると次は `NoBookmarks` で止まり根本解決にならない。
   bookmark 作成まで含めて 1 度に案内する 3 つ目の variant に分けた。

## 不採用

CodeRabbit Minor の日付指摘は不採用: CodeRabbit は UTC 基準で「2026-07-16」と
指摘しているが、本 repo の記録は JST 基準 (既存の T0/T1 も同様) のため
2026-07-17 が正しい。同指摘のうち PR 番号 (未採番 → #280) は採用した。

テスト: t8_empty_head_misdirection を 7 → 12 本に拡充 (193 → 198 passed)。
バイパス経路を固定していた既存テスト 1 本は中断側へ反転させた。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant