diff --git a/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job b/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job index 79ed31c..3259f16 100755 --- a/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job +++ b/.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job @@ -228,7 +228,11 @@ EOF # 3) START THE SUBSCRIBER local logf="$REGISTRY_DIR/$JOB_ID.subscriber.out" - local sub_extra_args=() + # Before the first event the subscriber is bounded by the wall clock only: + # delivery (T from the injection, which happens after the subscriber is + # up and can take a while itself) is judged by _wait_started, and a failed + # injection reaps the subscriber. From the first event on, K x N applies. + local sub_extra_args=(--ack-timeout "$TIMEOUT") [ -n "$_disp_tok" ] && sub_extra_args+=(--expect-dispatch-token "$_disp_tok") _is_remote "$AGENT_SESSION" && sub_extra_args+=(--remote) "$PY" "$SCRIPT_DIR/scripts/job_subscriber.py" --registry-dir "$REGISTRY_DIR" \ @@ -401,7 +405,7 @@ EOF # Start subscriber local logf="$REGISTRY_DIR/${JOB_ID}.iter_${iteration}_${display_role}.subscriber.out" - local loop_sub_args=(--attempt-id "$attempt") + local loop_sub_args=(--attempt-id "$attempt" --ack-timeout "$TIMEOUT") [ -n "$_disp_tok" ] && loop_sub_args+=(--expect-dispatch-token "$_disp_tok") _is_remote "$current_session" && loop_sub_args+=(--remote) "$PY" "$SCRIPT_DIR/scripts/job_subscriber.py" --registry-dir "$REGISTRY_DIR" \ diff --git a/MESSAGING.md b/MESSAGING.md index f64704e..e81367a 100644 --- a/MESSAGING.md +++ b/MESSAGING.md @@ -339,6 +339,7 @@ The subscriber acts as the central execution watchdog: * **Dual Timeout Semantics**: 1. **Wall-Clock Timeout**: Calculated relative to absolute startup time (`wall_deadline = start + wall_timeout`). It acts as a hard budget limit, guarding against an agent hanging indefinitely. 2. **Activity Idle Timeout**: Measured as the difference between the current monotonic time and the last packet arrival time (`idle_left = idle_timeout - (now - last_event)`). If the agent fails to publish any event (heartbeats and retained state included) for the duration of the idle window - K x N under the Issue #18 contract - the subscriber aborts and exits with code 2. +* **Idle budget before the first event (Issue #18)**: a standalone subscriber allows `ack_timeout_sec + idle_timeout_sec` before the first accepted event (the injection has to produce `started`). The delegate wrapper passes `--ack-timeout ` instead: it judges delivery itself with `_wait_started` (T from the injection, which happens after the subscriber is up) and reaps the subscriber when that fails, so the subscriber's own idle clock only starts with the first event. * **Retained state and seq gaps (Issue #18)**: the subscriber also subscribes to `/state`; a retained terminal state resolves the job at (re)connect, any state resets the idle clock, and a seq jump on either topic is written to the audit log as `seq_gap`. With `--remote` (or `transport: remote`) accepted `started`/terminal events are mirrored into the local job record. ---