feat(skill): refresh adversarial-review под Codex 0.132

- Зачем:
  - актуализация под новый Codex CLI (0.132 убрал флаг -a,
    ввёл -c approval_policy / -c approvals_reviewer);
  - переход на безопасные операторские дефолты
    (sandbox=workspace-write для эмпирической верификации,
    явные overrides sandbox:* и approvals:*);
  - наведение порядка в принятии решений по раунду ревью:
    review_quality + evaluation matrix + structural operator gate
    вместо «оператор сам разбирается».
- Что:
  - SKILL.md: override-граммар (sandbox:*, approvals:*, model:*,
    low/medium/high/xhigh), детект OPERATOR_LANGUAGE, runtime hint,
    conditional dirty-file warning в Step 2 (после захвата REPO_ROOT),
    dual-layer mutation snapshots (git status + sha256sum input-файлов),
    operation-aware dispatch table, evaluation matrix + structural
    operator gate (batch-pause), structured resume body
    (Applied / Re-scoped / Rejected / Specific asks), final operator
    summary на OPERATOR_LANGUAGE.
  - references/runner.md: переведён на Sonnet runner, добавлен
    Step R2.5 bwrap preflight, Step R4.5 review_quality + bounded
    triage, расширена 11-полевая JSON-схема результата.
  - docs/DESIGN.md: §4.14–§4.21 с обоснованиями новых решений,
    §7.8 refresh-era smoke checks, §8 version log с двумя раундами
    dogfood-а этого refresh-а (включая R2-корректировку
    обоснования residual gap для уже-грязных tracked-файлов).
  - README.md: таблица дефолтов, Safety considerations (честно
    задокументирован residual gap), Linux sandbox prerequisites
    (bwrap + AppArmor user namespaces), Operator language,
    Final operator summary, troubleshooting.
  - examples/review-output.md: модель в сэмпле обновлена на gpt-5.5.
  - docs/superpowers/specs/2026-05-20-...: сохранена спека дизайна
    с уточнениями после dogfood.
- Проверка:
  - dogfood: 2 раунда /adversarial-review code на этом refresh-е,
    R2 верифицировал R2#1 (ordering) и R2#2 (Option B, honest
    residual gap);
  - smoke: codex --version ≥ 0.132.0, bwrap preflight зелёный
    на reference WSL2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-21 09:56:08 +03:00
