Files
multi-agent-mux/.agents/reports/canary-projects-multi-agent-mux-reviewer-cline/report-skill-optimization-review-final.md
T
Godopu 7eeb4b709a perf(skills): optimize sleeps and modularize duplication with multi-agent consensus PASS
- OP-1: Implement reactive _wait_session_gone in lib.sh and stop_session.sh with set -e || true guard
- OP-2: Event-driven MQTT subscribe handshake with sub_pid liveness in delegate-job
- OP-3: Replace CPU time.sleep(0.5) spin with threading.Event wait in reconcile.sh
- OP-4: Define mam_tmux dispatcher targeting resolved _REAL_TMUX_PATH to prevent recursion
- OP-6 & OP-7: Add token variables and bash version source check in lib.sh
- Integrate approved optimization plan and PASS review reports from all agents
2026-07-11 10:08:41 +09:00

13 KiB
Raw Blame History

Report: Skill Optimization Implementation Review (Final)

  • Author: Reviewer Cline (canary-projects-multi-agent-mux-reviewer-cline)
  • Brief: .mam/reports/brief-rereview-skill-optimization.md
  • Plan reviewed against: .agents/reports/canary-projects-multi-agent-mux-planner-claude/report-skill-optimization-plan.md
  • Scope: Phase 1 (OP-1, OP-2, OP-3) + Phase 2 (OP-4, OP-5, OP-6) working-tree changes
  • Output path: .agents/reports/canary-projects-multi-agent-mux-reviewer-cline/report-skill-optimization-review-final.md

Verdict

PASS

All six focus-area items named in the brief (OP-1, OP-2, OP-3, OP-4, OP-6, OP-7) are correctly implemented in the working tree. bash -n passes on all four changed shell scripts; python3 -m py_compile passes on job_subscriber.py; no new shellcheck warnings were introduced (all reported SC2155/SC2164/SC2034 are pre-existing). Two non-blocking observations are noted below; one out-of-scope item (OP-5) is flagged for awareness.


Validation Commands (run inside this session)

Check Command Result
Syntax (shell) bash -n lib.sh stop_session.sh multi-agent-mux-delegate-job reconcile.sh All 4 OK
Syntax (python) python3 -m py_compile job_subscriber.py OK
Lint shellcheck -S warning on the 4 changed scripts No new warnings (all pre-existing)

Reported shellcheck warnings (all pre-existing, unchanged by this diff): lib.sh:1043,1046 SC2164 (cd in start_watchdog), stop_session.sh:71 SC2155 (export TMUX_SERVER_NAME=$(...)), reconcile.sh:33,34 SC2034 (ONCE/EMIT_DIFF — false positives, used by the --once/--emit-diff arg parser).


Per-Item Review

OP-1 - Reactive Tmux Graceful Stopping (stop_session.sh) — PASS

Plan: Implement _wait_session_gone in lib.sh polling tmux has-session at ~250 ms up to a deadline; call it from stop_session.sh replacing the fixed sleep 3 / sleep 5.

Implementation (lib.sh:1128-1136):

_wait_session_gone() {
  local sess="$1" max="${2:-5}" i
  for ((i = 0; i < max * 4; i++)); do
    _sks_tmux has-session -t "$sess" 2>/dev/null || return 0
    sleep 0.25
  done
  return 1
}

Call sites (stop_session.sh:193,200):

_wait_session_gone "$SESSION_NAME" 5 || true
...
tmux kill-session -t "$SESSION_NAME" 2>/dev/null || true
_wait_session_gone "$SESSION_NAME" 8 || true

Findings:

  • Poll interval 0.25 s × max*4 iterations = exactly max seconds deadline. Math is correct.
  • Uses _sks_tmux (server-aware), so it respects TMUX_SERVER_NAME. Correct.
  • || true appended at both call sites is essential: stop_session.sh runs under set -euo pipefail (line 30), and _wait_session_gone returns 1 on timeout. Without || true, a timeout would abort the whole graceful chain. The guard is present.
  • Happy path returns early on first has-session failure (~0.25 s), matching the plan's "<0.3 s" outcome.

Verdict: Correctly implements the plan.

OP-2 - MQTT Subscriber Event-Driven Handshake (delegate-job) — PASS (with minor observation)

Plan: job_subscriber.py writes SUBSCRIBED <topic> on SUBACK; the wrapper replaces sleep 1 with a fast-poll loop matching the sentinel, with a liveness check.

Implementationjob_subscriber.py:188-194:

def on_subscribe(_c, _u, mid, granted_qos, _props=None):
    for topic in subscribed_topics:
        print(f"SUBSCRIBED {topic}", flush=True)
client.on_subscribe = on_subscribe

Wrapper (multi-agent-mux-delegate-job:119-135, mirrored at :218-234):

