Unit 06.01: Validating the arguments the model chose
The arguments a model chose are untrusted input that happened to arrive from inside your own system.
Type checks and policy checks are different layers
Four proposed refunds against shape rules and a business ceiling.
The code validates each.
LIMITS = {"max_refund": 500.0, "currencies": {"USD", "EUR"}}
def validate_refund(args):
problems = []
amount = args.get("amount")
if not isinstance(amount, (int, float)):
problems.append("amount missing or not a number")
elif amount <= 0:
problems.append("amount must be positive")
elif amount > LIMITS["max_refund"]:
problems.append(f"exceeds the {LIMITS['max_refund']} limit")
if args.get("currency") not in LIMITS["currencies"]:
problems.append(f"currency {args.get('currency')!r} not permitted")
return problems
for args in [{"amount": 120.0, "currency": "USD"},
{"amount": 9000.0, "currency": "USD"},
{"amount": "120", "currency": "USD"},
{"amount": 120.0, "currency": "BTC"}]:
problems = validate_refund(args)
print(f"{'ALLOW' if not problems else 'BLOCK'} {str(args):40} {problems}")
# The model chose these arguments from text that may have come from outside
# your organisation. The 500 ceiling is policy, not a type check, and it
# belongs in code where it can be audited.
The 9,000 refund passes every type check - a positive number, a valid currency, a well-formed account - and fails the policy one. That ceiling is a decision about how much this feature may move, not a validation detail.
Policy in code is auditable and testable. The same limit in a prompt is a request to a component that has already been handed the amount.
The mistake this prevents
The mistake is trusting arguments because a schema was attached to the tool definition. Schema validation catches types and will happily accept nine thousand, because nine thousand is a number.
Takeaway
Validate shape and policy separately. Policy limits belong in code as data, where an auditor can read them and a test can assert them.
