コンテンツにスキップ

チームとしての従業員 (Team-as-Agent)

一人の AI 従業員の内部に 4 つの役割を置きます。規劃 / 執行 / 審核 / 合成です。各役割は別のベンダーのモデルで動かせます。ユーザーから見れば、従来どおり一人の従業員、一つの声です。


WP-1 から WP-5 までが反映済みです。基本部品、役割が動く土台、1 ラウンドを駆動する composer、そしてパケットを書き出す team_handoff ツールです。 1 ラウンドを 規劃 → 執行 → 審核 まで通せるようになりました。実際の goal に対して 14 回のライブラウンド(Claude が規劃、Codex が執行、Claude が審核)を実施し、以下に述べる統合上の欠陥が見つかりました。14 回目のラウンドは既存の判定器に受理されました。

項目 状態
[team] 設定スキーマ(グローバル + 従業員ごと、フィールド単位の cascade) 出荷済み (WP-1)
仕様の検証(runtime 許可リスト、model↔runtime の対応付け、審核者のファミリー規則、effort) 出荷済み (WP-1)
TaskPacket(役割間の引き継ぎ型とその上限) 出荷済み (WP-1)、spec/task-packet.md を参照
分解可能性ゲート(既定は Solo、L0/L1 ルール) 出荷済み (WP-1)、純関数として実装
一時的な役割メンバー(役割ごとの (runtime, model, effort) スキャフォールド、即時の破棄、独立した速度・容量の予算) 出荷済み (WP-2)
役割ごとの effort。duduclaw-core::effort で一度だけ解決し、spawn 時に各 runtime の表記へ変換 出荷済み (WP-3)
タスクごとの仕様凍結(tasks.team_spec_json)、ゲートの呼び出し箇所、3 段階のラウンド、予算の縮退チェーン、役割ごとの帰属(role_turns.jsonl) 出荷済み (WP-4)
team_handoff MCP ツール(パケットの書き手)、1 つの leg 上でのパケット fan-out、constraints / audience を絶対に削らないレンダリング 出荷済み (WP-5)
メンバーのネイティブツールイベントを監査証拠として永続化。成果物レシート(path / bytes / sha256)を審核者の prompt と settle の判定器入力に追加 出荷済み(ライブ第 8 ラウンド)
codex 向けの構造化された判定器出力(codex exec --output-schema) 出荷済み(ライブ第 8 ラウンド)
役割×モデルの能力マトリクス。執行 + 審核のセル、ボトルネック探索、role_model_matrix.toml 出荷済み (P2)、役割ごとのモデル選び (P2) を参照。P2b の全チーム 2×2 探索では 4 アームのライブスモークを 1 回完了(独立した審核判定 4 件はすべて FAIL)。サンプルは unresolved で、このファイルを composer はまだ読まない
役割ごとのコスト報告、ダッシュボードのチームカード 計画中
タスク詳細の「角色」タブ(段階の状態、モデル、実測 token 数) 出荷済み。パケット/ツールへのドリルダウンと USD 建てコストは引き続き計画中

v1.66 以降、[team] enabled の既定値は true です。変わったのはフラグ 1 つであり、実際に動くものは変わりません。チームが組まれるには、独立した 3 つの条件が揃う必要があり、[team] セクションを一度も書いたことのないインストールは従来と全く同じ挙動です。

  1. 仕様が検証を通ること。 [team.roles] がない場合、執行と審核はどちらも従業員自身の runtime と model に cascade するため同じモデルファミリーになり、執行者と同じファミリーの審核者は即座に拒否されます(規則 3 を参照)。実際には、2 つ目のベンダーを指定して初めてチームが有効になります。フラグは邪魔をしなくなっただけです。
  2. ゲートが Team と判定すること。 auto は 4 つのシグナルのうち 3 つを必要とします。通常のタスクは Solo になり、バイト単位で変わりません。
  3. 予算が 1 ラウンドを賄えること。 [dispatch.team_budget] が、完全に縮退させた最初のラウンドすら賄えないタスクは、始まってもいない作業のために人間待ちで停止するのではなく、Solo で実行されます。

enabled = false は引き続き本物のキルスイッチで、従業員側の明示的な false はグローバルの true に優先します。

(1) の拒否は意図的に静かです。設定のないデプロイでは debug! が 1 行出るだけで、監査行は書きません。書いてしまうと、全インストールの全 goal タスクに team_refused 行が付き、本物の拒否が見つけられなくなるためです。enabled = true を明記した運用者、またはロールを設定したのに検証に失敗した運用者には、従来どおり監査付きの目立つ拒否が返ります。

チーム goal が受理されると、TaskPacket に明示的に名前が挙がったファイルは、シェルコマンドで作られネイティブの Write イベントがない場合でも、従業員の attachments/ バケットにアーカイブされます。アーカイブは、各ソースが従業員ワークスペース内の通常ファイルであることを再確認し、通常の goal 成果物と同じサイズ上限に従います。タスク詳細の「角色」タブは、タスクの Viewer 権限で tasks.role_turns を読み、不明な token 使用量はゼロではなく不明として表示します。

役割ごとのコスト台帳は、provider が token を報告した場合に、Claude CLI などの runtime の使用量を goal タスク ID の下に記録します。チームの役割は、使用量の書き込みが完了するまで待ってから段階を終えます。報告されなかった token は不明のままで、推定値は実測値と区別して表示します。 失敗した役割行には、段階の境界(failure_edge)と閉じた集合の fault_side も記録されます。書き手は曖昧な失敗を unknown とし、観測の忠実度が欠落または未認識の段階は、モデルに責任を帰せません。これらのフィールドは症状の位置を示すもので、残りの帰属ゲートが接続されるまでは playbook 学習の根拠にはなりません。

役割メンバーの SOUL.md は、安定した役割契約で始まり、続いて独立したキャッシュ境界、その後に従業員のアイデンティティ文(あれば)が来ます。そのアイデンティティを変更しても役割契約は変わりません。タスクタイトル、パケット、受け入れ基準は、ラウンドごとのディスパッチ prompt で送られ、短命なメンバーごとに system プレフィックスを書き換えることはなくなりました。明示的な境界は Direct API のキャッシュに適用されます。CLI runtime は自前でキャッシュを管理します。コスト削減を主張するには、provider 側のキャッシュヒットの計測が依然として必要です。 Claude CLI の役割 spawn では、メインとサブエージェントのキャッシュ TTL を 1 時間に設定します。その他のエージェントの spawn は既存の TTL の挙動を維持します。 チームのラウンドが始まると、元の会話には既存の goal 通知経路を通じて進捗の 1 行が届きます。推定分数は、設定された進捗間隔に必須の 3 段階を掛けた値です。これは進捗の見積もりであり、完了の保証ではありません。

引き続き、人が見守る実験です。 本番環境のチームラウンドが 1 回、最後まで受理されています。1 ケース・4 アームの全チームライブ探索は、すべてのアームが独立した審核者まで到達しましたが、マトリクスのセルはすべて unresolved のままで、本番のモデルを確実に選べません。v1.66 の既定値の反転は、この経路が一度も実行されない原因だったフラグを取り除いたもので、計測された本番での勝利に変えたわけではありません。[team.roles] に 2 つ目のベンダーを指定したら、最初の数ラウンドは注意して見てください。enabled = false と gate = "always_solo" のどちらでも元に戻せます。


従業員は、ユーザーに見える唯一の単位です。agent ディレクトリ、その SOUL.md、チャネル、記憶、playbook がそれにあたります。これは変わりません。

チームは、一人の従業員の内部にある役割のグループです。

役割 仕事 UI 表記
planner 目標を分解して計画する 規劃
executor 作業を行う。fan-out 可 執行
verifier 独立して受理または却下する 審核
utility 要約、分類、雑務。spawn 枠を使わない 合成

各役割は自分の {runtime, model, effort} を持ちます。従業員は引き続き一つの声で話し、チームは一人の従業員が一つのタスクをこなすための実装上の詳細です。


チームは、起動時から待機している 4 つの役割ではありません。すべてのタスクはまず分解可能性ゲートを通り、大半のタスクは今日と同じ単一エージェントの経路にとどまります。バイト単位で変わりません。

根拠は Anthropic 自身のガイダンスです。「作業が依存関係のある一本の鎖である場合、または単一の context に収まる場合、orchestrator は計画、引き継ぎ、統合のコストを払うが、単一モデルならそれらは無料で得られる。」OneFlow(arXiv:2601.12307)は、単一エージェントがターンをループする方式が、同質なワークフローと同等の結果を出しつつキャッシュを温かく保てることを示し、arXiv:2609.19759 は、マルチエージェントの優位が現れるのは長いホライズンかつ依存が疎な場合だけだと示しています。

ゲートは LLM を使わない決定論的なものです。

サンドボックスルール(最初に確認): agent.toml [container] sandbox_enabled = true の従業員は常に Solo です(理由 sandbox_enabled)。このルールは always_team を含むすべてのモードより先に評価されるため、サンドボックスを有効にした従業員はチームを組まず、役割メンバーがホスト上で動くこともありません。goal ラウンドはタスクサンドボックス内で Solo として実行されます。

ハード除外、常に Solo: ライブのチャネルターン(ファサードが応答する)、承認待ちの plan-first goal、不可逆な操作を含む計画、または goal-loop の残り予算が 3 ラウンド未満の場合。

4 つのシグナル。 3 つ以上が成立 ⇒ チーム:

  1. 量: 独立して実行できる作業項目が 4 件以上あり、計測した依存ハブがゼロ。
  2. コンテキスト: タスクが 1 つの context window に収まらない。
  3. 能力差: 執行者と規劃者の候補の差が、能力マトリクスが宣言する最小検出効果(MDE)以上ある。MDE を下回る差はノイズ(Miller, arXiv:2411.00640)であり、数えません。
  4. 長いホライズン: 受け入れ基準が 3 つ以上あり、タスクが実際の成果物を生む。

