TL;DR:第二のAIを使ってエンジニアリングを審査させるとき、本当の技術は独立性を守ることにある。問いかけの仕方に自分の結論が混入すれば、それは同意を返すだけになる。有用であり続けさせるには、問い方・受け取り方・照合の仕方に規則を設けなければならない。最も直感に反する教訓はこれだ——審査が的確であるほど、鵜呑みにしてはいけない。

▶ 要約を聴く
AI合成音声・著者本人の声のクローン

Claudeにskillを書かせて、codexがコードレビューを手伝えるようにした。ツールが書き上がってから、まずはそれ自身を審査させてみた。二回の審査を経て、codexはかなりの数のバグを見つけ、その場で私の認識を打ち崩した。セカンドオピニオンが最も価値を持つのは、自分への確信を打ち砕いてくれる瞬間だ。

なぜ第二のAIを審査役に据えるのか

codexはローカルに接続した別のモデル(OpenAIのターミナル向けcoding agent、gpt-5.5で動作)であり、Claudeが書いたコード・データ・設計を審査する専用の役割を担っている。Claudeは実際に作業してコードを書くモデルであり、codexは別の血統を持つ審査者だ。読み取り専用のサンドボックスで動作し、私のファイルを変更せず、何かを勝手に送信することもない。その役割は非常に限定的で、一本の探針に過ぎない。自分が生み出したものを探針で突いてみて、独立して何を見つけるかを確認する。自分が見落としたものは、たいてい別の出所を通さないと照らし出せない。

もう一つの利点は、私の作業ウィンドウの中に存在することだ。内容をコピーして別のツールに貼り付け、意見を持ち帰るという手間が不要になる。Claude Codeのターミナルから直接codexを呼び出す場合でも、Coworkのようなデスクトップウィンドウを経由してMacに繋がったブリッジを通して同じローカルのcodexに繋ぐ場合でも、セカンドオピニオンを同じ作業ウィンドウの中で引き出せる。どちらのウィンドウも同じローカルのcodex・同じ設定に繋がっているため、どちら側から問いかけても基準が統一される。

Claudeとcodexによるワークフロー:ClaudeはCode(ターミナル)またはCowork(デスクトップブリッジ)から同一のローカルcodexを呼び出し独立審査を行う。問いかけに結論を混入させない、codexは問題を指摘するだけでコードを修正しない、生の出力はログファイルに保存、一致と相違を照合した上でPaulが最終判断する。codexが機能しないときは単一意見にダウングレードする。

なぜ必要なのか。同じモデルが書いたものを自分で振り返ると、自分の盲点には気づきにくく、以前の判断に沿って頷いてしまいやすい。異なるトレーニング・異なるフレームワークから来た別のモデルを使うことで、最初のモデルが見落とした箇所を突けるのだ。これはAnthropicが長時間動作するAI agentに関するワークショップで強調した原則とも呼応している。モデルは自分自身を信頼性をもって評価できないため、自己採点させるよりも批判的な対立者を与えるほうがよい、ということだ。この記事は私の人間と機械の協働のトピックの下に置いており、その対立者をどう繋げば機能するかについて論じている。

別のモデルに聞くこと自体は難しくない。難しいのは繋ぎ方だ——どう問いかけ、どう受け取り、どう照合するか。

セカンドオピニオン最大のリスク:同意してしまうこと

第二のモデルへの問いかけに自分の結論が既に混入していれば、そのモデルはあなたに同意し、偽の安心を与える可能性が高い。「この箇所はもう確認したので問題ないと思うが、もう一度見てほしい」と問えば、返ってくるのは往々にして高コストな「そうですね、おっしゃる通りです」であり、独立した審査とは程遠い。

だからセカンドオピニオンに価値を持たせるには、その独立性が保護されていることが前提になる。そして独立性は設計するものであり、自然に生まれてくるものではない。私は四段階のプロトコルを使ってこれを守っている。各段階は具体的な失敗パターンに対応している。複数のモデルが互いを校正する方法については、多モデル認知協調の記事でより詳しく論じた。ここでは「独立性をどう守るか」に絞る。

セカンドオピニオンの独立性を守る四段階プロトコル

