See also — Parent: docs/README.md, layer-model.md (cross-cutting mechanism hosted in Layer 5 + Layer 6, not a new layer) · Engine context: ORCHESTRATION_ENGINES.md (A2+ delegation loop only), orchestration.md · Complementary quality mechanisms: validation.md (static R1–R32), evaluation.md (workflow-level score) · Completion gate chain placement: runtime.md · Feeds: manager-intelligence.md (decision journal via pattern memory), refinement.md (critique defects are a gradient source) · Fixpoint guard (R35): this doc
The critique loop is the delegation loop's inner self-correction reflex. Where the manager decides what to do next, the critic asks — for every worker output, before the manager ever sees it — "is this output actually any good, and if not, can we fix it right here?" This turns each worker call into a small, reviewable artifact instead of a blind hand-off, and lets later workers in the same run learn from earlier failures via accumulated patterns.
Critique sits inside the delegation loop engine (A2+ only). It is one of three quality subsystems in AWP, each operating at a different scope:
| Subsystem | Scope | When | Where to read |
|---|---|---|---|
| Validation (R1-R32) | Static schema/graph correctness | Before/during run | validation.md |
| Critique (this doc) | Per-worker output, inside delegation loop | After every worker call | here |
| Evaluation | Whole-workflow score | After the run | evaluation.md |
Heads-up — Critique vs. Evaluation. Critique is a worker-level repair tool: it diagnoses specific defects in a single worker output and tells that same worker how to fix them. Evaluation is a workflow-level scoring tool: it produces a numeric quality score for the entire run and can trigger full retries. They are designed to be complementary and can be enabled independently — see the table below.
The critique system also feeds the manager intelligence decision journal: each defect pattern becomes a hint the manager uses on the next iteration.
| Aspect | Critique | Evaluation |
|---|---|---|
| Scope | Per-worker output | Per-workflow result |
| Question | "What's wrong with this output?" | "How good is the overall result?" |
| Output | Defect list + repair instructions | 0.0-1.0 score |
| Action | Targeted repair of specific defects | Retry/accept/fail the workflow |
| Location | delegation_loop.critique |
observability.evaluation |
| Engine | A2+ (delegation loop only) | Any engine (DAG or delegation loop) |
Both can be enabled independently. When both are active, critique repairs happen before evaluation scoring.
Critique is configured under orchestration.delegation_loop.critique in workflow.awp.yaml:
orchestration:
engine: delegation_loop
delegation_loop:
critique:
enabled: true
mode: inline # "inline" or "dedicated"
model: null # LLM model (null = inherit worker model)
max_repair_attempts: 2 # Per-worker repair cycles
repair_budget_fraction: 0.15 # Max 15% of total budget for repairs
min_score_to_complete: 0.6 # Block COMPLETE/DELEGATE below this mean critique score
pattern_memory: true # Accumulate cross-worker failure patterns
defect_categories:
- missing_data
- wrong_format
- incomplete
- hallucinated
- stale
- policy_violationWhen enabled: false (the default), critique is completely disabled and has zero runtime overhead.
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
bool | false |
Enable/disable the critique system |
mode |
string | "inline" |
"inline" (uses worker model, cheap) or "dedicated" (separate critic agent) |
model |
string | null |
LLM model for the critic. null inherits from the worker model |
max_repair_attempts |
int | 2 |
Maximum repair cycles per worker before escalation |
repair_budget_fraction |
float | 0.15 |
Maximum fraction of total budget that can be spent on repairs |
min_score_to_complete |
float | 0.6 |
Minimum mean critique score required for the manager to be allowed to complete. Below this, a COMPLETE decision is overridden into another iteration. The same gate also blocks a DELEGATE decision that re-issues an already-dispatched subtask signature (redundancy guard), forcing the manager into diagnose/repair instead. Setting to 0.0 disables the gate. |
pattern_memory |
bool | true |
Accumulate failure patterns across workers within a run |
defect_categories |
list | see above | Types of defects the critic should diagnose |
| Category | Description | Typical Severity |
|---|---|---|
missing_data |
Required data absent from output | critical |
wrong_format |
Output format doesn't match contract | critical |
incomplete |
Partial result, missing sections | warning |
hallucinated |
Fabricated data or unsupported claims | critical |
stale |
Outdated information | warning |
policy_violation |
Violates workflow policies | critical |
- critical — Defect that makes the output unusable. Triggers repair.
- warning — Quality issue but output is usable. Included in repair if repair is triggered.
- info — Minor observation. Never triggers repair.
| Score Range | Assessment | Action |
|---|---|---|
| 0.9-1.0 | Excellent, no critical defects | Accept |
| 0.6-0.89 | Acceptable with warnings | Accept (log warnings) |
| 0.3-0.59 | Needs repair, critical defects present | Trigger repair |
| 0.0-0.29 | Fundamentally broken | Escalate to manager |
When no LLM is available, a deterministic heuristic runs instead:
| Check | Penalty | Severity |
|---|---|---|
| Missing confidence field | -0.3 | critical |
| Low confidence (< 0.3) | -0.2 | warning |
| Error field present | -0.4 | critical |
| Required field missing | -0.2 each | critical |
| Empty string in field | -0.1 each | warning |
Score starts at 1.0, penalties are subtracted, result is clamped to [0.0, 1.0].
When pattern_memory: true, the critique engine accumulates failure patterns across all workers in a run.
- After each critique,
reusable_patternsfrom the CritiqueEnvelope are recorded - Patterns track: category, frequency, description, prevention rule, first/last seen iteration
- Patterns are sorted by frequency (most common first)
- A "Known Pitfalls" section is injected into the next worker's skills
## Known Pitfalls
The following issues have occurred in prior workers during this run.
Avoid repeating them:
- [seen 3x] missing_data: Always include the 'summary' field in your output
- [seen 2x] wrong_format: Output confidence as a float, not a stringThis creates a learning loop within a single run — later workers benefit from earlier mistakes without any human intervention.
Unlike evaluation retry (which re-runs the entire workflow), critique repair is targeted:
- Only critical + warning defects are included in repair instructions
- The worker receives its own previous output plus specific fix instructions
- The repair prompt says: "Fix ONLY these defects. Keep everything else unchanged."
- After repair, the result is re-critiqued to verify improvement
- Repair stops if score doesn't improve (prevents infinite loops)
- Repairs consume budget (tokens, loops, worker runs)
repair_budget_fractioncaps the total repair spend (e.g., 15% of total budget)max_repair_attemptscaps per-worker repair cycles- If budget is exhausted, repair is skipped and the original result is kept
Each repair attempt is tracked:
{
"worker_id": "analyst_01",
"attempt": 1,
"original_score": 0.45,
"repaired_score": 0.82,
"defects_fixed": 3,
"defects_remaining": 0
}When critique is enabled, additional artifacts are written per iteration:
workspace/runs/<run-id>/
iterations/
001/
critique.json # All worker critiques for this iteration
CRITIQUE.md # Human-readable summary
delegations/
<worker-id>/
critique.json # Per-worker critique detail
The LLM critic is grounded in the actual filesystem state of the run so it cannot hallucinate "file missing" defects when the file really exists on disk. Before each critique call, the engine captures a ground-truth snapshot of the worker's _workspace_dir and the run's _output_dir (file list with sizes) and injects it into the critic prompt. The critic is instructed to treat the snapshot as authoritative: if a file is listed there, claiming it is missing is a hallucination and must be suppressed. This closed a class of failure modes in which pessimistic LLM narratives would reject otherwise-valid worker output and push the delegation loop into endless repair cycles.
The min_score_to_complete threshold is only one of several completion gates the delegation loop enforces before accepting a manager COMPLETE decision. The others work in concert with critique:
- Placeholder gate. Before accepting completion, the runner scans the manager's
final_resultand all text-based files under_output_dir/workspace/outputsfor placeholder patterns ("TODO", "final output here", "XX%", stub key names likeyour,field_name,<your-...>). Any hit forces another iteration with a_placeholder_repair_requiredstate entry telling the manager exactly which stubs to replace. - File-validator gate. Trivial deliverables (1x1 PNGs, empty PDFs, files
< 512 B) are rejected as placeholders even if the filename exists. - Deliverable presence gate. When the task text implies a file deliverable (keywords like image, chart, pdf, csv, dataset, ...) the runner refuses
completeuntil at least one file of>= 512 Bexists in the run's_output_dir. This catches the pathological case where the manager finishes after only "investigating capabilities" without actually producing the artifact the user asked for. - Critique ground-truth bypass. When a task implies a file deliverable and that file already exists on disk at completion time, the LLM critic's pessimistic narrative is overruled — the filesystem is authoritative. This prevents endless repair loops on output that is already correct but that the critic keeps flagging on stylistic grounds. The bypass is advisory: the placeholder and file-size gates above still apply.
All four gates share a single trace channel so the experiment UI shows which gate fired on which iteration. Gates never accept an incomplete run — they only reject premature completions. When the overall budget envelope is exhausted the runner falls back to a partial result rather than blocking forever.
The manager receives a critique summary after each iteration, including:
- Per-worker scores and defect counts
- Top prescriptions
- Known patterns and their frequencies
- Repair history (original vs. repaired scores)
This helps the manager make better delegation decisions in subsequent iterations.
See Example 15: Critique Loop for a complete working demonstration with:
- Inline critique mode
- Pattern memory enabled
- 2 repair attempts per worker
- 20% repair budget fraction
- Evaluation metrics + retry policy combined with critique
Before the LLM critique runs on a worker's output, a bit-level contract chain checks for trivial defects that don't need a language model to detect. This is the Layer 0 Contract: linear-time, domain-agnostic, token-free.
Default checks (bundled with every conformant runtime):
| Check | What it rejects |
|---|---|
no_placeholder |
TODO, XXX, ???, Lorem ipsum, TBD, FIXME, TITLE GOES HERE, Author Name, to be filled |
no_text_loop |
≥ 20-word paragraphs whose pairwise simhash similarity exceeds 0.85 (detects the "produce more output by repeating yourself" anti-pattern) |
file_size_delta |
A repair output whose size is > 2.5× the previous attempt (detects append-leaks like the 341 MB runaway observed in practice) |
no_duplicate_headings |
Any Markdown # Title or LaTeX \section{Title} that appears more than once |
balanced_delimiters |
Unbalanced {} / [] / () counts (fast tokenizer, no AST) |
json_valid_if_claimed |
Files ending .json (or tools claiming JSON output) that fail json.loads |
Every check runs in O(n) and in under 100 ms on a 10 MB output.
L0 runs before critique → deliverable → placeholder → file → deliverable → structural → eval. A rejection at L0 emits a gate event
with fields l0_check, l0_reason, violating_path and sends the
worker back into repair mode with a specific, deterministic reason
string — no LLM tokens burned.
See validation-rules.md §10 for normative requirements.
Workflow authors add their own checks via YAML:
observability:
output_contract:
checks: [default]
extra:
- name: citation_keys_resolve
implementation: my_workflow.contracts:CitationCheckAn OutputContractCheck implementation is any Python callable
conforming to the Protocol in
packages/awp-runtime/src/awp/runtime/critique/contracts.py. The
callable MUST return within 100 ms on a 10 MB output. Extension
checks live in the workflow repo; AWP core ships only the generic
default set.
When a repair worker returns an output whose simhash similarity to
the previous repair output is ≥ 0.95, the runtime treats the subtask
as a fixpoint and aborts further repair. The subtask is marked
failed with reason repair_fixpoint_detected and its parent loop
decides whether to synthesise a differently-scoped subtask or
contribute the failure to the terminal status aggregation.
This prevents the "keep repairing the same wrong thing" failure mode observed in long-running delegation runs: a worker producing near-identical output across 4+ repair attempts is not converging, and every further iteration burns budget without information gain.
See validation-rules.md §11 for normative semantics.