--- name: auto-loop description: Auto Office 3.0 reference spoke, not loaded by 3.1 runs (they use the office CLI). Internal Auto Office v3 loop-driver spoke. Use after plan approval to dispatch waves without blocking, integrate dispatch branches through a validated merge, adjudicate contract disagreements, and hold the autonomy ceiling — proceeding end to end while never merging to main without an explicit user statement. --- # Auto Loop > **Auto Office 3.1:** this is 3.0 reference material. A 3.1 run is driven by the `office` CLI and runtime-delivered > role briefs; do not run the `office_runtime.py` helpers below for it. Follow `office status` and its `next:` line. Dispatch every task in the wave before waiting on any of them. One worktree per dispatch, cut from the run's pinned base SHA — regardless of executor count or gear. A single-dispatch run is not exempt: it is the case most tempting to skip the worktree for ("just one quick executor," work directly in the main checkout), and exactly the case where that shortcut is wrong. The orchestrator can never assume exclusive ownership of the repo's main working tree; another human or another agent/session may be concurrently editing it, independent of how many dispatches this orchestrator itself is running. Each executor commits its own work locally to its own dispatch branch — never pushes, never touches any other branch — as a checkpoint immediately before reporting done, so a finished dispatch survives an orchestrator mistake made later during post-dispatch verification or integration. The orchestrator still owns final integration and merge, and may amend, squash, or rewrite that commit while landing it. Two tasks in one wave never share a write scope — a wave is only real if it draws as disjoint. Every brief's completion criterion is a command whose output settles it, not a target — "under 120 lines" is a wish, "`wc -l` reports under 120" is a receipt (spec §4). A dispatch counts as in flight only once it has a receipt — an observed transition to working, or output in the pane — not a status read at dispatch time; harness `idle` semantics differ across codex and agy (spec §6). Polls while any dispatch is live. Between polls the orchestrator only touches write scopes no live dispatch holds: planning later waves, reviewing returned output, preparing briefs, reading state. Arm a background monitor over every dispatch at or before dispatch time, kept armed for the whole run. Completion is an event from it, not a wait, and it fires on every terminal state — finished, idle, blocked, unknown, disappeared — not just success. Talking to the user never suspends it. If the monitor is lost or unarmed, re-poll before asserting any dispatch's state. A wave ends when every dispatch in it has returned, or been declared dead by two independent liveness signals — the receipt is both signals; one alone is not a death. On each completion event: collect the result, close the pane of an agent that actually finished, update the spawn ledger. Leave `blocked` and `unknown` panes open — they're unresolved, not completions, and closing one destroys the evidence needed to recover (spec §6). On 3.1 runs a worker that ran `office raise` is blocked, not live: `office wait` exits 5 once, `office answer -- ""` reaches it. At integration: each worker's tree already carries its own checkpoint commit on its own dispatch branch; the orchestrator may amend, reauthor, or squash that commit while landing it, or commit directly if a worker's checkpoint is missing or incomplete, but never re-dispatches into a tree to redo the commit itself. Merge dispatch branches into the run's integration branch in wave order; resolve conflicts at the orchestrator, never by re-dispatching a worker into a tree it no longer owns; then run the plan's validation commands on the merged result. The receipt is that merged-result run — a green worker tree only proves itself, since N parallel trees have never coexisted until then. Re-merging a dispatch branch after its merge was reverted does not reapply it — git treats it as already merged and reverted, producing conflict markers instead of the fix; take corrected files straight from the owning branch, or revert the revert first (spec §7). When a test against the pinned contract disagrees with the implementation, name which one is wrong and why: repo convention outranks an ambiguous contract clause, and a contract clause outranks an implementation's convenience. This is an adjudication, not a re-plan. Review round caps: 3 substantive rounds per RECHECK sequence on `convergence-v1` runs (`docs/review-convergence.md`); 3.0 caps live in `auto-review`. A verification asserting only exit codes can't catch a gate that fails closed on everything — assert the reason it gives, not just its exit status (spec §8.1). After approval the run proceeds end to end with no further go-aheads: bootstrap a plan-only commit, named branch, and draft PR before the first task; commit each wave as it goes green; run verification and review rounds; remove the plan file and mark the PR ready at closeout; merge dispatch branches into its own working branch as needed. Merging to `main` stays the user's call — their most recent explicit statement, in the approval or the conversation, governs over any earlier default. Absent that sentence, the run stops at a ready PR. Report blockers, then carry out the authorized action — a defect exit pauses and reports, it doesn't decline an authority decision. A defect must concern the artifact it names; a scope objection raised to dodge an authority call is really that disagreement in disguise. If the harness itself blocks an action, ask the user instead of rephrasing past the guard (spec §9.1, §9.2). It stops for exactly two things: an external send, and a user-owned decision the plan didn't anticipate. Everything the plan named — production applies included — it executes without asking again. Send a mid-run contract amendment only to dispatches whose base contains its producer (`references/contract-amendments.md`). Reusing an executor or plan_reviewer whose context exceeds 272,000 tokens: send `/compact` and queue the next brief pointer back to back, then move on — no wait, no poll, no replacement worker. `scripts/office_runtime.py reuse-plan` is the pinned, pure decision (`compact_then_queue` vs `normal_reuse`); call it before reusing, don't hand-roll the threshold check.