第一段階、問いかけに自分の結論を混入させない。問いかけは中立に保ち、「何を審査するか・基準は何か」だけを伝え、「この箇所は問題ないと思う」という情報は与えない。私のラッパーは問いかけの中に結論が混入していることを検出すると警告を出す。このステップは法廷で言う「誘導尋問」を遮断するためにある。

第二段階、codexの生の出力をログファイルに残す。確認したら捨てるのではなく、後から照合し、他者が検証できる状態にしておく。確認して削除するのは、証拠を残さないことと同じだ。

第三段階、問題を説明するだけで、コードを修正してはいけない。これは安全上の境界だ。審査者に直接修正させれば、どこが元々の意図でどこが勝手に変えられた部分かを区別できなくなる。審査者の仕事は問題を指摘して重大度を示すことであり、修正するかどうか・どう修正するかは別の側が判断する。

第四段階、照合は自分で行い、「一致」と「相違」の二列に分ける。codexの言葉をそのまま書き写さない。一致した部分は採用する。意見が割れた部分は自分でコードを読んだ上で判断し、どちらの意見を採用したか・その理由を記録する。

この四段階を組み合わせることで、セカンドオピニオンは独立性を持ち、証拠を残し、越権せず、かつ鵜呑みにされない存在になる。どれも些細なことのように見えるが、一つでも欠ければ、対立者は鏡へと少しずつ退化していく。

審査が的確であるほど、鵜呑みにしてはいけない

これがこの協調の仕組み全体で最も直感に反する点であり、このツールを使って自分自身を審査させたときに学んだことだ。

codexは第一回で七件の問題を発見し、修正した後に再度独立審査させると、さらに三件を見つけた。合計十件だ。その中には本当に高リスクの脆弱性も含まれていた。例えば、私のタイムアウトラッパーがサブプロセスをシステムが強制終了させた場合に、失敗を成功として誤って伝えてしまう問題をcodexは発見した。これらの指摘は照合の結果、自分でコードを読み直した結論とも一致していたため、そのまま修正した。

しかし審査がこれほど的確であっても、最終的に全ては採用しなかった。第二回には「半成功」の判定が完全に空の出力しか防げておらず、「文字はあるが実質的な審査内容がない」ケースには対応できていないという指摘があった。問題は、「意味的な実質があるかどうか」を機械が信頼性をもって検証することが難しい点にある。機械的に検証できる部分だけを修正し、人が読んで判断しなければならない部分は明確に人間の責任として残した。

何を採用し、何を保留するかは、完全な文脈を握っている側に委ねられる。codexは精度の高い探針だが、誤ることがある。私も誤る。どちらも誤り得る二つのモデルが互いを照合するとき、両方が指摘した問題はほぼ間違いなく本物だ。一方だけが指摘した問題は、自分でコードを読んだ上で判断する必要がある。どちらか一方を絶対に誤らない神託として扱えば、この協調の仕組みは崩れる。

探針が壊れたときは、大きな声で壊れたと言わせる

探針は壊れる。ローカルのcodexがインストールされていないかもしれないし、クラッシュするかもしれないし、実行に時間がかかりすぎて応答しないかもしれない。このプロトコルがその状況に対してとる態度は、速やかに失敗すること、リトライしないことだ。

codexが存在しない場合、タイムアウトした場合、あるいは終了したにもかかわらず実質的な審査内容がない場合は、一律にダウングレードする。今回は単一の意見のみだったことを正直に記録し、私に通知して、そこで止まる。五回リトライしてから問題を報告するのではなく、「実行されたが結果がなかった」ことを成功として扱うこともしない。壊れうる依存関係に最も必要な能力は、壊れたときに大きな声でそれを伝えることだ。静かに引き延ばして待たせ続けることこそが、本当の落とし穴だ。

「完了」の定義もこの原則に従う。一回の審査が成功かどうかの判断基準は、「最終メッセージに実質的な内容があるか」であり、「プログラムが正常終了したか」ではない。codexの終了コードが0であることは、有用な何かが出力されたことを意味しない。これは冒頭の偽の不変条件と実は同じ教訓だ——「実行が終わった」ことを「完了した」と見なすことが、最も静かに誤りを生む場所だ。

