Summary#
Workflow.Inbox<T>() tells a person what is waiting for them. These three verbs are how they
answer it — from the row, without knowing in advance which slot it turned out to be.
Signature#
Workflow.Deposit(row, <Event>(args…)) // answer the slot this row is
Workflow.Claim(row) // take an unassigned slot you are eligible for
Workflow.Release(row) // hand a claimed slot back to the poolDescription#
Why the event is named, and not called#
Everywhere else a deposit is spelled <Workflow>.For(entity).<Slot>.<Event>(…) — every part of it written by the
author. A queue does not work that way. One row may be a manager's decision and the next a finance sign-off, so
row.Approve(…) cannot exist: the verb set differs per workflow, and a given row's verb is only known once the queue
has been read.
So the event is an argument, the same shape Workflow.Run (start a workflow) uses when you raise one by name
(OrderFlow.RaisePayment(order, 100)) — and the split in checking follows from that:
| checked by | what it checks |
|---|---|
| the compiler | Event is declared by a workflow that Tracks T, and its arguments type-check |
| the run | this row's slot is actually waiting for that event — and Candidates, Requires and quorum |
Naming an event the row is not waiting for is refused, not deposited. That matters more than it sounds: arguments bind to the arm by name, so a wrong event's payload would otherwise arrive as parameters nobody set.
It is the same deposit#
There is one deposit in the platform and this is it. A row does not carry permission — obtaining it changes nothing
about who may act. A principal holding someone else's row and naming the right event is still refused by the slot's
own Candidates, because the queue has no rules of its own and deliberately nowhere to keep any.
Claiming#
The queue shows unassigned work you are eligible for, so Workflow.Claim(row) takes it and Workflow.Release(row)
gives it back. Both need a principal — nothing can hold a slot on nobody's behalf. Only the current holder may
release.
To hand a slot to a named colleague rather than back to the pool, there is a third verb —
Workflow.Assign(row, principal). It is separated out because it is the one act here that asks
about the actor as well as the target: eligibility to hold work is not authority to move it.
Examples#
The morning screen, and the button on it:
enum ClaimStage { Filed, Approved, Rejected }
[Principal] entity Employee {
[Required] [MaxLength(80)] string DisplayName;
security {
allow read when IsAuthenticated;
allow create when IsAuthenticated;
}
}
entity Invoice {
[Required] [MaxLength(120)] string Title;
[Required] decimal Amount;
[Required] Employee Owner;
ClaimStage Stage;
security {
allow read, update when IsAuthenticated;
allow create when IsAuthenticated;
}
}
workflow ExpenseApproval {
Tracks = Invoice.Stage;
Autostart = true;
Initial = Filed;
event Decide(bool approved);
state Filed {
subscribe Decide(bool approved) as Manager { Assignee = this.Item.Owner; }
on Manager(bool approved) {
when (approved) { goto Approved; }
default { goto Rejected; }
}
}
terminal success Approved { }
terminal error Rejected { Message = "rejected"; }
}
void ApproveOldest() {
var oldest = Workflow.Inbox<Invoice>()
.OrderBy(r => r.OpenedAt)
.First();
Workflow.Deposit(oldest, Decide(approved: true));
}Once it is answered the row leaves the queue, because the queue is re-read rather than remembered.
Notes#
A fanned-out row acts on its own slot. A row addresses the slot it is a row for, so one principal holding two instances of the same fanned-out slot answers the one they picked — not whichever an alias lookup would have found.
The compiler checks less here, and nothing enforces less. The event and its arguments are supplied at the call site rather than derived from a slot the author named, so a mistake that the static form would catch at compile time is caught at run time instead. What is allowed is unchanged: the same authorization, the same requirements, the same quorum.
See also#
- Workflow.Inbox<T> (what is waiting for me) — the queue these verbs act on
- Candidates (slot) — who may hold or satisfy a slot, and
<Wf>.For(item).<Slot>.Candidates(u)for a screen deciding whether to OFFER the claim in the first place - Assign — handing a slot to a named colleague — handing a slot to a named colleague, and the
Reassignrule that permits it - Requires — named preconditions, and the live checklist — the criteria a deposit must satisfy, and how to show them before the click
- subscribe — declaring the slot and the event it waits for