local sub_ready=0
for ((i = 0; i < 25; i++)); do
  if kill -0 "$sub_pid" 2>/dev/null; then
    if grep -q '^SUBSCRIBED ' "$logf" 2>/dev/null; then
      sub_ready=1; break
    fi
  else
    echo "ERROR: subscriber died early (pid=$sub_pid, check $logf)" >&2; exit 1
  fi
  sleep 0.2
done
if [ "$sub_ready" -ne 1 ]; then
  echo "WARNING: subscriber subscribe handshake timed out — falling back to proceed" >&2
fi

Findings:

  • Sentinel ^SUBSCRIBED is written with flush=True so it is visible to the wrapper's grep immediately.
  • kill -0 "$sub_pid" liveness check runs before the grep, so a dead subscriber is caught and exits 1 rather than waiting the full 5 s. Correct ordering.
  • 25 × 0.2 s = 5 s deadline; falls back gracefully with a WARNING (non-fatal) on timeout. Matches plan.
  • on_subscribe signature (_c, _u, mid, granted_qos, _props=None) covers both paho-mqtt v2 (MQTTv3, 5-arg) and v3 (MQTTv5, 6-arg with props) — the _props=None default absorbs the extra arg. Forward-compatible.
  • Minor observation (non-blocking): on_subscribe iterates subscribed_topics and prints all topics on every suback. In the multi-job case, the sentinel fires after the first suback, not after all topics are subscribed. For the common single-job delegation this is exactly correct; for multi-job the wrapper proceeds slightly early. Since the orchestrator's own subscriber is the one that must be ready to receive the agent's started event — and that event is published to one job's topic — proceeding after the first suback is safe as long as the first-subscribed topic is the active job's. The registration order (for job in jobs) makes this hold. No fix required; noted for completeness.
  • Logic is correctly duplicated for both the direct path (:119) and the loop/discuss orchestrator path (:218).

Verdict: Correctly implements the plan.

OP-3 - Main Event Loop Pacing (reconcile.sh) — PASS (with minor observation)

Plan: Replace while True: time.sleep(0.5) with threading.Event().wait(timeout=next_deadline - now).

Implementation (reconcile.sh:242-266):

import threading
stop_event = threading.Event()
start = time.time()
try:
    while True:
        now = time.time()
        wall_left = (timeout - (now - start)) if timeout else None
        idle_left = (idle_timeout - (now - state['last_msg'])) if idle_timeout else None
        next_timeout = 5.0
        if wall_left is not None:
            next_timeout = min(next_timeout, wall_left)
        if idle_left is not None:
            next_timeout = min(next_timeout, idle_left)
        if next_timeout <= 0:
            ...print which deadline hit...
            break
        stop_event.wait(timeout=next_timeout)
finally:
    client.loop_stop()

Findings:

  • Computes next_timeout = min(5.0, wall_left, idle_left) so the main thread sleeps only as long as the nearest deadline, capped at 5 s — a strict improvement over the old fixed 0.5 s wake-up.
  • Deadline-expired branch (next_timeout <= 0) correctly distinguishes wall vs idle timeout in its log message.
  • Minor observation (non-blocking): stop_event is never set() by any callback (e.g. on_message), so stop_event.wait(timeout=...) behaves identically to time.sleep(timeout) here. It is still an improvement because Event.wait is interruptible by signals (e.g. SIGINT) and is the idiomatic primitive for a condition-style sleep; but the full "event-driven wakeup on terminal event" benefit described in the plan would require on_message to call stop_event.set() when event in ("completed","error"). The current implementation is correct and an improvement; the optional enhancement (waking immediately on terminal event rather than on the next deadline tick) is left for a follow-up. Non-blocking.

Verdict: Correctly implements the plan (the reactive-sleep core).

OP-4 - Unify Divergent Tmux Server Resolvers (lib.sh) — PASS

Plan: Extract a single canonical mam_tmux() dispatcher; have _tmux/_sks_tmux delegate to it.

Implementation (lib.sh:97-113):

mam_tmux() {
  _resolve_real_tmux_path
  if [ -n "${TMUX_SERVER_NAME:-}" ] && [ "$TMUX_SERVER_NAME" != "default" ]; then
    "$_REAL_TMUX_PATH" -L "$TMUX_SERVER_NAME" "$@"
  else
    "$_REAL_TMUX_PATH" "$@"
  fi
}
_tmux() { _init_tmux_isolation; mam_tmux "$@"; }
tmux()  { _tmux "$@"; }

_sks_tmux (lib.sh:1118) now reads: _sks_tmux() { mam_tmux "$@"; }.