足場は穴を埋めるためのものであり、穴が塞がれたら解体する

このプロトコルは永久的な教義ではない。「現在のモデルの穴」を埋めるために組んだ足場だ。

今日のモデルは同意しやすく、半成功を成功と見なし、強制終了されたときに成功を偽って報告する。だからこれらの規則が必要だ。いつかモデル自身が十分に独立し、十分に誠実になり、誤ったときに正直に認めるようになれば、対応する規則は削除すべきだ——儀式として残すのではなく。規則の寿命は、それが解決しようとする問題に紐付けるべきだ。問題がなくなれば、規則は退場する。このプロトコルに戻るたびに、「何を加えるか」に加えて、「今なら何を取り除けるか」を自問している。

言い返してくる鏡

最も価値あるセカンドオピニオンとは、「あなたの自己判断は間違っていた」と告げてくれる瞬間にある。

しかし、耳を傾けることと、鵜呑みにすることは、異なる能力だ。前者は自分への確信を手放すことを求め、後者はモデルへの盲信を手放すことを求める。本当に難しいのは、両方を同時にやり遂げることだ。

codexを繋いだのは、頷いてくれる声が欲しかったからではない。また自分を信じ過ぎているとき、別の血統を持つ対立者に一突きしてもらうためだ。そして最後に、完全な文脈を握っている私が、その一突きを信じるべきかどうかを判断する。

あなたも試してみる

あなたもClaude Codeを使っているなら、この仕組みはそのまま自分のプロジェクトに持ち込める。私を介す必要もないし、APIキーも要らない。下記の付録にある二つのファイルは、意図的に汎用版として書いた。私のプロジェクト構造に縛られず、個人情報も一切残していない。自分のワークフローに合わせて、自分に合った版に書き換えればいい。

大事なのは私の設定をそのまま写すことではなく、あの「四つの独立性ルール」の骨格を理解することだ。

前提条件は一つだけ。自分のローカル環境にcodex CLIをインストールしてログインしておくこと。自分のOpenAIアカウントを使えばいい。codexはOpenAIのターミナルツールであり、Claudeとは別の系統だ。そして、まさにこの「血統の違い」こそが、セカンドオピニオンに向いている理由になる。

この設計では、codexは読み取り専用のサンドボックスで動く。読むだけで、何も書き換えない。スクリプト自体はキーを含まず、ネットワークも叩かない。

手順は三ステップだけだ。

  1. 付録のSKILL.md~/.claude/skills/codex-second-opinion/SKILL.mdに保存する。
  2. 付録のcodex-review.shを同じフォルダに保存する。
  3. Claude Codeで「src/auth.jsのトークン検証をcodexで独立に審査して」のように一言伝える。するとこのラッパーが走り、codexが指定したコードを読んで指摘を挙げ、その結果をClaude Codeに持ち帰る。最終的な判断は依然としてあなたのものだ。突き合わせ、コードを読み、自分で決める。

最後に二つ注意しておきたい。これがこの記事の本当に言いたいことでもある。

一つ目。問いかけに自分の結論を混ぜないこと。「問題ないと思うが確認して」のような言い方は、モデルを自分の前提に同意させてしまいやすい。あなたが欲しいのは独立した審査であって、礼儀としての追認ではない。

二つ目。的確に審査してくれるほど、自分でコードを読み返す必要が増す。立ち止まる価値があるのは、それがあなたの判断と食い違うところであって、あなたの代わりに押してくれる承認の判子ではない。


付録:完全な実装

二つのファイル、コピーして貼れば動く。スクリプトは短い。走らせる前に自分で読める。あの四つの独立性ルールをデフォルトの動作に落とし込んだだけで、毎回の審査が記憶に頼らないようにしてある。

