hyf

Context-aware query service for Radroots
git clone https://radroots.dev/git/hyf.git
Log | Files | Refs | README | LICENSE

commit c390ebd82f8d71553bf825a15df2443e4cdc63c1
parent 572775a3c7783aac2c8c1017c8195ef4590c0852
Author: triesap <tyson@radroots.org>
Date:   Thu, 24 Sep 2026 02:51:07 +0000

C003: freeze D21 policy constants in the named runtime/application owners

ADR-0024 D44 PB01; ADR-0010 D21. The machine-readable policy table
(docs/spec/hyf_http_v1/policy/hyf_http_v1_policy.v1.toml) transcribes D21 plus
every later explicit supersession. This slice applies the already-selected
constants in their named owners; H092/H093 implement the planned derivations.

- resource_envelope.mojo: name the five semantic limits (64/8/4096/32/4) and use
  them in default_resource_envelope
- budget.mojo: freeze connect/read and output caps (1000 ms), wire-attempt
  ceiling (4), one retry (100 ms backoff), circuit threshold/cooldown/half-open
  (3 / 30000 ms / 1) as named constants; Budget() semantics unchanged
- config.mojo: name the default provider request timeout (15000 ms)
- test_runtime_paths.mojo: executed cap-1/cap/cap+1 boundary controls for the
  resource envelope, the absolute request budget and the inclusive stdio frame
  cap, plus a frozen-constant test
- no value enlarged or weakened; no production SLO claimed

Diffstat:
Msrc/hyf_application/resource_envelope.mojo | 27++++++++++++++++++++++-----
Msrc/hyf_runtime/budget.mojo | 20++++++++++++++++++++
Msrc/hyf_runtime/config.mojo | 7++++++-
Mtests/test_runtime_paths.mojo | 150+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 198 insertions(+), 6 deletions(-)

