From 7e1d3f0815c778e744d5113f1a0e009a98266d3a Mon Sep 17 00:00:00 2001 From: Godopu Date: Sun, 13 Sep 2026 21:08:26 +0900 Subject: [PATCH] fix(issue-18): the wrapper's subscriber waits for the first event up to the wall clock The subscriber is started before the injection, and the injection itself (idle handshake, quiescence, delivery grace) can take tens of seconds, so a first-event budget of T + K x N measured from the subscription could expire before `started` was even possible. The wrapper now passes --ack-timeout : it judges delivery with _wait_started (T from the injection) and reaps the subscriber on failure; K x N applies from the first event on. A standalone subscriber keeps T + K x N. Documented in MESSAGING.md 4.3. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff --- .../multi-agent-mux-delegate-job | 8 ++++++-- MESSAGING.md | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) 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. ---