📖 はじめに —「次に書くとき」が12日後に来た
前回は、cts-ec で育ったハーネスを cts-harness へ切り出し、プラグイン層と dist 層の二層で配るところまでを書いた。最後に残した宿題は、母体だった cts-ec 自身のプラグイン移行である。
その宿題は 2026 年 7 月 23 日に完了した。skills / agents / commands のローカル複製は消え、cts-ec と cts-pos は同じプラグインを別々のバージョンピンで使う、2 消費者体制になった。
そして 2 日後、Claude Opus 5 が来た。
新しいモデル ID へ置き換え、料金とコンテキスト長を台帳へ足せば終わる — そう見える変更は、実際には 69 分で 5 つのリリースタグを生んだ。モデル対応を入口に監査すると、新モデル検知の盲点、文書と実体の不一致、plugin 移行で残った旧パス、配る意味のないテスト、そして修正のために追加した doctor 自身の CI 回帰まで連鎖して見つかったからだ。
結果を先に書く。
| 項目 | 結果 |
|---|---|
| リリース | 09:45 の v0.11.0 → 10:54 の v0.12.1、69 分で 5 タグ |
| harness 差分 | 5 コミットの累積結果は 29 ファイル・+899 / -122 行 |
| roster | code-reviewer / plan-architect / design-reviewer を Opus 5 へ。design-reviewer は Fable 5 常時割当をやめ、入出力単価を半減 |
| 行動対策 | 冗長化・自己検証の二重化・スコープ拡大・過剰委譲を共通ルールへ追加 |
| 検知 | 新モデル監視を cts-ec 固有から全プロジェクト配布へ昇格。doctor に配線検査 D-h を追加 |
| 回帰 | model-master 3 箇所、plugin 旧パス、セルフテスト 20 本の誤配布、doctor D-i の CI 誤作動を修正 |
| 消費側 | 10:54 時点で cts-ec は v0.12.1、cts-pos main は v0.11.1。pin が v0.12.0 回帰の main への伝播を止めた |
| 同日追補 | 14:04 の v0.13.0 → 16:50 の v0.13.2。未修飾名、誤った検証手順、name 付き teammate の定義本文欠落を順に修正し、PreToolUse の非推奨 decision: "block" も清算 |
本稿の主役は Opus 5 の性能紹介ではない。モデルが進化した日に、ハーネスの古い前提がどう壊れ、どう局所化され、どう共通資産へ戻ったかである。
⏱️ 69分のタイムライン — リリース後に監査が始まった
cts-harness の git log は、当日の密度をそのまま残している。
| 時刻 | version | 変更と、その直後に分かったこと |
|---|---|---|
| 09:45 | v0.11.0 | Opus 5 roster・運用ルール・新モデル検知 H-7 を配布。22 ファイル、+632 / -86 行 |
| 10:01 | v0.11.1 | model-master に残った H-7 以前の説明 3 箇所を修正 |
| 10:27 | v0.11.2 | plugin 移行後も .claude/skills/ / .claude/agents/ を指していた参照を修正 |
| 10:45 | v0.12.0 | 利用側へ残っていたセルフテスト 20 本の配布を停止し、doctor D-i を新設 |
| 10:54 | v0.12.1 | その D-i が cts-pos の CI を落としたため、CI 環境では skip するよう修正 |
重要なのは、v0.11.0 が「失敗作だった」わけではないことだ。roster checker 16 件、statusline 18 件、doctor 49 件、sync 85 件など、リリース時点のテストは通っていた。それでも 利用側で文書を読み、plugin の実パスを辿り、別の CI イメージで doctor を動かすと欠陥が出た。
これはテスト不足という一語では片づかない。harness 単体テストが主張できる範囲と、消費プロジェクトでしか観測できない範囲が違ったのである。
🧠 モデル移行は、model 名の置換ではなかった
Opus 5 は API ID claude-opus-5、1M トークンのコンテキスト、最大 128K 出力トークン、$5 / $25 per MTok で、Opus 4.8 と同額である。thinking は未指定でも既定で有効になり、thinking: {"type":"disabled"} と effort xhigh / max の組み合わせは 400 になる。最小 cacheable prompt も 1,024 から 512 tokens へ下がった。これらは Anthropic の Opus 5 変更点と突合した。
この条件から、CTS の roster は次の形になった。
| agent | 変更前 | 変更後 | 判断 |
|---|---|---|---|
| code-reviewer | Opus 4.8 / xhigh | Opus 5 / xhigh | 同額でレビュー・バグ検出力を更新 |
| plan-architect | Opus 4.8 / xhigh | Opus 5 / xhigh | 同額で長い設計判断を更新 |
| design-reviewer | Fable 5 / xhigh | Opus 5 / xhigh | $10 / $50 → $5 / $25、入出力単価を半減 |
| implementation-validator | Sonnet 5 / xhigh | 据え置き | 3a の Opus が採否、3b は統合検査という役割分担を維持 |
Fable 5 を捨てたわけではない。Opus 5 でも判断が割れる設計、破壊的変更の影響分析、adversarial 検証だけ、呼び出し単位で Fable 5 へ上げる。最上位モデルを常設席から非常呼集席へ移すことで、品質の逃げ道を残しつつ常時利用の入出力単価を半分にした。総コストへの効果は、出力量とサブエージェント呼び出しを含む実使用量で継続測定する。
ここまでは model-master の仕事である。だが、Opus 5 で本当に変える必要があったのは、モデル表よりもプロンプトだった。
🗣️ 強くなったモデルを、古いプロンプトで増幅しない
Anthropic の Opus 5 prompting guide は、従来 Opus より回答と生成文書が長くなり、自己検証・スコープ拡大・サブエージェント(SubAgent)委譲も起きやすいと明記している。cts-harness はこの差を「気をつける」ではなく、全プロジェクトへ届く CLAUDE-shared.md の must-arrive ルールにした。
| Opus 5 の傾向 | やりがちな誤対処 | ハーネスの対策 |
|---|---|---|
| 応答・Markdown が冗長になる | effort を下げる | 簡潔さをプロンプトで指定。effort は思考量のレバーであり、表示文量とは分離 |
| 言われなくても自己検証する | verifier を削る | 削るのは重複した「念のため確認」指示だけ。evidence-gate / hook / CI は維持 |
| 依頼外の改善へスコープを広げる | 全判断で確認待ちにする | routine な判断は進め、読みが結果を変える場合だけ確認。依頼範囲は明示 |
| サブエージェントを出しやすい | サブエージェントを一律禁止 | 数手で終わる仕事は自分で処理。独立した大規模調査だけ委譲し、spawn 上限を持つ |
ここには、似て見えて正反対の 2 種類の検証がある。
- プロンプト由来の重複検証 —「最後にもう一度確認」「サブエージェントでも再確認」。Opus 5 自身の挙動と重なり、トークンだけを増やすため削る
- 構造が強制する検証 — verifier、evidence-gate、pre-push hook、CI。モデルが「確認した」と言っても代替できないため残す
サブエージェントも同じだ。数ファイルを読むだけの調査を 3 体へ投げるのは過剰委譲だが、/tdd-team の writer → implementer → verifier は責務と証跡を分ける設計である。新モデル対策を口実に、せっかく機構化した分業まで壊してはいけない。 抑える対象は「自発的で小粒な委譲」であって、「設計された独立性」ではない。
🕳️ H-7 — 新モデル検知は、新モデルを検知できなかった
Opus 5 対応で最も皮肉だったのは、モデル監視機構が Opus 5 の登場を検知していなかったことだ。
状態ファイル ~/.claude/state/model-watch/ はユーザー単位なのに、statusline の配線は cts-ec だけにあった。作業場所が cts-pos へ移っていた期間、known-models.tsv は 7 月 14 日で止まり、model-log.jsonl に Opus 5 はなく、エイリアスプローブも実行 0 回。全プロジェクトで共有する状態を、1 プロジェクトの入口からしか更新できないという所有境界のねじれである。
v0.11.0 はこれを次の 3 層で直した。
statusline-model-watch.shを cts-ec 固有ツールから cts-harness の dist へ昇格し、全利用プロジェクトへ配布- settings 雛形へ
statusLineを追加し、cd "$CLAUDE_PROJECT_DIR" &&を前置して cwd drift による silent failure を防止 - harness-doctor に D-h を追加し、「ファイルはあるが配線されていない」「cd 前置がない」という第三状態を SessionStart で赤表示
statusline は失敗しても画面から消えるだけで、エラーが目立たない。だから 検知器にも検知器が要る。配布した事実ではなく、入口から実行物までつながっていることを doctor が検証するようになった。
課金を伴い実行実績 0 回だった check-model-aliases.sh は昇格させず廃止した。フル ID ピンでは correctness に影響せず、同じ初見シグナルを statusline が無課金で取れるからだ。共有化は「全部を共通へ持っていく」ことではない。役目を果たしていない仕組みを捨てる機会でもある。
📚 model-master の不具合 — AIにとって文書ドリフトは実行時バグ
H-7 を直した v0.11.0 の直後、model-master に 3 つの古い説明が残っていることが分かった。
| 残っていた記述 | v0.11.0 の実体 |
|---|---|
| statusline は cts-ec 残置で「配布しない」 | dist へ昇格し、全プロジェクトへ配布 |
更新トリガは check-model-aliases.sh の警告 | 同スクリプトは廃止 |
alias-map.tsv は次回月次プローブで更新 | プローブ実績 0 回、今後も更新しない |
人間が読めば「書き換え忘れ」と判断できる。だが AI エージェントは、文書に「このコマンドを実行せよ」とあれば従う。存在しない更新経路を正規手順として提示する文書は、コメントの typo ではない。AI が文書準拠で誤動作する実行時バグである。
そこで v0.11.1 を 16 分後に切った。内容は doc 修正だけでも、公開済みの v0.11.0 タグは打ち直していない。すでに配ったタグの意味を変えず、HARNESS_VERSION と実内容を一致させるための patch release である。
🧭 v0.11.2 — プラグイン化は、ファイルを消しただけでは終わらない
次に見つかったのは、7 月 23 日の plugin 移行で取り残した旧レイアウトだった。
利用側の .claude/skills/ にはプロジェクト固有スキルしかない。それでも共通 Skill の一部は、まだ次のパスを案内していた。
/steeringが雛形を.claude/skills/steering/templates/から読む- create-mr が
.claude/skills/create-mr/create-mr.shを起動する - parallel-execution が
ls .claude/agents/で agent 名を確認する
plugin 化後、これらはリポジトリ内に存在しない。とくに steering の templates は中核経路なので、記載どおり辿れば必ず失敗する。v0.11.2 は「本 Skill と同じディレクトリ」「/agents または plugin agents/」へ参照を直し、相互参照 7 件と script コメントも機械監査した。
一度は ${CLAUDE_PLUGIN_ROOT} で統一しようとしたが、その変数が設定されないことを実測して撤回している。綺麗な抽象化より、実際に解決できるパスを選んだ。移行完了の定義は旧ファイルの削除ではなく、全参照が新しい所有者へ到達することだ。
🧪 20本・4,013行 — 配られたテストは、利用側を1行も見ていなかった
監査はさらに、dist 層へ向いた。scripts/ci/ のセルフテストは以前から非配布だったが、scripts/hooks/、scripts/codex/、scripts/*.sh は cp -r のため、20 本の *.test.sh が cts-pos へ配られ続けていた。
一見すると、テストも一緒に配るほうが安全そうに見える。しかし全テストを調べると、どれも mktemp で独立した仮リポジトリを作る密閉テストで、利用側の実ファイルを 1 箇所も見ていなかった。配線が壊れても pass し、CI や test-all から呼ばれる仕組みもない。コピーは 20 本、検知能力は 0だった。
v0.12.0 は配布を止めるだけでなく、「では環境差異をどこで検証するか」を整理した。
| 主張する性質 | 壊せる主体 | 正しい置き場 |
|---|---|---|
| script の入力 → 終了コード | harness を変更する人 | cts-harness のセルフテスト |
jq / python3 / perl、配線、パス解決 | 各プロジェクトの実行環境 | harness-doctor |
| 実コードとの統合、coverage、architecture | 各プロジェクト | プロジェクト CI |
この判断で cts-ec の v0.12.1 適用コミットは、20 本のテストを含む 4,013 行を削除した。削除伝播は前編で導入した HARNESS_MANIFEST が自動で担った。配布物を減らしても検知力を落とさないため、doctor には前提コマンドを調べる D-i を追加した。
そして、その D-i が次の回帰を作った。
💥 doctor がCIを落とした — 検査は「誰が走らせるか」までが仕様
D-i は hook が依存する jq / python3 / perl の有無を調べる。Claude Code セッション開始時には正しい。未導入なら hook は画面に出ず silent に死ぬため、doctor が赤を出す価値がある。
しかし check:doctor は CI でも動く。cts-pos の更新 MR が使う最小 Alpine イメージにはそれらのコマンドがなく、v0.12.0 の D-i は ❌ を返してパイプラインを落とした。CI では Claude Code hook 自体が動かないのに、hook 実行環境の前提を CI コンテナへ要求してしまったのである。
9 分後の v0.12.1 は、CI 環境変数があれば D-i を skip するよう修正した。ここで doctor の検査は 2 種類に分かれた。
- D-a〜D-h: リポジトリの内容・配線を見る。セッションでも CI でも意味が同じ
- D-i: 実行環境を見る。Claude Code セッションでだけ意味がある
「何を検査するか」だけでは足りない。どの実行主体に対する主張かまで書いて、初めて検査仕様になる。環境差異を拾うための機構が、環境の違いを誤って障害扱いした — これが 5 タグ目を必要にした理由だった。
🔀 2つの消費者 — pin は更新機構であり、伝播境界でもあった
10:20:07、cts-ec が v0.11.1 を適用した。その 13 秒後の 10:20:20、cts-pos も同じ版を適用した。前編で「これから」とした二消費者運用が、ここで本番になった。
しかし最終状態は同じではない。
| リポジトリ | 2026-07-25 10:54 時点の dist pin | 観測した役割 |
|---|---|---|
| cts-ec | 0.12.1 | 修正版を即時適用し、セルフテスト 20 本・4,013 行の削除伝播を確認 |
| cts-pos | 0.11.1 | v0.12.0 の D-i 回帰を更新 MR の CI で検出。main は同回帰を含まない直前導入版のまま |
もし共通リポジトリの main を全プロジェクトが毎回直接読んでいたら、v0.12.0 の 9 分間の回帰も全員へ即時伝播した。実際には project scope の version + SHA pin と、dist 側 HARNESS_VERSION が、更新を明示操作に限定した。
前編では pin を「EC だけ先行しても POS は動かない」ための隔離機構と説明した。今回はもう一段強い性質が観測できた。pin は正常性を保証する仕組みではない。それでも更新を明示操作に限定し、新しい回帰の自動伝播を止める境界になる。
そして cts-pos は単なる配布先ではなかった。別の CI イメージ・別のプロジェクト構成で共通ハーネスを叩き、harness 単体では見えなかった回帰を本家へ返した。共通化が成功したかどうかは、同じものを配れたかではなく、異なる消費者から違う故障信号が戻るかで分かる。
🧷 同日追補 v0.13.0〜v0.13.2 — 設定値と実効状態が三度ずれた
本記事の初稿コミットは 11:48 だった。その約 2 時間 15 分後に v0.13.0 を出し、さらに v0.13.1、v0.13.2 と修正が続いた。これは 09:45〜10:54 の「69 分で 5 タグ」とは別の追補で、当日のリリースは最終的に 8 タグになった。
| 時刻 | version | 発見した不具合 |
|---|---|---|
| 14:04 | v0.13.0 | plugin agent の未修飾名が無警告で別経路へ落ち、指定 model が採用されない |
| 14:53 | v0.13.1 | v0.13.0 の検証手順が正常なレビューを「定義未適用」と誤診して破棄させる |
| 16:50 | v0.13.2 | 修飾名と model が正しくても、name 付き teammate では agent 定義本文が適用されない |
v0.13.0 — 指定した model が agent に届いていなかった
plugin agent は cts-harness:<name> という修飾名で解決する。ところが配布済みの commands は、plugin 化前と同じ doc-reviewer のような素の名前で起動していた。Fable / Opus / Sonnet / Haiku のどれを割り当てても、名前解決に失敗すれば model 指定は採用されない。
しかも、失敗はエラーにならない 2 経路に分かれていた。
| 起動経路 | 素の agent 名を渡したときの挙動 | 結果 |
|---|---|---|
teammate の Agent / Task | agent_type を検証せず、そのまま子プロセスを起動 | first-party の teammate 既定である Opus 5 の素のセッションとして実行 |
command の context: fork + agent: | plugin agent 一覧を完全一致で検索 | 一致しなければ general-purpose へ無警告降格 |
cts-pos で起動した doc-reviewer 3 体は、roster の Sonnet 5 ではなく全て Opus 5 で動いた。Haiku 割当の agent は全て fork 経路だったため、plugin 移行後は一度も割当が適用されていなかった。Opus 指定はフォールバック先と表示モデルが同じなら異常が隠れ、Fable の選択投入も未解決名を経由すれば保証できない。
⚠️ 後続リリースによる訂正
v0.13.0 は「tools に Bash / Write / Edit がある」「定義本文が transcript に 0 回」を定義未適用の根拠にしたが、どちらも判定指標として誤りだった。v0.13.1 と v0.13.2 で実測し直した内容を後述する。
v0.13.0 では、commands 内の subagent_type 14 箇所と fork の agent: 3 箇所を修飾名へ統一した。さらに、次の 3 層で再発を止めた。
- 配布前の静的検査 —
check-agent-invocation.shが素の roster 名と fork の未修飾名を検出し、sync.shとリリースを止める - 実行時の決定論ガード —
pre-agent-spawn-guard.shが素の名前、または roster agent をgeneral-purposeで代用する起動を PreToolUse で deny する - 配線検査 — harness-doctor D-c の必須フックを 4 種から 5 種へ増やし、利用側
settings.jsonへのガード配線漏れを見つける
roster checker が green でも、それが保証するのは agent frontmatter と model-master の静的一致までだった。実行時の名前解決は別の性質として検証する必要がある。
非推奨の decision: "block" も同時に清算した
新しい PreToolUse ガードを実装する過程で、配布済みフック 7 本が旧形式の {"decision": "block"} を返していることも見つかった。Claude Code の Hooks リファレンスでは、PreToolUse の判断はトップレベルの decision ではなく、hookSpecificOutput.permissionDecision で返す。そこで deny 出力を現行形式へ移行した。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "拒否理由"
}
}
ここで block を deny、allow を allow と機械的に置き換えてはいけない。既存の {"decision": "allow"} は無効値として実質 no-op だったが、現行の permissionDecision: "allow" は権限確認をスキップする。push を毎回明示承認する運用を変えないため、成功時は JSON を出さず exit 0 にした。
最後に dist-hook-schema.test.sh を追加し、settings の PreToolUse に配線された 11 本を横断検査するようにした。検査するのは、非推奨 decision キーがないこと、permissionDecision に hookEventName が伴うこと、permissionDecision: "allow" を新規導入していないことの 3 点である。ガードの出力スキーマ自体も、壊れればガードを無言で外す実行コードとして扱った。
v0.13.1 — 誤った検証手順が正常な成果物を捨てさせた
v0.13.0 から 49 分後、その修正版に書いた検証手順自体が新しい不具合になった。v0.13.0 は「Read-only agent の tools に Bash / Write / Edit があれば定義未適用」としたが、teammate は独立したフルセッションとして起動するため、定義の model が正しく解決されていても tools: 許可リストは強制されない。この誤判定により、cts-ec では正常なレビューを「定義未適用」と診断して破棄する事故が実際に発生した。
決定的だったのは、7 月 22 日の同一チーム内の実績である。test-reviewer / pre-push-checker は定義どおり Sonnet、code-reviewer / implementation-validator は定義どおり Opus に分かれていた。その状態でも、Read / Grep / Glob / SendMessage のみを宣言した test-reviewer が Bash を 33 回使っていた。したがって、tools の広さから agent 定義の適用有無を逆算することはできない。
transcript も同じだった。system prompt は transcript に記録されないため、「定義本文が 0 回」という観測は未適用の証拠にならない。v0.13.0 が対照とした本文の出現は、agent 自身が定義ファイルを Read した tool result だった。
v0.13.1 は検証指標をいったんモデル ID に一本化し、Read-only を別の決定論ガードへ移した。enforce-agent-readonly.sh が 12 体の read-only agent に対する Write / Edit / NotebookEdit を PreToolUse で deny し、静的 checker が agent frontmatter との分類 drift を検査する。doctor D-c の必須フックも 5 種から 6 種へ増やした。
ただし Bash 経由のリダイレクトや sed -i は塞いでいない。Bash 全体を止めると grep / find による調査まで失うため、ここは意図的な限界として残した。そして「モデル ID だけを見ればよい」という v0.13.1 の訂正も、1 時間 57 分後に覆る。
v0.13.2 — model は合っているのに、専門指示が消えていた
実測環境の Claude Code 2.1.220 で name 付き spawn を再現すると、model と effort は frontmatter どおりなのに、agent 定義本文だけが適用されないことが分かった。Claude Code の Agent Teams 公式ドキュメントは、teammate が subagent 定義の tools と model を尊重し、本文を system prompt へ追加すると説明している。しかし cts-pos と cts-ec の実機結果は、この契約と一致しなかった。
「対応行数の上限は?」という、doc-reviewer の定義本文にしか答えがない質問で対照実験した。
| 起動方法 | 回答 | model |
|---|---|---|
--agent cts-harness:doc-reviewer | 1000 ✅ | — |
--agent-type …(tmux teammate と同経路) | なし ❌ | — |
Agent(…, name: "probe1")(in-process teammate) | なし ❌ | claude-sonnet-5 ✅ |
tmux / in-process の両方で同じ結果になり、teammateMode では回避できなかった。つまり model ID は必要条件にすぎず、roster と一致しても専門指示が届いた証明にはならない。失われていたのはレビュー観点、スコア基準、NG 表現辞書、出力フォーマット、検証項目である。/tdd-team は全 worker を name 付きで起動していたため、レビュー系だけでなく pre-push-checker / implementation-validator / test-reviewer も専門指示なしで走っていた。
v0.13.2 は teammate 経路をハーネスから全廃した。
name付き spawn を廃止 —Agentはsubagent_typeとrun_in_background: true、nameなしで background subagent として起動する- 継続先を agentId へ変更 — spawn の戻り値に含まれる agentId を Lead が保持し、
SendMessageの宛先に使う - 静的・実行時の両方で拒否 —
check-agent-invocation.shが roster agent へのname併記を検出し、pre-agent-spawn-guard.shの第 3 判定が起動前に deny する - 事後証跡を確認 — model ID だけでなく、
reviews/に SubagentStop の証跡が生成されたことと、成果物が定義どおりの形式であることを確認する
同日の調査では plugin 未ロードも実障害になった。agent type not found に加えて利用可能一覧が組み込み agent だけなら、修飾名の typo ではなく plugin 未ロードを疑う。とくに ~/.claude を bind mount する devcontainer では、ホスト側から plugin / marketplace を操作するとホスト絶対パスが共有状態へ書かれ、コンテナ側の installLocation と食い違う。plugin 操作は実行環境の内側で完結させる運用へ改めた。
この連鎖で分かったのは、実効状態の確認にも「使えない指標」があることだ。tools の広さ、transcript の文字列検索、model ID の一致を一つずつ根拠から外し、最後に残ったのは 壊れる起動経路を使わないことを静的・実行時に強制する設計だった。
🔍 検証の台帳 — 何が観測済みで、何がまだ仮説か
- git log で確認済み: v0.11.0〜v0.12.1 の 5 コミット時刻、69 分、29 ファイル +899 / -122 行
- v0.13.0 の実測と実装で確認済み: doc-reviewer 3 体の Sonnet 5 → Opus 5 逸脱、fork の general-purpose 降格。修飾名への統一、静的検査、実行時ガード、hook スキーマ検査を追加
- v0.13.1 の実測と実装で確認済み: tools の広さと transcript 内の本文出現回数は定義適用の判定に使えず、誤診で正常なレビューを破棄。read-only 書き込みガードと分類 drift 検査を追加
- v0.13.2 の独立再現で確認済み: cts-pos / cts-ec、tmux / in-process の両方で、
name付き teammate は model が一致しても定義本文を失う。named spawn を全廃し、agentId による background subagent 継続へ移行 - 実ファイルで確認済み: 17:02 時点で cts-ec / cts-pos の HARNESS_VERSION はともに 0.13.2。両 main へ teammate 全廃と
name併記ガードを適用済み - 消費側コミットで確認済み: cts-ec v0.12.1 適用で 25 ファイル・39 追加 / 4,013 削除。cts-harness CHANGELOG で確認済み: cts-pos の更新 MR で発生した D-i CI 回帰
- 公式仕様と突合済み: Opus 5 の価格、1M / 128K、thinking 既定オン、effort と冗長性の分離、自己検証・スコープ拡大・サブエージェント委譲傾向。PreToolUse の出力形式。teammate が subagent 定義を尊重するという公式説明と、Claude Code 2.1.220 の実測が不一致であること
- 未計測: design-reviewer を Fable 5 常時割当から Opus 5 へ替えた後の総コストと差し戻し品質。入出力単価の半減は価格表から確認できるが、総コストと品質同等性は今後の実使用量、findings、差し戻し率で測る
新モデルの日に一番危険なのは、性能表を読まずに切り替えることではない。切替直後の成功を見て、周辺の前提まで正しいと思い込むことだ。未計測は未計測のまま台帳に残す。
🧾 まとめ — 共有ハーネスは、壊れないものではなく直せるものになった
学びを 7 行に圧縮する。
- モデル移行は三点セットで行う。 model-master の仕様、roster の割当、プロンプトの行動制御。モデル ID だけを替えると、強化された冗長化・自己検証・委譲まで古い指示が増幅する
- AI が読む文書のドリフトは production bug と同じ重さで扱う。 存在しない script や旧 path を正規手順として書けば、AI は忠実に失敗する。文書と実体を同じリリースで検査する必要がある
- テストの置き場は、誰がその性質を壊せるかで決める。 harness の論理は harness、実行環境は doctor、プロジェクト統合は各 CI。安心感のためのコピーは検知力を生まない
- バージョンピンは blast radius を狭める。 v0.12.0 の回帰は POS が見つけ、修正版は EC が即時実走し、POS main は同回帰を含まない直前導入版に残れた。二層配布は更新路、pin は自動伝播を止める境界、複数消費者は統合テストになった
- model ID の一致は必要条件であって十分条件ではない。 Fable / Opus / Sonnet / Haiku が roster どおりでも、teammate 経路では専門指示が欠落し得る。tools の広さや transcript の文字列検索も適用判定には使えない
nameは表示名ではなく実行経路を変える入力だった。 named teammate を使わず、nameなしの background subagent と戻り値の agentId で並列・継続駆動する。壊れる経路は注意書きではなく静的検査と PreToolUse で閉じる- hook の出力は API 契約として検査する。 非推奨の
decision: "block"を残さず、deny は現行スキーマへ移す。一方、成功時の no-op をpermissionDecision: "allow"に変えて権限まで広げない
前編は「配れる形にして初めて、ハーネスは資産になる」と閉じた。今回、その定義を更新する。配れるだけでは足りない。別の現場で壊れ、壊れ方が本家へ戻り、直した版を必要な現場だけが選んで取れる。そこまで回って、共有ハーネスは運用資産になる。
69 分で 5 リリースは、安定性の自慢には見えないかもしれない。だが、最初のリリースから修正版の消費側適用までは約 71 分だった。隠れた不整合を抱えたまま「Opus 5 対応完了」と宣言するより、この 71 分のほうがはるかに価値がある。ハーネスが完成したのではない。壊れたときに、自分の配布網を使って治るようになったのである。
そして初稿を公開した同じ日の v0.13.0〜v0.13.2 は、話がそこで終わっていなかったことを示した。model を書いたことと、その model で動いたことは違う。さらに、model が一致したことと、専門指示どおりに動いたことも違う。block を返したことと、現行ランタイムが block と解釈し続けることも違う。設定値ではなく実効状態を測り、使えない観測指標を捨て、無言で壊れる経路そのものを機械的に拒否する。 これが 6〜8 番目のリリースで追加された、もう一段深い運用条件である。
📚 シリーズ記事(ステアリング駆動開発・実践編)
序章
第I部: 技術的負債ドメイン別の実録(総点検ガイド + 8 ドメイン・全 9 回)
- リファクタリング総点検ガイド — 7 つの観点と進め方
- DDD/SOLID/BC 編 — god class 一掃と境界の機械ガード
- SAGA 編 — 新アーキテクチャ挑戦と再発ゲート
- Atomic Design リファクタ編 — 47 page 新規移植
- Storybook × a11y 実機編
- テスト品質・網羅性編
- Python ジョブ群編
- パフォーマンス編
- セキュリティ編
第II部: 検証エンジン(クロスファミリー検証・全 6 回)
- 総論 — マルチ LLM の 2 系統と見取り図
- 裏取り編 — +18.1pt 論文の検証
- 設計編 — finder/verifier 分業と逆順禁止
- TDD×ハーネス編 — テスト保護と三層ゲート
- 実装編 — Claude Code の中から Codex を動かす
- モデル戦略編 — ティア割当と「買うか組むか」
終章
- クロスファミリー検証の最終型 —「正しく作る」から「自分で正しさを測り直す」へ — 検証エンジンに「計測」の層をはめ、自己修正ループを閉じる
番外編
- CI テスト 29 分 → 5.6 分 — 検証エンジンの平時運用実録 — 実測が有力仮説を殺し、退行前より速くなった 1 日
- GPT-5.6 sol 切替の当日実録 — もう一つのデフォルト追従 — CLI 更新が黙って替える finder と、当日中の再計測
- 遊休 90% の枠に仕事を振る — Codex 上流調査と verifier バッチ化 — 逆順禁止の境界を ADR で確定し、読む仕事を遊休枠へ移した 1 日
- ハーネスが単一プロジェクトを卒業する — プラグイン化と二層配布 — 4 プロジェクト展開への切り出しと、version + SHA ピンによる非強制追従
- 69分で5リリース — Opus 5 当日対応が暴いた共通ハーネスの死角(本記事)
関連記事
- 前編: ハーネスが単一プロジェクトを卒業する — 本稿で実走した二層配布・プロジェクト別 pin の設計
- モデル切替当日実録 — Codex 側の世代交代を実効モデルの計測で追った記録
- TDD×ハーネス編 — Opus 5 の自己検証でも削らなかった構造ゲートの原点
- Claude Code 7層ハーネスエンジニアリング — 共通化前のハーネス構造