Transitions
(Implemented in Phase 1.)
A transition moves an execution between states. A transition has a name (the
action that triggers it), a source state and a target state:
from workflow_kit import Transition
Transition(
name="approve",
source="manager_review",
target="finance_review",
)
Transitions are declared on a Workflow, either as Transition objects or as
(name, source, target) tuples:
workflow = Workflow(
name="invoice_approval",
initial="draft",
states=["draft", "manager_review", "finance_review", "approved", "rejected"],
transitions=[
("submit", "draft", "manager_review"),
("approve", "manager_review", "finance_review"),
("approve", "finance_review", "approved"),
("reject", "manager_review", "rejected"),
],
)
References to unknown states and duplicate (source, name) pairs raise
WorkflowConfigurationError at definition time.
Inspecting transitions
workflow.transitions_from("manager_review") # list[Transition]
workflow.actions_from("manager_review") # ["approve", "reject"]
workflow.transition_for("draft", "submit") # Transition | None
Atomic execution
Executing a transition validates the execution's current state, then persists
the new state atomically in a transaction while the execution row is locked
(select_for_update where the backend supports it). Validation and the state
change never run partially.
Transitions enforce:
- Correct source state →
InvalidTransitionError - Not running against a completed workflow →
WorkflowAlreadyCompletedError - Conditions (Phase 4) failing on every candidate →
ConditionFailedError - More than one condition passing for an action →
WorkflowConfigurationError
Permissions (Phase 2) and conditions (Phase 4) plug into the same lifecycle:
execution.transition("approve", user=user)
# engine-level equivalent:
workflow.transition(execution, "approve", user=user)