Findings:

  • mam_tmux calls "$_REAL_TMUX_PATH" (the resolved real binary), not the shell function tmux() — so there is no recursion. (This was verified carefully; an earlier transient revision of the diff showed a literal "tmux" call which would have recursed, but the final working tree uses $_REAL_TMUX_PATH.)
  • mam_tmux calls _resolve_real_tmux_path directly (not the full _init_tmux_isolation PATH-shim setup), so it is safe to use from hot paths that don't want the shim side effect. _tmux still runs the full _init_tmux_isolation for callers that rely on the PATH shim. Correct separation of concerns.
  • _sks_tmux previously had its own 4-line inline resolver with the SC2086-prone tmux -L $TMUX_SERVER_NAME "$@"; it now delegates to mam_tmux, removing the duplication.
  • All four duplication sites named in the plan are consolidated: _tmux, _sks_tmux, and the inline local_tmux in wait_for_tui_ready (which already used _sks_tmux/_tmux). The create_session.sh:212 local_tmux string is for the human-readable START_CMD YAML field, not a live call — left as-is, correctly.

Verdict: Correctly implements the plan; no recursion hazard.

OP-6 - Consolidate TUI Ready / Dialog Tokens (lib.sh) — PASS

Plan: Declare _MAM_DIALOG_TOKENS and _MAM_READY_TOKENS_CLAUDE at top of lib.sh; refer to them everywhere.

Implementation (lib.sh:25-27):

_MAM_DIALOG_TOKENS='Do you trust the files|Yes, proceed|No, exit|Allow this|Press Enter to continue|browser to authenticate|Use arrow keys|Esc to cancel'
_MAM_READY_TOKENS_CLAUDE='Anthropic|Assistant|Chat|Welcome|projects'

References (grep confirms 3 use sites):

  • lib.sh:1071 wait_for_tui_ready claude branch → grep -E -q "$_MAM_READY_TOKENS_CLAUDE"
  • lib.sh:1158 _pane_dialog_opengrep -Eq "$_MAM_DIALOG_TOKENS"
  • lib.sh:1224 handle_startup_dialogsgrep -Eq "$_MAM_READY_TOKENS_CLAUDE"

Findings:

  • Both constants are byte-identical to the previously-inlined literals. No behavioral drift.
  • All three former inline sites now reference the constants; no stray literal copies remain (grep for the raw token strings outside the constant declarations returns nothing).
  • Quoting is consistent ("$_MAM_DIALOG_TOKENS" preserves the | alternation for grep -E).

Verdict: Correctly implements the plan.

OP-7 - Guard against Non-Bash Sourced Environments (lib.sh) — PASS

Plan: Add a zsh-aware fallback or an explicit exit message warning users not to source from a foreign shell.

Implementation (lib.sh:17-20):

if [ -z "${BASH_VERSION:-}" ]; then
  echo "ERROR: lib.sh must be executed/sourced from bash (foreign shell detected)" >&2
  return 1 2>/dev/null || exit 1
fi

Findings:

  • The guard runs before any BASH_SOURCE use (line 21), so a zsh source exits cleanly with a diagnostic instead of silently resolving BASH_SOURCE[0] to empty and sourcing the wrong lib.sh.
  • return 1 2>/dev/null || exit 1 covers both cases: return works when sourced (function context), exit works when executed directly.
  • This implements the "explicit exit message" option from the plan. The fuller zsh ${(%):-%x} fallback was the alternative; the chosen approach is simpler and aligns with AGENTS.md "Simplicity First".

Verdict: Correctly implements the plan.


Out-of-Scope / Awareness

  • OP-5 (Single-Source YAML/SQLite Load Boilerplate) — listed under Phase 2 in the plan, but not in the brief's focus-area list and not implemented in this working-tree diff. The 7 duplicated load blocks remain. This is consistent with the brief's scoped focus (OP-1,2,3,4,6,7) but is called out so Phase 2 completion is not mis-reported. Recommend a follow-up PR for OP-5.
  • OP-8 (Reconcile Observability) — Phase 3 item, not in the brief's scope, not implemented. The fallback polling loop at reconcile.sh:269 still uses bash "$_self" --once --emit-diff >/dev/null 2>&1 || true. Recommend a follow-up.

Non-Blocking Observations (no action required for PASS)

  1. OP-2 multi-job sentinel: on_subscribe prints all topics on each suback; the wrapper proceeds after the first suback. Safe for single-job (the common path) and for multi-job given registration order, but a future multi-job refactor should gate on "all topics subacked" (e.g. count subacks vs len(subscribed_topics)).
  2. OP-3 unused stop_event.set(): stop_event is never set, so it functions as an interruptible time.sleep. Adding stop_event.set() in on_message on terminal events would let the loop wake immediately on job completion instead of on the next deadline tick — an optional latency improvement, not a correctness issue.

Both observations are enhancements, not defects; neither blocks the PASS verdict.