Representing processes

Processes

Introduction

State machines are powerful models used to represent and control the behavior of systems or processes. At their core, state machines provide a structured way to manage complex workflows, decision-making processes, and system behaviors. They offer clarity in process definition, improve error handling and system stability, simplify maintenance of logic, and enhance communication among stakeholders.

A state machine can be thought of as an abstract model of a system that exists in one of a finite number of states at any given time. As the system receives inputs or encounters specific conditions, it can transition between these states according to predefined rules. During these transitions, the machine may also produce outputs or trigger certain actions.

Interactions between AWMT and state machines

AWMT provides robust support for implementing and managing state machines. This integration allows for seamless creation, manipulation, and monitoring of state machines within the AWMT environment. The following sections will detail how to leverage AWMT's capabilities to work with state machines effectively.

Methods

Creating a process / state machine

To create a state machine in AWMT, we first need to define the model that the state machine will operate on, and then create the state machine itself.

Example:

mutation {
	create_model(path: "ticket") {
		title: create_submodel(subpath: "title", prototype: "string") {
			done
		}
		assigned_dev: create_submodel(subpath: "assigned_dev", prototype: "employee") {
			done
		}
		assigned_tester: create_submodel(subpath: "assigned_tester", prototype: "employee") {
			done
		}
		tested: create_submodel(subpath: "tested", prototype: "boolean") {
			done
		}
 
		task: create_submodel(subpath: "task", prototype: "task") {
			done
		}
		commit: create_submodel(subpath: "commit", prototype: "commit") {
			done
		}
	}
}
 
mutation {
	at(path: "ticket") {
		create_state_machine(name: "advancement") {
			path
		}
	}
}

In this example, we first create a "ticket" model with various submodels representing different attributes of a ticket. Then, we create a state machine named "advancement" associated with this ticket model.

The response confirms the creation of the model and its submodels, and provides the path to the newly created state machine:

{
	"data": {
		"create_model": {
			"title": { "done": true },
			"assigned_dev": { "done": true },
			"assigned_tester": { "done": true },
			"tested": { "done": true },
			"task": { "done": true },
			"commit": { "done": true }
		},
		"at": {
			"create_state_machine": {
				"path": "ticket.advancement"
			}
		}
	}
}

Defining states for a state machine

Once we have created a state machine, the next step is to define its states. Each state represents a distinct condition or situation in which the system can exist.

Example:

mutation {
	at(path: "advancement") {
		draft: add_state(name: "draft", entry: true) {
			done
		}
		posted: add_state(name: "posted") {
			done
		}
		assigned: add_state(name: "assigned") {
			done
		}
		awaiting_test: add_state(name: "awaiting_test") {
			done
		}
		solved: add_state(name: "solved") {
			done
		}
		canceled: add_state(name: "canceled", finale: true) {
			done
		}
		commited: add_state(name: "commited", finale: true) {
			done
		}
	}
}

In this example, we define seven states for our "advancement" state machine:

  • "draft" is marked as the entry state (where the process begins)
  • "posted", "assigned", "awaiting_test", and "solved" are intermediate states
  • "canceled" and "commited" are marked as finale states (where the process ends)

The response confirms the successful creation of all states:

{
	"data": {
		"at": {
			"draft": { "done": true },
			"posted": { "done": true },
			"assigned": { "done": true },
			"awaiting_test": { "done": true },
			"solved": { "done": true },
			"canceled": { "done": true },
			"commited": { "done": true }
		}
	}
}

Defining Transitions

Transitions define how the system moves from one state to another. They represent the allowed paths between states and often include conditions or triggers that cause the transition to occur.

Example:

mutation {
	at(path: "advancement:draft") {
		add_active_transition(to: "posted") {
			title: connect(submodel: "title")
		}
	}
}

In this example, we're adding a transition from the "draft" state to the "posted" state. The connect operation suggests that the "title" submodel is required for this transition to occur. When a user will request to run that transition, if the title is not filled yet, then AWMT will use its [/slot-filling](slot filling) capabilities to ask the user to provide the missing information.

The response confirms the successful creation of the transition:

{
	"data": {
		"add_active_transition": {
			"title": { "done": true }
		}
	}
}

Side effects

Side effects are actions or changes that occur as a result of state transitions.

Getting the current state

AWMT allows querying the current state of a process instance and its possible next steps. This is crucial for understanding where a process stands and what actions are available.

Example:

query {
	model(path: "my_ticket") {
		state(path: "advancement") {
			next_steps {
				path
				label
 
				next_steps {
					path
					label
				}
			}
		}
	}
}

This query retrieves the current state of a specific ticket ("my_ticket") and its possible next steps, including a second level of next steps. The response might look like this:

{
	"data": {
		"model": {
			"state": {
				"next_steps": [
					{
						"path": "posted",
						"label": "Posted",
						"next_steps": [
							{
								"path": "assigned",
								"label": "Assigned"
							}
						]
					}
				]
			}
		}
	}
}

This response indicates that the current state has one possible next step ("Posted"), which in turn has its own next step ("Assigned").

Finding instances in a specific state

AWMT also provides the ability to find all instances of a model that are currently in a specific state. This is useful for monitoring and managing processes at scale.

Example:

query {
	model(path: "ticket") {
		find_instances_by_state(state: "awaiting_state") {
			path
			label
			description
		}
	}
}

This query finds all ticket instances that are currently in the "awaiting_state". The response might look like:

{
	"data": {
		"model": {
			"find_instances_by_state": [
				{
					"path": "ticket.1",
					"label": "Ticket 1",
					"description": "This ticket is currently in the awaiting_test state."
				},
				{
					"path": "ticket.2",
					"label": "Ticket 2",
					"description": "This ticket is currently in the awaiting_test state."
				}
			]
		}
	}
}

This response lists all tickets currently in the "awaiting_test" state, providing their paths, labels, and descriptions.

Reasoning about a process

This could include:

  1. Identifying bottlenecks: States where many instances are stuck.
  2. Analyzing process efficiency: Examining the average time spent in each state.
  3. Predicting outcomes: Based on current states and historical data, estimating likely end states for ongoing processes.
  4. Optimizing workflows: Using state machine data to identify areas for process improvement.

AWMT likely provides additional querying and analysis tools to support these reasoning tasks, allowing for comprehensive process management and optimization.