事象
/ndf:cross-review は、レビュワーの母集合(全ランタイム − ホスト = 3 者)のうち 1 者でも認証できないと初期化ごと失敗する 。導入済みの 2 者でレビューを回す手段が無い。
ホスト: claude(explicit) / レビュワーの母集合: codex / agy / kiro
✅ codex: codex login status
✅ agy: agy models
❌ kiro: kiro-cli whoami
❌ 認証されていない CLI があります: kiro(コマンドが見つかりません)。参加者が欠けたまま進むと、その者のレビューが無いまま収束します。各 CLI でログインしてから再実行してください
codex と agy は動作しており、この 2 者でクロスレビューは成立する。それでも state.py init が die() するため、ループを 1 度も開始できない。
認証は通るが、実行で落ちる担当を外す手段も無い。 母集合から特定のランタイムを外す引数は無く、担当を絞る引数は 1 者へ絞る --only だけである(state.py:4355)。cross-refactoring にも除外の引数は無い。
$ git grep -n ' "--exclude"' -- plugins/ndf
(出力なし)
外したい場面は、次のように認証の確認では見分けられない。
担当が落ちる理由
認証の確認
課題
agy が監視の上限・CLI の上限で打ち切られる
通る
#598 / #537 (解決済み 。下の注記)
CLI の設定が引けないモデルを指し、404 で終わる
通る
#461
CLI の利用上限に達している
通る
#619
#598 / #537 は v10.13.0(2026-09-16)で解決した。 監視の上限は工程ごとの表
(plugins/ndf/scripts/lib/limits.py)が持ち、レビューの工程は 1200 秒になった。担当の CLI の
上限は、環境変数で解決した監視の上限 + 120 秒(既定 1320 秒)を導く。この理由で agy を外す必要は
無い。 残る 2 つ(モデルの 404、利用上限)は外す理由として成立する。
該当箇所
plugins/ndf/skills/cross-review/scripts/state.py(init、:1792-1797)
reviewers = assignment .review_pool (host )
info (f"ホスト: { host } ({ host_source } ) / レビュワーの母集合: { ' / ' .join (reviewers )} " )
_validate_only (args .only , host )
auth .check_auth (_auth_targets (args .only , host ), info = info , die = lambda m : die (m ))
_auth_targets() は --only が無ければ母集合 3 者をそのまま返し、check_auth は 1 件でも失敗すると die() する。
plugins/ndf/scripts/lib/assignment.py (cross-refactoring と共有する共通層)
ALL_RUNTIMES : tuple [str , ...] = ("claude" , "codex" , "agy" , "kiro" )
def review_pool (host : str ) -> list [str ]:
"""提案・レビューの母集合(全ランタイム − ホスト)。常に 3 者になる。"""
...
def review_assign (round_no : int , host : str ) -> list [str ]:
pool = review_pool (host )
dropped = (round_no - 1 ) % len (pool )
return [r for i , r in enumerate (pool ) if i != dropped ]
review_pool() は導入状況を見ず、常に 4 − 1 = 3 者を返す。review_assign() はそこから 1 者を輪番で外して 2 者にする。「3 者いる」ことが前提に組み込まれている。
影響
--only <1 者> へ逃がす以外に進む手段が無く、そのモードは「デバッグ用」と位置づけられているとおり 1 ラウンド 1 者 になる。この Skill の価値である「複数の観点で見て収束させる」性質が失われる。1 者のモードでは、反証する担当がいないため新しい指摘があっても収束と判定する (#624 )。
devbasex/devbase#159 (設計 PR)で起きたこと:
--only codex で 6 ラウンド回して APPROVE まで収束させた
状態ファイルを退避して --only agy で別ループを開始した
agy が 4 件(major 2 / minor 2)を指摘した
codex が APPROVE したのは、agy がまだ見ていない版に対してだった。 agy の指摘で文書が変われば、codex はその変更を見ていない状態になる。2 者が同じ最終版を承認したことを確かめるには、agy の収束後に codex をもう一度回すという手作業が要る。
母集合が 3 者揃っていれば輪番で自然に担保される性質を、利用者が手で組み立て直すことになっている。
agy の打ち切りを避けて codex + kiro の 2 者で回したいときも、状態ファイルを手で書き換えるしかない。
提案
認証確認を「関門」から「導入状況の把握」へ変える。 使える者でレビューし、使えない者は最初から数えない。
init で母集合の各ランタイムの認証を確かめ、通った者の一覧を state.json へ記録する (available_reviewers)。再開時はこの一覧を読み、ラウンドごとに調べ直さない(途中で担当が入れ替わると前ラウンドの記録と突き合わせられなくなるため)
明示的に外す手段を用意する (例: --exclude agy)。外した者は available_reviewers に入れず、外したことを状態ファイルに残す。認証は通るが実行で落ちる担当(agy の打ち切り、モデルの 404、利用上限)を外す用途でも使う。 再開時に渡されたときも反映する(再開時の引数の扱いは cross-review: 再開すると --only / --max-rounds / --verify-command などの引数が黙って無視される #648 )
使える者の数で分岐する
review_assign() は「母集合から 1 者を外す」ではなく「使える者が 3 者以上のときだけ 1 者を外す 」に変える
def review_assign (round_no : int , available : list [str ]) -> list [str ]:
if len (available ) <= 2 :
return list (available )
dropped = (round_no - 1 ) % len (available )
return [r for i , r in enumerate (available ) if i != dropped ]
全員揃っていることを要求したい運用のために --require-all を用意する(既定は付けない)
完了報告に「このループに参加したのは誰か」を出す。欠けたまま収束したことが後から読めるようにする
補足
現行の警告文「参加者が欠けたまま進むと、その者のレビューが無いまま収束します」は、欠けたまま進むことを利用者に選ばせる 書き方になっている。実際には選べず、必ず止まる
cross-refactoring も plugins/ndf/scripts/lib/assignment.py を共有しており、assign() 側にも同じ前提(母集合 3 者)が入っている。あわせて見直すのが望ましい
関連
進行
モード: standard / 作業ツリー: .worktrees/feat/issue-727-participants / 計画: issues/issue-727-p6-participants-plan.md
開いたままの理由
PR #793 で直し、ndf 10.16.0(2026-09-22、main / タグ ndf--v10.16.0、PR #810 )で配布した。リリース後テスト(#810 (comment) )で、AC45 前半(kiro-cli が無い環境で init が終了コード 0)が不合格 だった。利用者の PATH に読めないディレクトリがあると、auth.py の _run_probe が PermissionError を捕まえず init が落ちる。その項目を外した PATH では合格。#813 を直して AC45 を確かめ直してから閉じる。
振り返り: #810 (comment)
閉じる理由(2026-09-22)
10.16.0 のリリース後テストで AC45 前半が不合格だった (利用者の PATH に読めない /root/.local/bin があり、auth.py の _run_probe が PermissionError を捕まえず init が exit=1)。原因は #813 として切り出し、#820 で直した 。
レビュワーが 1 者欠けても初期化ごと失敗しない ことを、利用者の環境と同じ導入経路で確かめた。
振り返り: #832 (comment)
事象
/ndf:cross-reviewは、レビュワーの母集合(全ランタイム − ホスト = 3 者)のうち 1 者でも認証できないと初期化ごと失敗する。導入済みの 2 者でレビューを回す手段が無い。codexとagyは動作しており、この 2 者でクロスレビューは成立する。それでもstate.py initがdie()するため、ループを 1 度も開始できない。認証は通るが、実行で落ちる担当を外す手段も無い。 母集合から特定のランタイムを外す引数は無く、担当を絞る引数は 1 者へ絞る
--onlyだけである(state.py:4355)。cross-refactoring にも除外の引数は無い。外したい場面は、次のように認証の確認では見分けられない。
#598 / #537 は v10.13.0(2026-09-16)で解決した。 監視の上限は工程ごとの表
(
plugins/ndf/scripts/lib/limits.py)が持ち、レビューの工程は 1200 秒になった。担当の CLI の上限は、環境変数で解決した監視の上限 + 120 秒(既定 1320 秒)を導く。この理由で agy を外す必要は
無い。 残る 2 つ(モデルの 404、利用上限)は外す理由として成立する。
該当箇所
plugins/ndf/skills/cross-review/scripts/state.py(init、:1792-1797)_auth_targets()は--onlyが無ければ母集合 3 者をそのまま返し、check_authは 1 件でも失敗するとdie()する。plugins/ndf/scripts/lib/assignment.py(cross-refactoring と共有する共通層)review_pool()は導入状況を見ず、常に 4 − 1 = 3 者を返す。review_assign()はそこから 1 者を輪番で外して 2 者にする。「3 者いる」ことが前提に組み込まれている。影響
--only <1 者>へ逃がす以外に進む手段が無く、そのモードは「デバッグ用」と位置づけられているとおり 1 ラウンド 1 者になる。この Skill の価値である「複数の観点で見て収束させる」性質が失われる。1 者のモードでは、反証する担当がいないため新しい指摘があっても収束と判定する (#624)。devbasex/devbase#159(設計 PR)で起きたこと:
--only codexで 6 ラウンド回して APPROVE まで収束させた--only agyで別ループを開始したcodex が APPROVE したのは、agy がまだ見ていない版に対してだった。 agy の指摘で文書が変われば、codex はその変更を見ていない状態になる。2 者が同じ最終版を承認したことを確かめるには、agy の収束後に codex をもう一度回すという手作業が要る。
母集合が 3 者揃っていれば輪番で自然に担保される性質を、利用者が手で組み立て直すことになっている。
agy の打ち切りを避けて codex + kiro の 2 者で回したいときも、状態ファイルを手で書き換えるしかない。
提案
認証確認を「関門」から「導入状況の把握」へ変える。 使える者でレビューし、使えない者は最初から数えない。
initで母集合の各ランタイムの認証を確かめ、通った者の一覧をstate.jsonへ記録する(available_reviewers)。再開時はこの一覧を読み、ラウンドごとに調べ直さない(途中で担当が入れ替わると前ラウンドの記録と突き合わせられなくなるため)明示的に外す手段を用意する(例:
--exclude agy)。外した者はavailable_reviewersに入れず、外したことを状態ファイルに残す。認証は通るが実行で落ちる担当(agy の打ち切り、モデルの 404、利用上限)を外す用途でも使う。 再開時に渡されたときも反映する(再開時の引数の扱いは cross-review: 再開すると --only / --max-rounds / --verify-command などの引数が黙って無視される #648)使える者の数で分岐する
--only相当)。観点は 1 つだと明示する。収束の判定は cross-review: --only で 1 者だけのとき、反証する担当がおらず REQUEST_CHANGES の新しい指摘があっても収束と判定する #624 を直すまで誤るreview_assign()は「母集合から 1 者を外す」ではなく「使える者が 3 者以上のときだけ 1 者を外す」に変える全員揃っていることを要求したい運用のために
--require-allを用意する(既定は付けない)完了報告に「このループに参加したのは誰か」を出す。欠けたまま収束したことが後から読めるようにする
補足
cross-refactoringもplugins/ndf/scripts/lib/assignment.pyを共有しており、assign()側にも同じ前提(母集合 3 者)が入っている。あわせて見直すのが望ましい関連
launch-cli.shの bash 3.2 での起動失敗。そちらの「補足」に書いたこの件を、この課題へ切り出した--onlyなどの引数が無視される。除外の手段を足すなら、再開時の反映も一緒に決めるassignment.pyで決める進行
モード: standard / 作業ツリー:
.worktrees/feat/issue-727-participants/ 計画:issues/issue-727-p6-participants-plan.md開いたままの理由
PR #793 で直し、ndf 10.16.0(2026-09-22、
main/ タグndf--v10.16.0、PR #810)で配布した。リリース後テスト(#810 (comment) )で、AC45 前半(kiro-cliが無い環境でinitが終了コード 0)が不合格だった。利用者の PATH に読めないディレクトリがあると、auth.pyの_run_probeがPermissionErrorを捕まえずinitが落ちる。その項目を外した PATH では合格。#813 を直して AC45 を確かめ直してから閉じる。振り返り: #810 (comment)
閉じる理由(2026-09-22)
10.16.0 のリリース後テストで AC45 前半が不合格だった(利用者の
PATHに読めない/root/.local/binがあり、auth.pyの_run_probeがPermissionErrorを捕まえずinitが exit=1)。原因は #813 として切り出し、#820 で直した。mainへ、タグndf--v10.16.1)kiro-cliが無くPATHに読めないディレクトリがある環境で、initが exit=0 で終わり、使える者だけで 2 席(codex agy)を埋めた。記録: Release: ndf v10.16.1 #831 (comment)レビュワーが 1 者欠けても初期化ごと失敗しないことを、利用者の環境と同じ導入経路で確かめた。
振り返り: #832 (comment)