order_state_machine.iml
IML example from the CodeLogician agent skill.
(*
--------------------------------------------------------------------------
title: E-commerce Order State Machine
name: order-state-machine
description: Complex order state transitions with multiple conditions
--------------------------------------------------------------------------
Real-world TRICKY example: E-commerce Order State Machine
THE TRICKY PROBLEM:
Order states can transition based on multiple conditions:
- Current state (Pending, Confirmed, Shipped, Delivered, Cancelled, Refunded)
- Payment status (Paid, Unpaid, Failed, Refunded)
- Inventory status (InStock, OutOfStock, Reserved)
- Time elapsed (in hours)
- Customer action (None, CancelRequest, ReturnRequest)
TRICKY QUESTIONS:
- From which states can we transition to Cancelled?
- What are ALL the ways to reach Delivered state?
- Are there any impossible state combinations?
- What happens if payment fails after shipping?
- Can we refund before delivery?
WITHOUT decomposition: State diagram is complex, easy to miss edge cases
WITH decomposition: See ALL valid transitions, find dead states or impossible paths
*)
type order_state = Pending | Confirmed | Shipped | Delivered | Cancelled | Refunded
type payment_status = Paid | Unpaid | Failed | PaymentRefunded
type inventory_status = InStock | OutOfStock | Reserved
type customer_action = NoAction | CancelRequest | ReturnRequest
(* THE TRICKY FUNCTION: Determine next state based on current state and conditions *)
let next_order_state
current_state
payment inventory
hours_elapsed
customer_action =
match current_state with
| Pending ->
if customer_action = CancelRequest then
Cancelled
else if payment = Failed then
Cancelled
else if payment = Paid && inventory = Reserved then
Confirmed
else if payment = Paid && inventory = OutOfStock then
(* Edge case: paid but no stock - what to do? *)
Pending (* Keep pending until stock available *)
else if hours_elapsed > 48 && payment = Unpaid then
(* Timeout: cancel unpaid orders after 48 hours *)
Cancelled
else
Pending
| Confirmed ->
if customer_action = CancelRequest && hours_elapsed < 24 then
(* Allow cancellation within 24 hours of confirmation *)
Cancelled
else if payment = PaymentRefunded then
(* Payment was refunded - cancel order *)
Cancelled
else if inventory = OutOfStock then
(* Stock became unavailable after confirmation *)
Pending (* Back to pending *)
else if hours_elapsed >= 24 then
(* Ship after 24 hours *)
Shipped
else
Confirmed
| Shipped ->
if customer_action = CancelRequest then
(* Too late to cancel, but can request return after delivery *)
Shipped
else if hours_elapsed >= 72 then
(* Delivered after 72 hours of shipping *)
Delivered
else
Shipped
| Delivered ->
if customer_action = ReturnRequest && hours_elapsed < 168 then
(* Allow returns within 7 days (168 hours) of delivery *)
Refunded
else
Delivered
| Cancelled ->
if payment = Paid then
(* Refund paid orders that were cancelled *)
Refunded
else
Cancelled
| Refunded ->
(* Terminal state - no transitions *)
Refunded
[@@decomp top ()]
(* VARIATION 1: Using basis to keep state abstract
This shows the control flow without expanding state details
*)
let next_order_state_abstract
current_state
payment inventory
hours_elapsed
customer_action =
match current_state with
| Pending ->
if customer_action = CancelRequest then Cancelled
else if payment = Failed then Cancelled
else if payment = Paid && inventory = Reserved then Confirmed
else if payment = Paid && inventory = OutOfStock then Pending
else if hours_elapsed > 48 && payment = Unpaid then Cancelled
else Pending
| Confirmed ->
if customer_action = CancelRequest && hours_elapsed < 24 then Cancelled
else if payment = PaymentRefunded then Cancelled
else if inventory = OutOfStock then Pending
else if hours_elapsed >= 24 then Shipped
else Confirmed
| Shipped ->
if customer_action = CancelRequest then Shipped
else if hours_elapsed >= 72 then Delivered
else Shipped
| Delivered ->
if customer_action = ReturnRequest && hours_elapsed < 168 then Refunded
else Delivered
| Cancelled ->
if payment = Paid then Refunded
else Cancelled
| Refunded ->
Refunded
[@@decomp top ~ctx_simp:true ()]
(* VARIATION 2: With pruning to remove impossible transitions
Question: Are there any unreachable transitions?
*)
let transitions_from_confirmed
current_state
payment inventory
hours_elapsed
customer_action =
match current_state with
| Confirmed ->
if customer_action = CancelRequest && hours_elapsed < 24 then Cancelled
else if payment = PaymentRefunded then Cancelled
else if inventory = OutOfStock then Pending
else if hours_elapsed >= 24 then Shipped
else Confirmed
| _ -> current_state (* Other states unchanged *)
[@@decomp top ~prune:true ()]