loan_approval.iml
IML example from the CodeLogician agent skill.
(*
--------------------------------------------------------------------------
title: Loan Approval System
name: loan-approval
description: Multiple conflicting loan approval criteria
--------------------------------------------------------------------------
Real-world TRICKY example: Loan Approval with Conflicting Criteria
THE TRICKY PROBLEM:
Loan approval involves multiple criteria that can conflict:
1. Credit score: <600 reject, 600-700 manual review, >700 approve
2. Debt-to-income ratio: >43% reject, 36-43% conditional, <36% approve
3. Employment: <1 year unstable, 1-2 years questionable, >2 years stable
4. Down payment: <10% risky, 10-20% acceptable, >20% excellent
5. Special override: Existing customer with perfect payment history can override some rules
TRICKY QUESTIONS:
- What happens when credit score says "approve" but debt ratio says "reject"?
- How many scenarios require manual review vs automatic decisions?
- What are ALL the ways a loan can be automatically approved?
- Are there contradictory rules that always reject?
WITHOUT decomposition: Complex nested ifs, easy to miss cases
WITH decomposition: See ALL decision paths, find contradictions
*)
type decision = Approved | Rejected | ManualReview
(* Calculate base credit tier *)
let credit_tier score =
if score < 600 then "poor"
else if score <= 700 then "fair"
else "good"
(* Calculate employment stability score *)
let employment_score years =
if years < 1 then 0
else if years < 2 then 1
else 2
(* THE TRICKY FUNCTION: Multiple interacting approval criteria *)
let evaluate_loan credit_score debt_ratio employment_years down_payment_pct is_existing_perfect_customer =
(* Hard rejections that cannot be overridden *)
if credit_score < 500 then
Rejected
else if debt_ratio > 50 then
Rejected
else if employment_years < 0 || down_payment_pct < 0 then
(* Invalid input *)
Rejected
else
(* Check if customer override applies *)
if is_existing_perfect_customer && credit_score >= 650 then
(* Existing perfect customers get approved with relaxed criteria *)
Approved
else if credit_score >= 720 && debt_ratio < 36 && employment_years >= 2 && down_payment_pct >= 10 then
(* Ideal candidate: all green flags *)
Approved
else if credit_score < 600 then
(* Low credit: reject unless perfect customer (handled above) *)
Rejected
else if debt_ratio > 43 then
(* High debt ratio: automatic rejection *)
Rejected
else if credit_score >= 680 && debt_ratio <= 40 && employment_years >= 1 then
(* Good enough for approval *)
Approved
else if credit_score >= 600 && employment_years < 1 then
(* Insufficient employment history: manual review *)
ManualReview
else if down_payment_pct < 10 then
(* Low down payment needs review *)
ManualReview
else
(* All other cases: manual review *)
ManualReview
[@@decomp top ~basis:[[%id credit_tier]; [%id employment_score]] ()]
(* VARIATION: With pruning to remove impossible combinations
Question: Are there any branches that can never be reached?
*)
let evaluate_loan_pruned credit_score debt_ratio employment_years down_payment_pct is_existing_perfect_customer =
if credit_score < 500 then
Rejected
else if debt_ratio > 50 then
Rejected
else if employment_years < 0 || down_payment_pct < 0 then
Rejected
else
if is_existing_perfect_customer && credit_score >= 650 then
Approved
else if credit_score >= 720 && debt_ratio < 36 && employment_years >= 2 && down_payment_pct >= 10 then
Approved
else if credit_score < 600 then
Rejected
else if debt_ratio > 43 then
Rejected
else if credit_score >= 680 && debt_ratio <= 40 && employment_years >= 1 then
Approved
else if credit_score >= 600 && employment_years < 1 then
ManualReview
else if down_payment_pct < 10 then
ManualReview
else
ManualReview
[@@decomp top ~prune:true ~basis:[[%id credit_tier]; [%id employment_score]] ()]
(* VARIATION: With pruning to remove impossible combinations *)
let evaluate_loan_valid credit_score debt_ratio employment_years down_payment_pct is_existing_perfect_customer =
if credit_score < 500 then
Rejected
else if debt_ratio > 50 then
Rejected
else
if is_existing_perfect_customer && credit_score >= 650 then
Approved
else if credit_score >= 720 && debt_ratio < 36 && employment_years >= 2 && down_payment_pct >= 10 then
Approved
else if credit_score < 600 then
Rejected
else if debt_ratio > 43 then
Rejected
else if credit_score >= 680 && debt_ratio <= 40 && employment_years >= 1 then
Approved
else if credit_score >= 600 && employment_years < 1 then
ManualReview
else if down_payment_pct < 10 then
ManualReview
else
ManualReview
[@@decomp top ~prune:true ~ctx_simp:true ~basis:[[%id credit_tier]; [%id employment_score]] ()]