hyf

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

jev_provider_helper.mojo (28411B)


      1 """Strict scripted Jev provider HTTP fixture (ADR-0012 D29 / ADR-0014 D33).
      2 
      3 Same parent-owned lifecycle and phase/case/reason reporting as the MaxLocal
      4 fixture: parent-enforced startup/read/write/wait deadlines (FX06), bounded
      5 reporting (FX07) and exception-safe reaping (FX08).
      6 """
      7 
      8 from std.collections import List
      9 
     10 from flare.net import SocketAddr
     11 from flare.tcp import TcpListener
     12 from flare.utils import usleep
     13 
     14 from parent_lifecycle import (
     15     FIXTURE_DEFAULT_DEADLINE_MS,
     16     TERMINATION_GRACE_MS,
     17     CleanupGuard,
     18     PipedChildState,
     19     PipeFds,
     20     ProcessStatus,
     21     child_exit,
     22     close_fd,
     23     dup2_fd,
     24     finalize_owned_failure,
     25     fork_owned_or_close,
     26     make_pipe,
     27     parse_ready_or_cleanup,
     28     piped_child_state,
     29     set_alarm,
     30     sleep_ms,
     31     write_raw,
     32 )
     33 from strict_fixture import (
     34     STRICT_MAX_REPORT_BYTES,
     35     json_escape,
     36     STRICT_COMPLETION_GRACE_MS,
     37     ConnectionReader,
     38     ExchangeScript,
     39     FramedRequest,
     40     ServeReport,
     41     authorization_reason,
     42     exchange_script,
     43     parse_report,
     44     render_response,
     45     report_line,
     46     report_status_matches_exit,
     47     serve_scripts,
     48     validate_convenience,
     49     verify_exchange,
     50 )
     51 
     52 
     53 comptime STUB_ALARM_SECONDS = 20
     54 comptime JEV_INTENDED_PATH = "/v1/systemone"
     55 
     56 
     57 def allowed_jev_paths() -> List[String]:
     58     var paths = List[String]()
     59     paths.append(JEV_INTENDED_PATH)
     60     return paths^
     61 
     62 
     63 def allowed_jev_methods() -> List[String]:
     64     var methods = List[String]()
     65     methods.append("POST")
     66     return methods^
     67 
     68 
     69 def require_bearer_for(mode: String) -> Bool:
     70     return False
     71 
     72 
     73 def analysis() -> String:
     74     return (
     75         '{"model":"jev-1.13.0","answers":{'
     76         '"supply_status":{"type":"choice","choice":"offered","probabilities":{"offered":1.0,"forecast":0.0,"unclear":0.0},"confidence":1.0},'
     77         '"seconds_ok":{"type":"noul","noul":0.9},'
     78         '"culinary_fit":{"type":"score","score":2,"legend":{"0":"u","1":"l","2":"s"},"probabilities":{"0":0.0,"1":0.0,"2":1.0},"confidence":1.0}},'
     79         '"usage":{"input_tokens":10,"output_tokens":5}}'
     80     )
     81 
     82 
     83 def _status(mode: String) -> Int:
     84     if mode == "rate_limit":
     85         return 429
     86     if mode == "server_error":
     87         return 500
     88     if mode == "overloaded":
     89         return 529
     90     if mode == "auth":
     91         return 401
     92     return 200
     93 
     94 
     95 def _raw_response(mode: String) -> String:
     96     if mode == "truncated":
     97         return (
     98             "HTTP/1.1 200 OK\r\ncontent-type: application/json\r\n"
     99             "content-length: 999\r\nconnection: close\r\n\r\n"
    100             '{"model":"jev'
    101         )
    102     if mode == "redirect":
    103         return (
    104             "HTTP/1.1 302 Found\r\nlocation:"
    105             " http://127.0.0.1:1/steal\r\ncontent-length:"
    106             " 0\r\nconnection: close\r\n\r\n"
    107         )
    108     return ""
    109 
    110 
    111 def _delay_ms(mode: String) -> Int:
    112     if mode == "slow":
    113         return 2000
    114     return 0
    115 
    116 
    117 def header_names_json(headers_raw: String) -> String:
    118     """Captured request header *names* as a JSON array, values redacted.
    119 
    120     H006 characterization: the loopback fixture can report which headers it
    121     captured without ever embedding a real or sentinel credential value.
    122     """
    123     var out = String("[")
    124     var first = True
    125     for line in headers_raw.split("\r\n"):
    126         var entry = String(line)
    127         var colon = entry.find(":")
    128         if colon <= 0:
    129             continue
    130         var name = String(entry[byte=0:colon]).strip().lower()
    131         if name == "":
    132             continue
    133         if not first:
    134             out += ","
    135         out += json_escape(name)
    136         first = False
    137     return out + "]"
    138 
    139 
    140 def _body(mode: String) -> String:
    141     if mode == "ok" or mode == "slow":
    142         return analysis()
    143     if mode == "rate_limit":
    144         return '{"error":{"message":"slow down"}}'
    145     if mode == "server_error":
    146         return '{"error":{"message":"boom"}}'
    147     if mode == "overloaded":
    148         return '{"error":{"message":"overloaded"}}'
    149     if mode == "auth":
    150         return '{"error":{"message":"bad key"}}'
    151     if mode == "malformed_json":
    152         return "not json"
    153     if mode == "model_mismatch":
    154         return analysis().replace("jev-1.13.0", "jev-other")
    155     return '{"error":{"message":"unsupported_mode"}}'
    156 
    157 
    158 def _build_script(mode: String, framed: FramedRequest) -> ExchangeScript:
    159     var script = exchange_script(
    160         mode, framed.method, JEV_INTENDED_PATH, _status(mode), ""
    161     )
    162     script.delay_ms = _delay_ms(mode)
    163     script.close_connection = True
    164     script.require_bearer = require_bearer_for(mode)
    165     var raw = _raw_response(mode)
    166     if raw != "":
    167         script.raw_response = raw
    168     elif mode == "echo_headers":
    169         # Header capture with values redacted: only names are echoed.
    170         script.response_body = (
    171             '{"captured_headers":' + header_names_json(framed.headers_raw) + "}"
    172         )
    173     elif mode == "echo_authorization":
    174         var auth = authorization_reason(framed.headers_raw, True)
    175         if auth != "":
    176             script.status = 401
    177             script.response_body = '{"error":{"message":"' + auth + '"}}'
    178         else:
    179             script.echo_authorization = True
    180     else:
    181         script.response_body = _body(mode)
    182     return script^
    183 
    184 
    185 def serve_jev(port: Int, mode: String, requests: Int) raises -> ServeReport:
    186     var allowed = allowed_jev_paths()
    187     var methods = allowed_jev_methods()
    188     var listener = TcpListener.bind(SocketAddr.localhost(UInt16(port)))
    189     var actual_port = Int(listener.local_addr().port)
    190     write_raw(1, "ready " + String(actual_port) + "\n")
    191     var request_count = 0
    192     var connection_count = 0
    193     try:
    194         while request_count < requests:
    195             var stream = listener.accept()
    196             connection_count += 1
    197             var reader = ConnectionReader(stream^)
    198             while request_count < requests:
    199                 var framed = reader.read()
    200                 if not framed.ok:
    201                     if framed.error == "empty":
    202                         if request_count < requests:
    203                             return ServeReport(
    204                                 False,
    205                                 "accounting",
    206                                 mode,
    207                                 "missing_exchanges",
    208                                 request_count,
    209                                 connection_count,
    210                             )
    211                         break
    212                     return ServeReport(
    213                         False,
    214                         "read",
    215                         mode,
    216                         framed.error,
    217                         request_count,
    218                         connection_count,
    219                     )
    220                 var reason = validate_convenience(
    221                     framed, allowed, methods, False
    222                 )
    223                 if reason != "":
    224                     return ServeReport(
    225                         False,
    226                         "exchange",
    227                         mode,
    228                         reason,
    229                         request_count,
    230                         connection_count,
    231                     )
    232                 var next_index = request_count + 1
    233                 var script = _build_script(mode, framed)
    234                 var verify = verify_exchange(script, framed)
    235                 if verify != "":
    236                     return ServeReport(
    237                         False,
    238                         "exchange",
    239                         mode,
    240                         verify,
    241                         request_count,
    242                         connection_count,
    243                     )
    244                 if next_index == requests:
    245                     var extra = reader.probe_completion(
    246                         STRICT_COMPLETION_GRACE_MS
    247                     )
    248                     if extra != "":
    249                         return ServeReport(
    250                             False,
    251                             "accounting",
    252                             mode,
    253                             extra,
    254                             request_count,
    255                             connection_count,
    256                         )
    257                 request_count = next_index
    258                 if script.delay_ms > 0:
    259                     usleep(script.delay_ms * 1000)
    260                 reader.write_all(
    261                     render_response(
    262                         script,
    263                         framed.headers_raw,
    264                         request_count,
    265                         connection_count,
    266                     )
    267                 )
    268                 if script.close_connection:
    269                     break
    270         if request_count < requests:
    271             return ServeReport(
    272                 False,
    273                 "accounting",
    274                 mode,
    275                 "missing_exchanges",
    276                 request_count,
    277                 connection_count,
    278             )
    279         return ServeReport(
    280             True, "complete", mode, "ok", request_count, connection_count
    281         )
    282     except:
    283         return ServeReport(
    284             False, "read", mode, "io_error", request_count, connection_count
    285         )
    286 
    287 
    288 # ── Parent side ─────────────────────────────────────────────────────────────
    289 
    290 
    291 struct SpawnedJevStub(Movable):
    292     """Single-owner Jev fixture handle; the body receives a view."""
    293 
    294     var pid: Int
    295     var port: Int
    296     var state: PipedChildState
    297 
    298     def __init__(out self, pid: Int, port: Int, var state: PipedChildState):
    299         self.pid = pid
    300         self.port = port
    301         self.state = state^
    302 
    303     def __enter__(mut self) -> SpawnedJevStubView:
    304         return SpawnedJevStubView(self.pid, UnsafePointer(to=self))
    305 
    306     def __exit__(mut self):
    307         self.cleanup()
    308 
    309     def cleanup(mut self):
    310         """Fast, non-raising owned cleanup for assertion/error/early return.
    311 
    312         Ownership is released only once the child is provably collected. An
    313         uncertain wait keeps the handle retryable, records the failure in the
    314         required caller-held guard and retains the exact pid/report descriptor
    315         for recovery, instead of being silently marked complete. Never raises,
    316         so a body/assertion cause is preserved at scope exit.
    317         """
    318         if self.state.reaped:
    319             return
    320         var report_fd = self.state.report_fd
    321         var status = self.state.terminate_once(self.pid, TERMINATION_GRACE_MS)
    322         self.state.status = status.copy()
    323         if status.cleanup_proved():
    324             self.state.reaped = True
    325             self.state.close_reader()
    326             self.state.guard[].resolve_pid(self.pid)
    327             return
    328         self.state.record_unproved(
    329             self.pid,
    330             report_fd,
    331             "owned-child cleanup unproved",
    332             "unreaped:" + status.describe(),
    333         )
    334 
    335     def ok(self) -> Bool:
    336         return self.state.ok
    337 
    338     def phase(self) -> String:
    339         return String(self.state.phase)
    340 
    341     def failure_case(self) -> String:
    342         return String(self.state.case_label)
    343 
    344     def reason(self) -> String:
    345         return String(self.state.reason)
    346 
    347     def request_count(self) -> Int:
    348         return self.state.requests
    349 
    350     def connection_count(self) -> Int:
    351         return self.state.connections
    352 
    353     def cleanup_error(self) -> String:
    354         return String(self.state.cleanup_error)
    355 
    356     def describe(self) -> String:
    357         return (
    358             "phase="
    359             + self.state.phase
    360             + " case="
    361             + self.state.case_label
    362             + " reason="
    363             + self.state.reason
    364             + " requests="
    365             + String(self.state.requests)
    366             + " connections="
    367             + String(self.state.connections)
    368         )
    369 
    370     def status(mut self) -> ProcessStatus:
    371         """Observe child status without losing ownership or report truth.
    372 
    373         A terminal observation is cached so a later ``reap`` never performs a
    374         new wait on a stale/reused identity. A transient ``wait_error`` or any
    375         other nonterminal result is returned but deliberately *not* cached, so
    376         it stays retryable and cannot overwrite a valid terminal result.
    377         """
    378         if self.state.reaped:
    379             return self.state.status.copy()
    380         if self.state.observed_valid:
    381             return self.state.observed.copy()
    382         var st = self.state.wait_once(self.pid)
    383         if st.state == "reaped" or st.state == "gone":
    384             self.state.observed = st.copy()
    385             self.state.observed_valid = True
    386         return st^
    387 
    388     def reap(mut self):
    389         """Reap the owned child within one declared finite work budget.
    390 
    391         Never raises (so ``__exit__`` cannot mask a body error). Startup, wait,
    392         report line and EOF drain share ``deadline_ms`` measured from spawn: an
    393         expired budget fails with ``work_budget_expired`` and only the bounded
    394         cleanup allowance, and no fresh successful interval is granted.
    395         """
    396         if self.state.reaped:
    397             return
    398         if self.state.faults.wait_delay_ms > 0:
    399             sleep_ms(self.state.faults.wait_delay_ms)
    400             self.state.faults.wait_delay_ms = 0
    401         var remaining = self.state.work_remaining_ms()
    402         if remaining <= 0:
    403             self.state.store(
    404                 False, "watchdog", "-", "work_budget_expired", 0, 0
    405             )
    406             var expired = self.state.terminate_once(
    407                 self.pid, TERMINATION_GRACE_MS
    408             )
    409             self.state.status = expired.copy()
    410             if expired.cleanup_proved():
    411                 self.state.reaped = True
    412                 self.state.close_reader()
    413                 self.state.guard[].resolve_pid(self.pid)
    414             else:
    415                 self.state.reason = "work_budget_expired_unreaped"
    416                 self.state.record_unproved(
    417                     self.pid,
    418                     self.state.report_fd,
    419                     "owned-child cleanup unproved",
    420                     "unreaped:" + expired.describe(),
    421                 )
    422             return
    423         var status = ProcessStatus("pending", False, -1, 0, 0, "")
    424         if self.state.observed_valid:
    425             status = self.state.observed.copy()
    426         else:
    427             status = self.state.wait_until(self.pid, remaining)
    428         self.state.status = status.copy()
    429         if status.state == "running" or status.state == "interrupted":
    430             var term = self.state.terminate_once(self.pid, TERMINATION_GRACE_MS)
    431             self.state.status = term.copy()
    432             self.state.store(False, "watchdog", "-", "timeout", 0, 0)
    433             if term.cleanup_proved():
    434                 self.state.reaped = True
    435                 self.state.close_reader()
    436                 self.state.guard[].resolve_pid(self.pid)
    437             else:
    438                 self.state.reason = "timeout_unreaped"
    439                 self.state.record_unproved(
    440                     self.pid,
    441                     self.state.report_fd,
    442                     "owned-child cleanup unproved",
    443                     "unreaped:" + term.describe(),
    444                 )
    445             return
    446         if status.state == "gone":
    447             # No waitable owned child remains: cleanup is proved without a
    448             # signal and the report cannot be trusted, but ownership is done.
    449             self.state.store(False, "watchdog", "-", "gone", 0, 0)
    450             self.state.reaped = True
    451             self.state.close_reader()
    452             self.state.guard[].resolve_pid(self.pid)
    453             return
    454         if status.state == "wait_error":
    455             # Identity/ownership is unproved: retain it for a retry and record
    456             # the uncertainty instead of claiming the child was collected.
    457             self.state.store(False, "watchdog", "-", "wait_error", 0, 0)
    458             self.state.record_unproved(
    459                 self.pid,
    460                 self.state.report_fd,
    461                 "owned-child wait unproved",
    462                 "wait_error:" + status.error,
    463             )
    464             return
    465         if status.state != "reaped":
    466             # Unexpected nonterminal/unknown taxonomy: fail closed and keep the
    467             # exact ownership so a later retry can still collect it.
    468             self.state.store(False, "watchdog", "-", "unexpected_status", 0, 0)
    469             self.state.record_unproved(
    470                 self.pid,
    471                 self.state.report_fd,
    472                 "owned-child unexpected status",
    473                 "unexpected:" + status.describe(),
    474             )
    475             return
    476         var report_text = ""
    477         var report_error = ""
    478         var report_remaining = self.state.work_remaining_ms()
    479         if report_remaining <= 0:
    480             report_error = "report_budget_expired"
    481         else:
    482             try:
    483                 report_text = self.state.read_line(
    484                     STRICT_MAX_REPORT_BYTES, report_remaining
    485                 )
    486                 if self.state.last_terminated:
    487                     var drain_remaining = self.state.work_remaining_ms()
    488                     if drain_remaining <= 0:
    489                         report_error = "drain_deadline_expired"
    490                     else:
    491                         var surplus = self.state.drain_surplus(
    492                             STRICT_MAX_REPORT_BYTES, drain_remaining
    493                         )
    494                         if surplus > 0:
    495                             report_error = "duplicate_report"
    496                 elif report_text.byte_length() > 0:
    497                     # Bytes at EOF without a terminating newline are a
    498                     # truncated report, never a complete one.
    499                     report_error = "unterminated_report"
    500             except e:
    501                 report_error = String(e)
    502         self.state.close_reader()
    503         if report_text == "" and report_error == "":
    504             if status.exited and status.exit_code == 0:
    505                 self.state.store(False, "startup", "-", "missing_report", 0, 0)
    506             elif status.exited:
    507                 self.state.store(
    508                     False,
    509                     "startup",
    510                     "-",
    511                     "exit_" + String(status.exit_code),
    512                     0,
    513                     0,
    514                 )
    515             else:
    516                 self.state.store(
    517                     False,
    518                     "watchdog",
    519                     "-",
    520                     "signal_" + String(status.signal),
    521                     0,
    522                     0,
    523                 )
    524             self.state.reaped = True
    525             self.state.guard[].resolve_pid(self.pid)
    526             return
    527         if report_error != "":
    528             self.state.store(False, "parse", "-", report_error, -1, -1)
    529             self.state.reaped = True
    530             self.state.guard[].resolve_pid(self.pid)
    531             return
    532         var parsed = parse_report(report_text)
    533         if parsed.phase == "parse":
    534             self.state.store(False, "parse", "-", parsed.reason, -1, -1)
    535             self.state.reaped = True
    536             self.state.guard[].resolve_pid(self.pid)
    537             return
    538         self.state.store(
    539             parsed.ok,
    540             parsed.phase,
    541             parsed.case_label,
    542             parsed.reason,
    543             parsed.requests,
    544             parsed.connections,
    545         )
    546         if not report_status_matches_exit(
    547             status.exited, status.exit_code, parsed.ok
    548         ):
    549             self.state.ok = False
    550             self.state.phase = "startup"
    551             self.state.reason = "report_status_mismatch_" + status.describe()
    552         elif parsed.ok and parsed.requests != self.state.expected_requests:
    553             self.state.ok = False
    554             self.state.phase = "accounting"
    555             self.state.reason = "request_count_mismatch"
    556         elif parsed.ok and (
    557             parsed.connections < 1
    558             or parsed.connections > self.state.expected_requests
    559         ):
    560             self.state.ok = False
    561             self.state.phase = "accounting"
    562             self.state.reason = "connection_count_invalid"
    563         self.state.reaped = True
    564         self.state.guard[].resolve_pid(self.pid)
    565 
    566     def wait(mut self) raises:
    567         self.reap()
    568         if not self.state.ok:
    569             raise Error("fixture-failure " + self.describe())
    570 
    571     def terminate(mut self) raises:
    572         if self.state.reaped:
    573             return
    574         var report_fd = self.state.report_fd
    575         var status = self.state.terminate_once(self.pid, TERMINATION_GRACE_MS)
    576         self.state.status = status.copy()
    577         if status.cleanup_proved():
    578             self.state.reaped = True
    579             self.state.close_reader()
    580             self.state.guard[].resolve_pid(self.pid)
    581             return
    582         self.state.record_unproved(
    583             self.pid,
    584             report_fd,
    585             "owned-child cleanup unproved",
    586             "unreaped:" + status.describe(),
    587         )
    588         raise Error("lifecycle: owned child not reaped: " + status.describe())
    589 
    590 
    591 struct SpawnedJevStubView(Movable):
    592     """Body-scope view of an owned Jev fixture handle."""
    593 
    594     var pid: Int
    595     var target: UnsafePointer[SpawnedJevStub, MutAnyOrigin]
    596 
    597     def __init__(
    598         out self, pid: Int, target: UnsafePointer[SpawnedJevStub, MutAnyOrigin]
    599     ):
    600         self.pid = pid
    601         self.target = target
    602 
    603     def ok(self) -> Bool:
    604         return self.target[].ok()
    605 
    606     def phase(self) -> String:
    607         return self.target[].phase()
    608 
    609     def failure_case(self) -> String:
    610         return self.target[].failure_case()
    611 
    612     def reason(self) -> String:
    613         return self.target[].reason()
    614 
    615     def request_count(self) -> Int:
    616         return self.target[].request_count()
    617 
    618     def connection_count(self) -> Int:
    619         return self.target[].connection_count()
    620 
    621     def cleanup_error(self) -> String:
    622         return self.target[].cleanup_error()
    623 
    624     def describe(self) -> String:
    625         return self.target[].describe()
    626 
    627     def status(mut self) -> ProcessStatus:
    628         return self.target[].status()
    629 
    630     def reap(mut self):
    631         self.target[].reap()
    632 
    633     def wait(mut self) raises:
    634         self.target[].wait()
    635 
    636     def terminate(mut self) raises:
    637         self.target[].terminate()
    638 
    639     def inject_cleanup_failure(mut self):
    640         """Test-only bounded fault: force one unproved cleanup attempt.
    641 
    642         The exact-owned child keeps running, so the follow-up retry exercises
    643         the real recoverable ownership path rather than a synthetic identity.
    644         """
    645         self.target[].state.faults.cleanup_failures += 1
    646 
    647     def inject_wait_error(mut self):
    648         """Test-only bounded fault: force one transient wait error."""
    649         self.target[].state.faults.wait_errors += 1
    650 
    651     def inject_nonterminal_status(mut self):
    652         """Test-only bounded fault: force one unexpected nonterminal status."""
    653         self.target[].state.faults.nonterminal += 1
    654 
    655     def inject_wait_delay_ms(mut self, ms: Int):
    656         """Test-only bounded fault: consume work-budget time in the wait phase.
    657         """
    658         self.target[].state.faults.wait_delay_ms = ms
    659 
    660 
    661 @fieldwise_init
    662 struct SpawnedJevStubAuto(Movable):
    663     var port: Int
    664     var stub: SpawnedJevStub
    665 
    666     def __enter__(mut self) -> SpawnedJevStubAutoView:
    667         return SpawnedJevStubAutoView(
    668             self.port,
    669             SpawnedJevStubView(self.stub.pid, UnsafePointer(to=self.stub)),
    670         )
    671 
    672     def __exit__(mut self):
    673         self.stub.cleanup()
    674 
    675 
    676 struct SpawnedJevStubAutoView(Movable):
    677     """Body-scope view of an auto-port Jev fixture handle."""
    678 
    679     var port: Int
    680     var stub: SpawnedJevStubView
    681 
    682     def __init__(out self, port: Int, var stub: SpawnedJevStubView):
    683         self.port = port
    684         self.stub = stub^
    685 
    686 
    687 def reserve_jev_port() raises -> Int:
    688     var listener = TcpListener.bind(SocketAddr.localhost(0))
    689     var port = Int(listener.local_addr().port)
    690     listener.close()
    691     return port
    692 
    693 
    694 def spawn_jev_stub_auto(
    695     mode: String,
    696     requests: Int,
    697     mut guard: CleanupGuard,
    698     deadline_ms: Int = FIXTURE_DEFAULT_DEADLINE_MS,
    699 ) raises -> SpawnedJevStubAuto:
    700     var stub = _spawn_jev_stub(0, mode, requests, deadline_ms, guard)
    701     return SpawnedJevStubAuto(port=stub.port, stub=stub^)
    702 
    703 
    704 def spawn_jev_stub(
    705     port: Int,
    706     mode: String,
    707     requests: Int,
    708     mut guard: CleanupGuard,
    709     deadline_ms: Int = FIXTURE_DEFAULT_DEADLINE_MS,
    710 ) raises -> SpawnedJevStub:
    711     return _spawn_jev_stub(port, mode, requests, deadline_ms, guard)
    712 
    713 
    714 def serve_jev_scripted(
    715     port: Int, var scripts: List[ExchangeScript]
    716 ) raises -> ServeReport:
    717     var listener = TcpListener.bind(SocketAddr.localhost(UInt16(port)))
    718     var actual_port = Int(listener.local_addr().port)
    719     write_raw(1, "ready " + String(actual_port) + "\n")
    720     return serve_scripts(listener, scripts^, "scripted")
    721 
    722 
    723 def spawn_jev_scripted_auto(
    724     var scripts: List[ExchangeScript],
    725     mut guard: CleanupGuard,
    726     deadline_ms: Int = FIXTURE_DEFAULT_DEADLINE_MS,
    727 ) raises -> SpawnedJevStubAuto:
    728     return _spawn_jev_scripted(0, scripts^, deadline_ms, guard)
    729 
    730 
    731 def _spawn_child_or_cleanup(
    732     pipe: PipeFds,
    733     pid: Int,
    734     mode: String,
    735     deadline_ms: Int,
    736     requests: Int,
    737     guard: UnsafePointer[CleanupGuard, MutAnyOrigin],
    738 ) raises -> SpawnedJevStub:
    739     """Build the owned state, read exact readiness, or clean up and raise."""
    740     var state = piped_child_state(
    741         pid, pipe.read_fd, deadline_ms, requests, guard
    742     )
    743     var ready_line = ""
    744     try:
    745         ready_line = state.read_line(STRICT_MAX_REPORT_BYTES, deadline_ms)
    746     except e:
    747         var st = finalize_owned_failure(
    748             state, pid, "jev startup readiness cleanup unproved"
    749         )
    750         raise Error(
    751             "jev stub readiness failed ("
    752             + String(e)
    753             + " pid="
    754             + String(pid)
    755             + " / "
    756             + st.describe()
    757             + " cleanup="
    758             + ("proved" if st.cleanup_proved() else "unreaped")
    759             + ")"
    760         )
    761     var reported_port = 0
    762     try:
    763         reported_port = parse_ready_or_cleanup(pid, ready_line, 256)
    764     except e:
    765         var st = finalize_owned_failure(
    766             state, pid, "jev startup malformed-readiness cleanup unproved"
    767         )
    768         raise Error(
    769             "jev stub malformed readiness ("
    770             + String(e)
    771             + " pid="
    772             + String(pid)
    773             + " cleanup="
    774             + ("proved" if st.cleanup_proved() else "unreaped")
    775             + ")"
    776         )
    777     _ = mode
    778     return SpawnedJevStub(pid, reported_port, state^)
    779 
    780 
    781 def _spawn_jev_scripted(
    782     port: Int,
    783     var scripts: List[ExchangeScript],
    784     deadline_ms: Int,
    785     mut guard: CleanupGuard,
    786 ) raises -> SpawnedJevStubAuto:
    787     var total = len(scripts)
    788     var pipe = make_pipe()
    789     var pid = fork_owned_or_close(pipe.copy())
    790     if pid == 0:
    791         if dup2_fd(pipe.write_fd, 1) < 0:
    792             child_exit(126)
    793         close_fd(pipe.read_fd)
    794         close_fd(pipe.write_fd)
    795         _ = set_alarm(STUB_ALARM_SECONDS)
    796         try:
    797             var report = serve_jev_scripted(port, scripts^)
    798             _ = write_raw(1, report_line(report) + "\n")
    799             child_exit(0 if report.ok else 125)
    800         except:
    801             var failed = ServeReport(
    802                 False, "startup", "scripted", "serve_failed", 0, 0
    803             )
    804             _ = write_raw(1, report_line(failed) + "\n")
    805             child_exit(125)
    806     close_fd(pipe.write_fd)
    807     var stub = _spawn_child_or_cleanup(
    808         pipe, pid, "scripted", deadline_ms, total, UnsafePointer(to=guard)
    809     )
    810     return SpawnedJevStubAuto(port=stub.port, stub=stub^)
    811 
    812 
    813 def _spawn_jev_stub(
    814     port: Int,
    815     mode: String,
    816     requests: Int,
    817     deadline_ms: Int,
    818     mut guard: CleanupGuard,
    819 ) raises -> SpawnedJevStub:
    820     var pipe = make_pipe()
    821     var pid = fork_owned_or_close(pipe.copy())
    822     if pid == 0:
    823         if dup2_fd(pipe.write_fd, 1) < 0:
    824             child_exit(126)
    825         close_fd(pipe.read_fd)
    826         close_fd(pipe.write_fd)
    827         _ = set_alarm(STUB_ALARM_SECONDS)
    828         try:
    829             var report = serve_jev(port, mode, requests)
    830             _ = write_raw(1, report_line(report) + "\n")
    831             child_exit(0 if report.ok else 125)
    832         except:
    833             var failed = ServeReport(
    834                 False, "startup", mode, "serve_failed", 0, 0
    835             )
    836             _ = write_raw(1, report_line(failed) + "\n")
    837             child_exit(125)
    838     close_fd(pipe.write_fd)
    839     return _spawn_child_or_cleanup(
    840         pipe, pid, mode, deadline_ms, requests, UnsafePointer(to=guard)
    841     )