SKILL.md Claude Codeが「セカンドオピニオン」で自動的に呼び出すため(クリックでコピー)
---
name: codex-second-opinion
description: Get an INDEPENDENT second opinion on code, data, or a design by having codex (a different model) review it — without it just agreeing with you. Use when the user asks for a "second opinion", to "have codex review/check this", an "independent review", "cross-check", or to audit security-critical or complex code before trusting it. Trigger words include 第二意見, 獨立審查, 讓 codex 看一下, 交叉驗證, セカンドオピニオン, codex review, double-check this. Requires the codex CLI (logged in) installed locally. Do NOT use for applying fixes — this only surfaces problems; you decide what to do.
allowed-tools: Bash(bash:*)
---

# codex second opinion

Bring in codex (a different model from a different training regime) as an **independent**
reviewer of work — code, data, or design. The whole value is independence: a model reviewing
its own output misses its own blind spots. This skill protects that independence with four rules
so the second opinion does not degrade into agreement.

You run the bundled read-only wrapper `codex-review.sh`. codex runs in a read-only sandbox and
never edits files; it only reports problems. **You** do the final cross-check and decide.

## When to use
- The user asks for a "second opinion", "independent review", "cross-check", or to "have codex look at this".
- Before trusting security-critical code (auth / crypto / payments) or complex logic (race conditions, N+1, deadlocks).
- To sanity-check the credibility of data or an analysis.

## How to run

1. Figure out the target: a path in the project (`--target <path>`) or a snippet/pipeline output (`--stdin`).
2. Write the **review focus** as a neutral assertion or standard to check. Critical: do NOT put your
   own conclusion in it. "Review the token check for timing attacks and KV write races" — NOT
   "I already checked the auth, just confirm it's fine" (that taints codex's independence; the
   wrapper will warn you if you do).
3. Run the wrapper (default reasoning effort is medium; raise to high/xhigh only for security-critical
   or genuinely complex targets):

   ```bash
   # review a file
   bash ~/.claude/skills/codex-second-opinion/codex-review.sh \
     --target src/auth.js "Review token validation, timing attacks, and KV write races"

   # review a snippet / pipeline output via stdin
   cat data.json | bash ~/.claude/skills/codex-second-opinion/codex-review.sh \
     --stdin "Review this data's credibility and field completeness"

   # security-critical + a durable audit record under ./codex-audits/
   bash ~/.claude/skills/codex-second-opinion/codex-review.sh --effort high \
     --target src/payment.ts --audit payment "Review for double-charge and idempotency gaps"
   ```

4. If the wrapper exits non-zero (codex missing / timed out / blank output), do NOT retry or pretend.
   Tell the user this is a single opinion only, and stop.

5. On success, do the cross-check **yourself** (this is the part the wrapper deliberately does not do):
   read codex's findings, compare them against your own reading of the code, and split them into
   **agreed** and **disagreed**. For anything you disagree on, read the code and decide — do not just
   relay what codex said. Treat codex as a probe, not an oracle: a finding both of you reach is almost
   certainly real; a finding only one of you reached needs your own judgment.

## Notes
- No API keys involved — codex uses your own OpenAI/ChatGPT login via the local `codex` CLI.
- The only writes are a log under /tmp and, with `--audit`, a record under `./codex-audits/`.
- These rules are scaffolding for today's models. If a model becomes independent and honest enough
  on its own, drop the rule it was patching rather than keeping it as ritual.
- This is a template — adapt the trigger words, the reviewer model, the paths, and the rules to
  your own workflow. The idea is the four-rule independence protocol, not this exact wording.
