docs(improvements): prioritize and record execution roadmap Section 6 (100% PASS)
This commit is contained in:
+120
-13
@@ -1,6 +1,6 @@
|
||||
# 🛠️ Multi-Agent Mux 종합 개선 및 미해결 과제 백로그 (`IMPROVEMENTS.md`)
|
||||
|
||||
- **최종 갱신일**: 2026-08-09 (A-4 `BaseAgentAdapter` 어댑터 계층 설계 제안 등재)
|
||||
- **최종 갱신일**: 2026-08-09 (7747d745 Rev.2 — B-7 처방 신설 및 병렬화를 파일 소유권 슬롯으로 교체)
|
||||
- **통합 관리 대상**: 기존 `CODEBASE_REVIEW_REPORT.md` + `OPTIMIZATION.md`
|
||||
- **총 추적 미해결 과제**: **12건** (아키텍처 2건, 엣지케이스 6건, 오케스트레이션 1건, 레거시 잔재 3건)
|
||||
- **완료된 과제**: **10건** (A-1, A-3, A-5, B-1, B-3, B-4, C-1, C-2, O-1, O-3)
|
||||
@@ -16,7 +16,7 @@
|
||||
## 1. 🔴 아키텍처 결함 (Architecture Flaws — 2건)
|
||||
|
||||
### **A-2: 공개 브로커 + HMAC 인증 Off + 와일드카드 전파**
|
||||
- **현상**: `mqtt_common.py`의 기본 브로커가 공개 서버(`broker.hivemq.com`), HMAC 무조건 True 반환으로 설정되어 있습니다.
|
||||
- **현상**: `mqtt_common.py`의 기본 브로커가 공개 서버(`broker.hivemq.com`)이고, 잡 생성 시 `auth_token` 이 **한 번도 발급되지 않아**(실측 26/26 잡이 `auth_token=None`) `verify_hmac` 의 `if not auth_token: return True` 경로가 항상 타집니다. 발행자는 워크스페이스 지문 토픽을 채택하지 않고 전역 `python/mqtt/jobs/<job_id>/events` 로 발행하며, `reconcile.sh:237` 이 같은 전역 토픽을 구독합니다. (HMAC 구현 자체는 정상입니다 — 토큰이 없어 검증이 공허해지는 것이 원인입니다.)
|
||||
- **파급 효과**: 외부에서 유입되는 malicious `error` 이벤트 수신 시 `reconcile.sh`가 라이브 에이전트 pane을 `kill-session`으로 강제 파괴하는 치명적 보안/안정성 위험이 존재합니다.
|
||||
|
||||
### **A-4 (설계 제안): 에이전트 지식 산재 — `BaseAgentAdapter` 어댑터 계층 도입 (Rev.2)**
|
||||
@@ -69,14 +69,20 @@
|
||||
|
||||
## 2. 🟠 엣지 케이스 및 런타임 버그 (Edge-case Bugs — 6건)
|
||||
|
||||
### **B-5: `df --output` GNU 전용 플래그 사용으로 macOS NFS 감지 실패**
|
||||
- macOS/BSD 환경에서 `df --output` 구문 오류로 NFS 감지가 실패하고 "NFS 아님"으로 오판되어 SQLite WAL 포맷을 강행합니다.
|
||||
### **B-5: `df --output` GNU 전용 플래그 사용으로 macOS NFS 감지 실패** — ⚠️ **종결 권고 (재현 불가)**
|
||||
- 원 서술: macOS/BSD 환경에서 `df --output` 구문 오류로 NFS 감지가 실패하고 "NFS 아님"으로 오판되어 SQLite WAL 포맷을 강행합니다.
|
||||
- **실측(ecef05a3)**: `df --output=target` 은 여전히 `rc=64` 로 실패하나 `ea36e81` 에서 추가된 `df -P` 폴백이 정상 동작합니다(macOS 실측: `/System/Volumes/Data`). **결론("감지 실패")은 더 이상 참이 아니므로 종결을 권고합니다.**
|
||||
- **잔여분 → B-11 로 분리 권고**: `mount | grep -E "$mountpoint.*(nfs|cifs|smb|sshfs)"` 가 마운트포인트를 이스케이프 없이 ERE 에 보간하여 경로의 `.` 이 임의 문자로 해석됩니다(이론상 오탐).
|
||||
|
||||
### **B-6: 스킬 트리에 임시 파일 복사 및 유출**
|
||||
- `run_loop.sh::delegate_job_safe`가 래퍼 스크립트를 `.agents/skills/...` 트리 내부에 `.tmp`로 복사하여 버전 관리 트리를 오염시키고 rsync 배포 시 외부로 유출됩니다.
|
||||
|
||||
### **B-7: `run_loop.sh` 상대경로 cwd 의존 및 미추적 파일 누락**
|
||||
- 저장소 루트 밖에서 `run_loop.sh` 구동 시 `wait_for_job`이 3900초 무음 타임아웃을 발생시키며, `git diff`가 Creator가 새로 추가한 미추적 신규 파일을 리뷰어에게 누락합니다.
|
||||
### **B-7: `run_loop.sh` cwd 의존 및 미추적 파일 누락 — 리뷰어가 빈 diff 로 PASS**
|
||||
- 원 서술: 저장소 루트 밖에서 `run_loop.sh` 구동 시 `wait_for_job`이 3900초 무음 타임아웃을 발생시키며, `git diff`가 Creator가 새로 추가한 미추적 신규 파일을 리뷰어에게 누락합니다.
|
||||
- **실측(ecef05a3)**: `REPO_ROOT` 는 `BASH_SOURCE` 기반이라 cwd 비의존이지만(9-10행) **스크립트가 어디로도 `cd` 하지 않아** `git diff`(537·539행)가 호출자 cwd 에서 실행됩니다. 저장소 밖에서는 `rc=129` 이고 `|| echo "No git diff available"` 가 이를 삼켜, 리뷰어는 그 **문자열 하나를 받고 `[VERDICT: PASS]` 를 요구받습니다.**
|
||||
- 미추적 파일은 `git diff` 정의상 제외됩니다(실측 0 hunks). 신규 파일이 곧 산출물인 작업(예: A-4 의 `mam_agents/` 패키지)에서는 **리뷰가 사실상 존재하지 않게 됩니다.**
|
||||
- **파급**: 이 항목이 열려 있는 동안 나머지 11건의 구현 리뷰를 신뢰할 수 없습니다.
|
||||
- **처방**: §6.4 참조 ( + 미추적 파일 덧붙이기 + 크기 상한). ** 은 인덱스를 오염시키므로 채택하지 않습니다.**
|
||||
|
||||
### **B-8: `send_keys_safe` agy 경로 검증 이탈**
|
||||
- agy 세션 주입 시 주입 실패 여부를 검증하지 않고 무조건 `return 0`을 남겨 실패 시에도 성공으로 보고됩니다.
|
||||
@@ -89,7 +95,7 @@
|
||||
|
||||
---
|
||||
|
||||
## 3. 🟡 오케스트레이션 최적화 과제 (Orchestration Optimizations — 2건)
|
||||
## 3. 🟡 오케스트레이션 최적화 과제 (Orchestration Optimizations — 1건)
|
||||
|
||||
### **O-2 (구 ISSUE-7): 동일 워크스페이스 내 중복 루프 기동 방지 락 (Race-Free Lock)**
|
||||
- **현상**: 동일 작업 트리에서 다수의 `run_loop.sh` 스크립트가 병렬 기동될 경우 SQLite DB 갱신 경합 및 YAML 데이터 오염이 일어날 수 있음.
|
||||
@@ -98,16 +104,20 @@
|
||||
1. 락 소유자 레코드를 단순 `PID`에서 **`PID + 시작시각(lstart) + 워크스페이스`** 3중 구조로 결합하여 PID 재사용을 결정적으로 차단.
|
||||
2. `mkdir` 직후 생성 창 유예 대기(Sleep Grace Period)를 부여하여 락 도난 방지.
|
||||
3. `ps` CLI 부재 시 Fails-Open(락 무시) 대신 **Fails-Safe(락 존중 + 경고)** 로 전환하여 DB/YAML 오염 원천 방지.
|
||||
- **실측(ecef05a3) — 서술보다 위험**: `run_loop.sh:83-89` 는 `MAM_LOOP_MARKER` 를 **존재 확인 없이 덮어쓰고**, 종료 트랩(`_mam_release_guard`)이 소유권 대조 없이 삭제합니다. 따라서 먼저 종료한 인스턴스가 **아직 실행 중인 다른 인스턴스의 마커까지 지워**, 그 시점부터 **완료 처리된 O-3 위임 가드가 "루프 비활성"으로 오판**합니다. 해제는 자신이 기록한 `pid + lstart` 와 일치할 때만 수행해야 합니다.
|
||||
|
||||
---
|
||||
|
||||
## 4. ⚪ 레거시 잔재 및 죽은 코드 (Legacy Remnants — 3건)
|
||||
|
||||
### **C-3: 격리 스텁 4종 및 `stop_session.sh` 미사용 isolation 코드 잔존**
|
||||
- `provision_isolation` 등 4개 스텁 함수와 `stop_session.sh` 내 `.mam/agent_homes` 가드 코드가 호출자 0건인 채 잔존합니다.
|
||||
### **C-3: 격리 관련 잔재** — ⚠️ **C-3a / C-3b 로 분리 필요 (§6.5 참조)**
|
||||
- **C-3a (즉시 실행 가능)**: `provision_isolation` / `isolation_lever` / `isolation_env_prefix` / `isolation_cmd_args` 4종 **빈 스텁**. 프로덕션 호출자 0건. 이를 고정하던 공허한 테스트 5건(`test_tier1_unit.py` 3, `test_tier2_component.py` 1 등)도 함께 제거 대상.
|
||||
- **C-3b (보류 — A-4 M2 결정 사항)**: `isolation.root` 행 필드 소비자(`verify_session_uuid` 의 `iso_root` 분기, `mam_session_iso_root`, `find_workspace_uuid` 격리 분기, `stop_session.sh:277` purge 가드). **b4a1d094 / 44062a63 에서 의도적으로 되살린 코드**이므로 지우면 그 수정이 회귀합니다.
|
||||
|
||||
### **C-4: 참조 0회 미사용 심볼 7종**
|
||||
- `_HERDR_SHIM_DIR_PATTERN`, `_REAL_HERDR_PATH`, `TERMINAL_STATUSES`, `ISOLATE`, `local_herdr` 등 7개 미사용 심볼이 잔존합니다.
|
||||
### **C-4: 참조 0회 미사용 심볼** — ⚠️ **목록 정정됨 (7종 → 실질 3종)**
|
||||
- **실제 대상 3종**: `_REAL_HERDR_PATH`(대입·export 만), `TERMINAL_STATUSES`(`registry.py:38` 정의만), `ISOLATE`(`create_session.sh:57` 대입만).
|
||||
- **목록에서 제외**: `_HERDR_SHIM_DIR_PATTERN` 은 **사용 중**입니다(`lib.sh:57` 정의 → `lib.sh:79` 사용). 지우면 shim 경로 판정이 깨집니다. `local_herdr` 은 참조 0건으로 **이미 제거**되었습니다.
|
||||
- `provision_isolation` 은 **C-3a 와 중복**이므로 그쪽에서 함께 처리합니다.
|
||||
|
||||
### **C-6: `stop_session.sh` 도움말 문서 구버전 표기**
|
||||
- 스크립트 도움말에는 `--mode soft|hard` 등이 서술되어 있으나 실제 옵션 파서는 `exit 2`로 거부합니다.
|
||||
@@ -180,6 +190,103 @@
|
||||
|
||||
---
|
||||
|
||||
## 6. 결론 및 향후 보완 로드맵
|
||||
## 6. 🧭 우선순위 실행 로드맵 (Prioritized Execution Roadmap)
|
||||
|
||||
`IMPROVEMENTS.md` 문서에 따라 향후 코드베이스 개편 시 남은 백로그 항목(아키텍처 2건, 엣지케이스 7건, 오케스트레이션 2건, 레거시 잔재 4건)을 일원화된 보완 로드맵으로 관리합니다.
|
||||
> 평가 근거·항목별 실측 결과는 `.mam/jobs/ecef05a3/claude-reports/report-final.md` 참조.
|
||||
> **순위를 매기기 전에 12건을 전부 현재 코드에 대조했으며, 그중 4건(A-2·B-5·C-3·C-4)의 기존 서술이 현재 코드와 달라 본문을 정정했습니다.**
|
||||
|
||||
### 6.1 정렬 원칙
|
||||
|
||||
① 외부에서 트리거 가능한 위험 → ② 검증 신호를 **거짓으로** 만드는 결함 → ③ 다른 항목을 싸게 만드는 구조 작업 → ④ 국소 결함 → ⑤ 정리.
|
||||
|
||||
**조용한 실패에 가중치를 둡니다.** 시끄러운 실패는 사람이 보지만, 조용한 실패는 "통과"로 기록되고 그 위에 다음 작업이 쌓입니다.
|
||||
|
||||
### 6.2 실행 순서
|
||||
|
||||
| 순위 | 항목 | 근거 | 비용 | 선행 |
|
||||
|---|---|---|---|---|
|
||||
| **P0-1** | **A-2** | 공개 브로커 + `auth_token` 발급 0건 + 전역 토픽 발행이 한 줄로 이어져 **원격 pane kill 체인이 완결**됨 (실측: 26/26 잡이 `topic_prefix=python/mqtt/jobs/...`, `auth_token=None`) | 중 (3파일) | — |
|
||||
| **P1-1** | **B-7** | 저장소 밖 기동 시 리뷰어가 문자열 `"No git diff available"` 로 `[VERDICT: PASS]` 를 냄. 신규(미추적) 파일은 리뷰 대상 밖. **나머지 11건의 검증 근거를 훼손** | 소 (1파일) | — |
|
||||
| **P1-2** | **O-2** | 마커를 조건 없이 덮어쓰고 종료 트랩이 **타 인스턴스의 마커까지 삭제** → 완료 처리된 **O-3 가드가 조용히 무력화**됨 | 소~중 (1파일) | — |
|
||||
| **P2-1** | **A-4 M0~M1** | `PYTHONPATH` 부트스트랩·배포/CI 등록·`own_key` 이관. B-8/B-10/C-3b 를 싸게 만듦 | 중 | B-7 |
|
||||
| **P2-2** | **B-8** | agy 주입이 검증 없이 `return 0` → 아무것도 전달되지 않은 잡이 `started` 로 기록됨. A-4 M0(`_pane_capture` 디코딩) 이후엔 **회피책 제거**로 축소 | 소 | A-4 M0 |
|
||||
| **P3-1** | **B-6** | 버전 관리 트리 오염 + rsync 배포 유출. `mktemp -d` 로 옮기는 1~2줄 | 소 | — |
|
||||
| **P3-2** | **C-3a + C-4** | 빈 스텁 4종 + 이를 고정하던 **공허한 테스트 5건** + 죽은 심볼 3종 제거 (회귀 시간 단축 효과) | 소 | — |
|
||||
| **P3-3** | **C-6** | 도움말 3줄 정정 | 극소 | — |
|
||||
| **P4-1** | **A-4 M2~M7** | 어댑터 본이관. 진행 중 **B-10 · C-3b 처분 결정** | 대 | P2-1 |
|
||||
| **P4-2** | **B-10** | tier-3 신원 캐시 존치/제거 결정 + PyYAML 의존 완화 | 중 | A-4 M2 |
|
||||
| **P4-3** | **C-3b** | `isolation.root` 소비자 처분 결정 | 소 | A-4 M2 |
|
||||
| **P5** | **B-9** | 기본값 한정. `logs_dir` 인자·`DELEGATE_JOB_LOGS_DIR` 두 가지 회피 수단 존재 | 극소 | — |
|
||||
| **종결 권고** | **B-5** | 폴백(`df -P`)으로 이미 해소 — 서술된 실패가 재현되지 않음 | — | — |
|
||||
|
||||
**A-2 를 B-7 보다 앞에 두는 이유**: B-7 의 피해는 우리 워크플로 내부에 머물고 리뷰 결과를 다시 읽으면 회복 가능하지만, A-2 는 외부에서 트리거되고 살아 있는 세션을 파괴하며 우리 쪽 행동으로 예방할 수 없습니다.
|
||||
|
||||
**정리(C 계열)를 P3 에 두는 이유**: (a) C-3a 는 공허한 테스트 5건을 함께 제거해 이후 모든 전체 회귀를 단축하고, (b) C-4 는 **잘못 실행하면 버그를 만듭니다**(아래 6.5). 방치할수록 누군가 "쉬운 정리"로 집어 들 확률이 올라갑니다.
|
||||
|
||||
### 6.3 병렬 실행 — 파일 소유권 슬롯 (Rev.2 교체)
|
||||
|
||||
> Rev.1 은 "주제별 트랙"으로 병렬화를 서술했고 **그 분해는 4곳에서 틀렸습니다**(챌린지 `7d604ee7` 계기로 파일 단위 재대조). 병렬 단위는 **주제가 아니라 파일**입니다.
|
||||
|
||||
**항목별 처방이 건드리는 파일**
|
||||
|
||||
| 파일 | 건드리는 항목 |
|
||||
|---|---|
|
||||
| `run_loop.sh` | **B-6, B-7, O-2** |
|
||||
| `lib.sh` | **A-4, B-8, B-10, C-3a, C-4** |
|
||||
| `reconcile.sh` | **A-2, A-4, B-10** |
|
||||
| `mqtt_common.py` | **A-2, B-9** |
|
||||
| `stop_session.sh` | **B-10, C-6** |
|
||||
| `registry.py` | **A-2, C-4** |
|
||||
| `create_session.sh` | **A-4, C-4** |
|
||||
|
||||
**슬롯 배치 — 슬롯 안은 직렬, 슬롯 간은 병렬**
|
||||
|
||||
| 슬롯 | 순서 |
|
||||
|---|---|
|
||||
| **`run_loop.sh`** | `B-7` → `O-2` → `B-6` |
|
||||
| **`lib.sh`** | `C-3a`+`C-4` → `B-8` |
|
||||
| **MQTT 계열** (`mqtt_common.py`·`registry.py`·`publish_event.py`·`job_subscriber.py`·`reconcile.sh`) | `A-2` → `B-9` |
|
||||
| **`stop_session.sh`** | `C-6` |
|
||||
| **단독 실행** (슬롯 경계를 넘음) | `A-4`, `B-10` |
|
||||
|
||||
- `A-4`(`lib.sh`+`reconcile.sh`+`create_session.sh`+`resume_session.sh`)와 `B-10`(`lib.sh`+`reconcile.sh`+`stop_session.sh`)은 **어떤 슬롯 조합과도 겹치므로 단독 실행**합니다.
|
||||
- `A-4` 는 신규 파일을 대량 추가하므로 **B-7 이 먼저 닫혀 있어야 리뷰가 성립**합니다.
|
||||
- **Rev.1 오류 정정 4건**: `B-6`(트랙 C→`run_loop.sh` 슬롯), `C-3a`·`C-4`(트랙 C→`lib.sh` 슬롯), `B-9`(독립→MQTT 슬롯), `C-6`(독립→`stop_session.sh` 슬롯).
|
||||
- 참고: `reconcile.sh` 는 `MAM_LOOP_MARKER`·`send_keys_safe` 를 **참조 0건**이므로 `O-2`·`B-8` 과는 경합하지 않습니다(자체 `.mam/monitor.lock` 보유).
|
||||
|
||||
### 6.4 B-7 처방 (Rev.2 신설 — 진단만 있고 처방이 없었음)
|
||||
|
||||
`cd "$REPO_ROOT"` 만으로는 **미추적 신규 파일이 여전히 100% 누락**됩니다. `git diff` 는 정의상 추적 파일만 봅니다.
|
||||
|
||||
```bash
|
||||
CHANGES_DIFF=$(
|
||||
cd "$REPO_ROOT" || exit 1
|
||||
git diff "$BASE_COMMIT"
|
||||
# 미추적 신규 파일을 인덱스 변경 없이 덧붙인다.
|
||||
# --exclude-standard 가 .gitignore / .git/info/exclude 를 그대로 존중한다.
|
||||
git ls-files -o --exclude-standard -z | while IFS= read -r -d '' f; do
|
||||
git diff --no-index --binary /dev/null "$f" 2>/dev/null || true
|
||||
done
|
||||
)
|
||||
```
|
||||
|
||||
**`git add -N .` 은 채택하지 않습니다.** 미추적 파일을 diff 에 넣는 목적은 달성하지만(실측 확인) **인덱스에 `A` 항목을 남기며**, 그 상태에서 Creator 가 `git commit -am` 을 실행하면 **추가한 적 없는 파일이 내용째 커밋됩니다**(실측 확인). `run_loop.sh` 는 Creator 가 같은 저장소에서 작업하는 동안 반복 실행되므로 실제 위험입니다. 위 대안은 동일 결과를 내면서 인덱스를 건드리지 않습니다.
|
||||
|
||||
**크기 상한도 함께 필요합니다.** 현재 `CHANGES_DIFF`(537·539행)는 **아무 제한 없이** 547행 리뷰 프롬프트에 보간되고 `send_keys_safe` paste-buffer 로 주입됩니다. 미추적 파일을 포함시키면 커지기만 하므로 상한을 두고, 초과 시 `--stat` 요약으로 대체하되 **잘렸다는 사실을 리뷰어에게 반드시 노출**해야 합니다(조용히 자르면 "빈 diff PASS" 가 "부분 diff PASS" 로 바뀔 뿐입니다). 구체적 임계값은 구현자가 샌드박스 세션에서 paste-buffer 실패 지점을 측정해 확정할 것.
|
||||
|
||||
### 6.5 ⚠️ 실행 전 반드시 확인할 정정 사항
|
||||
|
||||
|
||||
1. **C-3 은 그대로 실행하면 회귀를 만듭니다.** 항목이 성격이 다른 둘을 묶고 있습니다.
|
||||
- **C-3a (즉시 실행 가능)**: `provision_isolation` / `isolation_lever` / `isolation_env_prefix` / `isolation_cmd_args` 4종 빈 스텁 — 프로덕션 호출자 0건. 이를 고정하던 `tests/test_tier1_unit.py` 3건 + `tests/test_tier2_component.py` 1건도 함께 제거 대상.
|
||||
- **C-3b (보류 — A-4 M2 결정 사항)**: `isolation.root` 소비자(`lib.sh` `verify_session_uuid` 의 `iso_root` 분기, `mam_session_iso_root`, `find_workspace_uuid` 격리 분기, `stop_session.sh:277` purge 가드). **b4a1d094 / 44062a63 에서 방금 의도적으로 되살린 코드**이며, 지우면 그 수정이 되돌아갑니다.
|
||||
2. **C-4 의 "7종" 중 2종은 사실과 다릅니다.**
|
||||
- `_HERDR_SHIM_DIR_PATTERN` — **사용 중입니다** (`lib.sh:57` 정의, `lib.sh:79` 사용). 목록대로 지우면 shim 경로 판정이 깨집니다.
|
||||
- `local_herdr` — 참조 0건, **이미 제거됨**.
|
||||
- 실제 대상은 `_REAL_HERDR_PATH`, `TERMINAL_STATUSES`, `ISOLATE` 3종이며 `provision_isolation` 은 C-3a 와 중복입니다.
|
||||
3. **A-2 의 원인 표현 정정** — `verify_hmac` 구현 자체는 정상입니다(토큰이 있으면 `hmac.compare_digest` 로 검증). 원인은 **토큰이 아무 데서도 발급되지 않아 검증이 공허해지는 것** + 발행자가 워크스페이스 지문 토픽을 채택하지 않은 것입니다. 수정은 ① 발행자 토픽 교체 ② `reconcile.sh:237` 레거시 전역 구독 제거 ③ `verify_hmac` fail-closed + 토큰 발급 순입니다.
|
||||
4. **B-5 잔여분** — 폴백으로 감지는 정상화됐으나 `mount | grep -E "$mountpoint.*(nfs|...)"` 가 마운트포인트를 **이스케이프 없이 ERE 에 보간**합니다(경로의 `.` 이 임의 문자로 해석). 이것만 신규 항목(B-11)으로 분리 권고.
|
||||
|
||||
### 6.6 결론
|
||||
|
||||
`IMPROVEMENTS.md` 는 남은 백로그 항목(아키텍처 2건, 엣지케이스 6건, 오케스트레이션 1건, 레거시 잔재 3건 — 총 12건)을 위 우선순위에 따라 일원화된 보완 로드맵으로 관리합니다.
|
||||
|
||||
Reference in New Issue
Block a user