hyf

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

commit e02e759eba7d2a706e7863cd834dae4a24f311c6
parent 986fa89e553578f3686d83a5fda9f502a7fd1eff
Author: triesap <tyson@radroots.org>
Date:   Wed, 23 Sep 2026 18:24:33 +0000

H007: restrict expected-close acceptance to real peer-close classes

- Require the declared expected cause to be a peer close, not a timeout.
- Derive the observed phase from the write step actually attempted.
- Rename the refused-connection control to match its characterized outcome.
- Add a control proving a declared write timeout is still rejected.

Diffstat:
Mtests/strict_fixture.mojo | 30++++++++++++++++++++++++------
Mtests/test_provider_adapter.mojo | 37+++++++++++++++++++++++++++++++++++--
2 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/tests/strict_fixture.mojo b/tests/strict_fixture.mojo @@ -639,6 +639,16 @@ def classify_write_error_cause(text: String) -> String: return "unrelated_error" +def is_peer_close_cause(cause: String) -> Bool: + """True only for the bounded peer-close classes a script may expect. + + A declaration is structurally restricted to an actual peer close, so a + write timeout, an invalid descriptor or an unrelated handler error can + never be waived by naming it as the expected cause (ADR-0020 TC01). + """ + return cause == "peer_reset" or cause == "broken_pipe" + + def serve_scripts( listener: TcpListener, var scripts: List[ExchangeScript], label: String ) raises -> ServeReport: @@ -707,10 +717,7 @@ def serve_scripts( request_count = next_index if script.delay_ms > 0: usleep(script.delay_ms * 1000) - var phase = ( - "body_stall" if script.stall_after_head_ms - > 0 else "delayed_write" - ) + var phase = "delayed_write" try: if script.stall_after_head_ms > 0: # Headers-then-stall control (H007): write the complete @@ -718,7 +725,10 @@ def serve_scripts( # the declared bounded stall, then attempt the body. This # separates a body-read stall from a connection timeout # and from the overall budget using a bounded fixture - # delay that never hangs the owning test. + # delay that never hangs the owning test. ``phase`` is + # the write step actually being attempted, not a script + # label, so a head-write failure is not reported as a + # body stall. var rendered = render_response( script, framed.headers_raw, @@ -728,14 +738,18 @@ def serve_scripts( var separator = rendered.find("\r\n\r\n") if separator >= 0: var head_end = separator + 4 + phase = "head_write" reader.write_all(String(rendered[byte=0:head_end])) + phase = "body_stall" usleep(script.stall_after_head_ms * 1000) if script.inject_write_error != "": raise Error(script.inject_write_error) reader.write_all(String(rendered[byte=head_end:])) else: + phase = "head_write" reader.write_all(rendered) else: + phase = "delayed_write" if script.inject_write_error != "": raise Error(script.inject_write_error) reader.write_all( @@ -752,10 +766,14 @@ def serve_scripts( # whose exact bounded cause and phase match is accepted; # unexpected/wrong-phase closes, write timeouts, invalid # descriptors and unrelated handler errors fail the fixture - # with a bounded, cause-specific reason. + # with a bounded, cause-specific reason. The declared cause + # is itself restricted to a real peer-close class, so a + # timeout or unrelated error cannot be waived by declaring + # it as the expected cause. var observed = classify_write_error_cause(String(e)) if ( script.expect_peer_close + and is_peer_close_cause(script.expected_close_cause) and observed == script.expected_close_cause and phase == script.expected_close_phase ): diff --git a/tests/test_provider_adapter.mojo b/tests/test_provider_adapter.mojo @@ -393,9 +393,10 @@ def _bounded_timeout_provider_config( ) -def test_provider_connect_timeout_is_bounded_and_specific() raises: +def test_provider_refused_connection_is_bounded_and_specific() raises: # H007: a refused connection is a bounded, cause-specific transport failure, - # not a hang. No provider client policy is changed here. + # not a hang. It is explicitly characterized as a refusal, not as a real + # connect-timeout scenario, and no provider client policy is changed here. var guard = CleanupGuard() var dead_port = reserve_loopback_port() var config = _bounded_timeout_provider_config(dead_port, 300) @@ -700,6 +701,38 @@ def test_provider_scripted_injected_write_error_fails() raises: guard.assert_clean() +def test_provider_scripted_declared_non_peer_cause_is_rejected() raises: + # TC01: the declared expected cause is restricted to a real peer-close class, + # so a write timeout can never be waived by declaring it as expected. + var scripts = List[ExchangeScript]() + var script = exchange_script( + "declared_timeout", + "POST", + "/v1/chat/completions", + 200, + '{"choices":[]}', + ) + script.stall_after_head_ms = 200 + script.expect_peer_close = True + script.expected_close_cause = "write_timeout" + script.expected_close_phase = "body_stall" + script.inject_write_error = "Timeout" + scripts.append(script^) + var guard = CleanupGuard() + with spawn_max_local_scripted(0, scripts^, guard) as provider_stub: + _ = _raw_send_and_read(provider_stub.port, "/v1/chat/completions") + provider_stub.reap() + assert_true(not provider_stub.ok()) + assert_equal(provider_stub.phase(), "peer_close") + assert_true( + provider_stub.reason().find( + "unexpected_write_write_timeout_body_stall" + ) + >= 0 + ) + guard.assert_clean() + + def test_provider_stalled_call_is_parent_bounded() raises: # TC02: a real risky client call against a stalling peer runs under the # parent deadline and is stopped/reaped by the parent instead of hanging.