codex-review.sh 審査ラッパー、約220行(クリックでコピー)
#!/usr/bin/env bash
# codex-review.sh — a "second opinion" wrapper that has codex review code/data/design
#                   written by another model (e.g. Claude), as an INDEPENDENT reviewer.
#
# Why this exists: a model reviewing its own output tends to miss its own blind spots,
# and tends to nod along with its prior judgments. A model from a different training
# regime (codex / gpt-5.5) can catch what the first one missed — but only if you protect
# its independence. This script bakes four rules into the default behavior:
#   #1 Independence : the prompt forces codex to evaluate on its own, never assume a prior
#                     reviewer was right, never agree just to agree (see build_prompt).
#   #2 Fail fast    : codex missing / times out / exits non-zero / returns blank → it
#                     degrades to "single opinion", tells you, and STOPS. No silent retries.
#   #3 Protocol     : (a) the prompt carries none of YOUR conclusions  (b) raw output is
#                     logged  (c) codex only describes problems + severity, never edits code
#                     (d) you do the cross-check yourself — this script only does (a)(b)(c).
#   #4 Cost         : reasoning effort defaults to "medium"; raise with --effort only when
#                     a real security/complexity signal warrants it.
#
# SAFETY (read before you run):
#   • codex runs in a READ-ONLY sandbox (`-s read-only`): it can read the files you point it
#     at, but it cannot modify, delete, or write anything in your project.
#   • This script contains NO API keys. codex authenticates with YOUR OWN OpenAI/ChatGPT
#     login (whatever your local `codex` CLI is already configured with).
#   • The only files this script writes are a log under /tmp and, if you pass --audit, a
#     markdown record under ./codex-audits/ in your current directory. Nothing else.
#   • No network calls of its own, no eval, no curl|bash. Read the whole thing — it's short.
#
# PREREQUISITES:
#   • The `codex` CLI installed and logged in (https://developers.openai.com/codex/cli).
#   • bash + perl (perl only needed if you use --timeout; preinstalled on macOS/Linux).
#
# USAGE:
#   bash codex-review.sh [options] "<review focus>"
#   echo "<content to review>" | bash codex-review.sh --stdin "<review focus>"
#
# OPTIONS:
#   --target <path>   file/dir for codex to read (repeatable; read in the read-only sandbox)
#   --stdin           read the content to review from stdin (good for snippets / pipeline data)
#   --dir <path>      directory codex runs in (default: current directory)
#   --effort LEVEL    low|medium|high|xhigh  (default: medium)                       [rule #4]
#   --audit <slug>    also write a durable record to ./codex-audits/<slug>-<date>.md  [rule 3b]
#   --timeout <sec>   max seconds before giving up (default 0 = no limit; uses perl) [rule #2]
#   --model <id>      override codex model (default: whatever your codex config uses)
#   -h | --help
#
# EXIT CODES: 0 ok & non-empty / 2 usage error / 3 codex missing / 4 codex failed or empty
#             / 124 timeout. (3/4/124 = the "single opinion" degrade path.)
#
# License: MIT — free to use, modify, and adapt into your own version. No attribution required.
#
# This is a generic, self-contained template. It assumes nothing about your project layout,
# names no tools or services beyond the `codex` CLI, and stores no identity. Make it yours:
# change the rules, the prompt, the paths, the model — the four-rule structure is the idea,
# not the exact wording.
set -uo pipefail

WORKDIR="$(pwd)"
TS="$(date +%Y%m%d-%H%M%S)"
DATE="$(date +%Y-%m-%d)"

EFFORT="medium"
declare -a TARGETS=()
USE_STDIN=0
AUDIT_SLUG=""
TIMEOUT=0
MODEL=""
FOCUS=""

usage() { sed -n '2,57p' "$0"; exit "${1:-0}"; }
# Guards for value-taking options: (1) bail gracefully instead of a set -u unbound crash when
# the value is missing; (2) if the next token looks like another option (-?*), the value was
# probably forgotten — error out instead of silently misparsing.
req() {
  [ "$2" -ge 2 ] || { echo "ERROR: $1 needs a value" >&2; exit 2; }
  case "$3" in -?*) echo "ERROR: the value for $1 looks like another option ($3) — did you forget the value?" >&2; exit 2 ;; esac
}

while [ $# -gt 0 ]; do
  case "$1" in
    --target)   req "$1" "$#" "${2:-}"; TARGETS+=("$2"); shift 2 ;;
    --stdin)    USE_STDIN=1; shift ;;
    --dir)      req "$1" "$#" "${2:-}"; WORKDIR="$2"; shift 2 ;;
    --effort)   req "$1" "$#" "${2:-}"; EFFORT="$2"; shift 2 ;;
    --audit)    req "$1" "$#" "${2:-}"; AUDIT_SLUG="$2"; shift 2 ;;
    --timeout)  req "$1" "$#" "${2:-}"; TIMEOUT="$2"; shift 2 ;;
    --model)    req "$1" "$#" "${2:-}"; MODEL="$2"; shift 2 ;;
    -h|--help)  usage 0 ;;
    --) shift
        if [ $# -gt 1 ]; then echo "ERROR: multiple positional args after -- ; wrap the focus in one quoted string" >&2; exit 2; fi
        [ $# -ge 1 ] && FOCUS="$1"; break ;;
    -*) echo "Unknown option: $1" >&2; usage 2 ;;
    *)  if [ -n "$FOCUS" ]; then echo "ERROR: multiple review-focus positional args; wrap the focus in one quoted string" >&2; exit 2; fi
        FOCUS="$1"; shift ;;
  esac
