commit b065cef0baf1fdb1dd91c6156e9d62dcdc4b5c39
parent 76426ad7e9264c8ae50735abb82464cfb2046d4c
Author: triesap <tyson@radroots.org>
Date: Wed, 23 Sep 2026 03:35:47 +0000
test(hyf): split-duplicate control, Jev scope/startup paths and stale-doc fix (C002D review 3)
Third independent read-only review of 76426ad returned FAIL. Repair within
ADR-0017 D37 PC01/PC02; test-only.
PC01: add the missing split-duplicate control (first report line spans two
512-byte reads with a second report after it -> duplicate_report) plus split
positive controls on both provider reap paths.
PC02: execute the Jev startup-readiness failure path against a real owned
child (occupied port -> serve_failed) with cleanup truth exposed; add the
absent Jev generic-error and early-return scope-cleanup paths and the Jev
scope-exit cleanup-failure observability control.
Provider helper refactor: SpawnedJevStub owns its reported port so the auto
and explicit-port spawners no longer move a nested field out of a value now
that the lifecycle record holds an undecoded byte buffer.
Also correct the stale terminate_owned docstring (wait_error is returned
without signalling, never as completed cleanup) and tighten the late-success
control to prove the declared budget was actually consumed.
Re-verified on final source: provider-helpers 80/80, repo-local-process 9/9,
test-stdio 56/32/24/0 with identical D16 names and reasons, format/architecture/
build green.
Diffstat:
5 files changed, 89 insertions(+), 21 deletions(-)
diff --git a/tests/jev_provider_helper.mojo b/tests/jev_provider_helper.mojo
@@ -266,10 +266,12 @@ struct SpawnedJevStub(Movable):
"""Single-owner Jev fixture handle; the body receives a view."""
var pid: Int
+ var port: Int
var state: PipedChildState
- def __init__(out self, pid: Int, var state: PipedChildState):
+ def __init__(out self, pid: Int, port: Int, var state: PipedChildState):
self.pid = pid
+ self.port = port
self.state = state^
def __enter__(mut self) -> SpawnedJevStubView:
@@ -575,7 +577,8 @@ def spawn_jev_stub_auto(
deadline_ms: Int = FIXTURE_DEFAULT_DEADLINE_MS,
ledger: CleanupLedger = CleanupLedger(),
) raises -> SpawnedJevStubAuto:
- return _spawn_jev_stub(0, mode, requests, deadline_ms, ledger)
+ var stub = _spawn_jev_stub(0, mode, requests, deadline_ms, ledger)
+ return SpawnedJevStubAuto(port=stub.port, stub=stub^)
def spawn_jev_stub(
@@ -583,9 +586,9 @@ def spawn_jev_stub(
mode: String,
requests: Int,
deadline_ms: Int = FIXTURE_DEFAULT_DEADLINE_MS,
+ ledger: CleanupLedger = CleanupLedger(),
) raises -> SpawnedJevStub:
- var started = _spawn_jev_stub(port, mode, requests, deadline_ms)
- return started.stub^
+ return _spawn_jev_stub(port, mode, requests, deadline_ms, ledger)
def serve_jev_scripted(
@@ -612,7 +615,7 @@ def _spawn_child_or_cleanup(
deadline_ms: Int,
requests: Int,
ledger: CleanupLedger,
-) raises -> SpawnedJevStubAuto:
+) raises -> SpawnedJevStub:
"""Build the owned state, read exact readiness, or clean up and raise."""
var state = piped_child_state(
pid, pipe.read_fd, deadline_ms, requests, ledger
@@ -639,7 +642,7 @@ def _spawn_child_or_cleanup(
try:
reported_port = parse_ready_or_cleanup(pid, ready_line, 256)
except e:
- _ = finalize_owned_failure(
+ var st = finalize_owned_failure(
state, pid, "jev startup malformed-readiness cleanup unproved"
)
raise Error(
@@ -647,12 +650,12 @@ def _spawn_child_or_cleanup(
+ String(e)
+ " pid="
+ String(pid)
+ + " cleanup="
+ + ("proved" if st.cleanup_proved() else "unreaped")
+ ")"
)
_ = mode
- return SpawnedJevStubAuto(
- port=reported_port, stub=SpawnedJevStub(pid, state^)
- )
+ return SpawnedJevStub(pid, reported_port, state^)
def _spawn_jev_scripted(
@@ -681,9 +684,10 @@ def _spawn_jev_scripted(
write_raw(1, report_line(failed) + "\n")
child_exit(125)
close_fd(pipe.write_fd)
- return _spawn_child_or_cleanup(
+ var stub = _spawn_child_or_cleanup(
pipe, pid, "scripted", deadline_ms, total, ledger
)
+ return SpawnedJevStubAuto(port=stub.port, stub=stub^)
def _spawn_jev_stub(
@@ -692,7 +696,7 @@ def _spawn_jev_stub(
requests: Int,
deadline_ms: Int,
ledger: CleanupLedger = CleanupLedger(),
-) raises -> SpawnedJevStubAuto:
+) raises -> SpawnedJevStub:
var pipe = make_pipe()
var pid = fork_owned_or_close(pipe.copy())
if pid == 0:
diff --git a/tests/max_local_process_helper.mojo b/tests/max_local_process_helper.mojo
@@ -753,7 +753,7 @@ def _spawn_max_local(
try:
reported_port = parse_ready_or_cleanup(pid, ready_line, 256)
except e:
- _ = finalize_owned_failure(
+ var st = finalize_owned_failure(
state, pid, "max_local startup malformed-readiness cleanup unproved"
)
raise Error(
@@ -761,6 +761,8 @@ def _spawn_max_local(
+ String(e)
+ " pid="
+ String(pid)
+ + " cleanup="
+ + ("proved" if st.cleanup_proved() else "unreaped")
+ ")"
)
return SpawnedMaxLocalStub(pid, reported_port, state^)
diff --git a/tests/parent_lifecycle.mojo b/tests/parent_lifecycle.mojo
@@ -651,11 +651,11 @@ def wait_bounded(pid: Int, deadline_ms: Int) -> ProcessStatus:
def terminate_owned(pid: Int, grace_ms: Int) -> ProcessStatus:
"""Reap a child this test owns, escalating SIGTERM -> SIGKILL.
- A pid already reaped or not waitable (``gone``) is never signaled, so a
- reused PID from an unrelated process can never be targeted. An
- ``interrupted``/``wait_error`` status still owns a live child, so it is
- signaled and reaped; the returned status is only ``reaped`` when the child
- was actually collected.
+ In ``terminate_owned`` a pid already reaped or not waitable (``gone``) is
+ never signaled, so a reused PID from an unrelated process can never be
+ targeted. An ``interrupted`` status still owns a live child and is
+ retried/signaled; a ``wait_error`` leaves identity/ownership unproved and is
+ returned without signalling and never as completed cleanup.
"""
var st = wait_nohang(pid)
if st.cleanup_proved():
diff --git a/tests/test_provider_helpers.mojo b/tests/test_provider_helpers.mojo
@@ -63,6 +63,7 @@ from max_local_process_helper import (
from jev_provider_helper import (
SpawnedJevStub,
spawn_jev_scripted_auto,
+ spawn_jev_stub,
spawn_jev_stub_auto,
)
@@ -965,7 +966,7 @@ def _owned_jev_report_child(
child_exit(exit_code)
close_fd(pipe.write_fd)
var state = piped_child_state(pid, pipe.read_fd, 2000, 1, CleanupLedger())
- return SpawnedJevStub(pid, state^)
+ return SpawnedJevStub(pid, 0, state^)
# ── LC01: automatic scope ownership ─────────────────────────────────────────
@@ -1024,6 +1025,49 @@ def test_jev_scope_cleanup_on_assertion_failure() raises:
assert_true(pid_not_waitable(held_pid))
+def test_jev_scope_cleanup_on_generic_error() raises:
+ var held_pid = 0
+ var message = ""
+ try:
+ with spawn_jev_stub_auto("ok", 1) as started:
+ held_pid = started.stub.pid
+ raise Error("intentional jev scope error")
+ except e:
+ message = String(e)
+ assert_equal(message, "intentional jev scope error")
+ assert_true(pid_not_waitable(held_pid))
+
+
+def _jev_early_return_owner() raises -> Int:
+ with spawn_jev_stub_auto("ok", 1) as started:
+ return started.stub.pid
+ return 0
+
+
+def test_jev_scope_cleanup_on_early_return() raises:
+ var held_pid = _jev_early_return_owner()
+ assert_true(held_pid > 0)
+ assert_true(pid_not_waitable(held_pid))
+
+
+def test_jev_startup_failure_is_truthful_and_cause_specific() raises:
+ # PC02/LC01: the Jev startup-readiness failure path executes against a real
+ # owned child, reports its cause and exposes the finalizer's cleanup truth.
+ var blocker = TcpListener.bind(SocketAddr.localhost(0))
+ var port = Int(blocker.local_addr().port)
+ var message = ""
+ try:
+ var started = spawn_jev_stub(port, "ok", 1)
+ started.cleanup()
+ except e:
+ message = String(e)
+ blocker.close()
+ assert_true(message.find("phase=startup") >= 0)
+ assert_true(message.find("reason=serve_failed") >= 0)
+ assert_true(message.find("cleanup=") >= 0)
+ assert_true(message.find("pid=") >= 0)
+
+
def test_wait_error_taxonomy_distinguishes_causes() raises:
assert_equal(classify_wait_errno(Int(ErrNo.EINTR.value)), "interrupted")
assert_equal(classify_wait_errno(Int(ErrNo.ECHILD.value)), "gone")
@@ -1568,6 +1612,18 @@ def test_report_stream_controls_both_providers() raises:
assert_equal(first.byte_length(), 512)
_report_controls(first + VALID_REPORT, 0, "duplicate_report")
_report_controls(VALID_REPORT + VALID_REPORT, 0, "duplicate_report")
+ var split_first = "result ok phase=complete case="
+ while split_first.byte_length() + tail.byte_length() < 700:
+ split_first += "y"
+ split_first += tail
+ assert_equal(split_first.byte_length(), 700)
+ _report_controls(split_first + VALID_REPORT, 0, "duplicate_report")
+ var split_positive = _owned_report_child(0, split_first)
+ split_positive.reap()
+ assert_true(split_positive.ok())
+ var jev_split = _owned_jev_report_child(0, split_first)
+ jev_split.reap()
+ assert_true(jev_split.ok())
var unterminated = String(
VALID_REPORT[byte = 0 : VALID_REPORT.byte_length() - 1]
)
@@ -1785,7 +1841,7 @@ def test_provider_reap_descriptor_read_error_both_paths() raises:
var jev_state = piped_child_state(
jev_pid, jev_closed_fd, 2000, 1, CleanupLedger()
)
- var jev_stub = SpawnedJevStub(jev_pid, jev_state^)
+ var jev_stub = SpawnedJevStub(jev_pid, 0, jev_state^)
jev_stub.reap()
assert_true(not jev_stub.ok())
assert_equal(jev_stub.reason(), "read_error")
@@ -1794,7 +1850,7 @@ def test_provider_reap_descriptor_read_error_both_paths() raises:
def test_cleanup_failure_survives_scope_exit() raises:
# PC02: cleanup failure must remain observable after the owning handle is
- # destroyed at scope exit, not merely stored in an inaccessible object.
+ # destroyed at scope exit, for BOTH provider handles.
var recorded = List[String]()
var ledger = CleanupLedger(UnsafePointer(to=recorded))
var state = piped_child_state(0, -1, 100, 1, ledger)
@@ -1802,6 +1858,11 @@ def test_cleanup_failure_survives_scope_exit() raises:
_ = holder
assert_equal(len(recorded), 1)
assert_true(recorded[0].find("unproved") >= 0)
+ var jev_state = piped_child_state(0, -1, 100, 1, ledger)
+ with SpawnedJevStub(0, 0, jev_state^) as jev_holder:
+ _ = jev_holder
+ assert_equal(len(recorded), 2)
+ assert_true(recorded[1].find("unproved") >= 0)
def test_descriptor_census_unavailable_propagates() raises:
diff --git a/tests/test_repo_local_process_contract.mojo b/tests/test_repo_local_process_contract.mojo
@@ -145,7 +145,8 @@ def test_run_stdio_entrypoint_rejects_late_success() raises:
or message.find("read_deadline_expired") >= 0
)
assert_true(message.find("cleanup_error=") >= 0)
- assert_true(elapsed >= 1000)
+ assert_true(message.find("child_failed") < 0)
+ assert_true(elapsed >= 1150)
assert_true(elapsed <= 3700)