Four ways the loop stops and asks — unverifiable, no consensus, out of rounds, paused — and what each looks like.
View raw Markdown · llms.txt · For agents
An unattended loop is judged by how it stops. These are the four ways, in the order they happen to a real project.
Reconstructed, not captured. Every block below is the shape the loop writes — the event names, fields and messages come from the code, and the issue keys and reasons are invented. Capturing them for real would mean letting a loop write to a tracker, and this release was built read-only. The captures that are real are labelled as such:
doctor, a dry-run tick andobserve.
1. The contract cannot be frozen
The ticket says "improve onboarding". The orchestrator produces zero executable outcomes and one blocking ambiguity, and the loop escalates before any worker exists:
contract.escalated · REP-141
reasons:
- no outcome maps to an executable check (command or test)
- 1 blocking ambiguity: which of the three onboarding surfaces is in scope?Nothing was spent beyond one orchestrator call. The alternative — dispatching anyway — buys a confident pull request against a requirement nobody stated.
2. The plan finds no consensus
Three cycles, three rejections, each carrying a concrete objection:
plan.voted · REP-152 · cycle 1 · 1/3 approved
plan.voted · REP-152 · cycle 2 · 1/3 approved
plan.voted · REP-152 · cycle 3 · 0/3 approved
plan.escalated · REP-152 · cycles 3
unresolved:
- no step reaches outcome o2 (the migration is never run)
- step s3 changes packages/billing, which the contract puts out of scopeThree models disagreeing three times is an ambiguous requirement. The unresolved objections are exactly what the human is being asked to settle — and they are more useful than any summary of them would be.
3. The fix rounds run out
worker.review-round · REP-160 · pr 412 · round 1
worker.ci-round · REP-160 · pr 412 · round 2
worker.review-round · REP-160 · pr 412 · round 3
worker.blocked · REP-160 · fix rounds exhausted (3/3); a human needs to take overThe pull request carries every round's text, the worktree is kept for inspection, and the slot is released so the rest of the queue keeps moving. The loop does not try a fourth round more cheaply.
4. The issue is paused
Two consecutive dispatch failures on the same issue — a worktree that could not be created, a setup command that failed:
issue.paused · REP-166 · consecutive 2
reason: worktree setup failed: pnpm install --frozen-lockfile exited 1The configured label goes on the ticket, and the next tick skips it. Removing that label is a resume signal, as
is ak-harness loop resume REP-166 — but find out why first:
ak-harness loop paused
ak-harness loop debrief --issue REP-166The shape they share
Every one of these writes an event, comments once on the ticket (deduplicated — a stuck issue does not
accumulate identical comments), and calls the configured channel when the type is listed in
notifications.events. None of them retries more cheaply, and none of them degrades a gate to get through it.
That is the whole contract of an unattended loop: it stops where a human would want to be asked, and it says exactly what it needs.