commit 3e6fd4bf258c004fe0971069f865d2843b4bbb3c
parent 2dff4e31b3a7d62be074f3102de81338500eca6b
Author: triesap <tyson@radroots.org>
Date: Thu, 24 Sep 2026 16:19:26 +0000
H092: derive internal request/stage timeout caps under D21
Diffstat:
2 files changed, 124 insertions(+), 0 deletions(-)
diff --git a/src/hyf_runtime/budget.mojo b/src/hyf_runtime/budget.mojo
@@ -51,3 +51,64 @@ def budget_remaining_ms(value: Budget, now_ns: Int) -> Int:
def budget_exhausted(value: Budget, now_ns: Int) -> Bool:
return budget_remaining_ms(value, now_ns) == 0
+
+
+def request_budget_cap_ms(
+ request_deadline_ms: Int, configured_request_timeout_ms: Int
+) raises -> Int:
+ """ADR-0010 D21 absolute request-budget derivation.
+
+ The assisted-work cap is ``min(positive request deadline_ms, configured
+ provider request_timeout_ms)``. A non-positive configured timeout is an
+ invalid configuration and is rejected; a non-positive request deadline
+ means the caller supplied none, so the configured cap governs. The result
+ is always positive and neither input can enlarge the other.
+ """
+ if configured_request_timeout_ms <= 0:
+ raise Error("configured provider request_timeout_ms must be positive")
+ if request_deadline_ms <= 0:
+ return configured_request_timeout_ms
+ if request_deadline_ms < configured_request_timeout_ms:
+ return request_deadline_ms
+ return configured_request_timeout_ms
+
+
+def derived_stage_cap_ms(stage_cap_ms: Int, remaining_budget_ms: Int) -> Int:
+ """``min(stage cap, remaining overall budget)``, never negative.
+
+ D21 connect/read and output caps are derived from the positive remaining
+ absolute budget; this helper never replaces or extends the total deadline.
+ """
+ if remaining_budget_ms <= 0:
+ return 0
+ if remaining_budget_ms < stage_cap_ms:
+ return remaining_budget_ms
+ return stage_cap_ms
+
+
+def derived_connect_read_cap_ms(remaining_budget_ms: Int) -> Int:
+ return derived_stage_cap_ms(CONNECT_READ_CAP_MS, remaining_budget_ms)
+
+
+def derived_output_block_cap_ms(remaining_budget_ms: Int) -> Int:
+ return derived_stage_cap_ms(OUTPUT_BLOCK_CAP_MS, remaining_budget_ms)
+
+
+def budget_stage_cap_ms(value: Budget, now_ns: Int, stage_cap_ms: Int) -> Int:
+ """Absolute-deadline-aware stage cap: ``min(stage cap, remaining budget)``.
+ """
+ return derived_stage_cap_ms(
+ stage_cap_ms, budget_remaining_ms(value, now_ns)
+ )
+
+
+def request_budget_from_config(
+ request_deadline_ms: Int,
+ configured_request_timeout_ms: Int,
+ now_ns: Int,
+) raises -> Budget:
+ """One monotonic absolute budget from an explicit D21 derivation."""
+ var cap_ms = request_budget_cap_ms(
+ request_deadline_ms, configured_request_timeout_ms
+ )
+ return budget_from_clock(cap_ms, cap_ms, now_ns)
diff --git a/tests/test_runtime_paths.mojo b/tests/test_runtime_paths.mojo
@@ -782,3 +782,66 @@ def test_new_operation_configuration_matrix() raises:
assert_true(not operation_enabled(config, "farm_update.interpret"))
assert_true(not operation_enabled(config, "buyer_request.interpret"))
assert_true(not operation_enabled(config, "buyer_request.match"))
+
+
+# H092 / ADR-0010 D21: internal timeout derivation, positivity and total-phase bounds.
+from hyf_runtime.budget import (
+ budget_stage_cap_ms,
+ derived_connect_read_cap_ms,
+ derived_output_block_cap_ms,
+ derived_stage_cap_ms,
+ request_budget_cap_ms,
+ request_budget_from_config,
+)
+
+
+def test_h092_request_budget_derivation_table() raises:
+ # min(positive deadline, configured timeout); the configured cap governs
+ # when the caller supplies no (or a non-positive) deadline.
+ assert_equal(request_budget_cap_ms(2500, 15000), 2500)
+ assert_equal(request_budget_cap_ms(20000, 15000), 15000)
+ assert_equal(request_budget_cap_ms(15000, 15000), 15000)
+ assert_equal(request_budget_cap_ms(1, 15000), 1)
+ assert_equal(request_budget_cap_ms(0, 15000), 15000)
+ assert_equal(request_budget_cap_ms(-5, 15000), 15000)
+ # A non-positive configured timeout is invalid configuration, not a
+ # silently zero/unbounded budget.
+ with assert_raises():
+ _ = request_budget_cap_ms(2500, 0)
+ with assert_raises():
+ _ = request_budget_cap_ms(2500, -1)
+ assert_true(request_budget_cap_ms(2500, 15000) > 0)
+
+
+def test_h092_stage_cap_derivations_are_bounded_and_inclusive() raises:
+ # connect/read and output caps are min(1000, remaining), inclusive at cap.
+ assert_equal(derived_connect_read_cap_ms(999), 999)
+ assert_equal(derived_connect_read_cap_ms(1000), 1000)
+ assert_equal(derived_connect_read_cap_ms(1001), 1000)
+ assert_equal(derived_output_block_cap_ms(999), 999)
+ assert_equal(derived_output_block_cap_ms(1000), 1000)
+ assert_equal(derived_output_block_cap_ms(1001), 1000)
+ # Zero/negative remaining budget collapses to zero, never negative and
+ # never an extension of the deadline.
+ assert_equal(derived_connect_read_cap_ms(0), 0)
+ assert_equal(derived_output_block_cap_ms(0), 0)
+ assert_equal(derived_connect_read_cap_ms(-10), 0)
+ assert_equal(derived_output_block_cap_ms(-10), 0)
+ assert_equal(derived_stage_cap_ms(1000, -1), 0)
+
+
+def test_h092_budget_stage_cap_respects_absolute_deadline() raises:
+ var value = request_budget_from_config(500, 15000, 0)
+ assert_equal(value.cap_ms, 500)
+ assert_equal(budget_remaining_ms(value, 0), 500)
+ assert_equal(budget_stage_cap_ms(value, 0, 1000), 500)
+ assert_equal(budget_stage_cap_ms(value, 200_000_000, 1000), 300)
+ assert_equal(budget_stage_cap_ms(value, 499_000_000, 1000), 1)
+ assert_equal(budget_stage_cap_ms(value, 500_000_000, 1000), 0)
+ assert_equal(budget_stage_cap_ms(value, 900_000_000, 1000), 0)
+ # The configured timeout governs when it is smaller than the deadline, and
+ # the same object never resets across staged clock advancement.
+ var configured = request_budget_from_config(20000, 1500, 0)
+ assert_equal(configured.cap_ms, 1500)
+ assert_equal(budget_stage_cap_ms(configured, 1_000_000_000, 1000), 500)
+ assert_equal(budget_stage_cap_ms(configured, 1_500_000_000, 1000), 0)