Appendix B - 2. Agent-orchestration model (developer journeys)
The Structure of Agent-orchestration model (developer journeys) — its shape at a glance:
Two typed state machines carry the developer journey. The agent lifecycle runs from dispatch to a clean teardown, with an abandoned/recovered branch; the orchestrator loop observes a completion, lands it, refills the freed slot, and banks state. A drift gate reconciles the declared states against the live registry's event vocabulary.
stateDiagram-v2 [*] --> Dispatched Dispatched --> Working: prepare Working --> Landed: commit + verify Working --> Abandoned: stream-silence Abandoned --> Working: recover Landed --> Tombstoned: clean Tombstoned --> [*]
Accessible description: an agent moves from dispatched to working to landed to tombstoned, with a branch where a stalled agent is abandoned and later recovered back to working. The declared states are what a drift gate checks against the live registry.
Projected from the catalogue entry system-models / Agent-orchestration model (developer journeys).
On this page: Intent · Motivation · Applicability · Structure · Sample Code · Consequences · Example use within DocAble · Related Patterns
Intent
Intent — Model the agent fleet and the orchestrator's own loop with the same MBSE method you point at the product: typed lifecycle states, typed seams, and invariants whose verification tier is derived (not hand-typed), all held to reality by a drift gate. The substrate that produces the software becomes as checkable as the software. It is the developer-journey view (dispatch→work→land→tombstone; the refill/bank loop), not the user-journey view (our instance: an agent_orch model that reuses the product state-machine's tier-derivation and drift machinery, and carries the reflection-facet registry as a first-class modeled node).
Motivation
The bridge models tie agents to the product, but the fleet that builds the product usually goes unmodeled. Its lifecycle (dispatch → prepare → sentinel → work → commit → land → tombstone → clean, with the abandoned/recovered branch) and the orchestrator's own loop (observe a completion → land + run the definition-of-done → refill the freed slot → bank state if the freshness window lapsed → rest) live implicitly, scattered across the dispatch tool, the registry, the tombstone tool, the worktree tool. Nothing names them as typed state machines, so the failures are all invisible: an agent reaches a state no transition allows; the orchestrator rests with ratified work still queued; a fleet invariant (exactly-one-live-marker per agent, upload-before-teardown, exactly-one-completer) is asserted nowhere; and the reflection substrate the fleet runs on itself drifts from what anyone modeled. The fleet is the one system the team operates every hour and the one system it never drew.
Applicability
- The trunk method already exists (the tier-derivation, the coordination/temporal types, the drift-gate machinery), so the orchestration arm reuses it rather than reinventing. That reuse is why this subject is modeled as a second arm rather than as a bespoke fleet doc.
- The fleet lifecycle is enacted through addressable substrate (a registry, a tombstone record, a worktree tool) the model can reconcile against. Without a real event vocabulary to check the states against, it is a hand-authored doc, not a checked model.
- A live fleet substrate to anchor model = territory, here the reflection-facet registry.
Structure
The Structure diagram appears at the top of this page.
Sample Code
The lifecycle is a transition table, not scattered flags. A guard function accepts a move only if the table allows it, and a reconcile step fails when a declared state has no counterpart in the live event vocabulary — the check that keeps the model equal to the fleet it describes.
import sys
# The fleet lifecycle as an explicit transition table (the source of truth).
TRANSITIONS = {
"dispatched": {"working"},
"working": {"landed", "abandoned"},
"abandoned": {"working"}, # recover branch
"landed": {"tombstoned"},
"tombstoned": set(),
}
def legal(frm: str, to: str) -> bool:
return to in TRANSITIONS.get(frm, set())
def reconcile(live_events: set[str]) -> list[str]:
"""Every declared state must appear in the live event vocabulary, and vice versa."""
declared = set(TRANSITIONS)
findings = [f"declared state '{s}' has no live event" for s in declared - live_events]
findings += [f"live event '{e}' has no declared state" for e in live_events - declared]
return findings
if __name__ == "__main__":
# `read_registry_vocab` returns the state names the live registry actually emits.
findings = reconcile(read_registry_vocab())
for f in findings:
print(f"MODEL-DRIFT: {f}")
sys.exit(1 if findings else 0)
Consequences
- The fleet lifecycle gains one authoritative source of truth (SSOT). A new fleet state, or a new reflection facet, is now a model edit, or the drift gate fails. Deliberately; that is the freshness gate working.
- Modeling the operator's own loop can feel like navel-gazing until the first time it catches the orchestrator resting with ratified work queued, or a facet silently drifting from the registry. Those are the invariants that only fire under the dynamics, invisible to a static read.
- It inherits the product method's ceremony (derived tiers, drift gates) for the fleet, worth paying only because the fleet is operated constantly and its failures (a lost agent, a double-completer, an un-reflected recurrence) are expensive.
Example use within DocAble
- An
agent_orchmodel: the fleet-lifecycle state machine (dispatch → … → tombstone → clean, with the abandoned/recovered branch) + the orchestrator-loop state machine (observe → land + DoD → refill → bank → rest), a closed set of typed seams, and invariants with derived verification tiers reconciled against the registry's event vocabulary. - The reflection-facet registry modeled as first-class nodes (genre + built/interface-ready + policy-material references), with a drift gate reconciling the declared nodes against the live registry both ways: model = territory over the reflection-facet substrate.
Related Patterns
- Sibling (same method, other subject) — the product-facing models (service-flow · user-journey): this is the developer- journey counterpart. Same trunk method (derived-tier invariants, drift gates), reified toward the fleet instead of the product: the orchestration arm of the Y to their product arm.
- Bridge — it models the very substrate the agents run on; the reflection-facet substrate's registry is one of its first-class nodes (the model = territory anchor).
- See also — formal-invariant-verification: the fleet-invariant tier derivation is that mechanism applied to the orchestration subject; drift-parity-gates: the node↔registry reconciliation is that parity applied to the fleet model.