co-authored by Claude Opus 4.7
parent 983a7a04ff
commit 1237e168c3
6 changed files with 2085 additions and 106 deletions
+325 -13
View File
@@ -75,6 +75,10 @@ If Codex is missing: `npm install -g @openai/codex`
- Sign in interactively: `codex` (opens browser)
- Or set `CODEX_API_KEY` env var for non-interactive use
**Codex CLI version.** The skill targets Codex CLI ≥ 0.132.0. From 0.132 onward the top-level `-a` / `--ask-for-approval` flag is gone from `codex exec`; approval policy is expressed only via `-c approval_policy=...`. The skill emits the `-c` form unconditionally. If you are stuck on an older Codex CLI, upgrade before using the refreshed defaults.
**Linux sandbox prerequisites.** The default sandbox (`workspace-write`) relies on `bubblewrap` (`bwrap`) and unprivileged user namespaces. See the [Linux sandbox prerequisites](#linux-sandbox-prerequisites) section below — Ubuntu 24.04+ requires installing an AppArmor profile.
### 2. Install the skill
```bash
@@ -113,9 +117,10 @@ chosen config file:
```jsonc
// --- adversarial-review permissions ---
// Git: diff, status, branch detection, repo root, submodule check
// Git: diff, status, branch detection, repo root, submodule check, scoped status snapshots
"Bash(git diff*)",
"Bash(git status*)",
"Bash(git -C * status --porcelain*)",
"Bash(git symbolic-ref*)",
"Bash(git rev-parse*)",
// Codex: initial launch (uses -C; prompt fed via cat | pipe for env portability)
@@ -126,6 +131,19 @@ chosen config file:
"Bash(find ~/.codex/sessions*)",
// Diagnostic aid when filesystem fallback finds nothing
"Bash(ls -t ~/.codex/sessions*)",
// Sandbox preflight probe (runner subagent runs this on every initial / fresh-exec when CODEX_SANDBOX uses bwrap)
"Bash(bwrap --dev-bind / / --unshare-net /bin/echo ok*)",
// Workspace mutation snapshots (main thread, per dispatch)
"Bash(sha256sum /tmp/codex-*)",
"Bash(diff -q /tmp/codex-*)",
"Write(/tmp/codex-git-pre-*)",
"Write(/tmp/codex-git-post-*)",
"Write(/tmp/codex-inputs-pre-*)",
"Write(/tmp/codex-inputs-post-*)",
"Read(/tmp/codex-git-pre-*)",
"Read(/tmp/codex-git-post-*)",
"Read(/tmp/codex-inputs-pre-*)",
"Read(/tmp/codex-inputs-post-*)",
// Temp files: prompts (initial + resume), plans, review output, JSONL stdout, stderr
"Write(/tmp/codex-plan-*)",
"Write(/tmp/codex-prompt-*)",
@@ -138,13 +156,16 @@ chosen config file:
"Bash(mv /tmp/codex-stderr-* /tmp/codex-stderr-*-failed-resume.txt)",
// Cleanup
"Bash(rm -f /tmp/codex-*)",
// Main thread: write prompt body for the runner subagent (NEW in refactor)
// Main thread: write prompt body for the runner subagent
"Write(/tmp/codex-body-*)",
// Main thread: read the structured JSON result returned by the runner (NEW)
// Main thread: write resume body (structured Applied / Re-scoped / Rejected)
"Write(/tmp/codex-resume-body-*)",
// Main thread: read the structured JSON result returned by the runner
"Read(/tmp/codex-runner-result-*)",
// Runner subagent (inherited): read the prompt body main wrote (NEW)
// Runner subagent (inherited): read the prompt body main wrote
"Read(/tmp/codex-body-*)",
// Runner subagent (inherited): write the result JSON main reads (NEW)
"Read(/tmp/codex-resume-body-*)",
// Runner subagent (inherited): write the result JSON main reads
"Write(/tmp/codex-runner-result-*)",
// Runner-spec discovery: tier 1 (user-scoped install)
"Bash(ls ~/.claude/skills/adversarial-review/references/runner.md*)",
@@ -162,12 +183,24 @@ chosen config file:
// adversarial-review
"Bash(git diff*)",
"Bash(git status*)",
"Bash(git -C * status --porcelain*)",
"Bash(git symbolic-ref*)",
"Bash(git rev-parse*)",
"Bash(cat /tmp/codex-prompt-* | timeout 600 codex exec *)",
"Bash(cd * && cat /tmp/codex-resume-prompt-* | timeout 600 codex exec resume *)",
"Bash(find ~/.codex/sessions*)",
"Bash(ls -t ~/.codex/sessions*)",
"Bash(bwrap --dev-bind / / --unshare-net /bin/echo ok*)",
"Bash(sha256sum /tmp/codex-*)",
"Bash(diff -q /tmp/codex-*)",
"Write(/tmp/codex-git-pre-*)",
"Write(/tmp/codex-git-post-*)",
"Write(/tmp/codex-inputs-pre-*)",
"Write(/tmp/codex-inputs-post-*)",
"Read(/tmp/codex-git-pre-*)",
"Read(/tmp/codex-git-post-*)",
"Read(/tmp/codex-inputs-pre-*)",
"Read(/tmp/codex-inputs-post-*)",
"Write(/tmp/codex-plan-*)",
"Write(/tmp/codex-prompt-*)",
"Write(/tmp/codex-resume-prompt-*)",
@@ -178,8 +211,10 @@ chosen config file:
"Bash(mv /tmp/codex-stderr-* /tmp/codex-stderr-*-failed-resume.txt)",
"Bash(rm -f /tmp/codex-*)",
"Write(/tmp/codex-body-*)",
"Write(/tmp/codex-resume-body-*)",
"Read(/tmp/codex-runner-result-*)",
"Read(/tmp/codex-body-*)",
"Read(/tmp/codex-resume-body-*)",
"Write(/tmp/codex-runner-result-*)",
"Bash(ls ~/.claude/skills/adversarial-review/references/runner.md*)",
"Bash(ls ~/.claude/plugins/cache/*/*/*/skills/adversarial-review/references/runner.md*)"
@@ -191,10 +226,13 @@ chosen config file:
</details>
**Security note:** The `codex exec` rule allows any `codex exec` invocation
wrapped in `timeout 600`. The skill only uses read-only mode (`-s read-only`),
but Claude Code's permission patterns are prefix-based and cannot enforce flag
constraints. If you prefer tighter control, omit the `codex exec` rule and
approve each invocation manually.
wrapped in `timeout 600`. The default sandbox is `workspace-write` (the reviewer
needs to run tests, builds, and CLI introspection to verify findings — read-only
blocks all of that). Reviewer-side mutation is governed by the prompt-level
"auditor, not contributor" contract plus pre/post `git status --porcelain` and
`sha256sum` snapshots on every dispatch. If you prefer tighter control, see the
[Safety considerations](#safety-considerations) section below for the
`sandbox:read-only` opt-out and the worktree-isolation pattern.
### 4. Use
@@ -204,9 +242,24 @@ approve each invocation manually.
/adversarial-review code # force code review
/adversarial-review path/to/f # review a specific file
/adversarial-review xhigh # higher reasoning effort
/adversarial-review model:gpt-5.3-codex # use a different model
/adversarial-review model:gpt-5.4 # use a different model
/adversarial-review sandbox:read-only # block reviewer writes (loses empirical verification)
/adversarial-review approvals:never # boundary crossings fail instead of asking
```
Overrides can be combined: `/adversarial-review plan xhigh sandbox:read-only`.
### Defaults
| Setting | Default | Override |
|---------------------|------------------------------------------------|-----------------------------------------------------------------------------------------|
| Reviewer model | `gpt-5.5` | `model:<name>` |
| Reasoning effort | `high` | `low` / `medium` / `high` / `xhigh` |
| Codex sandbox | `workspace-write` | `sandbox:read-only` / `sandbox:workspace-write` / `sandbox:danger-full-access` / `sandbox:inherit` |
| Approval policy | `on-request` with `auto_review` reviewer | `approvals:user` / `approvals:auto_review` / `approvals:never` |
| Max rounds | `5` | not configurable |
| Operator language | auto-detected from recent messages, fallback English | not configurable |
## Prompt architecture
The skill uses XML-structured prompts with adversarial stance:
@@ -224,13 +277,269 @@ The skill uses XML-structured prompts with adversarial stance:
See [examples/review-output.md](examples/review-output.md) for a sample review.
## Safety considerations
The default sandbox is `workspace-write`, not `read-only`. This is a deliberate
trade-off: the reviewer needs to run tests, builds, project CLIs, MCP doc
lookups, and web searches to produce findings worth more than a same-model
self-check. Read-only blocks all of that.
Reviewer-side mutation is governed by three layers:
1. **Prompt-level contract** — every review prompt includes a
`<reviewer_permissions>` block that constrains the reviewer to read +
verify, not edit. The reviewer must report mutation as a limitation
instead of performing it.
2. **Tracked-tree status detection** — main captures `git status --porcelain`
before and after every Codex dispatch. New modifications, new untracked
files, or status transitions (e.g. clean → modified) on tracked files
trigger a hard stop before fixes are applied. This catches the common
case where the reviewer touches a previously-clean tracked file.
3. **Review-input detection** — main captures `sha256sum` of
`/tmp/codex-{body,plan,resume-body}-*` before and after every dispatch.
Any change is treated identically to tracked-file mutation.
### Residual risk: already-dirty tracked files
`git status --porcelain` records status codes, not content hashes. If a
tracked file was already modified (`M`) pre-dispatch and the reviewer
mutates the same file again, the porcelain line stays ` M file`
the status snapshot diff is empty, and main does not hard-stop.
**This is an accepted residual safety gap.** Workspace writes are
permitted by the `workspace-write` sandbox and do NOT generate an
approval request; the `approval_policy=on-request` + `auto_review`
machinery only reviews approval requests, so it never sees these
writes. The single protection layer at the skill level is the
`<reviewer_permissions>` prompt contract telling the reviewer not to
modify project files. The realistic vector is a reviewer-invoked
verification command with an unintended side effect — a formatter,
snapshot updater (`pytest --update-snapshots`, jest `--ci=false`),
lockfile regeneration (`npm install`, `cargo update`), or code
generator — that legitimately runs but writes to a file the operator
was already editing. Damage is bounded (the mutation remains visible
in `git diff` after the review concludes), but the skill does not
hard-stop at "apply fixes" time.
Mitigations available to the operator:
1. **Runtime warning** — at the start of every review, if `git status
--porcelain` shows any already-modified tracked files, the skill
emits a warning naming the count and pointing operators to the
options below.
2. **Commit (or stash) before review** — the simplest defense. A
review of branch commits against `master` with a clean working tree
is fully covered by the porcelain snapshot; any reviewer-side
mutation produces a fresh ` M` line and trips the hard-stop.
3. **`sandbox:read-only` opt-out** — when the working file matters more
than empirical verification by the reviewer, switch to read-only.
Same trade-off as for gitignored state below.
If this risk class hits in practice, the design notes a clear path
to a content-aware snapshot — see `docs/DESIGN.md §4.20`.
### Residual risk: gitignored state inside REPO_ROOT
There is one mutation vector that the snapshots do NOT detect:
`.gitignored` files already present inside `REPO_ROOT`. Examples include
local SQLite databases (`dev.sqlite`), `.env.local`, service-state
directories, and build caches. `git status` ignores them by definition,
and full-tree snapshotting would be too expensive to run every round.
The realistic exposure is the reviewer running a project test or build
command that side-effects an ignored file — for example `pytest`
triggering an unintended migration on `dev.sqlite` because the test
settings point at it. The damage is bounded (the state is re-seedable;
tests generally read `.env.local`, they do not write to it), but it is
real on default `workspace-write` reviews.
Three operator-facing mitigations:
1. **`sandbox:read-only` opt-out** — operators who know they have
sensitive ignored state can opt out per-run:
```bash
/adversarial-review sandbox:read-only
```
**Trade-off:** the reviewer loses empirical verification — it cannot
run tests, linters, builds, project CLIs, or most MCP-backed
verification. You trade reviewer capability for write-protection.
Use when the sensitivity of the local state outweighs the value of
empirical findings.
2. **Worktree isolation** — for repositories where the trade-off above is
unacceptable, run the review in an isolated git worktree:
```bash
git worktree add /tmp/review-worktree HEAD
cd /tmp/review-worktree
/adversarial-review
# ... when done ...
cd -
git worktree remove /tmp/review-worktree
```
The worktree shares git history but has its own working tree — the
reviewer can run tests freely, and any gitignored state lives in
`/tmp/review-worktree`, not in your primary checkout. This is the
recommended pattern for sensitive repos.
**Important — committed work only.** `git worktree add … HEAD` creates a
clean worktree at the HEAD commit and does NOT transfer unstaged or
staged changes from your primary checkout. If your WIP is uncommitted,
the review will only see branch commits (`master...HEAD`) and silently
skip your local edits. Commit (or `git stash`) before running the
recipe, and double-check with `git status --short` inside the new
worktree to confirm what the review will cover.
3. **Runtime hint** — at the start of every review (unless an explicit
`sandbox:*` override was passed), the skill emits a one-line reminder:
```
workspace-write in effect; pass sandbox:read-only if sensitive
ignored state lives under REPO_ROOT.
```
This is a deliberate trade-off. Defaulting reviews to `read-only` or to
an isolated worktree would gut the reviewer's empirical verification
capability — which is precisely what makes adversarial cross-model
review more valuable than a same-model self-check.
## Linux sandbox prerequisites
With the default `workspace-write` sandbox, Codex relies on `bubblewrap`
(`bwrap`) and unprivileged user namespaces. On Ubuntu 24.04+ this is
restricted by AppArmor and needs explicit setup.
**Probe whether bwrap works on your host:**
```bash
bwrap --dev-bind / / --unshare-net /bin/echo ok
```
If this prints `ok`, you're done. If it fails (typical errors:
`bwrap: setting up uid map: Permission denied`, or
`bwrap: clone: Operation not permitted`), apply the official bwrap
AppArmor profile:
```bash
sudo apt install -y apparmor-profiles apparmor-utils
sudo install -m 0644 /usr/share/apparmor/extra-profiles/bwrap-userns-restrict \
/etc/apparmor.d/bwrap-userns-restrict
sudo apparmor_parser -r /etc/apparmor.d/bwrap-userns-restrict
```
Then re-run the probe:
```bash
bwrap --dev-bind / / --unshare-net /bin/echo ok
```
If the probe still fails, see the official Codex sandboxing documentation:
<https://developers.openai.com/codex/concepts/sandboxing>.
**For installer agents:** do NOT change AppArmor policy silently. Probe
first, show the exact `apt install` / `install` / `apparmor_parser`
commands, request explicit operator permission, apply the profile only
after approval, and re-run the probe.
**Per-dispatch preflight.** The runner subagent runs the same `bwrap`
probe before every initial / fresh-exec dispatch that selects a
bwrap-backed sandbox mode (`read-only` or `workspace-write`). If the
probe fails, the runner returns a `success + degraded_environmental`
result with a one-line `user_warning` pointing back to this section,
which the lead surfaces and treats as terminal. The preflight is
skipped under `sandbox:inherit` (effective sandbox is unknown until
Codex launches) and under `sandbox:danger-full-access` (no bwrap).
## Operator language
The skill detects the operator's language from recent conversation
messages and translates runtime prose accordingly: the runtime hint,
the structural-gate prompt, the workspace-mutation diagnostics, the
final operator summary, and ad-hoc warnings.
Machine-readable literals stay in English regardless:
- Severity tags: `[severity: critical|high|medium]`
- Verdict line: `VERDICT: APPROVED` / `VERDICT: REVISE`
- Review section headers: `Summary`, `Findings`, `Verdict`
Repository documentation (this README, `SKILL.md`, `references/runner.md`,
`docs/DESIGN.md`, specs under `docs/superpowers/specs/`) is always in
English. If you contribute changes, keep documentation paragraphs in a
single language.
## Final operator summary
Every terminal state — approved, max rounds reached, not verified, or
aborted — produces a final operator-facing summary in the operator's
language, emitted AFTER the canonical per-state header block and AFTER
the final verbatim reviewer response (where one exists).
The summary covers:
- Final status and what it means for what the operator should do next.
- What changed across all rounds (compact, no full diffs).
- Findings applied / re-scoped / rejected, with focus on rejections
and structural changes.
- Whether structural fixes received operator sign-off (or were applied
in autonomous / headless mode).
- Verification performed by the reviewer vs. by the lead vs. still
unverified.
- Remaining findings or risks (for non-approved terminal states).
The summary is built from per-round decision accounts already shown
earlier in the conversation. Main never reads Codex stdout, stderr, or
rollout files to assemble it. If context compaction has obscured part
of the history, the summary states that explicitly rather than
fabricating details.
## Troubleshooting
**`codex exec` exits with model error.**
Some models are unavailable with ChatGPT accounts (e.g. `o3-mini`).
The default `gpt-5.4` works with both ChatGPT and API key auth.
The default `gpt-5.5` works with both ChatGPT and API key auth.
Override with `/adversarial-review model:<name>`.
**`codex exec` rejects `-c approval_policy=...` or `-c approvals_reviewer=...`.**
You are on a Codex CLI older than 0.132. Upgrade
(`npm install -g @openai/codex@latest`). The skill emits the `-c` form
unconditionally because the top-level `-a` / `--ask-for-approval` flag was
removed in 0.132.
**Review aborts with "Reviewer or runner mutated tracked files during dispatch".**
The pre/post `git status --porcelain` snapshot detected changes to tracked
files between dispatch start and runner return. This is a HARD STOP — the
artifact under review may have been silently mutated. Inspect the diff
shown in the diagnostic, decide whether to keep or revert manually, and
re-invoke `/adversarial-review` when the working tree is in the state you
expect. If you suspect a specific verification command in the reviewer's
toolchain is responsible (test runner doing a migration, build script
regenerating a file), pass `sandbox:read-only` next time.
**Review aborts with "ABORTED — environmental failure before any valid review".**
The initial Codex dispatch returned a `degraded_environmental` review (the
reviewer self-reported it could not run because of sandbox or environment
failure). Common causes on Linux: `bwrap` not installed, AppArmor
restricting unprivileged user namespaces, or a rate-limit / trust-prompt
stub from Codex. Run the [Linux sandbox prerequisites](#linux-sandbox-prerequisites)
probe and apply the AppArmor profile if needed.
If the failure is the bwrap preflight specifically, `sandbox:read-only` does
NOT bypass it — `read-only` is bwrap-backed and runs the same probe. The
actual bypass options are `sandbox:danger-full-access` (no bwrap, only use
in trusted local debugging), `sandbox:inherit` (trust your local Codex
config), or fixing bwrap/AppArmor per the prerequisites section.
**`degraded_environmental` on resume.**
The resume produced a non-actionable review (typically a sandbox or
rate-limit issue mid-loop). The skill does NOT count it as a round and
routes through the Step 7.4 fallback chain using the prior round's
severity. If the fallback's fresh-exec also returns
`degraded_environmental`, the review terminates as `NOT VERIFIED`.
**Permission prompts on every action.**
Add the permissions from the [setup section](#3-add-permissions). Check that
the file is valid JSON and in the right location (project `.claude/settings.local.json`
@@ -293,8 +602,11 @@ review correctness.
- **Plan Mode and `/tmp` writes.** Writing review prompts to `/tmp` may trigger
a permission prompt or cause Plan Mode to exit. Does not affect review correctness.
- **`resume` inherits sandbox.** `codex exec resume` does not accept `-s`
sandbox is inherited from the original session (always `read-only`).
- **`resume` inherits sandbox.** `codex exec resume` does not accept `-s`,
`-m`, or approval-related `-c` overrides — sandbox and approval mode are
properties of the original session. Changing `sandbox:` or `approvals:`
mid-review requires aborting and re-invoking `/adversarial-review` with
the new override, which starts a fresh review.
- **`resume` has no `-C` flag.** The skill captures `REPO_ROOT` via
`git rev-parse --show-toplevel` at Step 2 and prefixes every resume with
`cd '<REPO_ROOT>' && ...`. This requires paths without single quotes;