Assignment Policy Ifc
The subsystem's principal extension point: who gets sent where.
suspend is the whole design in one keyword. A rule that answers immediately is a dispatching rule of the ordinary kind; a policy that first waits ten minutes is batching; a policy that calls for proposals and waits for a deadline is an auction. All three are "decide assignments", and they differ only in whether deciding takes simulated time. An interface that could not suspend would admit only the first, which is exactly the limitation this subsystem exists to remove.
A policy decides only (A7). It cannot move a vehicle, claim a zone, post a task, or mutate the board -- the board it is given is read-only and AssignmentProposal is inert, so this is enforced by the types rather than by a rule. It may read anything.
A policy must also be a function of what it is given, drawing any randomness from a model-controlled stream (A8). Consulting wall-clock time or unmanaged global state would make a run unreproducible in a way no test would catch.
Why assign is written as an extension on the process builder
KSLProcessBuilder is annotated @RestrictsSuspension, which means a process body may only invoke suspending functions that are members or extensions of the builder itself. A plain suspend fun assign(context) on this interface would therefore not compile at the one call site that matters -- the dispatcher's process -- however sound it looked in isolation.
Declaring it as a member extension satisfies the restriction and buys something as well: an implementation receives the real process builder as its receiver, so it may delay for a batching window, hold, or call contractNet to run an auction, rather than being confined to whatever a context object thought to expose. The dispatcher calls it as with(policy) { assign(context) }.