# Debate and peer review

The `com.tnsai.coordination.debate` package has two executors that improve an answer by setting LLMs against each other. `DebateExecutor` has a proponent and an opponent argue a topic for a few rounds, then asks a judge for a verdict. `PeerReviewExecutor` has a producer write a draft and a reviewer approve it or send it back for revision.

Both take `LLMClient` instances, not agents, and call `chat(prompt)` with fixed prompts. They are not related to the `@Debate` messaging protocol in [Protocols](protocols.md) or the `DEBATE` group strategy in [Group topologies](topologies.md).

## Debate

`execute(topic)` runs the rounds and then the judge:

1. In each round the proponent argues in favor and the opponent argues against. In the first round the proponent opens and the opponent answers it. In later rounds the proponent sees the opponent's last argument, and the opponent sees the proponent's newest argument and its own previous one.
2. If a side's call throws, its argument for that round is the text `Error: Unable to generate argument.` (or `counter-argument.` for the opponent), and the debate goes on.
3. After the last round the judge gets the whole transcript and is asked for five numbered sections: VERDICT, REASONING, PRO SUMMARY, CON SUMMARY and CONFIDENCE.

| Builder method | Default | Meaning |
|---|---|---|
| `proponent(client)` | required | Argues in favor |
| `opponent(client)` | required | Argues against |
| `judge(client)` | required | Reads the transcript and decides |
| `maxRounds(n)` | 3 | Number of rounds; must be at least 1 |
| `timeout(duration)` | 10 minutes | Checked before each round |
| `format(format)` | `STRUCTURED` | `STRUCTURED` or `FREE_FORM`; stored but not used, so both produce the same prompts |

The timeout only stops new rounds from starting. A round that has started finishes, and the judge always runs.

<!-- java-contract: src/main/java/com/example/tnsai/docs/DebateExample.java -->
```java
package com.example.tnsai.docs;

import com.tnsai.coordination.debate.DebateExecutor;
import com.tnsai.coordination.debate.DebateResult;
import com.tnsai.coordination.debate.DebateRound;
import com.tnsai.coordination.debate.PeerReviewExecutor;
import com.tnsai.coordination.debate.PeerReviewExecutor.PeerReviewIteration;
import com.tnsai.coordination.debate.PeerReviewExecutor.PeerReviewResult;
import com.tnsai.llm.LLMClient;

import java.time.Duration;

/** Compilation contract for multi-agent/debate.md. */
public final class DebateExample {

    private DebateExample() {
    }

    static DebateResult debate(LLMClient pro, LLMClient con, LLMClient judge) {
        DebateExecutor debate = DebateExecutor.builder()
            .proponent(pro)
            .opponent(con)
            .judge(judge)
            .maxRounds(3)
            .timeout(Duration.ofMinutes(5))   // checked before each round
            .build();

        DebateResult result = debate.execute("Should this service move to microservices?");

        for (DebateRound round : result.rounds()) {
            System.out.println("Round " + round.roundNumber());
            System.out.println("  Pro: " + round.proponentArgument());
            System.out.println("  Con: " + round.opponentArgument());
        }
        System.out.println("Verdict: " + result.verdict());
        System.out.println("Confidence: " + result.confidence()
            + (result.isHighConfidence() ? " (high)" : ""));
        return result;
    }

    static String review(LLMClient writer, LLMClient editor) {
        PeerReviewResult result = PeerReviewExecutor.builder()
            .producer(writer)
            .reviewer(editor)
            .maxIterations(3)
            .build()
            .execute("Write release notes for version 2.0");

        for (PeerReviewIteration iteration : result.iterations()) {
            System.out.println(iteration.iterationNumber() + ": approved=" + iteration.approved());
        }
        // Without approval, finalOutput is the last draft, which was not approved.
        return result.approved() ? result.finalOutput() : null;
    }
}
```

### The result

`DebateResult` is a record:

| Field | Meaning |
|---|---|
| `verdict` | The judge's VERDICT section, or the whole judge answer if that section is missing |
| `confidence` | 0–1, from the first "Confidence: NN%" in the judge answer; 0.5 when none is found |
| `rounds` | One `DebateRound` per round: `roundNumber`, `proponentArgument`, `opponentArgument`, `duration` |
| `roundsUsed` | Rounds that ran, fewer than `maxRounds` after a timeout |
| `proponentSummary`, `opponentSummary` | The judge's PRO SUMMARY and CON SUMMARY sections; empty if missing |
| `duration` | Total time |

`isHighConfidence()` is true when `confidence` is at least 0.7. If the judge's call throws, the verdict starts with `Unable to reach verdict due to error:`, the confidence is 0 and the summaries are empty.

## Peer review

`execute(task)` loops for up to `maxIterations` iterations:

1. The producer writes a draft. In the first iteration it gets the task. In later iterations it gets its previous draft and the reviewer's feedback, but not the task text.
2. The reviewer gets the task and the draft and is asked for APPROVED (yes or no), FEEDBACK and STRENGTHS.
3. The draft counts as approved when the reviewer's answer contains `approved: yes` or `approved:yes`, ignoring case. Any other wording, such as `Approved: **yes**`, counts as a rejection.
4. An approved draft ends the loop. Otherwise the feedback goes into the next iteration.

| Builder method | Default | Meaning |
|---|---|---|
| `producer(client)` | required | Writes and revises the draft |
| `reviewer(client)` | required | Approves or gives feedback |
| `maxIterations(n)` | 3 | Drafts to try; must be at least 1 |
| `timeout(duration)` | 10 minutes | Checked before each iteration |

If the reviewer's call throws, the draft is not approved and the next revision gets `Review unavailable: …` as its feedback. If the producer's call throws, the loop stops.

`PeerReviewResult` has `finalOutput`, `approved`, `iterations`, `iterationsUsed` and `duration`. Each `PeerReviewIteration` has `iterationNumber`, `output`, `feedback`, `approved` and `duration`. When `approved` is false, `finalOutput` is the last draft, which was not approved, or an empty string if the producer never answered. Check `approved` before you use it.

## Related

- [Council and voting](council.md)
- [Judge](judge.md)
- [Recursive task solver](recursive-solver.md)
- [Protocols](protocols.md)
