Delegation, and what a unit owner decides without asking
Two shapes of work exist here. Flat: the coordinator dispatches an agent per step, verifies it, merges it. Two-tier: the coordinator dispatches one unit owner, which dispatches its own agents, integrates and verifies their work, and reports one result up.
Two-tier exists because the coordinator's context is the scarce resource, not tokens. An owner plus three agents probably costs more tokens than the coordinator doing the same unit. What it buys is that the coordinator stays short and can therefore keep running.
The rule that makes the layer worth having
The owner's authority was the owner's own objection to this design, on 2026-09-16:
if for every question the actual implementing agent asks his owner, and the owner needs to reach back to you, then we're just paying more tokens, not less.
He is right, and it is decisive. A middleman that forwards questions is pure overhead - it adds a context, a round trip and a summary, and removes nothing. So:
Reversible and inside the unit: decide. Irreversible or outside the unit: ask.
That is the same test adr-008 and adr-013 use one level down, and it resolves nearly everything. The default is decide and record the decision in the commit message, not ask. An owner that escalates a reversible choice has failed at its job in the direction that costs the most.
What a unit owner decides alone
Everything on this list, without asking, including when it is unsure:
- Every implementation choice. Naming, structure, which function carries the logic, what the tests assert, which fixtures exist.
- Its own fleet. How many agents, what each brief says, when to stop dispatching. And whether a returned result is acceptable - rejecting work and re-dispatching is the owner's call and needs no permission.
- Conflicts inside its unit, including conflicts with
mainin files its unit touches. - Scope it drops. An owner may cut a sub-task, and then it must say which and why in its report. Silently narrowing is the failure; deciding to narrow is not.
- Strengthening anything. A wider test, a new gate, a stricter fixture, a known-bad input. Never needs asking.
- Filing tickets for what it finds and will not fix.
- Anything the repository's own rules already settle. The rules are in
CLAUDE.md,docs/PROCESS.mdand each directory'sCLAUDE.md. An owner reads them; it does not ask the coordinator to interpret them.
What a unit owner must escalate
Short on purpose. Each of these is irreversible, outside the unit, or a decision somebody with more context has to make:
- An architectural decision - a new ADR, or anything that contradicts one.
- Anything that spends money or touches production. A deploy, a
tofu apply, a DNS record, a paid API call. - A Tier 1 shared resource per
adr-013: the database, credentials, the merchant account, the sending identity. - A rule change. Editing
CLAUDE.md,docs/PROCESS.md, or a gate's subject. Fixing a gate is the owner's; changing what a gate is for is not. - A red gate it cannot turn green honestly. Never narrow the gate. Stop and say so - that is a finding, not a blocker.
- Anything needing the human: a credential, a billing decision, a legal choice, a name only he can pick.
How to escalate without wasting the round trip
An escalation costs a stop, a notification, a reply and a resume. So it must carry its weight:
- Do everything that does not depend on the answer first. Then ask.
- Ask once, with everything. Four questions in one stop cost one round trip. Four stops cost four.
- State your recommendation and what you will do absent an answer. A question with a default attached can be answered with one word, and can sometimes be left unanswered entirely.
- Say what you already did, so the answer lands on a known state rather than on an imagined one.
The mechanism: the owner stops and its report carries the question. The coordinator answers with SendMessage to the same agent, which resumes with its context intact. There is no live interrupt, so a stop is a real cost and step 1 is the one that matters.
What the coordinator owes the owner
Delegation fails from above as often as from below.
- A brief that names what it is unsure of. On 2026-09-16 every one of nine agents corrected something in its brief - a count, a premise, a claim about what had never been run. All nine corrections came from briefs that said "verify this rather than trust it". A brief written as though it were complete gets confirmed rather than corrected.
- The map, not the treasure hunt. An owner that has to locate the declarations before it can work pays the coordinator's orientation cost again, once per unit. That is what
docs/ORIENTATION.mdis for. - A compound branch. The owner merges its agents to
atomic/<unit>/<step>and then tocompound/<unit>. The coordinator mergescompoundtomain. Nobody else touchesmain, which is also the owner's standing rule.
dev, and why every pull request now targets it
OPS-215, 2026-09-20, the owner's decision. Pull requests go to dev. Only dev -> main goes to main, and that merge is rare and deliberate.
The reason is money and it is arithmetic rather than taste. CI is priced per minute and one pull-request event costs 20 billed minutes. The GitHub Free allowance is 2,000 minutes a month, so it buys 100 runs a month. At the cadence of 2026-09-20 - 25 pull requests and 7.7 pushes to main a day - the repository wanted 990 runs a month, 9.9x the allowance, which is how it reached a billing refusal that stopped every job for six days.
With dev, ci.yml runs on pull requests that target main and on pushes to main, so one dev -> main merge costs 2 runs. One merge per working day is 44 runs a month: 44% of the free allowance, and nothing to pay.
The invariant is dev >= main, always at or ahead. Two things would break it and both are handled:
scripts/reserve_ticket_id.pypublished ticket stubs straight torefs/heads/main. Dozens a day, each one movingmainunderdevand firing a CI run. It now publishes toPUBLISH_BRANCH, which isdev.- A
dev -> mainmerge breaks it, and that is the happy path. The merge creates a merge commit that exists only onmain, so using this model exactly as designed inverts the invariant every time. It broke three hours afterdevwas created, this way, not by the hotfix originally predicted.
So the rule is not "do not commit to main". It is:
Everydev -> mainmerge is two operations, and the second isgit push origin origin/main:refs/heads/dev.
make branch-invariant is the enforcer - OPS-230, and it is one command with a real exit code. The argument order is the whole correctness of it: git merge-base --is-ancestor origin/dev origin/main reads naturally and passes on the exact failure it is meant to catch. The correct spelling puts main first, and the script's self-test asserts both directions so the reading cannot drift back.
What this costs: a red dev -> main run does not say which of the batched branches broke it. That is the real price of batching and it is why workflow_dispatch exists on ci.yml - run CI on dev deliberately before merging, and keep batches small enough to bisect by eye.
What the coordinator must not delegate
Verification of the claim it is about to repeat.
Every agent report on 2026-09-16 contained at least one error about its own work - six commits reported as nine, one conflict as two, 25 self-tests that were 26, two survivors that were artefacts of a narrow selection. None of it dishonest; a report is written from memory of intent while the branch is a record of what happened.
A unit owner reviewing its own agents inherits that blindness one level up. The coordinator reading the owner's summary of their summaries is what docs/GLOSSARY.md calls vacuous corroboration, and OPS-124 is the ticket.
So the owner's report is claims with commands, and the coordinator runs a sample of them against the artifact. One or two turns. On 2026-09-16 that habit caught every one of the errors above.