diff --git a/.agents/skills/lib.sh b/.agents/skills/lib.sh index ee120a6..59f587f 100644 --- a/.agents/skills/lib.sh +++ b/.agents/skills/lib.sh @@ -2322,7 +2322,7 @@ delegate_publish_cmd() { pub_reg="${MAM_JOBS_DIR:-${WORKSPACE_ROOT:+$WORKSPACE_ROOT/.mam/jobs}}" pub_reg="${pub_reg:-.mam/jobs}" mkdir -p "$pub_reg" && pub_reg="$(cd -P "$pub_reg" && pwd -P)" - pub_logs="$(PYTHONPATH="$SKILL_DIR:${PYTHONPATH:-}" "$py_bin" -c 'import os; from lib_py.delegation.mqtt_common import get_logs_dir; print(os.path.abspath(get_logs_dir()))' 2>/dev/null || true)" + pub_logs="$(PYTHONPATH="$SKILL_DIR:${PYTHONPATH:-}" "$py_bin" -c 'import os, sys; from lib_py.delegation.mqtt_common import get_logs_dir; print(os.path.abspath(get_logs_dir(sys.argv[1])))' "$pub_reg" 2>/dev/null || true)" local -a argv=("$py_bin" "$pub_script" --registry-dir "$pub_reg" --job "$job_id") [ -n "$tok" ] && argv+=(--expect-dispatch-token "$tok") [ -n "$att" ] && argv+=(--attempt-id "$att") @@ -2372,10 +2372,16 @@ except Exception: # Never the registry status: a record leaves `pending` when another writer # closes it or another dispatch claims it. Lines are parsed as JSON, never # pattern-matched. rc 0 = recorded, 1 = not (yet). +delegate_logs_dir() { + PYTHONPATH="$SKILL_DIR:${PYTHONPATH:-}" "$(_delegate_py_bin)" -c 'import os, sys; from lib_py.delegation.mqtt_common import get_logs_dir; print(os.path.abspath(get_logs_dir(sys.argv[1])))' "$1" 2>/dev/null +} + delegate_started_recorded() { local job_id="$1" tok="${2:-}" logs_dir="${3:-}" local reg_dir="${MAM_JOBS_DIR:-${WORKSPACE_ROOT:-$PWD}/.mam/jobs}" - [ -n "$logs_dir" ] || logs_dir="${DELEGATE_JOB_LOGS_DIR:-${WORKSPACE_ROOT:-$PWD}/.mam/delegate_job_logs}" + # Issue #57: the audit log is resolved by the one rule (next to the registry + # unless DELEGATE_JOB_LOGS_DIR says otherwise); no bash copy of the default. + [ -n "$logs_dir" ] || logs_dir="$(delegate_logs_dir "$reg_dir")" || return 1 local ev_log="$reg_dir/$job_id.events.log" local audit="$logs_dir/$job_id/events.ndjson" [ -f "$ev_log" ] || [ -f "$audit" ] || return 1 @@ -2431,10 +2437,12 @@ delegate_wait_started() { local job_id="$1" ack_s="${2:-180}" tok="${3:-}" [ -n "$job_id" ] || return 1 ack_s=$(mam_int "$ack_s" 0) || { echo "WARNING: onboarding ack timeout ${2-} ignored (not a decimal integer >= 0); using 180" >&2; ack_s=180; } - local deadline + local deadline logs_dir deadline=$(( $(date +%s) + ack_s )) + # Issue #57: resolve the audit-log root once, not once per 1 s poll. + logs_dir="$(delegate_logs_dir "${MAM_JOBS_DIR:-${WORKSPACE_ROOT:-$PWD}/.mam/jobs}")" || logs_dir="" while :; do - if delegate_started_recorded "$job_id" "$tok"; then + if delegate_started_recorded "$job_id" "$tok" "$logs_dir"; then return 0 fi if [ "$(date +%s)" -ge "$deadline" ]; then diff --git a/.agents/skills/lib_py/control_plane.py b/.agents/skills/lib_py/control_plane.py index 3fb41ee..2503588 100644 --- a/.agents/skills/lib_py/control_plane.py +++ b/.agents/skills/lib_py/control_plane.py @@ -21,6 +21,8 @@ import shlex import sys from typing import Dict, Optional +from lib_py.delegation import mqtt_common + KEYS = ("workspace_root", "agent_sessions_yaml", "mam_jobs_dir", "delegate_job_logs_dir") ENV = {"workspace_root": "WORKSPACE_ROOT", "agent_sessions_yaml": "AGENT_SESSIONS_YAML", "mam_jobs_dir": "MAM_JOBS_DIR", "delegate_job_logs_dir": "DELEGATE_JOB_LOGS_DIR"} @@ -45,6 +47,10 @@ def from_env(env=None) -> Dict[str, str]: v = (env.get(var) or "").strip() if v: b[k] = _abs(v) + # Issue #57: without an explicit DELEGATE_JOB_LOGS_DIR the audit log is + # the delegate_job_logs next to the registry in use, not the workspace's. + if not (env.get("DELEGATE_JOB_LOGS_DIR") or "").strip(): + b["delegate_job_logs_dir"] = _abs(mqtt_common.sibling_logs_dir(b["mam_jobs_dir"])) return b diff --git a/.agents/skills/multi-agent-mux-create/scripts/worktree_prepare.sh b/.agents/skills/multi-agent-mux-create/scripts/worktree_prepare.sh index fc81607..1677478 100755 --- a/.agents/skills/multi-agent-mux-create/scripts/worktree_prepare.sh +++ b/.agents/skills/multi-agent-mux-create/scripts/worktree_prepare.sh @@ -234,8 +234,10 @@ if [ -n "$CREATOR_AGENT" ]; then env_add=(WORKSPACE_ROOT="$MAIN" AGENT_SESSIONS_YAML="${AGENT_SESSIONS_YAML:-$MAIN/.mam/agent-sessions.yaml}" MAM_JOBS_DIR="${MAM_JOBS_DIR:-$MAIN/.mam/jobs}" - DELEGATE_JOB_LOGS_DIR="${DELEGATE_JOB_LOGS_DIR:-$MAIN/.mam/delegate_job_logs}" MAM_NO_SUBSCRIBER_DAEMON=1) + # Issue #57: an explicit audit-log root is passed on; otherwise create's + # binding derives it from MAM_JOBS_DIR (the delegate_job_logs next to it). + if [ -n "${DELEGATE_JOB_LOGS_DIR:-}" ]; then env_add+=(DELEGATE_JOB_LOGS_DIR="$DELEGATE_JOB_LOGS_DIR"); fi if [ -z "${MAM_ENV_FILE:-}" ] && [ -f "$MAIN/.mam.env" ]; then env_add+=(MAM_ENV_FILE="$MAIN/.mam.env"); fi rc=0 env "${env_add[@]}" bash "$SKILL_DIR/multi-agent-mux-create/scripts/create_session.sh" "${args[@]}" || rc=$? 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 83531b0..6fc8075 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 @@ -87,11 +87,12 @@ _abs_registry_dir() { export SKS_REGISTRY_DIR="$REGISTRY_DIR" } -# The audit-log root this wrapper's own subscriber resolves (same resolver), -# pinned into the injected commands so an agent publishing from another cwd -# does not fall back to /.mam/delegate_job_logs. +# The audit-log root this wrapper's own subscriber resolves (same resolver: +# next to $REGISTRY_DIR unless DELEGATE_JOB_LOGS_DIR says otherwise, Issue +# #57), pinned into the injected commands so an agent publishing from another +# cwd does not fall back to its own default. _logs_dir_abs() { - "$PY" -c 'import os, sys; sys.path.insert(0, sys.argv[1]); from lib_py.delegation.mqtt_common import get_logs_dir; print(os.path.abspath(get_logs_dir()))' "$SCRIPT_DIR/.." + "$PY" -c 'import os, sys; sys.path.insert(0, sys.argv[1]); from lib_py.delegation.mqtt_common import get_logs_dir; print(os.path.abspath(get_logs_dir(sys.argv[2])))' "$SCRIPT_DIR/.." "$REGISTRY_DIR" } # Issue #17 item 4: the wrapper's decisions are lib_py/delegation/wrapper.py; @@ -184,7 +185,7 @@ multi-agent-mux-delegate-job [options] list [--registry-dir ] verify --job --validate