Files
coyote/assets/agents/adversary
Dark-Alex-17 1e46743420 fix(TASK-017): bound run_checks runtime and fail-close its node-level death
Adversary conformance-review fixes for the TASK-017 exec-evidence stage:

- run_checks.py: total-runtime deadline (3300s = node timeout minus margin);
  each command gets min(900s, remaining budget), commands past the deadline
  are recorded as {cmd, skipped: deadline} entries so in-script handling
  stays authoritative instead of the node timeout killing the script from
  outside. POSIX hardening: per-command process group (start_new_session)
  + killpg on timeout so hung grandchildren cannot linger; non-POSIX
  limitation documented in the docstring.
- graph.yaml: run_checks gains fallback: pipeline_fault; check_criterion
  treats SKIPPED records as at-best PARTIAL (unproven, never failed).
- pipeline_fault.py: run_checks-stage attribution grounded in real engine
  behavior (script-node fallback writes nothing into state, executor.rs
  script arm) — nonempty diff_text proves facts completed, so the fault is
  the verification runner; emits 'PIPELINE-FAULT: verification runner
  killed'. Empty diff_text still attributes to diff resolution.
- verdict.py: renders skipped records as [SKIPPED] instead of a bogus
  [FAIL] exit-? line; non-degraded verdict semantics untouched.
- tests: outer-except ENVIRONMENT degradation, deadline timeout+skip (env
  seam ADVERSARY_RUN_CHECKS_DEADLINE_SECS), pipeline_fault stage
  attribution (parse / facts / run_checks), check_criterion prompt cites
  {{exec_results}}, verdict SKIPPED rendering; run_adversary_script_env
  helper for env-carrying invocations.
- cargo fmt violations in 3d7dea9 test code fixed (fmt --check exit 0).
2026-09-14 10:50:33 -06:00
..

Adversary

Important

v2: now a GRAPH agent. The plan's acceptance criteria are extracted into a list and the graph fans out ONE fresh-context verification branch per criterion — partial coverage ("checked 8 of 12") is structurally impossible. Each verdict passes a deterministic contract gate (MET requires evidence including a proving test; no test = at best PARTIAL), a holistic ADDITIVE-only pass hunts absence/scope-drift/substitution/gamed-tests, and the CONFORMS/DIVERGES sentinel is computed by a script (missing plan = DIVERGES, fail-closed). The conformance doctrine below is unchanged — now structurally enforced.

An adversarial plan-conformance reviewer. Where code-reviewer asks "is this code good?", adversary asks a different, harder question:

"Is this the code the plan asked for — all of it, and only it?"

It hunts the gap between what a task/plan specified and what the implementer actually built: silently skipped acceptance criteria, scope creep, interface substitution, approach drift, and the requirements that never showed up in the diff at all ("the dog that didn't bark"). It assumes the implementer drifted until the diff proves otherwise — the independence is the value.

Why it's separate from code-reviewer

code-reviewer adversary
Question Is the code correct/clean/safe? Does the code match the plan?
Input The diff The diff + the plan's acceptance criteria
Blind spot it covers slop, bugs, coupling, footguns skipped criteria, scope drift, contract breakage
Output severity-tagged findings (🔴🟡🟢) a blocking verdict: CONFORMS / DIVERGES

They are complementary passes, not substitutes. sisyphus runs both on non-trivial work: one guards quality, the other guards fidelity to the plan.

Verdict (blocking)

The agent ends every review with one sentinel:

ADVERSARIAL_REVIEW: CONFORMS
Criteria: N/N met (all with tests).
ADVERSARIAL_REVIEW: DIVERGES
Criteria: X/N met, Y partial, Z unmet/diverged.
Complaints:
1. Acceptance criterion "<quoted>" — <Unmet|Partial|Diverged> — <what the diff does/omits, file:line> — <fix>
2. ...

A DIVERGES verdict blocks completion. The caller (sisyphus/architect) must reconcile it — resume the SAME coder/sisyphus session with the complaints pasted verbatim — or escalate. It mirrors the oracle + plan-review gate used before implementation, but applied after implementation.

Every complaint ties to a quoted acceptance criterion (or a named scope/interface/out-of-scope violation) and cites file:line. Vague complaints are not emitted.

How it reviews

flowchart TD
    A["parse (llm): extract acceptance criteria"] --> B["diff_facts (script): resolve + bound the diff"]
    B --> C["map over criteria: one fresh-context branch each (parallel)"]
    C --> D["check_criterion (llm + fs/ast tools)"]
    D --> E["crit_gate (script): MET needs change+test evidence"]
    E -. "reject-retry once; exhausted = PARTIAL" .-> D
    E --> F["holistic (llm): ADDITIVE-only hunt - absence, scope drift, substitution, gamed tests"]
    F --> G["verdict (script): CONFORMS iff ALL MET + zero extras; no criteria = DIVERGES"]
    G --> H(["ADVERSARIAL_REVIEW: CONFORMS | DIVERGES"])

The conformance doctrine is baked into the graph's own nodes:

  1. Every acceptance criterion gets its own fresh-context verification branch — MET / PARTIAL / UNMET / DIVERGED, machine-gated (MET requires the satisfying change AND the proving test, cited). No test ⇒ at best PARTIAL. Partial coverage of the criteria list is structurally impossible.
  2. Ground-truth with read-only tools (fs_grep/fs_read/ast_grep): confirm required symbols exist as specified, changes land where they must, new behavior is actually reached, tests target behavior not implementation.
  3. Hunt adversarially for the absent: skipped criteria, scope creep, interface/approach substitution, out-of-scope touches, downstream contract breakage.

It is read-only — it produces a verdict, never a fix.

Usage

Typically spawned by sisyphus (or architect) alongside code-reviewer. The spawn prompt IS its entire context, so it must include the diff (or a base ref to fetch) and the acceptance criteria:

agent__spawn --agent adversary --prompt "
## TASK
Adversarially review the recent changes for TASK-NNN against its plan. Return CONFORMS/DIVERGES.

## DIFF
Run get_diff (or --base main), or: <paste diff>

## PLAN — acceptance criteria to check against
<paste the task index.md body + the relevant PLAN-*.md section, verbatim>
"

Direct invocation for ad-hoc use:

coyote -a adversary --agent-variable project_dir /path/to/repo \
  "Review staged changes against these criteria: <paste criteria>"

Tools

  • The graph's diff_facts script resolves the diff itself (staged → unstaged → HEAD~1, or an explicit ref/range named in the prompt) — there is no get_diff tool anymore.
  • Criterion branches carry read-only fs_read/fs_cat/fs_grep/ast_grep for ground-truth checks.
  • code-reviewer — the quality reviewer it runs alongside.
  • plan-review — the pre-implementation plan gate; adversary is its post-implementation counterpart.