Generated from
cat-harness/skills/sdlc/sdlc-core/adversarial-code-review.md— do not edit here.
Adversarial code review
The Task_Review step of
code-change-review.bpmn,
for a change an agent touched. Its verdict is what check:adversarial-review
reads (bean w8jq, proposal docs/proposals/merge-gate-2026-10-02.md §5–§6).
It is warn-only by the owner’s ruling of 2026-10-03: a missing, stale or
failing verdict is reported, not blocking, until the owner promotes the gate.
Who may review
Not the author. A different session id from every Claude-Session: /
Agent-Session: trailer on merge-base..head; a different model family when
one is configured. The gate checks the session, and refuses a verdict that does
not record the reviewer’s session and model.
The stance
Construct the strongest case that this change is wrong, unsafe, or not what
it claims. It is the stance of generalise-the-fix
and devils-advocate-watcher,
applied to a diff. The claim under test is the
pull request’s description and the ## Done when of the bean it names.
Scope: the whole diff, or unknown
- Review
git diff <merge-base>..<head>, file by file. Count every changed file intocoverage.files_total. - A generated file that a check reproduces may be skipped, by name, in
coverage.skippedwith its reason. Nothing is skipped silently. - If you cannot read the whole diff, set
coverage.truncated: trueandresult: "unknown". Neverpasson part of a diff.
What you look for
The RED FLAG categories are closed and live in schemas/red-flag.ts:
security, data-loss, correctness, false-green, provenance,
scope-breach, irreversible-action and licence. Read the definitions
there rather than from a copy: the proposal’s own table already differs from
the schema. Beyond the categories, ask:
- can a new or changed check report green without evaluating its subject?
- does prose (a skill, the PR body, the bean) assert something the code does
not do? That is
narrative-asserts-code; - does the change reach outside its bean, or hand-edit a generated file?
A finding is blocking only with evidence: a reproducible observation, such
as an input and its wrong output, or a command and what it printed. Without
one it is recorded as a suggestion. The author may answer each flag once;
then the verdict is final.
Recording the verdict
The verdict lives on its own state branch, never in the pull request. Committing it into the pull request moves the head it names, which makes it stale at once (owner, 2026-10-20, “State branch”).
bun run cat state:mountmounts themerge-reviewsgraph atmerge-reviews/.- Write
merge-reviews/<head sha>.json, amerge-review/v1document:pr,repository(owner/repo, so the store’s viewer can link the pull request),base_sha,head_shaandreviews[]. Each review records:reviewer {by, session, model};author_sessions, from the trailers;skill_hash, the sha256 of this file as you ran it;atandcoverage;result(pass,failorunknown);flags[], each withid,category,severity,weight,where,evidenceandstatus: "open".
- Push with
bun run cat state:push, nevergit pushfrom the mount. - Check it:
bun run cat check:adversarial-review --head <sha> --base <base>.
A push to the pull request after the review leaves the verdict naming a commit
that is no longer the head. The gate reports that as stale, and the review
runs again on the new head.
Overrides
A flag is never deleted. A person with standing overrides it with a
qa-review decision (who, when, why, flag id), which sets
status: "overridden". The gate passes resolved and overridden flags and
holds on open.
In a merge train
A review is per head, because it reviews a change, not an accident of
batching. A pull request in a merge-queue train keeps the
verdict on its own head; a pull request taken out of the train keeps it too,
because its head did not move. A conflict resolved by hand while building
the train is a change of its own and needs its own review. The compile gates,
not the review, run again on the train’s combined result.
Processes that run this skill
| process | step(s) that name it |
|---|---|
| Code change and review | Review the change |