diff --git a/src/hyf_application/resource_envelope.mojo b/src/hyf_application/resource_envelope.mojo @@ -1,3 +1,19 @@ +"""Frozen semantic resource envelope (ADR-0010 D21; policy table +``docs/spec/hyf_http_v1/policy/hyf_http_v1_policy.v1.toml``). + +These are Codex-selected local regression bounds, not production SLOs. The +values are frozen here as named constants and applied by +:func:`default_resource_envelope`; dependent slices (H093 and the operation +pipelines) consume them and may not enlarge or weaken them. +""" + +comptime RESOURCE_ENVELOPE_MAX_CANDIDATES: Int = 64 +comptime RESOURCE_ENVELOPE_MAX_PLANS: Int = 8 +comptime RESOURCE_ENVELOPE_MAX_STATE_BYTES: Int = 4096 +comptime RESOURCE_ENVELOPE_MAX_QUESTIONS: Int = 32 +comptime RESOURCE_ENVELOPE_MAX_PROVIDER_CALLS: Int = 4 + + @fieldwise_init struct ResourceEnvelope(Copyable, Movable): var max_candidates: Int @@ -9,11 +25,11 @@ struct ResourceEnvelope(Copyable, Movable): def default_resource_envelope() -> ResourceEnvelope: return ResourceEnvelope( - max_candidates=64, - max_plans=8, - max_state_bytes=4096, - max_questions=32, - max_provider_calls=4, + max_candidates=RESOURCE_ENVELOPE_MAX_CANDIDATES, + max_plans=RESOURCE_ENVELOPE_MAX_PLANS, + max_state_bytes=RESOURCE_ENVELOPE_MAX_STATE_BYTES, + max_questions=RESOURCE_ENVELOPE_MAX_QUESTIONS, + max_provider_calls=RESOURCE_ENVELOPE_MAX_PROVIDER_CALLS, ) @@ -25,6 +41,7 @@ def within_envelope( questions: Int, provider_calls: Int, ) -> Bool: + """True when every dimension is at or below its inclusive cap.""" return ( candidates <= envelope.max_candidates and plans <= envelope.max_plans diff --git a/src/hyf_runtime/budget.mojo b/src/hyf_runtime/budget.mojo @@ -1,3 +1,23 @@ +"""Shared absolute request budget and frozen timeout/retry/circuit constants +(ADR-0010 D21; policy table +``docs/spec/hyf_http_v1/policy/hyf_http_v1_policy.v1.toml``). + +:class:`Budget` is one monotonic absolute cap with no per-stage reset. The +named constants freeze the Codex-selected local bounds so the dependent slices +(H092 timeout derivation, C006/C007 transport, C043 circuit) consume exact +values instead of restating them; they are not production SLOs. +""" + +comptime CONNECT_READ_CAP_MS: Int = 1000 +comptime OUTPUT_BLOCK_CAP_MS: Int = 1000 +comptime MAX_WIRE_ATTEMPTS: Int = 4 +comptime MAX_RETRIES_PER_CALL: Int = 1 +comptime RETRY_BACKOFF_MS: Int = 100 +comptime CIRCUIT_OPEN_THRESHOLD: Int = 3 +comptime CIRCUIT_COOLDOWN_MS: Int = 30000 +comptime CIRCUIT_HALF_OPEN_PROBES: Int = 1 + + @fieldwise_init struct Budget(Copyable, Movable): var start_monotonic_ns: Int diff --git a/src/hyf_runtime/config.mojo b/src/hyf_runtime/config.mojo @@ -3,6 +3,11 @@ from std.pathlib import Path from morph.toml import from_toml +# ADR-0010 D21 freeze: the request budget is min(positive request deadline, the +# configured provider request_timeout_ms). This named default is consumed by +# H092's derivation and must not be enlarged or weakened here. +comptime DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS: Int = 15000 + @fieldwise_init struct HyfServiceRuntimeConfig(Copyable, Defaultable, Movable): @@ -57,7 +62,7 @@ struct HyfTypesafeProviderRuntimeConfig(Copyable, Defaultable, Movable): self.enabled = False self.base_url = "https://api.typesafe.ai" self.model = "jev-1.13.0" - self.request_timeout_ms = 15000 + self.request_timeout_ms = DEFAULT_PROVIDER_REQUEST_TIMEOUT_MS @fieldwise_init diff --git a/tests/test_runtime_paths.mojo b/tests/test_runtime_paths.mojo @@ -602,6 +602,156 @@ def test_budget_boundaries_are_deterministic() raises: assert_true(budget_exhausted(staged, 250_000_000)) +from hyf_application.resource_envelope import ( + RESOURCE_ENVELOPE_MAX_CANDIDATES, + RESOURCE_ENVELOPE_MAX_PLANS, + RESOURCE_ENVELOPE_MAX_PROVIDER_CALLS, + RESOURCE_ENVELOPE_MAX_QUESTIONS, + RESOURCE_ENVELOPE_MAX_STATE_BYTES, + default_resource_envelope, + within_envelope, +) +from hyf_runtime.budget import ( + CIRCUIT_COOLDOWN_MS, + CIRCUIT_HALF_OPEN_PROBES, + CIRCUIT_OPEN_THRESHOLD, + CONNECT_READ_CAP_MS, + MAX_RETRIES_PER_CALL, + MAX_WIRE_ATTEMPTS, + OUTPUT_BLOCK_CAP_MS, + RETRY_BACKOFF_MS, +) +from hyf_stdio.server import MAX_FRAME_BYTES, frame_too_large + + +def _frame_of(count: Int) -> String: + var out = List[UInt8]() + for _ in range(count): + out.append(UInt8(97)) + return String(unsafe_from_utf8=Span(ptr=out.unsafe_ptr(), length=len(out))) + + +def test_policy_constants_match_frozen_d21_values() raises: + # C003 / ADR-0010 D21: the already-selected constants are frozen exactly in + # their named capsule owners; this slice may not enlarge or weaken them. + assert_equal(MAX_FRAME_BYTES, 1048576) + assert_equal(CONNECT_READ_CAP_MS, 1000) + assert_equal(OUTPUT_BLOCK_CAP_MS, 1000) + assert_equal(MAX_WIRE_ATTEMPTS, 4) + assert_equal(MAX_RETRIES_PER_CALL, 1) + assert_equal(RETRY_BACKOFF_MS, 100) + assert_equal(CIRCUIT_OPEN_THRESHOLD, 3) + assert_equal(CIRCUIT_COOLDOWN_MS, 30000) + assert_equal(CIRCUIT_HALF_OPEN_PROBES, 1) + assert_true(MAX_RETRIES_PER_CALL < MAX_WIRE_ATTEMPTS) + + +def test_resource_envelope_boundaries_are_inclusive() raises: + # C003 / D21 limits: every semantic dimension is cap-1/cap/cap+1 tested and + # the cap itself is inclusive. + var envelope = default_resource_envelope() + assert_equal(envelope.max_candidates, RESOURCE_ENVELOPE_MAX_CANDIDATES) + assert_equal(envelope.max_plans, RESOURCE_ENVELOPE_MAX_PLANS) + assert_equal(envelope.max_state_bytes, RESOURCE_ENVELOPE_MAX_STATE_BYTES) + assert_equal(envelope.max_questions, RESOURCE_ENVELOPE_MAX_QUESTIONS) + assert_equal( + envelope.max_provider_calls, RESOURCE_ENVELOPE_MAX_PROVIDER_CALLS + ) + # candidates + assert_true( + within_envelope( + envelope, RESOURCE_ENVELOPE_MAX_CANDIDATES - 1, 0, 0, 0, 0 + ) + ) + assert_true( + within_envelope(envelope, RESOURCE_ENVELOPE_MAX_CANDIDATES, 0, 0, 0, 0) + ) + assert_true( + not within_envelope( + envelope, RESOURCE_ENVELOPE_MAX_CANDIDATES + 1, 0, 0, 0, 0 + ) + ) + # plans + assert_true( + within_envelope(envelope, 0, RESOURCE_ENVELOPE_MAX_PLANS - 1, 0, 0, 0) + ) + assert_true( + within_envelope(envelope, 0, RESOURCE_ENVELOPE_MAX_PLANS, 0, 0, 0) + ) + assert_true( + not within_envelope( + envelope, 0, RESOURCE_ENVELOPE_MAX_PLANS + 1, 0, 0, 0 + ) + ) + # state bytes + assert_true( + within_envelope( + envelope, 0, 0, RESOURCE_ENVELOPE_MAX_STATE_BYTES - 1, 0, 0 + ) + ) + assert_true( + within_envelope(envelope, 0, 0, RESOURCE_ENVELOPE_MAX_STATE_BYTES, 0, 0) + ) + assert_true( + not within_envelope( + envelope, 0, 0, RESOURCE_ENVELOPE_MAX_STATE_BYTES + 1, 0, 0 + ) + ) + # questions + assert_true( + within_envelope( + envelope, 0, 0, 0, RESOURCE_ENVELOPE_MAX_QUESTIONS - 1, 0 + ) + ) + assert_true( + within_envelope(envelope, 0, 0, 0, RESOURCE_ENVELOPE_MAX_QUESTIONS, 0) + ) + assert_true( + not within_envelope( + envelope, 0, 0, 0, RESOURCE_ENVELOPE_MAX_QUESTIONS + 1, 0 + ) + ) + # logical provider calls + assert_true( + within_envelope( + envelope, 0, 0, 0, 0, RESOURCE_ENVELOPE_MAX_PROVIDER_CALLS - 1 + ) + ) + assert_true( + within_envelope( + envelope, 0, 0, 0, 0, RESOURCE_ENVELOPE_MAX_PROVIDER_CALLS + ) + ) + assert_true( + not within_envelope( + envelope, 0, 0, 0, 0, RESOURCE_ENVELOPE_MAX_PROVIDER_CALLS + 1 + ) + ) + + +def test_budget_cap_boundaries_are_inclusive() raises: + # C003 / D21 timeout: the absolute request budget is + # min(positive deadline, server cap) and the cap itself is inclusive. + var server_cap = 1000 + var at_cap = budget_from_clock(server_cap, server_cap, 0) + assert_equal(at_cap.cap_ms, server_cap) + var under_cap = budget_from_clock(server_cap - 1, server_cap, 0) + assert_equal(under_cap.cap_ms, server_cap - 1) + var over_cap = budget_from_clock(server_cap + 1, server_cap, 0) + assert_equal(over_cap.cap_ms, server_cap) + # remaining-time boundary: 1 ms left at cap-1, exhausted at cap. + assert_equal(budget_remaining_ms(at_cap, (server_cap - 1) * 1_000_000), 1) + assert_equal(budget_remaining_ms(at_cap, server_cap * 1_000_000), 0) + + +def test_stdio_frame_cap_boundaries_are_inclusive() raises: + # C003 / D21 stdio frame cap: the frame limit is inclusive (cap-1 and cap + # are accepted; only cap+1 is oversized). + assert_true(not frame_too_large(_frame_of(MAX_FRAME_BYTES - 1))) + assert_true(not frame_too_large(_frame_of(MAX_FRAME_BYTES))) + assert_true(frame_too_large(_frame_of(MAX_FRAME_BYTES + 1))) + + from hyf_runtime.jev_composition import compose_jev