Files
multi-agent-mux/bug-report/mam_upstream_bug_fix_report.md
T

8.1 KiB

[Bug Fix & PR Proposal] Multi-Agent Mux (MAM) Resume & 런타임 제어 결함 보고서

  • 대상 프로젝트: Multi-Agent Mux (MAM) Skills (multi-agent-mux-*, lib.sh, lib_py)
  • 보고 일자: 2026-08-30
  • 작성자: GAIA Canary Project Team
  • 심각도: High (다중 에이전트 복원 누락, 세션 복원 실패, TUI 타임아웃 유발)

1. Executive Summary (요약)

MAM 스킬을 이용해 복수의 에이전트(claude, grok, agy, opencode)를 생성하고 일괄 복원(/multi-agent-mux-resume)하는 과정에서 발견된 4가지 핵심 버그와 이에 대한 수정 패치 내역입니다.

  1. lib.sh::_resolve_herdr_pane_id의 과도한 Fallback 매칭 버그 (세션 오인으로 인한 복원 누락)
  2. opencode.py::resume_spec--session 플래그 누락 버그 (기존 대화 복원 실패)
  3. opencode.py::ready_tokens의 ASCII 배너 미인식 버그 (TUI 준비 감지 타임아웃)
  4. 다중 에이전트 생성/복원 시 유휴 페인(Idle Pane) 미재사용 및 분할 경합 (Grid 레이아웃 깨짐)

2. 세부 결함 분석 및 수정 패치 (Detailed Bugs & Patches)

Bug 1: _resolve_herdr_pane_id의 Generic agent_kind 오인 매칭

📌 문제 현상

  • resume_session.sh 실행 시 herdr has-session -t creator-agy-01을 호출하여 세션 생존 여부를 검사합니다.
  • creator-agy-01 페인이 실제로 종료된 상태임에도 has-sessiontrue(0)를 반환하며 "herdr 'creator-agy-01' already running. Attaching..." 메시지와 함께 새로운 페인 생성을 건너뛰어 에이전트가 복원되지 않는 문제가 발생했습니다.

🔍 근본 원인 (Root Cause)

lib.sh_resolve_herdr_pane_id 내 파이썬 fallback 코드에서 세션명(tn/tsa) 일치 검색에 실패했을 때, agent_kind(agy) 타입 검사를 무조건 수행합니다. 워크스페이스 내에 다른 단일 agy(예: Orchestrator 세션)가 1개라도 실행 중이면 len(matching) == 1에 걸려 전혀 다른 페인을 creator-agy-01로 오인 반환했습니다.

🔧 해결 코드 (Diff)