ちょうど 2 つのシグナル ⇒ グレーゾーン。 規劃者を 1 回走らせ(このタスクがどのみち払う呼び出しです)、計画が実際にどう分解したかに基づいてゲートを再実行します。コイン投げにはしません。

それ以外は Solo。 Solo の判定にも effort のヒントを付けられます。Anthropic のコストガイダンスには、アーキテクチャの変更より effort の調整が勝ったという記録があり、この経路で一番安い改善はたいていチームではなくノブだからです。

計測されていないシグナルは単に成立しません。そのためゲートは Solo に傾きます。この向きは意図的です。高くつく失敗は、1 つのエージェントで終わったはずの作業のためにチームを組むことだからです。

すべての判定には安定した理由トークンが付き、後でタスクの実際の結果と照らして採点できます。この較正が統計的に裏付けられるまで、ダッシュボードはゲートを実験的と表示します。一度も採点されていないゲートは仮説にすぎません。


グローバルの既定値は config.toml、従業員ごとの上書きはその従業員の agent.toml に置きます。どちらも同じ形です。

[team]
enabled = true # v1.66 以降の既定は true。false はキルスイッチ
executor_fanout = 1 # 1..=3。範囲外は丸められ、拒否はされない
gate = "auto" # auto | always_solo | always_team
[team.roles.planner]
runtime = "claude"
model = "claude-fable-5-1"
effort = "high"
[team.roles.executor]
runtime = "codex"
model = "gpt-5.5"
effort = "medium"
[team.roles.verifier]
runtime = "antigravity"
model = "gemini-3.7-flash"
effort = "low"
[team.roles.utility]
runtime = "claude"
model = "claude-haiku-4-5"

cascade はフィールド単位で、3 段階です。

  1. 従業員の agent.toml [team] の値(書かれていれば)。
  2. なければ config.toml [team]。
  3. それもなく、runtime も model も指定しない役割については、従業員自身の [model] preferred。

したがって [team.roles.executor] effort だけを上書きした従業員は、その役割のグローバルな runtime と model を維持します。「未設定」と「明示的な false」は別の状態です。そのため、1 人の従業員の enabled = false は、継承された true ではなく本物のオプトアウトになります。

auto は上記のルールを実行します。always_solo はキルスイッチです。always_team はテスト専用で、不可逆な操作の除外を含むすべてのハード除外を迂回します。サンドボックスルールは迂回しません。認識できない値は auto に縮退し、報告されます。

値は low、medium、high、xhigh、max(大文字小文字を区別しない)です。列挙型そのもの、runtime ごとの上限、ベンダーごとに綴りの異なる CLI フラグは、すべて一か所(duduclaw-core::effort)にあります。[team] はこのキーを生の文字列のまま持ち、そこへ渡して解析させるため、同じノブの綴りを 2 種類持つことはありません。解析できない値はチームを拒否します(invalid_effort)。

最初のバッチで引き続きサポートする 4 つの runtime は、呼び出しごとの effort を受け付けます(2026-09-24 に実バイナリで確認)。Claude Code は --effort、Codex は -c model_reasoning_effort=、Antigravity は --effort、Grok は --reasoning-effort です。

runtime も model も束縛しない役割に宣言した effort は効果がありません(その役割は従業員のモデルに cascade し、それが従業員の effort を持つため)。この場合は黙って捨てずに報告します。


ダッシュボードから設定する(v1.68.0)

Section titled “ダッシュボードから設定する(v1.68.0)”
  • 全体の既定値:システム設定 → 詳細設定 → 自動化エンジン → 1 人 4 役(全体の既定値)で config.toml [team] enabled、gate、[team.roles.<役割>] runtime/model/effort を書き込みます。画面上の統合役は utility として保存されます。次のゴールから反映されます。
  • 社員ごと:社員の編集ページ → 頭脳とエンジン → 1人の社員に4つの役割で agent.toml [team] enabled と [team.roles.<役割>] を書き込みます。
  • システム設定 → 詳細設定 → 自動化エンジン → ディスパッチ方針に role_team が追加されました。

バリデータが強制する 3 つの規則

Section titled “バリデータが強制する 3 つの規則”

どれか 1 つでも破る仕様はチームを組みません。タスクは Solo で実行され、ダッシュボードが理由を示します。不完全なチームが組まれることは決してありません。

1. 役割は (role, runtime, model) の 3 つ組

Section titled “1. 役割は (role, runtime, model) の 3 つ組”

