Chapter 18 — The Orchestrator
Maya opens O-1001 in ShopOps. A worker could let the model decide what happens next — skip Policy because the draft “sounds fine,” call Outreach twice, or never pause for Maya’s approval. That is not orchestration. It is an unreviewable process change at runtime.
Intake → Resolution → Policy → Outreach (pause when policy or approval requires)
Without a deterministic scheduler, you cannot test budgets, audit events, or stage order. Jordan’s case becomes whatever the model felt like doing this run.
This chapter adds the orchestrator: code that creates cases, assigns the next stage, ticks one unit of progress, and pauses — it does not compose empathy or invent novel topologies per order.
First principles
The orchestrator owns:
create_case— identity, topology, initial stateassign— next stage / task contracttick— run one unit of progress- pause / resume for approval
- record events on the ledger
It does not own:
- Free-form planning of novel topologies per request
- Bypassing policy because a worker is “really sure”
- Channel credentials
Topologies are a closed vocabulary (shop_standard, shop_intake_only). Adding one is a reviewed code change with tests—like adding an FSM transition. A worker may reason about a refund or reship; it cannot remove the Policy stage.
ShopOps: Intake opens the case, Resolution proposes, Policy judges, Outreach drafts or sends only on the resulting state. The orchestrator schedules and stops; it does not compose empathy.
Concrete example
ShopOps skeleton:
Intake → Resolution → Policy → Outreach
Each tick advances one stage via Supervisor.run_task. If Policy returns permit=false, Outreach still runs but returns blocked=true (or you pause before Outreach — product choice). Sends that need humans call pause_for_approval and later resume_after_approval.
Diagram
flowchart LR
API[API / intake] --> Orch[Orchestrator]
Orch --> Sup[Supervisor]
Sup --> I[intake]
Sup --> R[resolution]
Sup --> P[policy]
Sup --> O[outreach]
Orch --> L[Ledger]
Orch --> CP[Checkpoints]
Orch --> AQ[Approval queue]
Implementation
Reference: shopops/orchestrator.py.
from shopops.orchestrator import Orchestrator, TOPOLOGIES, default_supervisor
assert "shop_standard" in TOPOLOGIES
orch = Orchestrator(default_supervisor())
orch.create_case("O-1001", topology="shop_standard", order_total_cents=240_00)
# Optional: simulate send window before policy/outreach
orch.states["O-1001"].send_window = True
for _ in range(8):
run = orch.tick("O-1001")
if run.status != "open":
break
print(run.status, run.cursor, orch.states["O-1001"].facts.get("permit"))
# Ledger holds proposals, verdicts, conflicts from workers
assert orch.ledgers["O-1001"].entries
# Approval path
orch.pause_for_approval("O-1001")
assert orch.cases["O-1001"].status == "awaiting_approval"
Dead-letter preview: when tick ends in failed, push case_id to a DLQ (Ch 32) rather than inventing a new topology. Operators replay with the same closed graph after fixing data/policy.
Failure modes
- LLM-invented topology — skips policy under load.
- God orchestrator — all tools mounted on the scheduler.
- Tick without checkpoint — crash loses assignments (Ch 8).
- Hidden parallelism — two ticks same case without lease.
- Approval black hole — paused forever; need timeouts → safe default no-send (Ch 29).
Production considerations
- Orchestrator is a service with an API: create / tick / approve / status.
- Idempotent
tickkeyed by(case_id, stage, task_id). - Metrics: stage latency, fail rate, approval age.
- Keep topology YAML/code reviewed like policy packs.
- Map later to workers and queues without changing the stage names.
What “tick” means under failure
A tick is one finite unit of progress, not “run until the model is happy.”
| Tick outcome | Next |
|---|---|
| stage DONE | cursor++ |
| schema REJECTED | fail case or retry-once policy |
| worker exception | fail + DLQ |
| approval required | pause; no further stages |
| unknown topology stage | hard error at assign time |
Compare to an LLM orchestrator that “decides” to skip Policy when Resolution confidence is high. That decision belongs in a reviewed topology or an explicit policy flag — never in sampled tokens. Durable workflow engines make the same point with different vocabulary: activities are deterministic with respect to control decisions even when payloads are not. [VERIFY Temporal (or peer) docs if you cite them in training.]
Skeleton path for O-1001 once Part X lands: intake event → create_case → ticks through Intake/Resolution/Policy → Outreach drafts → HITL if needed → audit pack. The orchestrator’s job on that path is scheduling and stopping, not composing empathy.
Closed topologies as code review units
Adding shop_express_skip_policy should be as hard as deleting a policy test. Require:
- Name in
TOPOLOGIES - Stage list reviewed
- Eval scenarios that prove Policy still runs or an explicit legal exception documented
- Trace attribute
topology=...on every run
If product wants “faster,” optimize Intake/Resolution latency — do not invent a topology that skips the control gate.
Chapter summary
- Orchestration ≠ intelligence.
- Closed topology vocabulary only.
create_case / assign / tickis enough API surface to start.- Approvals pause the machine legally.
- Ledger + checkpoints make ticks auditable and resumable.
- DLQ for failed cases, not creative new graphs.
- One tick lane per case.
- Workers hold tools; orchestrator holds schedule.
Exercises
- Reject
create_case(..., topology="skip_policy")with a clear error. - Add topology
shop_standard_no_outreachand a test that never calls the outreach worker. - Make
tickidempotent when the current task is alreadyDONE. - Sketch Temporal/activity mapping for the four stages — concepts only. [VERIFY SOURCE]
References
- Temporal documentation (workflows, activities, determinism). [VERIFY]
- Anthropic. Building Effective Agents. — workflows vs agents. [VERIFY URL]
- Ch 7–8 FSM/checkpoints; Ch 32 queues — production topology.