done

# --- validation ---
case "$EFFORT" in low|medium|high|xhigh) ;; *) echo "ERROR: --effort must be low|medium|high|xhigh (got: $EFFORT)" >&2; exit 2 ;; esac
case "$TIMEOUT" in ''|*[!0-9]*) echo "ERROR: --timeout must be a non-negative integer of seconds (got: $TIMEOUT)" >&2; exit 2 ;; esac
if [ -z "$FOCUS" ]; then echo "ERROR: missing <review focus> (the last positional argument)" >&2; usage 2; fi
if [ "${#TARGETS[@]}" -eq 0 ] && [ "$USE_STDIN" -eq 0 ]; then
  echo "ERROR: need at least one --target <path> or --stdin" >&2; usage 2
fi

# rule #2: codex missing = fail fast to the single-opinion path. No retry, no pretending.
if ! command -v codex >/dev/null 2>&1; then
  echo "DEGRADE: no 'codex' CLI found on this machine (not installed / broken). Honestly note this is a single opinion and stop. Install: https://developers.openai.com/codex/cli" >&2
  exit 3
fi

STDIN_CONTENT=""
if [ "$USE_STDIN" -eq 1 ]; then STDIN_CONTENT="$(cat)"; fi

# rule #3(a) soft guard: warn if the focus carries YOUR conclusion (which would taint codex's
# independence). Warn only, never block. Matches common English/Chinese "already checked" phrasings.
if printf '%s' "$FOCUS" | grep -qiE 'i already|already (checked|verified|confirmed|reviewed)|no (bug|issue|problem)|looks (fine|good|correct)|should be (fine|ok|correct)|我已|已檢查|已確認|沒問題|應該沒'; then
  echo "WARNING (rule a): your review focus looks like it carries your own conclusion (e.g. \"already checked / no issues\")." >&2
  echo "    codex should judge independently — restate it as a neutral \"what to review / what the bar is\", don't feed it your verdict." >&2
fi

# --- build the prompt (rules a + c: independent framing + describe-only, no code edits) ---
build_prompt() {
  local stdin_block=""
  if [ "$USE_STDIN" -eq 1 ]; then
    stdin_block=$'\n## Inlined target content\n```\n'"$STDIN_CONTENT"$'\n```\n'
  fi
  local target_lines=""
  if [ "${#TARGETS[@]}" -gt 0 ]; then
    target_lines="## Review targets (read these yourself in the read-only sandbox)"$'\n'
    local t
    for t in "${TARGETS[@]}"; do target_lines+="- $t"$'\n'; done
  fi
  cat <<EOF
You are an independent second-opinion reviewer (codex / gpt-5.5). Evaluate the target entirely on your own: do not assume any other reviewer (human or AI) has already checked anything. Your judgment must come only from what you read yourself.

$target_lines$stdin_block
## Review focus (the original request)
$FOCUS

## Output rules (follow strictly)
1. Only describe "problem + severity (high/medium/low)". Do not rewrite code, do not apply fixes, do not output diffs.
2. One finding per item: problem / location (file:line) / severity / why it is a problem / your confidence.
3. Where you judge there is no problem, say "no finding" — do not invent issues to pad the list.
4. Do not rely on or agree with any external conclusion; be faithful only to the facts you read yourself.
EOF
}

PROMPT="$(build_prompt)"

# --- assemble the codex command ---
LOG="/tmp/codex-review-${TS}.log"
LASTMSG="/tmp/codex-review-${TS}.last.md"
declare -a CMD=(codex exec --skip-git-repo-check -s read-only -C "$WORKDIR"
                -c "model_reasoning_effort=\"$EFFORT\"" -o "$LASTMSG")