Goose の Lead/Worker 機能は、モデル名だけを持つ役割設定を保存していたため、qwen-* の lead が Claude バックエンドで実行される結果になりました(goose#10731)。ここでは、モデルのファミリーが宣言された runtime に属さない場合は即拒否(model_runtime_mismatch)、runtime カタログがファミリーを認識しないモデルも拒否します。プラットフォームは、位置づけられないモデル id に provider を推測で当てることは決してしません。

model だけの宣言は問題ありません。カタログがそのファミリーを提供する runtime に束縛します。runtime だけの宣言も問題なく、model は従業員の [model] preferred に cascade します。

この cascade には罠が 1 つあります。 従業員の preferred は、宣言された runtime のファミリーに属していなければなりません。preferred が Claude モデルの従業員に runtime = "codex" を宣言すると、毎ラウンドそのメンバーが拒否され(validate_role_runtime_model)、DISPATCH_FAILURE_LIMIT でループが終わるまでパケットはゼロです。fail-closed ではありますが、毎ラウンド失敗します。役割の runtime が従業員自身のものと異なる場合は、model を明示的に固定してください。

claude、codex、antigravity、grok。それ以外は openai_compat、qwen、copilot、cursor を含めすべて拒否されます(runtime_not_allowed)。

理由は能力ではなくツールです。この 4 つは DuDuClaw の MCP サーバーをネイティブに登録するため、その上で動く役割はツール群をすべて使えます。ツールを黙って失った役割は、ツール呼び出しのない自信満々の語りを生み、審核者はそれを本当の作業と区別できません。

3. 審核者は執行者とモデルファミリーを共有してはならない

Section titled “3. 審核者は執行者とモデルファミリーを共有してはならない”

同じファミリー ⇒ チームの編成を拒否(verifier_same_family)。警告ではありません。デコリレーションこそが機構のすべてです(arXiv:2607.13918: 相関した審核者では失敗率は多項式的にしか減衰せず、効くのは独立性であって、判定器を積み増すことではありません)。

ファミリーは runtime カタログから導かれます。実行者と検証者には、実際に異なるモデルファミリーを選んでください。

関連する知見をはっきり述べておきます。VP-CONTROL(arXiv:2609.10969)では、証拠を共有するモデル間投票は不安全な提案の 62.9% を通過させ、独立した証拠源ではそれが 22.9% に下がりました。証拠の独立性の寄与は 40.9 ポイントで、モデルの多様性は 11.3 でした。そのため審核者が読むのは、凍結された契約、パケット、ツール活動のダイジェストであり、執行者による自分の作業の説明ではありません。

規則 2 と 3 は凍結時だけでなく毎ラウンド再検査される

Section titled “規則 2 と 3 は凍結時だけでなく毎ラウンド再検査される”

検証は仕様の凍結時に一度だけ走ります。しかし凍結された仕様は、変更可能なタスク行に JSON として置かれ、各役割のモデルファミリーを記録するフィールドには、今回の修正まで読み手が全く存在しませんでした。規則が導入される前のバックアップの復元や、手で直された行は、もう不変条件を満たさない仕様を生み、下流の誰もそれに気づきませんでした。

現在は、各ラウンドが spawn を消費する前に、保存された仕様を再検査します。各役割の runtime が 5 つのうちのどれかであること(規則 2。以前は執行者の経路だけがこれでフィルタしていて、審核者の経路にはありませんでした)、そして審核者に保存されたファミリーが執行者と異なること(規則 3)です。失敗した仕様は Failed となり、監査行に frozen_spec_family_violation / frozen_spec_runtime_not_allowed が入り、どの役割をどう直すべきかを運用者向けのメッセージで示します。この検査が読むのは保存されたファミリー文字列で、カタログの再解決ではありません。再解決が答えるのは「この設定は今日なら何を意味するか」であり、ここで問うべきは、今実行中のこのタスクの仕様がまだ成り立っているかだからです。


役割が交換するのはパケットであり、トランスクリプトではない

Section titled “役割が交換するのはパケットであり、トランスクリプトではない”

役割の境界を越えられるのは TaskPacket だけです。目的、出力形式、ツール範囲、境界、列挙された制約、audience の許可リスト、受け入れアサーション、成果物 / wiki / 記憶 / 状態への参照、構造化された所見と次のステップ、観測の忠実度、予算を含みます。

トランスクリプト、ベンダーの tool-call ブロック、thinking や推論のペイロード、型のない抜け道は意図的に存在せず、これは慣習ではなく型によって強制されています。完全なフィールド表、上限、実例は spec/task-packet.md にあります。

役割は team_handoff MCP ツールを呼んでパケットを引き渡します。ツールは (task, round, from_role, to_role) からファイルパスを導出し、パスは決して受け取りません。

~/.duduclaw/team_packets/<task_id>/r<round>/planner-to-executor.json
~/.duduclaw/team_packets/<task_id>/r<round>/planner-to-executor.01.json
~/.duduclaw/team_packets/<task_id>/r<round>/planner-to-executor.02.json … .99 まで

1 つの leg が複数のパケットを運ぶのは正当です。規劃者が goal を 4 つのサブタスクに fan-out すれば 4 つ書きます。そこで、すでに使われている leg に新しい packet_id が来ると次の番号のスロットを取り、同じ packet_id を再保管すると自分のファイルを上書きします。タイムアウト後のリトライは冪等で、サブタスクが重複することはありません。書き込みはアトミック(一時ファイル、fsync、rename)で、正規化したパス上のプロセス間ロックのもとで行われるため、composer が書きかけのパケットを読むことはありません。これは両方の書き手に当てはまります。新しいパケットを保管する team_handoff と、欠けた sha256 を補ったり誤って宣言された fidelity を直したりするときにパケットをその場で書き換える composer です。両者は同じ正規化済み leg パスでロックを取るため、何もない相手ではなくお互いに対して直列化されます。

誰が保管しているかを示せるのは、呼び出し側自身の [team_member] セクションだけです。[agent] role へのフォールバックはありません。そのフィールドは組織上の役割で、独自の planner 値があり、それを認めると、そのように設定された任意の従業員が、別のタスクのディレクトリに偽造した planner→executor パケットを保管できてしまいました。task_id/round のピン留めを持たないアイデンティティも、同じ理由で即拒否します。そうしないと、パケットの 2 つの相互検査が両方スキップされるためです。

composer は同じスロットを数値順(正規ファイルが先、続いて .01、.02……)で読み戻します。これは到着順でもあります。ファイル名は信用されません。パケットが使われるのは、自身の from_role / to_role / goal_id / round が読み取り中の leg と一致し、かつ検証を通った場合だけです。どれかに失敗したファイルは、推測せずに監査行を残してスキップされ、1 つの不良ファイルが leg の残りを失わせることもありません。leg 上の候補がすべて不良の場合は、その段階が空なのは沈黙ではなく破損のためだと示す行がもう 1 行記録されます。

team_handoff は自己エコーの拒否リストに入っているため、役割が書いたパケットが、その役割自身の grounding の証拠になることは決してありません。

  • 制約と audience は決して圧縮されません。 composer はこの 2 つのフィールドを固定の見出し(## 約束、## 受眾)の下にレンダリングし、prompt 圧縮パイプラインはその見出しの内容を削りません。計測された失敗は、予算がまず境界に課税し、明示的な制約を黙って暗黙の制約に戻してしまうことでした。パケットのそれ以外はすべて圧縮可能で、保護される区間はパケットの終わりで終わります。

    免除は、テキストではなく出どころに紐づきます。 この 4 つの見出しはただの markdown であり、圧縮パイプラインの history は 11 のチャネルの会話履歴で、ユーザーが入力したメッセージも含みます。見出しだけでは何も守れません。composer は各見出しの直下に推測不能なマーカー行(<!-- ddc-protected:… -->、32 バイトの CSPRNG、gateway プロセスごとに一度生成)を書き、その行とぴったり一致するものが続く見出しだけが保護区間を開きます。ユーザーはこの値を作れません。チャネルの返信には現れず、ユーティリティ要約器に渡されるトランスクリプトからは、保護区間があらかじめ取り除かれています。失敗側の方向は 3 つあり、いずれも意図的です。sentinel を持たない読み手(embedder が渡さない限りの duduclaw-llm の CCR プレビュー、および gateway 以外のプロセス)は何も保護しません。gateway の再起動前に生成されたマーカーはもう一致しないため、古い要約は通常の圧縮可能な履歴へ劣化します。OS の CSPRNG が使えなければ sentinel は空になり、免除は単に無効になります。本物の制約を削りすぎるのは高くつきますが回復できます。信頼できないテキストに免除を渡すことは回復できません。

    2 つの上限は、正当な出力側がパケットのフィールド上限を超えてレンダリングする場合に備えた多層防御として残っています。予算の下限は履歴全体で保護内容を最大約 6k token まで尊重し、セッション要約器は保護テキストを逐語で最大 4 KiB まで固定し、切り詰めたときは要約にそう記します。このマーカーは composer の settle 要約で再び取り除かれます(レンダリングされたパケットのテキストが人間に届く唯一の経路です)。そのため /goals やチャネルのプッシュには現れません。知っておくべき帰結が 1 つあります。DelegationEnvelope::to_prompt が組み立てる、agent 供給の ## Constraints ブロックにはマーカーがなく、保護されません(そもそも history の一部ではないので、実際には何も変わっていません)。

  • 役割メンバーは常に team_handoff を保持します。 [capabilities] allowed_tools がチーム機能より前に作られた従業員は、まだ存在しなかったツールを名指しできません。そのため引き継ぎチャネルは、その許可リストに関係なく役割メンバーに認められます。これはチーム自身の機構で、到達範囲は working_state_* と同じです。team_packets/ 配下の導出された 1 つのパスだけで、他にはありません。役割が求める他のすべてのツールは引き続き従業員のエンベロープに照らして検査され、明示的な denied_tools の項目は引き続き優先され、agent 向けの spawn_ephemeral 経路にはこの免除は一切ありません。


役割は 2 人目の従業員ではありません。役割メンバーであり、~/.duduclaw/agents/.ephemeral/ 配下の使い捨ての agent ディレクトリです。1 つの (task, round, role) のために作られ、そのラウンドが終わると削除されます。従業員だけが引き続きユーザーに見える存在で、メンバーはレジストリにも名簿にもなく、heartbeat も進化もなく、その支出はコスト報告で従業員に折り返されます。

DuDuClaw にすでにあった一時的なサブエージェントとの違いは、メンバーが自分専用の頭脳の割り当てを持つことです。その agent.toml は従業員のもののコピーから始まり、次の 4 つが上書きされます。

キー 値
[runtime] provider 役割の runtime(正規化済み。agy は antigravity と書かれる)
[model] preferred 役割の model id
[model] effort 役割の effort。役割が宣言した場合のみ書き込む
[team_member] role / task_id / round / parent このメンバーがどのスロットを埋めるか

従業員が設定したそれ以外のすべて(ユーティリティモデル、アカウントプール、コンテナ隔離、予算)は継承されます。意図的に継承しないキーが 2 つあります。未設定の effort はキーを一切書かないため、spawn はフラグを渡さずベンダー自身の既定の深さが適用されます。そして継承された [runtime] fallback は破棄されます。最初の失敗で役割を黙って別のベンダーに移すと、チームが存在する理由である執行者/審核者の独立性が失われるためです。

agent.toml と SOUL.md に加えて、メンバーは自分の .mcp.json を持ちます。duduclaw MCP サーバーと、メンバーのアイデンティティ用の env(DUDUCLAW_AGENT_ID、署名付き token、MCP 子プロセスが継承できない home/port)が入っています。このファイルが、引き継ぎチャネルを含め、メンバーがあらゆるツールへ到達する唯一の経路です。CLI は作業ディレクトリからこれを読み、gateway の起動時修正は .ephemeral/ の中へは決して降りないためです。従業員の他の MCP サーバー(たとえばブラウザ)は意図的にコピーしません。メンバーの到達範囲は、そのラウンドが求めたツールの部分集合にとどまります。メンバーは記憶の蒸留も行いません。ラウンドの settle で削除されるため、学んだことは存在しなくなった id の下に保存されてしまうからです。

メンバーの [capabilities] allowed_tools はその役割のツールの部分集合で、固定のリテラルではなく従業員から導出されます。

役割 ツール codex メンバーの実効サンドボックス
planner team_handoff、wiki_search、memory_search read-only
executor 従業員自身の実効ツール + team_handoff + memory_search + wiki_read workspace-write
verifier / utility team_handoff read-only

「従業員自身の実効ツール」とは、許可リストがあればその [capabilities] allowed_tools をそのまま、なければ通常のディスパッチが使うのと同じ既定の集合(Read、Write、Edit、Bash、Glob、Grep、TodoWrite、WebFetch、WebSearch、mcp__duduclaw__*)を指します。どちらでも執行者は従業員の部分集合です。読み取り専用の従業員からは読み取り専用の執行者が生まれ、従業員の denied_tools にあるツールは決して要求されません。

執行者が他の役割のような小さな固定リストではない理由は、作業を行うことそのものが定義上の役割であり、2 つの強制レイヤーがどちらもそのリストを読むからです。Codex はそれを粗い単一のサンドボックスモードに対応づけ、書き込み系ツールのないリストは --sandbox read-only を意味するため、メンバーは mkdir できず、apply_patch も拒否されます。Claude はそれを --allowedTools にそのまま渡し、Write / Edit / Bash のない許可リストは 1 つ上のレイヤーで同じ拒否になります。ライブ第 5 ラウンドは、この両方に同時に当たりました。

規劃者と審核者は意図的に読み取り専用のままです。ファイルを編集する規劃者は執行者の仕事をしていますし、自分が判定している作業を書き換えられる審核者は独立した審核者ではないからです。

モデルはモデル自身が選ぶものではない

Section titled “モデルはモデル自身が選ぶものではない”

役割の経路は生の model id を受け付ける唯一の場所で、gateway の composer からしか到達できません。agent 向けの spawn_ephemeral ツールは変わりません。引き続き 3 つのティアキーワード(cheap / standard / preferred)のどれかしか受け付けず、生の id は拒否します。チームがあってもなくても、AI 従業員は自分が動くモデルを指名できません。

何かが作られる前に、その組はランタイムカタログに照らして検査されます。runtime は第一バッチの 5 つのどれかで、モデルのファミリーはその runtime が実際に提供するものでなければなりません。カタログが認識しないファミリーは最善の推測ではなくエラーで、gpt-5.4 が Claude バイナリに届いて後で他人の API で失敗することはありません。

メンバーは自分のスキャフォールドではなく従業員のワークスペースで動く

Section titled “メンバーは自分のスキャフォールドではなく従業員のワークスペースで動く”

スキャフォールドが持つのは設定です。agent.toml、SOUL.md、.mcp.json、.claude/ です。作業は従業員自身のディレクトリ(~/.duduclaw/agents/<employee>/)で行われ、その従業員の Solo ラウンドが使うのと同じ作業ディレクトリです。

これは見た目の話ではありません。執行段階まで到達した最初のライブラウンドでは、メンバーはスキャフォールドを作業ディレクトリとして動き、そこにメモを書き、ラウンド終了時の破棄がそれらを削除しました。審核者はファイルが作られた証拠を探しましたが何も見つからず、ラウンドを正しく却下しました。尋ねられた成果物は、すでに存在しないディレクトリを指していたのです。

作業ディレクトリを動かすと 2 つ目の問題が出ます。Claude CLI は MCP サーバーを <cwd>/.mcp.json から探すため、従業員のディレクトリにいるメンバーは従業員のアイデンティティで duduclaw MCP サーバーを起動し、すべてのツール呼び出し、引き継ぎ、監査行が親に帰属してしまいます。そこでアイデンティティは、探索ではなく明示的に指名します。Claude メンバーは --mcp-config <member_dir>/.mcp.json --strict-mcp-config で起動されます(2 つ目のフラグは、CLI が周囲の設定まで併合するのを止めるものです)。Codex メンバーは --cd <employee_dir> を受け取り、-c mcp_servers.duduclaw.env.DUDUCLAW_AGENT_ID=… の上書きがメンバー id を運びます。この 2 つは構造上、互いに独立しています。メンバーの .mcp.json が欠けている場合、その段階は親のアイデンティティでディスパッチされるのではなく拒否されます(member_mcp_config_missing)。

メンバーでは未対応:antigravity、grok、および汎用の print モード CLI。 これらの runtime は MCP の登録を作業ディレクトリ内のファイル(.agents/mcp_config.json、.grok/config.toml など)から読むため、cwd を動かすとアイデンティティも一緒に動いてしまいます。これらの runtime 上のメンバーは、スキャフォールドを作業ディレクトリのままにし、そのファイルは引き続きラウンドを越えて残りません。この隙間が埋まるまでは、ファイルを書く役割には claude か codex を使ってください。

もう 1 つの帰結は、文書化ではなく塞ぐ必要がありました。 従業員の作業ディレクトリを共有するということは、その中の .claude/settings.json も共有するということで、そこに登録されたファイル保護フックは呼び出し元として従業員を名指ししています。そのため、フックは役割メンバーのファイル書き込みを、従業員が自分のファイルを書いているものと読み、素通りさせていました。その結果、メンバーは従業員の agent.toml [capabilities] を編集できました。os_native / computer_use の切り替え、allowed_tools の拡大、denied_tools の空にする操作、自分への db_sources 項目の付与で、次のラウンドの部分集合検査は拡大されたエンベロープを認めてしまいます。「役割メンバーは従業員が持たないツールを決して持てない」というプラットフォームの約束は、まさにそのファイルから読み取られるもので、第三者のものかもしれないモデルがそれを書き換えられたのです。

[capabilities] は、組織フィールドと同じ形でフックに対して凍結されるようになりました。Write / Edit / Bash によるこのセクションのどのキーへの変更も拒否されます。比較は手で管理するリストではなく両側のキーの和集合をたどるため、後のリリースで追加された capability キーは、追加された日から凍結されます。運用者には影響しません。ダッシュボード、MCP の agent_update ツール、通常のエディタは、いずれもフックの外からファイルを書くためです。

知っておくべき帰結が 1 つあります。cwd が上書きされる Codex メンバーは、役割の指示を AGENTS.md ではなく prompt の中(XML で区切った <role_system_prompt> ブロック)で受け取ります。codex exec には 0.156.1 時点で system-prompt フラグがなく、作業ルートの AGENTS.md が唯一のファイル経路であり、メンバーの指示を従業員の AGENTS.md に書くと従業員自身のファイルを壊し、兄弟メンバーと競合します。prompt ブロックは本物の system prompt より弱い配置であり、黙って省かずにここに明記します。

成果物パスはワークスペースに照らして検査される

Section titled “成果物パスはワークスペースに照らして検査される”

パケットの artifacts[].path は、実在のディレクトリにある実在のファイルについての主張になったため、検査されます。解決後に従業員のワークスペースの外に出るパスは、黙って受け入れられるのではなく監査行付きで拒否されます(team_packet_artifact_refused)。既存のパスは正規化されるので、ワークスペース内に置かれた、外を指すシンボリックリンクは検出されます。ファイルが存在する前に宣言されたパスは、.. が外へ抜けないことの字句検査にフォールバックします。通常ファイルでないパスや 64 MiB を超えるパスもレシートを得ません。composer は読む前に stat するため、FIFO が worker を止めることも、巨大ファイルがハッシュ化のためにメモリへ読み込まれることもありません。

拒否は、監査証跡だけでなく審核者にも見えるようになりました。レンダリングされたパケットには artifacts: セクションがあり、宣言ごとに 1 行、監査が記録した状態が付きます。レシートのあるパスは exists / missing / mismatch、ワークスペースを抜け出したものは outside_workspace、意図的に読まなかったもの(通常ファイルでない、または 64 MiB 超)は unverified、artifacts.jsonl の id があってパスがない宣言は id_only です。2026-09-28 までレンダラーは artifacts[] を全く出力しなかったため、拒否されたパスは通常の成果物として審核者の入力に入ってしまい、包含検査が約束していた「審核者は監査と同じものを見る」は真ではありませんでした。人間向けの settle 要約も同じセクションを(unchecked の状態で。要約はファイルシステムの作業をしないため)レンダリングします。

これらの状態は、監査行を生んだただ 1 回の検証から来ます。宣言された各パスは、パケットが検査されるときに一度だけ stat・読み取り・ハッシュ化され、レンダラーはその結果の判定を引き当て表として受け取ります。レンダラー自身はファイルシステムに一切アクセスしません。この節の最初の版は prompt 構築中に検査全体を再実行し、宣言された各ファイルを(最大 64 MiB、ブロッキング I/O で)もう一度ハッシュ化し、監査されたものと一致する保証のない2 つ目の観測を審核者の前に置いていました。composer が一度も検証していない成果物(保管後にディスパッチがエラーになったメンバー、同じラウンドの以前の試行が残したスロット)は、prompt 時に読み直されたり、別のパケットの観測でラベル付けされたりせず、unchecked と報告されます。

正直な限界が 1 つ残ります。宣言されたパスは主張であって、免除ではありません。agent の内部機構を指す成果物(SOUL.md、CLAUDE.md、state/、.claude/、logs/、memory/ などの配下のあらゆるもの)は settle 時のアーカイブから除外され、ダウンロード可能な「產物」には決してなりません。

審核者と判定器が実際に見せられるもの

Section titled “審核者と判定器が実際に見せられるもの”

2 つの証拠ブロックがあり、どちらも同じ tool_calls.jsonl の窓から作られ、チームの審核者と、settle 経路の evaluator および MAV パネルの両方が読みます。そのため、役割の成果が 2 通りの経緯に基づいて判定されることは決してありません。

窓はそのラウンド自身の開始時刻です。 これを正しくできるかが、この仕組みが機能するか空回りするかの分かれ目でした。以前は tasks.claimed_at で、これはチームタスクでは構造上 None です(誰もそれをクレームせず、composer が team-composer として完了させます)。そのため審核者は毎ラウンド (無工具活動紀錄) を渡されレシートは一切なく、settle 経路の窓は黙って created_at まで広がり、ラウンド 1 のレシートがラウンド 3 を裏付けていました。composer は現在、最初のメンバーが動く前にラウンドの開始時刻を刻み、それを渡します。settle 経路は自分のラウンドの task_iterations.dispatched_at を読み、なければそのラウンドで最も早い role_turns.jsonl のタイムスタンプを使います。どちらもなければ窓はありません。grounding は、以前のラウンドへ遡らずにスキップへ縮退します。確立できない窓は、「ツールは使われなかった」を意味するのと同じ空のブロックではなく、明示的な「時窗不明」の 1 行として表示されます。この 2 つを区別できない審核者は、誠実な作業を却下するか、自分が計測していない不在を根拠に主張を受理してしまうためです。

<tool_activity>: ツールごとに 1 行、name: N ok, M err。対象は従業員 ∪ そのラウンドのメンバーです。

<artifact_receipts>: パケットが宣言した成果物ごとに 1 行で、証拠のうち決定論的な半分です。

notes/a.md 128B sha256=3f2a… exists
notes/b.md missing
notes/c.md 44B sha256=aa11… mismatch (declared bb22…)

包含されたすべてのパスは、パケットが読まれるとすぐに stat とハッシュ化が行われます。ハッシュを宣言しなかったパケットには、観測された値が書き戻されます。宣言されたハッシュがバイト列と一致しないパケットは、宣言値を保持したまま mismatch として記録され、team_packet_artifact_mismatch の監査行が付きます。すり替えは見える状態に保たなければならないので、パケットは静かに訂正されることはありません。確認として数えられるのは exists だけです。missing や mismatch のレシートは失敗した観測として記録され、主張の grounding には決してなりません。

ここは研究の結論が明確です。VP-CONTROL(arXiv:2609.10969)は、1 つの証拠源を共有するモデル間の審核パネルが不安全な提案の 62.9% を通過させ、証拠源が独立していれば 22.9% だったと計測しました。効果の 40.9 ポイントは証拠から、11.3 ポイントはモデルの多様性から来ています。ディスク上のバイト列の sha256 が、その独立した情報源です。

ネイティブツールの作業も証拠になる

Section titled “ネイティブツールの作業も証拠になる”

ラウンドの下流にあるすべて(審核者のダイジェスト、LLM を使わない grounding の事前検査、判定器の監査ダイジェスト)は tool_calls.jsonl を読みます。ネイティブツール(codex の shell 呼び出し、Claude の Write)で作業するメンバーは MCP 呼び出しをしないため、そこには何も書かれず、ライブ第 8 ラウンドは、確かに存在した 3 つのファイルについて「これらのファイルが作られたことを示すツール活動は存在しない」と言う settle に至りました。

メンバーのネイティブツールイベントは、それぞれそのメンバーの id の下で tool_calls.jsonl の 1 行として書かれ、ツール名、結果、マスク済みの呼び出し入力とマスク済みの結果テキストに加えて、source = "native"、evidence_source = "native_tool_event"、それを生んだ runtime / model を持ちます。失敗したイベントには error_class = "native_tool_error" が付きます。ブロックされた、または失敗した呼び出しは痕跡を残さなければならず、MCP のディスパッチゲートが従うのと同じ規則です。

Antigravity agy 1.2.10 は、stream-json 出力を通じて端末ツールイベントを提供するようになりました。パーサーは進行中のイベントを無視し、最後の usage ブロックから実測の token 数を使います。サンドボックスに拒否されたコマンドはライブ探索で観測されています。Antigravity のツール実行が成功するケースは、別途ライブでの検証が必要です。

MCP の行とは 2 点が意図的に異なり、どちらも緩めるのではなく締める方向です。

  • 入力は常に取得されます。 読み取り専用のツール名でも同様です。これは、grounding の証拠として数えられるものから自己エコーされた区間を差し引くためにだけ使われます。
  • 自己エコーのツールでは結果テキストは抑制されます。 team_handoff のようなツールは、おおむね呼び出し側自身の言葉で応答し、codex メンバーは MCP 呼び出しをネイティブイベントとして報告します。その出力を保存すると、役割が自分のパケット要約に基づいて主張の grounding を得られてしまいます。呼び出し自体は記録され、出力だけが保留されます。

証跡に届くネイティブイベントはメンバーごとに最大 200 件です。それを超えた分は黙って捨てられず、native_tool_events_truncated の誠実な 1 行に数えられます。

メンバーはラウンドが終わったときに片付けられ、数時間後ではない

Section titled “メンバーはラウンドが終わったときに片付けられ、数時間後ではない”

通常の一時的なサブエージェントは、完了後に 1 時間の猶予があり、上限は 24 時間です。役割メンバーにはどちらもありません。ラウンドが終了状態に達した時点で、スキャフォールドは消えます。

これは整頓ではなく算術です。役割ごと・ラウンドごとにメンバー 1 つ、役割 3 つ、最大 5 ラウンド、同時進行のタスク最大 3 つで、生きたディレクトリは 45 個になり、既定の上限は 32 です。猶予窓の方針では、あふれた分はキューに入り期限切れになり、ラウンドは、ログのどこにもガベージコレクションとの関連が出ないまま、静かに役割を 1 つ欠いて動くことになります。適切に破棄される前にラウンドが落ちたメンバーは、古い窓を待たずに次のメンテナンスパスで掃除されます。チーム以外のサブエージェントの後始末は何も変わりません。

すでに書かれたコスト行はそのままです。メンバーの id の下で SQLite にあり、レポート時に従業員へ折り返されるため、ディレクトリを削除しても会計は失われません。

同じ「終了状態」は、ラウンドの受け付けチケットも解放するようになりました。一時的な上限が満杯のとき、メンバーの spawn は即失敗ではなく永続的にキューへ入り、待機中の各ラウンドは自分の進行に合わせて自分のチケットを取り除きます。これが覆っていたのは通常の経路だけでした。待機者が到達する前に終わったラウンド(早期の拒否、失敗した段階、panic)は、チケットを共有キューに残し、TTL が切れるまで queue_max_depth を占有していました。現在はラウンドが生存期間全体にわたってパージガードを保持するため、すべての終了経路(accepted、rejected、needs_human、cancelled、failed、panicked)が、ちょうどそのラウンドのキュー待ちメンバーだけを片付け、兄弟ラウンドのものには触れません。

役割はラウンドの途中でベンダーを変えない

Section titled “役割はラウンドの途中でベンダーを変えない”

通常のディスパッチは、設定された runtime に到達できないとき別の runtime にフェイルオーバーし、フォールバック先が実際に提供するモデルに差し替えることがあります。役割メンバーはそうしません。メンバーのファミリーをまたぐフェイルオーバーは拒否されます。codex の執行者が spawn できなければ、その段階は失敗し、team_stage_failed が役割、runtime、model、エラーを記録し、台帳の行は outcome=failed となり、ラウンド既存の縮退チェーンが次の対応を決めます(執行者のレプリカ → 修復パスなしの審核 → 人間待ちで停止)。

理由はライブ第 3 ラウンドです。すべての codex spawn が設定のバグで起動時に落ち、フェイルオーバーが黙って Claude に差し替え、作業は Claude として完了し、台帳には runtime=codex … completed と書かれたままでした。ベンダーを黙って入れ替えると、チームが存在する理由である執行者/審核者の独立性が消えます。しかも黙ってやれば、その後の「どのモデルが何に強いか」の計測がすべて、間違った対象の計測になります。

区別する必要があった 2 つの上限

Section titled “区別する必要があった 2 つの上限”

どちらも上限であり、新しい抜け道ではありません。

  • レート。 役割メンバーの spawn は、従業員自身の spawn を守る 1 分あたり 20 件の予算を共有せず、独自の経路種別(role_team)と独自の予算([dispatch_guard] role_team_max_in_window、既定 60)の下で数えられます。正しく設定された 3 役割のチームは、1 タスクで 1 分あたり 9 回、3 つ同時進行で約 30 回 spawn します。算術だけで共有予算を超え、それは「上限に達した」ではなく「プラットフォームが壊れた」と読まれてしまいます。
  • 容量。 生きたスキャフォールドの上限([dispatch] ephemeral_max_active)にすでに達しているとき、役割メンバーは即拒否ではなく永続的にキューへ入るようになりました。キュー、深さ、TTL の設定は従来と同じです。キュー待ちのメンバーはそれを要求したラウンドに紐づくため、終わったラウンドは自分の保留中メンバーをパージし、誰も読まない答えを待つものは残りません。無効なリクエスト(不正な runtime/model の組、従業員が持たないツール)は引き続き即拒否され、キューには入りません。再試行しても成功しないからです。

この上限は他のすべての一時的なサブエージェントと共有されるため、チームを有効にする前に少なくとも max_concurrent × iteration_cap × roles が必要です。今日の既定では 45 で、既定値は 32 です。チームの経路はこの算術を検査してそう伝えるので、後になって審核者の欠落として表面化することはありません。2 つのキーは config/duduclaw.example.toml を参照してください。


凍結された仕様と Team の判定が揃うと、goal の 1 ラウンドは単一の起床メッセージではなくなり、同じ従業員の内部で 3 つの段階になります。

仕様はタスクごとに凍結される

Section titled “仕様はタスクごとに凍結される”

goal タスクが作成されるとき、マージされた config.toml [team] + agent.toml [team] が一度だけ検証され、結果がタスク自体に保存されます。以後それは決して変わりません。明日、役割→モデルのマトリクスや bandit がモデルの順位を入れ替えても、影響するのは次のタスクであり、実行中のタスクではありません。凍結された受け入れ基準と同じ規律で、「このタスクは実際にどのチームによって作業され、判定されたか」は、タスク行だけから常に答えられます。

検証に失敗した仕様は、チームをまったく組みません。拒否は記録され、何も保存されず、タスクは単一の従業員として実行されます。不完全なチームというものは存在しません。

凍結はデータベースレベルで一度だけ設定できます(WHERE team_spec_json IS NULL)。そのため、同じタスクで 2 つの作成経路が競合するのは普通のことで、安全です。以前危険だったのは、負けた側から見た状態でした。goal loop は「自分が凍結した」という答えしか扱わず、競合に負けたラウンドは自分の古いタスクのコピーを読み続け、仕様が見つからないまま黙って Solo で動き、以後のラウンドは新しい行を読んで Team として動きました。同じタスクで 2 通りの実行形態になり、どこにも痕跡が残りません。負けた側は現在、行を読み直して、実際に勝った仕様を採用します。

  1. 規劃: 1 つの役割メンバーが目的、凍結された受け入れ基準、リスク境界を受け取り、独立して完了できるサブタスクごとにパケットを 1 つ返します。サブタスク間の依存は明示的に列挙されます。自分では作業をしません。何も返さない規劃者は、散文から分解を推測するのではなく、タスクを人間待ちで停止させます。
  2. 執行: サブタスクのパケットごとに 1 つのメンバーが、設定された fan-out の数まで動き、互いに通信しません。各メンバーは自分のパケットを返します。何をしたか、証拠がどこにあるか、何が未解決か、です。証拠への参照がない主張は、所見ではなく「未解決の問い」に属します。
  3. 審核: 審核者は自分のベンダーのモデルで動き、3 つのものを見ます。凍結された受け入れ基準、執行者のパケット、実際に起きたツール呼び出しの監査証跡です。規劃者の語りは見えず、執行者の文章も見えません。作業を失敗と判定した場合、同じ執行者には、指摘されたギャップに限定した 1 回の修復パスが与えられます。書き直しではなく、より広い指示でもありません。

執行者が最後に出したものは、既存の受理経路に渡されます。2 段階の evaluator、3 観点のパネル、ギャップのフィンガープリント、振動検出、最良ラウンドの選択です。チームは 2 つ目の判定システムを追加しません。変えるのは誰が作業するかであり、誰が終わりと決めるかではありません。

ゲートがちょうど 2 つのシグナルに落ちたとき、タスクがどのみち必要とする呼び出しの値段で、誠実な答えが得られます。規劃を走らせ、実際に何個に分解したかを数えます。真に独立したサブタスクが 4 つ以上あればチームを組み、それ未満ならラウンドは通常の単一従業員のディスパッチに戻り、計画は後のラウンドが読めるようディスクに残されます。

ラウンドは spawn を消費し、タスクにはその上限があります。1 ラウンドは planner? + executors + verifier + repair? として課金されます。審核者はスキャフォールドではなくユーティリティ呼び出しですが、自分の role_turns.jsonl 行を書き、予算カウンターはメンバー id を持つ行をちょうどそれだけ数えます。計画はこの項を以前は省いていたため、すべてのラウンドが計画より 1 つ多くコストを使い、4 ラウンド目を計画した max_spawns_per_task = 12 のタスクは途中で「budget exhausted」で落ちていました。計画と課金は現在同じ算術を使い、クランプの下限は 2 ではなく 3(規劃者 + 執行者 + 審核者)です。

残り予算が減るにつれ、ラウンドを単に失敗させるのではなく、能力が決まった順に手放されます。

  1. 合成(ユーティリティ)が使われなくなります。失うものが最も安いからです。
  2. 審核者の修復パスがなくなります。失敗したラウンドは 2 回目の機会なしに受理経路へ直行します。
  3. fan-out が執行者 1 つに縮みます。
  4. 手放せるものがなくなる ⇒ タスクは「budget exhausted」として人間待ちで停止し、これまでに得た最良のラウンドを添えます。

どのステップが取られたかは記録されるため、安く済んだラウンドは、劣ったチームではなく安く済んだラウンドとして読めます。

# config.toml、グローバルの既定値
[dispatch.team_budget]
max_spawns_per_task = 12 # 4 役割 x 3 ラウンド。>= 3 にクランプ
max_turns_per_role = 3
degrade_order = ["utility", "verifier_second_pass", "executor_replica"]

認識できない degrade_order の項目は警告とともに破棄されます。使える項目が 1 つもないリストは、既定のチェーンを維持します(超過のたびに即座に人間へのエスカレーションにするのは、タイプミスが求めるより厳しい変更になるため)。

各段階は <home>/role_turns.jsonl に 1 行を追記します。advisory ロック付きの追記、0600 のモード、ハッシュチェーン、サイズ上限付きのローテーションは tool_calls.jsonl と同じです。読み手は、直近のローテーション世代(.jsonl.old)と現行ファイルの両方を読みます。spawn 予算はこれらの行から数えられるため、現行ファイルだけを読むと、実行中のタスクの途中でローテーションが起きたときに消費済みの予算が黙ってゼロに戻ってしまっていたからです。(遡れるのは 1 世代だけで、ローテーションのたびに前の .old は上書きされます。2 つのファイルのハッシュチェーンは境界で再スタートするので、これは読み取りと集計のための連結であり、チェーンが連続しているという主張ではありません。)1 行には、task_id、round、role、member_id、要求した runtime と request_model、実際に応答した runtime_used / response_model / provider と failover フラグ、effort、それが生んだパケット、観測の証拠グレード(full / mcp_only / none、混同はされない)、どう終わったか、そして役割の runtime または model が変わると変わる config_fingerprint_hard が入ります。

要求と応答を分けるのは、この行が以前は設定の繰り返ししかできなかったためです。ライブ第 3 ラウンドでは、codex の執行者が黙って Claude にフェイルオーバーし、行には runtime=codex … completed とありました。runtime_used と response_model は実行経路自身が報告し、応答した runtime が要求したものと異なるときは常に failover が true になります。一度も spawn されなかった段階の行は、推測せずにこの 3 つを空にします。

証拠グレードは composer が埋め、メンバーが埋めることは決してありません。runtime 自身のツールイベントストリームが呼び出しを見たときは full、メンバーがそのディスパッチ窓に監査行を持つときは mcp_only、何も観測されなかったときは none です。メンバー自身の主張は上書きされ、不一致は監査されます(team_packet_fidelity_corrected)。これ以前は、このフィールドを埋めるものが何もなかったため、すべてのパケットが none で返っていました。fan-out がある場合、複数の執行者が 1 つの leg を共有するため、composer はディスパッチ前に leg をバイト単位でスナップショットし、そのメンバーが作成または書き換えたファイルだけを格付けします。兄弟のパケットを他人の観測で格付けし直すことは決してありません。

これはプラットフォームにこれまでなかった次元です。他のすべての帰属の面は agent id をキーにしており、1 人の従業員のタスクを 3 つのモデルが作業した時点で、「どの agent か」は、誰が何をしたかを特定しなくなります。fault_side は計算されて書かれます(行を書く時点で、閉じた FaultSide 列挙から決定論的に決まり、証拠で側を確定できないときは unknown)。設計に挙がっているが今は何も計算できないフィールド(trace/span id と役割の Shapley 値)は、空で書くのではなく、意図的に存在しません。

runtime が使用量を報告しなかった場合、使用量のフィールドは丸ごと省かれます。0 と書けば「計測済みで、しかも無料だった」と主張することになるからです。

使用量は最後の leg のものではなく段階の合計です。1 つの段階は複数の leg にわたって応答できます(openai-compat の tool loop、またはフォールバックが応答する前に主系の試行が token を消費したフェイルオーバーチェーン)。2026-09-28 までは、行が最後の 1 つしか公開せず、cost_telemetry はすべての呼び出しを記録していたため、同じ段階について 2 つの台帳が食い違っていました。現在は各 leg の数値が(飽和加算で)合算され、1 つの leg しか計測しなかった次元は、報告しなかった leg にゼロにされずその値を保持し、usage_legs は何個の leg が寄与したかを示します。usage_legs > 1 は、この段階が 1 回の呼び出しではなかったことのシグナルです。このフィールドがない場合は、どの leg も使用量を報告しなかったことを意味します(これは、このフィールドが現れる前に書かれたすべての行の形でもあります)。

会話の中に新しいものはありません。従業員は引き続き一つの声で答え、進捗は同じボードに届き、needs_human は引き続き 6 つの一時停止クラスのいずれかを伴います。チームのラウンドは通常の goal-loop の進捗として見え、役割の詳細は、ダッシュボードのチームカードが出荷されるまで、監査ログと role_turns.jsonl にあります。


ライブラウンドで変わったこと

Section titled “ライブラウンドで変わったこと”

一時的な home を持つ 2 つ目の gateway インスタンスで、実際の goal に対して 8 回のラウンドを実行しました(規劃者は Claude Sonnet 4.6、執行者は Codex CLI 0.156.1 上の Codex gpt-5.6-sol、審核者は Claude Sonnet 4.6)。ラウンドごとに前より先へ進み、どれも元が取れました。

ラウンド 到達点 見つかったこと
1 規劃者は動いたがパケットはゼロ メンバーに .mcp.json がなく、team_handoff が存在しなかった。
2 規劃者が team_handoff を 13 回呼んだ ツールの説明からはパケットのスキーマが推測できなかった。アイデンティティの読み取りが、一時的なメンバーの場合に別のディレクトリを見ていた。
3 規劃 → 執行 → 審核 を完走、判定器が却下 4 つの欠陥。後述。
4 codex メンバーがまだ起動しない codex exec は、信頼された git リポジトリでない作業ディレクトリを --skip-git-repo-check なしでは拒否し、開いたままの stdin で待つ。
5 codex メンバーが起動し、ツールを見たが何もできない 2 つの拒否。後述。
6–7 codex の承認バリアント 6 種を直接探索 MCP 呼び出しを通すのは --approve-for-me だけで、--sandbox <MODE> とは排他的。
8 実バックエンドでパイプライン全体を実行、settle で却下 2 つの欠陥。後述。

ラウンド 3 の却下は正しいものでした。審核者と settle 経路は、実際に作業を裏付けるツール活動を確かに見られなかったからです。誤っていたのは 4 点です。

  1. すべての codex spawn が起動前に落ちていた。 codex exec -c key=value は値の側を TOML として解析します。メンバーの env ブロックのポートが引用符なしで出力され、codex は 18999 を整数と読みましたが、mcp_servers.<id>.env テーブルは文字列を要求するため、spawn は終了コード 1 で終わりました。これは既存の codex-runtime のバグで、通常の codex agent や codex の受理判定器も同様に壊していました。-c のすべてのスカラーは、引用符付きの TOML 文字列になりました。
  2. メンバーが黙ってベンダーを変えた。 役割はラウンドの途中でベンダーを変えないを参照してください。
  3. メンバーが削除される寸前のディレクトリで作業していた。 メンバーは自分のスキャフォールドではなく従業員のワークスペースで動くを参照してください。
  4. 誰もパケットの証拠グレードを埋めなかったため、すべてのパケットが none と読まれた。役割ごとの帰属を参照してください。

ラウンド 5 では、メンバーが duduclaw のツールをツール一覧に載せた状態で動きました(mcp__duduclaw__team_handoff と working_state_handoff はどちらもありました)が、どれも使えませんでした。強制レイヤーごとに 1 つ、計 2 つの拒否です。

  1. すべての MCP 呼び出しが MCP tool call requires approval, but approval policy is never で返った。 これは codex が fail-closed なのであって、壊れているのではありません。非対話の codex exec には承認プロンプトに答える人がいないため、承認が必要なツールは拒否されるしかありません。サーバー単位の抜け道は mcp_servers.duduclaw.default_tools_approval_mode = "auto" で、登録の残りと同じ -c チャネルで渡されるようになりました。範囲は DuDuClaw 自身のサーバーに限られます。codex の shell と patch ツールは --sandbox が許す範囲のままで、運用者が登録した他の MCP サーバーも自分の既定を保ちます。duduclaw のツールの本当の認可は、誰も見ていない承認プロンプトではなく、MCP サーバー(ツール単位のスコープ、agent の capability ゲート、監査ログ)にあります。
  2. ワークスペースが読み取り専用だった(mkdir と apply_patch が両方とも拒否された)。執行者のツールリストに書き込み系ツールがなく、codex はこのリストから単一のサンドボックスモードを導くためです。各役割が得るツールを参照してください。

ラウンド 8 は、ついに実バックエンドでパイプライン全体を走らせました。規劃者は Claude、執行者は実際の codex gpt-5.6-sol(runtime_used = codex、忠実度 full)で従業員のワークスペースに notes/a.md、b.md、index.md を作成し、パケットを審核者へ渡し、審核者は Claude で動き、settle に進みました。それでも却下され、またしても、その時点では真であった理由によるものでした。

  1. 証拠が書き残されなかった。 執行者の作業はネイティブの shell とファイルツールで行われました。それらのイベントは数えられ(fidelity: full はそこから来ます)、しかしメンバーのディスパッチとともに消えるタスクローカルのリストにしかなく、下流の読み手はすべて tool_calls.jsonl を見ます。そのため、最も信じられる必要があったラウンドが、構造上、最も信じにくいものでした。2 通りで修正されました。ネイティブツールの作業も証拠になると、成果物レシートがパケットの言葉を鵜呑みにせず、宣言されたパスをファイルシステムと照合することです。
  2. codex の判定器が解析可能な判定を出せなかった。 [dispatch] judge_provider = "codex" では、2 つの判定段階がどちらも散文で答え、2 つのパーサーが fail-closed で拒否しました(「evaluator reply has no string decision field」、「面板回覆無法解析」)。どちらも正しい挙動でした。ゴミを自動で受理することは、判定器のパーサーが絶対にしてはならないことだからです。しかし、構造上解析できない判定器は機能しない継ぎ目です。codex exec --output-schema <FILE> が根本から解決します。各段階は自分のパーサーが要求する JSON スキーマ(evaluator の decision 列挙、パネルの観点オブジェクト)を公開し、パーサーの契約から導出されるため、両者がずれることはありません。構造化出力フラグのない runtime は要求を記録して無視します。スキーマは好みであり前提条件ではなく、バックエンドが出力を制約できないという理由で判定が失敗してはなりません。

さらに、バグではなく構造上の問題が 1 つありました。審核者も受理経路も、ツール証拠を単一の agent id に限定して読んでいました。チームの作業は、それぞれ別の id を持つ一時的なメンバーが行うため、従業員の監査窓は空で、「ツール活動なし」は、見せられたものに対する誠実な読み方でした。チームのラウンドの証拠集合は、両方の経路で従業員 ∪ そのラウンドのメンバーになりました。チーム以外のタスクは id を追加せず、バイト単位で同一の証拠を見ます。

ラウンド 9〜13 では、settle 中のパス解釈と古い 2 つ目のインスタンスの状態が露わになりました。修正は設計の内部ライブテスト記録にあり、この記録は公開されていません。ラウンド 14 は 1 回のチームラウンドで既存の受理判定器を通過しました。これは単一の統合結果であり、比較による品質の計測ではありません。

役割はそれぞれ別のベンダーのモデルで動かせますが、ではどの役割にどのモデルを使うのか。P2 はリーダーボードではなく計測で答えます。duduclaw eval --matrix です。運用者向けの完全なリファレンスは guides/evals.md → Capability matrix にあります。

(domain, role, runtime, model) ごとに 1 セルで、domain は eval-suite ディレクトリです。

  • 執行 (executor): その (runtime, model) で suite のケースをライブで実行し、決定論的な [expect] アサーションを採点します。LLM の判定器は関与しません。
  • 審核 (verifier): ケースの記録済みトランスクリプトと受け入れ基準をモデルに見せ、PASS/FAIL を答えさせ、その判定を同じトランスクリプトに対するアサーション結果と照合して採点します。セルは一致率に加え、Wilson 区間付きの誤受理率と誤却下率を報告し、1 行目にどちらの判定もない返信は unparseable として数え、すべての率から除外します。「要求された形で答えられない」ことは、「判定が下手」とは別の知見だからです。
  • 規劃 (planner): --team-2x2 は、ケースごとに、eval home の隔離されたコピー上で、対応する 4 つの本番 composer ラウンドを実行します。ケースは [case] team_acceptance を宣言する必要があり、固定の独立した審核者の PASS は 1、FAIL は 0 です。判定が得られないものは採点されず、4 アームがそろった行だけが Shapley の結果と規劃者のセルに寄与します。通常の --roles planner は引き続き拒否されます。規劃者の返信 1 件は、採点されたチームの結果ではないためです。

審核のセルは、記録済みトランスクリプトを正当に再生します。テスト対象は worker ではなく、それを判定するよう求められたモデルであり、そちらは常にライブで呼び出されます。凍結されたトランスクリプトを通して執行者を比較すると Replay Gap になるため、--matrix --replay は即座に拒否されます。

--weak と --strong を与えると、各役割は同じケース上で Δ = score(strong) − score(weak) を得ます(ケース単位の対応、クラスタロバスト SE)。Δ が大きい役割は、モデルへの支出が最も効く役割ですが、その信頼区間が他のすべての役割の区間を除外したときに限りボトルネックと名指しされ、そうでなければ答えは unresolved で、これは本物の答えです。

これは AgentCARD の Shapley 探索(arXiv:2606.20629)の分離形式です。各役割は単独で計測され、チーム全体の同時実行はありません。そのため現実的なコストに収まります(|models|^|roles| 通りのチーム構成ではなく、2 役割 × 2 モデル)が、同じ理由で見えないものもあります。本物の相互作用(弱い執行者の後ろでしか効果が出ない強い審核者)は、構造上見えません。「まずどの役割に投資するか」として読み、チームレベルの帰属としては決して読まないでください。

何を書き出すか、そして何がまだ読まないか

Section titled “何を書き出すか、そして何がまだ読まないか”

--report は JSON レポートと、その隣に role_model_matrix.toml を書き出します。1 つの [header](宣言された MDE、α、power、K、cluster key、planner = "deferred")と、計測された各セルごとの [[cell]] があり、n、平均、区間、達成された MDE、3 状態の verdict を持ちます。計算できなかった統計量は、捏造された数値ではなく、存在しないキーです。使える観測がゼロのセルにはレポート行があってもマトリクスのセルはありません。ファイルは書き込み時と読み込み時の両方で検証されるため、手で編集された重複セルや未知の runtime id は信じられずに拒否されます。

composer はこれを事前分布として読みます。 role_model_matrix.toml を <DUDUCLAW_HOME> に置くと、model を未設定にした役割は、従業員の [model] preferred へ直接落ちる代わりに、マトリクスの勝者を採用します。5 つの条件があり、そのどれも範囲を狭める方向です。

  • 明示的に設定された [team.roles.*] model が常に優先されます。設定は決定であり、マトリクスは計測だからです。
  • unresolved のセルは完全に無視されます。 区間が宣言された MDE を解決できないセルはランキングの入力ではなく、スコアの高い unresolved のセルが resolved のセルを上回ることはありません。
  • 役割自身の runtime 上のセルだけが数えられるため、事前分布が、仕様が凍結された (role, runtime, model) の 3 つ組を書き換えることはありません。
  • 勝者は役割のモデルファミリーを保たなければならず、そうしないと執行者 ≠ 審核者の不変条件がその下で黙って壊れます。
  • 同点は勝者ではなく、このホストに CLI や認証情報がない runtime はスキップされます。

不明な点はすべてマトリクス導入前の cascade にフォールバックするため、マトリクスファイルのないデプロイはバイト単位で同一に振る舞います。composer には独自の domain がない(goal タスクは eval-suite ディレクトリではない)ので、domain をまたいだ同じ (role, runtime, model) のセルは n で重み付けした平均で集約されます。

ファイルを新しく保つオンライン bandit は引き続き P5 で、ゲートの capability_gap シグナルには依然としてデータ源がありません(後述)。

最初のスモーク実行で見つかったこと

Section titled “最初のスモーク実行で見つかったこと”

最初の探索実行(2026-09-25、hr-recruit、4 ケース、haiku と codex での執行 + 審核)は 3 つの知見を生み、3 つとも対処済みです。

知見 対処
執行セルが 12/12 でエラー。探索用の home にはプロビジョニング済みの agent が 1 つしかなく、suite の hr-recruit がなかった --agent <id> は、すべてのケースを 1 つのプロビジョニング済み agent の下で実行する。マトリクスが測るのはペルソナではなくモデルなので、探索上の妥協として許容でき、レポートのヘッダーと各実行で agent_override として宣言され、推測はされない
Codex の審核セルが 4/4 で unparseable。codex は返信の先頭に素の PASS/FAIL トークンを安定して置かない すべての審核呼び出しは、既存の --output-schema の仕組みを通じて {"verdict":"PASS"|"FAIL","reasons":[...]} を要求する(従来どおり codex のみ)。パーサーはその JSON オブジェクトまたは散文の先頭トークン形式を受け付け、引き続き fail-closed で unparseable に落とす
gold がすべてのケースで FAIL(記録済みトランスクリプトが古い)だったため、常に FAIL と言う審核者の一致率が 1.00 になった 各審核セルは gold_pass / gold_fail を報告し、単一クラスの gold は degenerate_gold: true を設定し、verdict: "unresolved"(理由 degenerate_gold)を強制し、その役割をボトルネックの比較から外す

3 回目の探索実行(実際の hr-recruit ペルソナ、gold が 2P/2F 混在の再記録済み 4 ケース、haiku / codex / sonnet での執行 + 審核)は本物のスコアを生み、同時にそのスコアを嘘にしていたであろう 2 つのバグを見つけました。

知見 対処
すべてのセルにクラスタが 1 つ(suite ディレクトリが 1 つ)しかなく、その場合クラスタロバスト SE は恒等的にゼロになる。CI は点に潰れ(mean 0.25 ci=[0.25,0.25])、両方の Δ 区間は幅ゼロで、ボトルネックは 4 ケースで resolved と宣言された クラスタが 2 つ未満のときは、クラスタなしの CLT SE を報告して明示する(se_source: clt_single_cluster)。セルも対応する Δ も同様。同じ欠陥は、通常の eval 経路の suite レベルの行でも洗い出して修正済み。真に幅ゼロの区間(n=1、またはすべての観測が同一)は degenerate_interval で unresolved を強制し、ボトルネックはそのような区間では resolve を拒否する
Codex の審核者の返信が unparseable だった。解析対象のテキストが、agent のメッセージではなくストリームの最後のイベント {"type":"turn.completed","usage":{…}} だったため 判定は、runtime が生のイベントストリームを返す場合に、そこから復元した agent のメッセージから読む(codex の agent_message/message 項目、claude の assistant/result イベント)。fail-open で、本物の答えはバイト単位で同一のまま通過する。復元が働いた実行は message_recovered_from_stream でフラグが付く

2 つ目の根本原因は上流にあり、まだ未解決です。runtime/codex.rs::parse_codex_stdout は item.type == "message" + content[].type == "output_text" の形しか認識しないため、agent_message の形を出力する CLI は空のコンテンツを生み、CodexRuntime::execute は stdout.lines().last() にフォールバックします。その runtime の呼び出し側はすべてこれを継承します。eval 経路は今や影響を受けませんが、gateway の修正は duduclaw-gateway を編集してよい別のウェーブに属します。

これが残す P2 の負債。 出荷済みの premium suite の記録済みトランスクリプトは、現在のアサーションに対して古くなっています(P0 のライブテストは再生で 98/360 を計測し、前リリースのバイナリと変わりませんでした)。そのため、それらに対するすべての審核セルは degenerate_gold です。審核マトリクスが意味を持つ前に、再記録するかアサーションを直す必要があります。執行セルは影響を受けません。ライブで実行され、記録済みトランスクリプトを決して読まないためです。

小さなマトリクスの正直な限界

Section titled “小さなマトリクスの正直な限界”

マトリクスは自身の解像度を宣言します。スモーク実行の規模(6 ケース、K=1)では、達成される MDE は数十パーセントポイントなので、ほぼすべてのセルが unresolved で返ります。Haiku 級と Opus 級を見分けるには十分ですが、隣り合う 2 つのモデルを順位付けするにはまったく足りません。宣言された MDE がコンソールのサマリーに出力され、ファイルのヘッダーに保存されるのは、サンプルサイズが支えられない順位を後から誰も引用しないようにするためです(research 13 §4.2: 40 ケース、K=3 で約 21pp、200 ケースで約 9pp を解決)。


何も実際より完成して見えないようにするための正直な一覧です。

  • 受理されたラウンドは単一のスモーク結果にすぎません。 ラウンド 14 は既存の受理判定器を通りましたが、それは Solo に対する本番での勝利を立証するものではありません。役割×モデルのマトリクスの 4 ケースのスモークでは、宣言された MDE を解決できません。
  • ファイルを書く役割は claude と codex に限られます。 antigravity / grok / 汎用 CLI のメンバーは、スキャフォールドを作業ディレクトリのままにするため、そのファイルはラウンドを越えて残りません。
  • 役割×モデルの能力マトリクスは、現在 composer が事前分布として読みます(上記)が、役割がモデルを未設定にした場合のみで、unresolved のないセルからのみです。2026-09-29 以降は、同じファイルがゲートの能力差シグナルにも答えます。執行者の (role, runtime) に対するマトリクスの勝者モデルと、その役割が現在実際に動いているモデルとの、n で重み付けした距離(パーセントポイント)で、マトリクスのヘッダー自身が宣言する MDE と組み合わされるため、ノイズの下限を下回る差は成立しません。この比較は両側に resolved のセルが必要なので、出荷済みのあらゆるマトリクスでこのシグナルは依然として暗いままです。 4 つのセルはすべて unresolved で、ゲートは以前のまま(4 つのうち計測できるシグナルは 2 つで、Team には 3 つ必要)です。運用者が resolve できるマトリクスを初めて計測したときに有効になり、それまでは有効になりません。ファイルを新しく保つオンライン bandit は引き続き P5 です。P2b の全チームプロデューサーは、実際の審核判定と引き継ぎを伴う、3 ケース・12 アームのライブパイプライン探索を完了しました。4 つのモデルのセルはすべて unresolved で、1 つの domain の 3 つの合成ケースは正式なマトリクスの受け入れ閾値を満たさず、これは実際には、今日出荷されているマトリクスは何も選択しないということです。
  • 既定オンへの反転は、既定値としてライブテストされていません。 設定のないインストールで生じる挙動は、ユニットテストで網羅されています(静かな Solo、監査行なし、ディスパッチがバイト単位で同一)。実行されていないのは、[team.roles] が設定されているうえで、enabled がオフであることに頼って Solo を保っていたフリートです。そのようなデプロイは現在チームを組みます。enabled = false が 1 行での巻き戻しです。
  • 審核セルが何かを計測できるのは、再記録された suite のみです。 出荷済みの premium suite のトランスクリプトは単一クラスの gold を与えるため、それらに対するセルは正直に degenerate_gold です。スモーク 3 は、gold が混在する 4 ケースを再記録すれば本物のスコアが得られることを示したので、直し方はわかっていますが、出荷済みの 18 の suite にはまだ適用されていません。
  • 1 ディレクトリの suite ではクラスタロバスト SE がまったく使えないため、その区間はより弱い CLT 推定量から来ており、ディレクトリ内の相関を見られません。本当の解像度には、単にケースを増やすことではなく、設計にある 8 個以上のディレクトリが必要です(research 13 §4.3)。
  • gateway は codex の agent_message 項目を抽出し、チームの審核者は、オフラインの審核セルと同じ厳密な PASS/FAIL の JSON スキーマを codex に要求するようになりました。codex を審核者としたチームのライブラウンドは、これから確認が必要です。
  • 現行モデルの価格は、運用者による入力が引き続き必要です。 マトリクスはディスパッチ前に <DUDUCLAW_HOME>/models.toml を読み込み、価格のないモデルがあると --budget-usd を拒否します。その見積もりは provider の請求額を正確に頭打ちにはできず、大きなツール実行は実行前の予約額より高くつくことがあります。
  • ゲート自体の較正(結果に対するゲートの判断の Brier 採点)は設計済みですが、接続されていません。
  • Fan-out は、異なるサブタスクを 1 つの執行者モデル上のメンバーに分散させます。レプリカごとのモデルの多様性は設計にありますが、出荷された [team.roles.executor] の形では表現できません。
  • パケットの tool_scope と irreversible は運ばれるだけで、何も読みません。 どちらも検証されて保存されますが、spawn には到達せず、render_packet_for_prompt はレンダリングすらしないため、規劃者が tool_scope.denied = ["mail_send"] と書いても全く効果がありません。役割メンバーの本当のツールエンベロープは、check_tool_subset を通じて従業員の [capabilities] から来ており、ActionGuard はフラグに関わらず呼び出しの時点で不可逆な呼び出しを守ります。型のドキュメントと spec/task-packet.md は以前は逆のこと(「ここでの拒否は本物の拒否である」)を主張していましたが、現在は「not wired」と書いています。これらを接続するのは今後の作業です。
  • L0 の「計画中の不可逆な操作」の除外はゲートでは評価されません。ActionGuard は引き続き呼び出しの時点で不可逆な呼び出しを守り、チームはそれを変えません。
  • 削らない免除は composer ではなく、4 つのリテラルな markdown 見出しをキーにしている。 解消済み: 免除はプロセスごとの sentinel マーカー行で composer に結び付けられ、2 つの上限は多層防御として残ります。「知っておくべき 2 つの継ぎ目」を参照してください。
  • role_turns.jsonl は、plan_round が計画していない spawn 予算に審核者の行を数えます。 審核者はユーティリティ呼び出しですが、その台帳の行には member_id = "team-verifier" があり、spawns_used_for_task はメンバー id を持つすべての行を数えるため、各ラウンドは計画の見積もりより 1 つ多く spawn を消費します。
  • cost.by_role は、役割とモデルごとの実測のチーム段階の支出を報告し、タスク id(episode_id)で絞り込むこともできます。役割のない古い行は引き続き帰属されません。v1.68.0 からチーム設定はダッシュボードで変更できます(「役割の設定」を参照)。パケット/ツールのドリルダウンは、これから接続します。
  • 審核者の token 使用量は、runtime が usage ブロックを提供したときに取得されます。そうでなければ usage_* フィールドはゼロではなく存在しません。同じ規則が規劃者と執行者の使用量にも適用されます。ライブ探索の役割コスト台帳は不完全で、provider の請求書の代わりにはなりません。
  • 構造化された判定器出力は codex のみです。 --output-schema は接続された唯一の構造化出力フラグで、antigravity や openai-compat の判定器は引き続き prompt で説得する必要があります。チームの審核者はオフラインの審核者のスキーマを共有し、厳密な JSON と先頭トークンの散文の両方を受け付けます。codex でのチーム審核には、ライブラウンドがまだ必要です。
  • 成果物レシートは、パケットが宣言したパスだけを対象にします。 メンバーが artifacts[] に挙げずに書いたファイルは、ネイティブツールの行で証拠づけられますが、ハッシュはありません。宣言されていない変更のためにワークスペースを走査することは、今後の作業です。
  • 切り離された composer は、生きたスキャフォールドの上限に達したとき、FIFO の受け付けチケットを待つようになりました。期限切れ、欠落、または読めないチケットは段階を明示的に失敗させ、キャンセルされた待機は自分のチケットを取り除きます。キューの状態とスキャフォールド解放のテストは通っています。負荷のかかったライブラウンドのテストはまだ必要です。