commit 2f82400203262eacfa488ced2fd058d2465f6c41
parent d04a0ddf77b6e96f107bcd174df46d2df929d25b
Author: triesap <tyson@radroots.org>
Date: Mon, 21 Sep 2026 13:05:54 +0000
provider: map jev failures into stable internal outcomes
Diffstat:
2 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/src/hyf_provider/jev_failures.mojo b/src/hyf_provider/jev_failures.mojo
@@ -0,0 +1,37 @@
+
+
+@fieldwise_init
+struct JevFailure(Copyable, Movable):
+ var family: String
+ var retryable: Bool
+
+
+def map_jev_failure(kind: String) raises -> JevFailure:
+ var lowered = kind.lower()
+ if lowered == "authentication":
+ return JevFailure(family="provider_auth", retryable=False)
+ if lowered == "validation":
+ return JevFailure(family="provider_validation", retryable=False)
+ if lowered == "bad_request":
+ return JevFailure(family="provider_validation", retryable=False)
+ if lowered == "not_found":
+ return JevFailure(family="provider_validation", retryable=False)
+ if lowered == "unprocessable_entity":
+ return JevFailure(family="provider_validation", retryable=False)
+ if lowered == "rate_limit":
+ return JevFailure(family="provider_capacity", retryable=True)
+ if lowered == "overloaded":
+ return JevFailure(family="provider_capacity", retryable=True)
+ if lowered == "internal_server":
+ return JevFailure(family="provider_transport", retryable=True)
+ if lowered == "request_timeout":
+ return JevFailure(family="provider_transport", retryable=True)
+ if lowered == "connection":
+ return JevFailure(family="provider_transport", retryable=True)
+ if lowered == "timeout":
+ return JevFailure(family="provider_transport", retryable=True)
+ if lowered == "response_validation":
+ return JevFailure(family="provider_response_contract", retryable=False)
+ if lowered == "transport":
+ return JevFailure(family="provider_transport", retryable=False)
+ raise Error("unknown provider failure kind: " + kind)
diff --git a/tests/test_jev.mojo b/tests/test_jev.mojo
@@ -144,3 +144,21 @@ def test_parse_jev_response_validates_answer_set() raises:
var missing = loads('{"model":"jev-1.13.0","answers":{"supply_status":{"type":"choice","choice":"offered","confidence":1.0}}}')
with assert_raises():
_ = parse_jev_response(missing, _bundle())
+
+
+from hyf_provider.jev_failures import map_jev_failure
+
+
+def test_jev_failure_mapping_permanent_vs_transient() raises:
+ assert_equal(map_jev_failure("authentication").family, "provider_auth")
+ assert_true(not map_jev_failure("authentication").retryable)
+ assert_equal(map_jev_failure("validation").family, "provider_validation")
+ assert_true(not map_jev_failure("validation").retryable)
+ assert_equal(map_jev_failure("rate_limit").family, "provider_capacity")
+ assert_true(map_jev_failure("rate_limit").retryable)
+ assert_true(map_jev_failure("overloaded").retryable)
+ assert_true(map_jev_failure("internal_server").retryable)
+ assert_equal(map_jev_failure("response_validation").family, "provider_response_contract")
+ assert_true(not map_jev_failure("response_validation").retryable)
+ with assert_raises():
+ _ = map_jev_failure("mystery")