Skip to content

cross-review: レビュワーが 1 者でも欠けると初期化ごと失敗する — 使える者だけで回せるようにする #478

Description

@takemi-ohama

事象

/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 でログインしてから再実行してください

codexagy は動作しており、この 2 者でクロスレビューは成立する。それでも state.py initdie() するため、ループを 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.pyinit: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)で起きたこと:

  1. --only codex で 6 ラウンド回して APPROVE まで収束させた
  2. 状態ファイルを退避して --only agy で別ループを開始した
  3. agy が 4 件(major 2 / minor 2)を指摘した

codex が APPROVE したのは、agy がまだ見ていない版に対してだった。 agy の指摘で文書が変われば、codex はその変更を見ていない状態になる。2 者が同じ最終版を承認したことを確かめるには、agy の収束後に codex をもう一度回すという手作業が要る。

母集合が 3 者揃っていれば輪番で自然に担保される性質を、利用者が手で組み立て直すことになっている。

agy の打ち切りを避けて codex + kiro の 2 者で回したいときも、状態ファイルを手で書き換えるしかない。

提案

認証確認を「関門」から「導入状況の把握」へ変える。 使える者でレビューし、使えない者は最初から数えない。

  1. init で母集合の各ランタイムの認証を確かめ、通った者の一覧を state.json へ記録するavailable_reviewers)。再開時はこの一覧を読み、ラウンドごとに調べ直さない(途中で担当が入れ替わると前ラウンドの記録と突き合わせられなくなるため)

  2. 明示的に外す手段を用意する(例: --exclude agy)。外した者は available_reviewers に入れず、外したことを状態ファイルに残す。認証は通るが実行で落ちる担当(agy の打ち切り、モデルの 404、利用上限)を外す用途でも使う。 再開時に渡されたときも反映する(再開時の引数の扱いは cross-review: 再開すると --only / --max-rounds / --verify-command などの引数が黙って無視される #648

  3. 使える者の数で分岐する

    使える者 挙動
    3 者 現行どおり。輪番で 2 者を選ぶ
    2 者 毎ラウンド その 2 者で回す。輪番も除外もしない
    1 者 警告を出したうえで 1 者で回す(--only 相当)。観点は 1 つだと明示する。収束の判定は cross-review: --only で 1 者だけのとき、反証する担当がおらず REQUEST_CHANGES の新しい指摘があっても収束と判定する #624 を直すまで誤る
    0 者 失敗する
  4. 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]
  5. 全員揃っていることを要求したい運用のために --require-all を用意する(既定は付けない)

  6. 完了報告に「このループに参加したのは誰か」を出す。欠けたまま収束したことが後から読めるようにする

補足

  • 現行の警告文「参加者が欠けたまま進むと、その者のレビューが無いまま収束します」は、欠けたまま進むことを利用者に選ばせる書き方になっている。実際には選べず、必ず止まる
  • cross-refactoringplugins/ndf/scripts/lib/assignment.py を共有しており、assign() 側にも同じ前提(母集合 3 者)が入っている。あわせて見直すのが望ましい

関連

進行

モード: standard / 作業ツリー: .worktrees/feat/issue-727-participants / 計画: issues/issue-727-p6-participants-plan.md

  • 要求と受け入れ条件 — 2026-09-15 12:46
  • 作業場所の用意 — 2026-09-15 12:45
  • 設計 — 2026-09-15 14:11
  • 素材の収集と出典の確定
  • ドキュメント再構成 — 2026-09-15 14:11
  • ドキュメントレビュー — 2026-09-15 14:11
  • 計画 — 2026-09-19 19:41
  • 実装 — 2026-09-19 19:44
  • 構造改善 — 2026-09-21 20:59
  • 実装レビュー — 2026-09-22 02:12
  • 完了判定 — 2026-09-22 03:08
  • Pull Request — 2026-09-19 20:44
  • 確定仕様化 — 2026-09-22 03:43
  • 後片付け — 2026-09-19 19:36
  • 配布 — 2026-09-22 14:17
  • 体裁レビュー
  • リリース後テスト — 2026-09-22 15:06
  • 振り返り — 2026-09-22 15:38

開いたままの理由

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_probePermissionError を捕まえず init が落ちる。その項目を外した PATH では合格。#813 を直して AC45 を確かめ直してから閉じる。

振り返り: #810 (comment)

閉じる理由(2026-09-22)

10.16.0 のリリース後テストで AC45 前半が不合格だった(利用者の PATH に読めない /root/.local/bin があり、auth.py_run_probePermissionError を捕まえず init が exit=1)。原因は #813 として切り出し、#820 で直した

レビュワーが 1 者欠けても初期化ごと失敗しないことを、利用者の環境と同じ導入経路で確かめた。

振り返り: #832 (comment)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: ndf-skillNDF の Skill 本体enhancementNew feature or requestpriority: high実害・安全機構の欠落など、優先して対応する

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions