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 ()]