@@ -254,8 +254,9 @@ def __init__(
254254 self .scheduler .set_drain_observer (self .enforce_system_idle_cap )
255255 # Idle-gap cap (ms) for the t* boundary the load-time warp can't see (t*
256256 # is the sampling instant, not a request). Consumed two ways:
257- # - WARMUP: clamps each warmup lead so priming doesn't start hours
258- # early (``_capped_warmup_lead_ms``); priming spacing is meaningless.
257+ # - WARMUP: this cap and the global system-idle cap both clamp each
258+ # warmup lead so priming doesn't start hours early
259+ # (``_capped_warmup_lead_ms``); priming spacing is meaningless.
259260 # - PROFILING: a single uniform shift caps the leading idle (t* ->
260261 # earliest stream) while preserving recorded inter-stream spacing
261262 # (``_leading_idle_shift_ms``); a per-stream clamp would collapse
@@ -548,9 +549,19 @@ def _capped_warmup_lead_ms(self, lead_ms: float) -> float:
548549 PROFILING dispatch offsets are NOT clamped this way -- see
549550 :meth:`_leading_idle_shift_ms`.
550551 """
551- if self ._phase_offset_cap_ms is not None :
552- return min (lead_ms , self ._phase_offset_cap_ms )
553- return lead_ms
552+ caps_ms = [
553+ cap
554+ for cap in (
555+ self ._phase_offset_cap_ms ,
556+ (
557+ self ._system_idle_gap_cap_seconds * MILLIS_PER_SECOND
558+ if self ._system_idle_gap_cap_seconds is not None
559+ else None
560+ ),
561+ )
562+ if cap is not None
563+ ]
564+ return min (lead_ms , * caps_ms ) if caps_ms else lead_ms
554565
555566 def _leading_idle_shift_ms (self , offsets : Iterable [float ]) -> float :
556567 """Excess to subtract UNIFORMLY from every PROFILING dispatch offset so
@@ -878,15 +889,21 @@ async def _handle_accelerated_warmup_return(self, credit: Credit) -> None:
878889 await self .credit_issuer .issue_credit (turn )
879890
880891 async def _issue_child_continuation_or_drain (self , turn : TurnToSend ) -> None :
881- """Dispatch a DAG child continuation, draining the join on refusal .
892+ """Dispatch a DAG child continuation, draining terminal refusals .
882893
883894 ``dispatch_child_turn`` returns True iff the turn reached the wire; on
884- any refusal (e.g. the ``--request-count`` cap) notify the orchestrator
885- so the parent's join drains deterministically instead of deadlocking on
886- a child whose remaining turns will never be issued.
895+ a terminal refusal notify the orchestrator so the parent's join drains
896+ deterministically instead of deadlocking on a child whose remaining
897+ turns will never be issued. Accelerated warmup refusals are different:
898+ the remaining child and its active join are persisted for profiling, so
899+ marking the child stopped here would release the parent prematurely.
887900 """
888901 on_wire = await self .credit_issuer .dispatch_child_turn (turn )
889- if not on_wire and self .branch_orchestrator is not None :
902+ if (
903+ not on_wire
904+ and self .branch_orchestrator is not None
905+ and not self .allows_pending_branch_handoff_after_sending_complete
906+ ):
890907 await self .branch_orchestrator .on_child_stopped (turn .x_correlation_id )
891908
892909 async def finalize_phase (self ) -> None :
@@ -1460,11 +1477,12 @@ async def _dispatch_next_turn(self, credit: Credit) -> None:
14601477
14611478 DAG child continuations (``agent_depth > 0``) go through the single
14621479 child-issuance chokepoint (``_issue_child_continuation_or_drain``) so a
1463- ``--request-count`` cap refusal is routed to ``on_child_stopped`` (drain
1464- the parent join) instead of being silently swallowed by the discarded
1465- ``issue_credit`` return -- including on the delayed (``delay_ms``) path,
1466- where the refusal would otherwise fire long after the callback handler
1467- decided the child could proceed. Root continuations keep ``issue_credit``.
1480+ terminal refusal is routed to ``on_child_stopped`` (drain the parent
1481+ join) instead of being silently swallowed by the discarded
1482+ ``issue_credit`` return. A warmup cutoff is preserved for profiling
1483+ handoff instead. This applies equally to delayed continuations, whose
1484+ refusal may happen after the callback handler decided the child could
1485+ proceed. Root continuations keep ``issue_credit``.
14681486 """
14691487 next_meta = self .conversation_source .get_next_turn_metadata (credit )
14701488 turn = TurnToSend .from_previous_credit (credit , next_meta )
0 commit comments