--- a/.agents/skills/lib.sh
+++ b/.agents/skills/lib.sh
@@ -436,7 +436,7 @@ _resolve_herdr_pane_id() {
-    if agent_kind:
+    if agent_kind and (tn == agent_kind or tsa == agent_kind):
         matching = [p.get('pane_id') for p in panes if p.get('agent') == agent_kind and p.get('pane_id')]
         if len(matching) == 1:
             print(matching[0])
             sys.exit(0)

Bug 2: OpenCodeAgentAdapter.resume_spec--session 옵션 누락

📌 문제 현상

  • reviewer-opencode-01/multi-agent-mux-resume로 재개할 때, 기존 대화 ID(ses_...)가 존재함에도 복원 플래그가 붙지 않고 새로운 빈 세션(opencode --auto --agent build)으로 시작되는 문제가 발생했습니다.

🔍 근본 원인 (Root Cause)

lib_py/agents/adapters/opencode.pyresume_spec 함수에 if materialized and session_uuid: 조건이 걸려 있어, 호출자가 materialized 플래그를 넘기지 않거나 False일 경우 --session <id> 플래그가 누락되었습니다.

🔧 해결 코드 (Diff)

--- a/.agents/skills/lib_py/agents/adapters/opencode.py
+++ b/.agents/skills/lib_py/agents/adapters/opencode.py
@@ -188,4 +188,4 @@ class OpenCodeAgentAdapter(BaseAgentAdapter):
     def resume_spec(self, binary: str, session_uuid: str, materialized: bool = False) -> str:
-        if materialized and session_uuid:
+        if session_uuid:
             return f"{binary} --session {session_uuid} --auto --agent build"
         return f"{binary} --auto --agent build"

Bug 3: OpenCodeAgentAdapter.ready_tokens의 ASCII 배너 미인식

📌 문제 현상

  • opencode 에이전트 신규 생성 시 wait_for_tui_ready 함수가 TUI 렌더링 완료를 감지하지 못하고 30초 대기 루프에 진입하여 타임아웃을 유발했습니다.

🔍 근본 원인 (Root Cause)

OpenCode CLI 초기 기동 시 상단 로고가 일반 영문 텍스트가 아닌 ASCII 아트 특수문자 블록(█▀▀█...)으로 그려집니다. 기존 ready_tokens = 'OpenCode|Chat'은 일반 텍스트 매칭만 기대하여 TUI 렌더링 감지에 실패했습니다.

🔧 해결 코드 (Diff)

--- a/.agents/skills/lib_py/agents/adapters/opencode.py
+++ b/.agents/skills/lib_py/agents/adapters/opencode.py
@@ -22,3 +22,3 @@ class OpenCodeAgentAdapter(BaseAgentAdapter):
     @property
     def ready_tokens(self) -> str:
-        return 'OpenCode|Chat'
+        return 'OpenCode|Chat|Ask anything|tab agents|ctrl\\+p|Build auto|commands'

Bug 4: Herdr 유휴 페인(Idle Pane) 미재사용 및 분할 레이아웃 경합

📌 문제 현상

  • 다중 에이전트 생성/복원 과정에서 워크스페이스 내에 에이전트가 종료된 빈 유휴 페인(p.agent == None)이 이미 존재함에도 불구하고 무조건 pane split을 호출하여 불필요하게 페인이 증식하거나 2x2 그리드 레이아웃이 깨지는 문제가 발생했습니다.

🔍 근본 원인 (Root Cause)

lib.shnew-session 구현부에서 existing_ws가 감지되었을 때 해당 워크스페이스의 유휴 페인을 먼저 탐색하지 않고 곧바로 pane split을 수행했습니다.

🔧 해결 코드 (Diff)

--- a/.agents/skills/lib.sh
+++ b/.agents/skills/lib.sh
@@ -702,4 +702,18 @@ _init_herdr_isolation() {
     ws_id=""
     target_pane=""
     if [ -n "$existing_ws" ]; then
+      idle_pane=$(_real_herdr pane list 2>/dev/null | TARGET_WS="$existing_ws" python3 -c "
+import sys, json, os
+tws = os.environ.get('TARGET_WS', '')
+try:
+    d = json.loads(sys.stdin.read())
+    panes = d.get('result', {}).get('panes', [])
+    for p in panes:
+        if p.get('workspace_id') == tws and not p.get('agent') and p.get('pane_id'):
+            print(p.get('pane_id'))
+            break
+except Exception:
+    pass
+" 2>/dev/null || echo "")
+      if [ -n "$idle_pane" ]; then
+        target_pane="$idle_pane"
+      fi
+    fi
+    if [ -n "$existing_ws" ] && [ -z "$target_pane" ]; then

3. 검증 결과 (Verification Results)

위 4가지 패치를 적용한 후 4개 이종 에이전트 동시 복원 및 TUI 준비 감지, Graceful Stop, 재복원 사이클을 모두 통과했습니다.

agent-sessions status — 2026-08-30T00:09:58Z  (herdr_confirmed=False)
======================================================================================================================================================
NAME                                         SOCKET       WORKSPACE      YAML       HERDR  CMD    RESUME   JOB_ID     JOB_STATUS   DRIFT
------------------------------------------------------------------------------------------------------------------------------------------------------
planner-reviewer-claude-01                   mam-gaia-exp mam-agents     running    alive  claude yes      271a2a78   cancelled    -
reviewer-creator-grok-01                     mam-gaia-exp mam-agents     running    alive  grok   yes      bad791a0   cancelled    -
creator-agy-01                               mam-gaia-exp mam-agents     running    alive  agy    yes      4314d052   cancelled    -
reviewer-opencode-01                         mam-gaia-exp mam-agents     running    alive  opencode yes      7ac72973   cancelled    -
========================================================================================================================================
alive herdr: ['creator-agy-01|mam-gaia-exp', 'planner-reviewer-claude-01|mam-gaia-exp', 'reviewer-creator-grok-01|mam-gaia-exp', 'reviewer-opencode-01|mam-gaia-exp']

4. 권장 상류(Upstream) 조치 사항

  1. lib.sh_resolve_herdr_pane_id에서 fallback agent_kind 매칭 범위를 타겟 이름이 generic한 경우로 제한.
  2. lib_py/agents/adapters/opencode.pyresume_specready_tokens 패치 반영.
  3. lib.shnew-session 처리 시 기존 유휴 페인 재사용 로직 공식 반영.