/// Demonstrates the same resilient order flow as chapter 6 while highlighting good operator design.
/// Each operator owns one clear responsibility: fetch nodes return stable data shapes, CalcPriceOperator is a pure fan-in calculation, CreditCheckOperator emits a tiny decision contract, and the terminal nodes each model exactly one business outcome.
/// Because the contracts stay explicit, timeout, retry, fallback, transform, and branch rules remain easy to read and reason about.
graph orderProcessV5 {
  node fetchUser : FetchUserOperator {
    input {
      userId = ctx.userId
    }
    timeout = 3s
    retry = { attempts: 2, backoff: 200ms, strategy: exponential }
  }

  node fetchProducts : FetchProductsOperator {
    input {
      productIds = ctx.productIds
    }
    timeout = 5s
  }

  node calcPrice : CalcPriceOperator {
    depends_on = [fetchUser, fetchProducts]
    input {
      user = fetchUser.output
      products = fetchProducts.output
    }
  }

  transform orderSummary {
    customerName = fetchUser.output.name
    itemCount = calcPrice.output.itemCount
    total = calcPrice.output.total
  }

  node checkCredit : CreditCheckOperator {
    depends_on = [fetchUser, calcPrice]
    input {
      userId = fetchUser.output.id
      amount = calcPrice.output.total
    }
    retry = { attempts: 3, backoff: 100ms, strategy: jitter }
    fallback = { approved: false, reason: "credit service unavailable" }
  }

  branch on checkCredit.output.approved {
    true -> createOrder
    false -> rejectOrder
  }

  node createOrder : CreateOrderOperator {
    depends_on = [calcPrice]
    input {
      user = fetchUser.output
      price = calcPrice.output
    }
  }

  node rejectOrder : RejectOrderOperator {
    depends_on = [checkCredit]
    input {
      userId = fetchUser.output.id
      reason = checkCredit.output.reason
    }
  }
}