[ -n "$MODEL" ] && CMD+=(-m "$MODEL")
CMD+=("$PROMPT")

# perl alarm wrapper (macOS has no `timeout` binary). Exit codes are faithfully propagated:
# timeout=124, signal-killed=128+sig (so a killed child is NOT misreported as success),
# exec failure=1, else the child's exit code. TIMEOUT=0 → prefix is empty, run directly.
declare -a TPREFIX=()
if [ "$TIMEOUT" -gt 0 ]; then
  TPREFIX=(perl -e 'my $t=shift; my $rc; eval { local $SIG{ALRM}=sub{die "TIMEOUT\n"}; alarm $t; $rc=system(@ARGV); alarm 0; }; if($@ eq "TIMEOUT\n"){exit 124} if($rc==-1){exit 1} if($rc & 127){exit(128+($rc & 127))} exit($rc>>8);' "$TIMEOUT")
fi
runit() { if [ "${#TPREFIX[@]}" -gt 0 ]; then "${TPREFIX[@]}" "$@"; else "$@"; fi; }

echo "codex-review: effort=$EFFORT  targets=[${TARGETS[*]:-stdin}]  dir=$WORKDIR  log=$LOG"

# --- run (rule b: raw output goes to the log) ---
runit "${CMD[@]}" 2>&1 | tee "$LOG"
rc="${PIPESTATUS[0]}"

# rule #2: "done" = exit 0 AND a non-empty final message. A half-success must not be silently
# reported as success.
if [ "$rc" -eq 124 ]; then
  echo "DEGRADE: codex timed out after ${TIMEOUT}s. No retry. Note it's a single opinion and tell the human. log=$LOG" >&2
  exit 124
fi
if [ "$rc" -ne 0 ]; then
  echo "DEGRADE: codex exited non-zero (rc=$rc, incl. signal-killed). No retry. Single opinion only. log=$LOG" >&2
  exit 4
fi
# The trustworthiness invariant is "the final message (-o) has non-whitespace content", NOT
# "the log is non-empty" (the log always contains the codex banner). Blank/missing = no real
# review happened = treat as failure.
if ! grep -q '[^[:space:]]' "$LASTMSG" 2>/dev/null; then
  echo "DEGRADE: codex exited 0 but the final message is blank/missing (half-success, no trustworthy review). Treating as failure. log=$LOG" >&2
  exit 4
fi

# --- rule 3(b) durable: --audit writes a record (ensure dir first, verify non-empty before claiming success) ---
if [ -n "$AUDIT_SLUG" ]; then
  AUDIT_DIR="$WORKDIR/codex-audits"
  AUDIT="$AUDIT_DIR/${AUDIT_SLUG}-${DATE}.md"
  mkdir -p "$AUDIT_DIR"
  if {
    echo "---"
    echo "source: codex-review.sh"
    echo "date: $DATE"
    echo "effort: $EFFORT"
    echo "targets: ${TARGETS[*]:-(stdin)}"
    echo "raw_log: $LOG"
    echo "---"
    echo ""
    echo "# codex second-opinion raw output — ${AUDIT_SLUG}"
    echo ""
    echo "**Review focus**: $FOCUS"
    echo ""
    echo '```'
    cat "$LASTMSG"
    echo '```'
  } >"$AUDIT" && [ -s "$AUDIT" ]; then
    echo "audit record: $AUDIT"
  else
    echo "WARNING: failed to write audit record: $AUDIT" >&2
  fi
fi

# --- rule (d) reminder: YOU do the cross-check, splitting "agreed" vs "disagreed" ---
echo ""
echo "OK: codex finished (rc=0). raw log: $LOG"
echo "    final message: $LASTMSG"
echo "Next (rule d, you do this): independently cross-check codex's findings against your own"
echo "    judgment. Split them into \"agreed\" and \"disagreed\", each with a reason. For"
echo "    disagreements, read the code yourself and decide — don't just relay what codex said."

この記事は方法論だ。次の三本がその骨格になる: