docs(improvements): prioritize and record execution roadmap Section 6 (100% PASS)

This commit is contained in:
2026-08-09 19:55:25 +09:00
parent 29f0be5296
commit 4d1c381033
3 changed files with 481 additions and 13 deletions
@@ -0,0 +1,269 @@
# 7747d745 — 우선순위 평가 및 실행 로드맵 **Rev.2**
**Job**: 7747d745 · **Role**: Planner · **Supersedes**: ecef05a3 (Rev.1)
**응답 대상**: 챌린지 `7d604ee7` (`agy`, `[CHALLENGE: RAISED]`) — B-7 해법 미비 · 트랙 병렬 경합
**Base**: `245abe6` + 작업 트리
---
## 1. 판정 요약
**두 건 모두 채택한다.** 다만 두 건 다 지적 내용 그대로는 성립하지 않는다.
| # | 챌린지 | 판정 | 실측 |
|---|---|---|---|
| C-1 | B-7 해법이 `cd $REPO_ROOT` 뿐이라 미추적 파일을 못 잡는다 | **채택 — 단 전제 오류** | Rev.1 은 B-7 **해법을 아예 명시하지 않았다**. 인용된 `cd "$REPO_ROOT" && git diff` 는 내 문서에 없는 문장이다. 그러나 "진단만 하고 처방을 안 썼다"는 것 자체가 결함이고, 제안된 `git add -N .`**동작한다**(실측) |
| C-2 | A-2 와 O-2/B-8 이 `reconcile.sh` 에서 충돌한다 | **채택 — 지목한 쌍은 존재하지 않음, 그러나 내 트랙 분해가 더 틀렸다** | `reconcile.sh``MAM_LOOP_MARKER` 참조 **0건**, `send_keys_safe` 참조 **0건** → O-2·B-8 은 `reconcile.sh` 를 건드리지 않는다. 반면 파일 단위 매트릭스를 만들어 보니 **내 §4.3 트랙 분해가 4곳에서 틀렸다** |
정정부터. Rev.1 §4.3 은 "트랙 C(정리)는 트랙 A/B 와 독립"이라고 썼다. **틀렸다.**
`B-6``run_loop.sh` 를 고치므로 B-7·O-2 와 같은 파일이고, `C-3a`·`C-4``lib.sh`
고치므로 B-8·A-4 와 같은 파일이다. agy 는 엉뚱한 쌍을 지목했지만 **"파일 단위 대조 없이
독립을 선언했다"는 지적의 실질은 옳고, 실제 피해는 그들이 본 곳보다 넓다.**
`git add -N .` 은 채택하되 **그대로는 쓰지 않는다.** 인덱스를 오염시켜
이후 `git commit -a`**작성자가 추가한 적 없는 파일을 조용히 커밋한다**(실측 §2.3).
Creator 에이전트가 같은 저장소에서 동시에 git 을 쓰는 구조라 이건 이론이 아니다.
**인덱스를 건드리지 않는 동등 대안**을 권한다(§2.4).
---
## 2. C-1 — B-7 해법: 채택, 기전 교체
### 2.1 전제 정정
챌린지는 "Plan §4 의 해법(`cd $REPO_ROOT && git diff`)"을 인용한다.
Rev.1 §4 표의 B-7 칸 전문은 다음과 같다:
> 리뷰어가 빈 diff 로 PASS. 신규 파일은 리뷰 대상 밖. **나머지 11건의 검증 근거를 훼손**(§3.2)
**근거만 있고 해법은 없다.** `cd "$REPO_ROOT"` 는 내가 쓴 적 없는 문장이다.
그러나 이건 방어가 아니라 자기 결함의 확인이다 — **P1-1 로 올려 놓고 처방을 안 썼다.**
구현자가 §3.2 의 두 원인 중 눈에 띄는 쪽(cwd)만 고치고 끝냈을 가능성이 크고,
챌린지는 정확히 그 시나리오를 예측했다. 처방을 명시하는 것으로 갚는다.
### 2.2 `git add -N .` 은 동작한다 (실측)
빈 저장소에 tracked 수정 1건 · untracked 신규 2건 · `.gitignore` 대상 1건을 심고 측정했다.
```
[before] git diff $BASE --stat
tracked.txt | 1 + ← 신규 파일 0건
[after] git add -N . ; git diff $BASE --stat
pkg/__init__.py | 1 + ← 잡힘
sub/newfile.py | 1 + ← 잡힘
tracked.txt | 1 +
ignored.log hunks: 0 ← .gitignore 존중됨
```
**제안의 두 가지 핵심 주장이 모두 참이다**: 미추적 신규 파일이 diff 에 포함되고,
`.gitignore` 는 그대로 존중된다.
### 2.3 그러나 인덱스가 오염된다 — 그리고 그게 커밋으로 샌다
`git add -N .` 직후 인덱스 상태:
```
A pkg/__init__.py
A sub/newfile.py
M tracked.txt
```
이 상태에서 Creator 가 `git commit -am "wip"` 을 실행하면:
```
$ git commit -qam "creator wip" ; git show --stat HEAD
pkg/__init__.py | 1 +
sub/newfile.py | 1 +
tracked.txt | 1 +
-> sub/newfile.py in that commit? brand new ← 내용까지 들어갔다
```
**작성자가 `git add` 한 적 없는 파일이 `-a` 한 번에 커밋된다.** 평소 `git commit -a`
미추적 파일을 건드리지 않으므로, 이건 **git 의 기본 안전 성질을 바꾸는 부작용**이다.
MAM 에서 이게 가설이 아닌 이유: `run_loop.sh` 는 Creator 에이전트가 **같은 저장소에서
동시에 작업하는 동안** 돌아간다. 루프가 인덱스를 바꾸는 시점과 Creator 가 git 을 쓰는
시점이 겹친다. 게다가 루프는 반복 실행되므로 오염이 매 사이클 재발한다.
`git reset` 으로 되돌리는 보정을 붙일 수도 있지만, (a) 비정상 종료 시 남고
(b) 되돌리는 순간과 Creator 의 git 호출이 또 경합한다. **부작용을 만들고 지우는 대신
애초에 만들지 않는 편이 낫다.**
### 2.4 권고: 인덱스를 건드리지 않는 동등 대안
```bash
CHANGES_DIFF=$(
cd "$REPO_ROOT" || exit 1
git diff "$BASE_COMMIT"
# 미추적 신규 파일: 인덱스를 바꾸지 않고 /dev/null 대비 diff 로 덧붙인다.
# --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
)
```
같은 픽스처 실측:
```
diff --git a/tracked.txt b/tracked.txt ← 기존 파일 수정
diff --git a/sub/newfile.py b/sub/newfile.py ← 신규 파일
--- /dev/null
+++ b/sub/newfile.py
ignored.log present? 0 ← .gitignore 존중
[index] M tracked.txt / ?? sub/ ← 인덱스 무변경
```
동일한 결과를 내면서 인덱스를 건드리지 않는다.
> `git diff --no-index` 는 두 경로가 모두 저장소 밖일 때 rc=1 을 반환하지만,
> 여기서는 차이가 있을 때 rc=1 이 정상이므로 `|| true` 로 흡수한다.
> `-z` + `IFS= read -r -d ''` 는 공백·개행이 든 파일명을 위한 것이다.
### 2.5 함께 고쳐야 할 것 — `cd` 와 크기 상한
**(a) `cd "$REPO_ROOT"`** 는 여전히 필요하다. §3.2 의 두 원인 중 하나이고
서브셸 안에서 처리하면 호출자 cwd 를 오염시키지 않는다(위 코드에 반영).
**(b) 크기 상한이 없다.** 실측: `run_loop.sh:537,539` 에서 만든 `CHANGES_DIFF`
**아무 제한 없이** 547행의 리뷰 프롬프트 문자열에 그대로 보간되고,
그 프롬프트는 `send_keys_safe` 를 통해 TUI paste-buffer 로 주입된다.
미추적 파일을 포함시키면 diff 는 **커지기만 한다**. 누군가 큰 산출물을 ignore 하지 않은 채
남겨 두면 리뷰 주입이 통째로 실패하거나 잘린다.
**권고**: 상한(예: 200 KB / 4000 줄)을 두고 초과 시 `--stat` 요약 + 초과 사실 명시로 대체.
**잘렸다는 사실이 리뷰어에게 반드시 보여야 한다** — 조용히 잘리면 B-7 을
"빈 diff 로 PASS" 에서 "부분 diff 로 PASS" 로 바꾸는 것에 지나지 않는다.
---
## 3. C-2 — 트랙 경합: 지목한 쌍은 없고, 내 분해가 더 틀렸다
### 3.1 지목된 두 쌍은 성립하지 않는다
```
reconcile.sh 내 MAM_LOOP_MARKER / loop-guard-active 참조 → 0건
reconcile.sh 내 send_keys_safe / inject_instructions 참조 → 0건
```
- **O-2**: 마커는 `run_loop.sh:83-89` 에만 있다. `reconcile.sh`**자기 자신의 별도 락**
(`.mam/monitor.lock`, `fcntl.flock`, 86-95행)을 이미 갖고 있다 — 다른 프로세스를 위한
다른 뮤텍스다. O-2 의 처방은 `run_loop.sh` 안에서 끝난다.
- **B-8**: `send_keys_safe``lib.sh` 함수이고 `reconcile.sh` 는 이를 호출하지 않는다.
따라서 "A-2 ⟂ O-2/B-8 이 `reconcile.sh` 에서 충돌"은 **실재하지 않는다.**
### 3.2 그러나 Rev.1 §4.3 은 실제로 틀렸다
챌린지가 제기한 방법론적 문제 — **파일 단위 대조 없이 독립을 선언했다** — 는 옳다.
각 항목의 처방이 건드리는 파일을 근거에서 도출해 매트릭스를 만들었다.
| 파일 | 건드리는 항목 |
|---|---|
| `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** |
Rev.1 §4.3 의 오류 4건:
1. **`B-6` 을 트랙 C(독립)에 뒀다.** `run_loop.sh` 이므로 B-7·O-2 와 같은 파일이다.
2. **`C-3a`·`C-4` 를 트랙 C(독립)에 뒀다.** `lib.sh` 이므로 B-8·A-4 와 같은 파일이다.
3. **`B-9` 를 P5 독립으로 뒀다.** `mqtt_common.py` 이므로 A-2 와 같은 파일이다.
4. **`C-6` 을 독립으로 뒀다.** `stop_session.sh` 이므로 B-10 과 같은 파일이다.
agy 가 지목한 A-2↔O-2 는 없지만 **A-2↔A-4, A-2↔B-10, A-2↔B-9, A-2↔C-4** 는 있다.
`lib.sh` 는 5개 항목이 몰리는 최대 경합 지점이다.
### 3.3 결론: "트랙"이 아니라 "파일 소유권"으로 직렬화한다
트랙 개념 자체가 잘못된 추상화였다. 병렬 단위를 **주제**가 아니라 **파일**로 잡는다.
| 파일 소유 슬롯 | 순서 | 동시 실행 가능 |
|---|---|---|
| **`run_loop.sh`** | B-7 → O-2 → B-6 | 다른 슬롯과 병렬 |
| **`lib.sh`** | C-3a+C-4 → B-8 → (A-4 M0~) | 다른 슬롯과 병렬 |
| **MQTT 계열**(`mqtt_common.py`·`registry.py`·`publish_event.py`·`job_subscriber.py`·`reconcile.sh`) | A-2 → B-9 | 다른 슬롯과 병렬 |
| **`stop_session.sh`** | C-6 → (B-10) | 다른 슬롯과 병렬 |
- 한 슬롯 안은 **직렬**, 슬롯 간은 **병렬**. 슬롯을 넘는 항목(**A-4**, **B-10**)은
**단독 실행**한다 — A-4 는 `lib.sh`+`reconcile.sh`+`create_session.sh`,
B-10 은 `lib.sh`+`reconcile.sh`+`stop_session.sh` 이므로 어떤 슬롯 조합과도 겹친다.
- `reconcile.sh` 를 MQTT 슬롯에 넣은 이유: A-2 가 그 파일에서 가장 큰 변경을 하고,
나머지 두 소비자(A-4·B-10)는 어차피 단독 실행이다.
**우선순위 표(Rev.1 §4)의 순위 자체는 바뀌지 않는다.** 바뀌는 것은 병렬화 방식뿐이다.
---
## 4. 변경 요약 (Rev.1 대비)
| ID | 대상 | 내용 |
|---|---|---|
| R-1 | B-7 처방 (신규) | `cd "$REPO_ROOT"` + `git ls-files -o --exclude-standard` 기반 미추적 파일 덧붙이기. **`git add -N` 은 채택하지 않음**(인덱스 오염, §2.3) |
| R-2 | B-7 처방 (신규) | `CHANGES_DIFF` 크기 상한 + **잘림 사실 명시** |
| R-3 | §4.3 교체 | "트랙" → **파일 소유권 슬롯**. Rev.1 의 독립 선언 4건 정정 |
| R-4 | A-4 · B-10 | 슬롯 경계를 넘으므로 **단독 실행** 명시 |
우선순위(P0-1 ~ P5, 종결 권고 B-5)와 §3 실측 결과는 **전부 그대로 유효**하다.
---
## 5. 검증
전부 임시 저장소(`scratchpad/b7`, `b7b`)에서 실측했다. 프로덕션 저장소의 인덱스는
**건드리지 않았다** — 인덱스 오염이 바로 이 논점이므로 실 저장소에서 재현하는 것은 부적절하다.
| 검증 | 결과 |
|---|---|
| `git add -N .` 이 미추적 파일을 diff 에 포함시키는가 | ✅ 포함 (2/2 신규 파일) |
| `.gitignore` 존중 | ✅ `ignored.log` 0 hunks |
| 인덱스 잔존 여부 | ❌ `A pkg/__init__.py`, `A sub/newfile.py` 잔존 |
| 잔존 상태에서 `git commit -a` | ❌ **추가한 적 없는 파일이 내용째 커밋됨** |
| 대안(`ls-files -o` + `--no-index`) 포함 여부 | ✅ 포함 |
| 대안의 `.gitignore` 존중 | ✅ 0 hunks |
| 대안의 인덱스 영향 | ✅ 무변경 (`?? sub/` 유지) |
| `reconcile.sh` 의 O-2 심볼 참조 | 0건 → C-2 전제 반증 |
| `reconcile.sh` 의 B-8 심볼 참조 | 0건 → C-2 전제 반증 |
| `CHANGES_DIFF` 크기 상한 | 없음 (537·539 → 547 무제한 보간) |
---
## 6. 남는 불확실성
Rev.1 §6 의 4건(A-2 노출도 · O-2 경합 창 · B-9 호출자 전수 · A-4 상한)은 그대로 유효하다. 추가분:
**6.5 크기 상한값은 근거 없이 제시했다.** §2.5 의 "200 KB / 4000 줄"은 관례적 수치이지
측정값이 아니다. `send_keys_safe` 의 paste-buffer 가 실제로 어느 크기에서 실패하는지는
측정하지 않았다 — 실 세션에 대용량 주입을 시도하는 실험이라 Planner 범위에서 부적절하다.
**B-7 구현자가 샌드박스 세션에서 상한을 측정해 확정할 것.**
**6.6 파일 매트릭스는 처방 기준의 추정이다.** 각 항목이 실제로 어느 파일을 건드릴지는
구현 단계에서 늘어날 수 있다(특히 테스트 파일). 슬롯 배치는 구현 착수 시 재확인해야 한다.
**6.7 `git ls-files -o` 는 서브모듈·심링크를 이 저장소에서 검증하지 않았다.**
MAM 저장소에는 서브모듈이 없어 실측 대상이 아니었다. 다른 워크스페이스에 배포될 때를
고려하면 구현자가 한 번 확인하는 편이 좋다.
---
## 7. 결론
두 챌린지 모두 **전제는 틀렸고 결론은 맞다.**
C-1 이 인용한 `cd $REPO_ROOT && git diff` 는 내 문서에 없다 — 나는 B-7 의 처방을
**아예 쓰지 않았다**. 그게 더 나쁘다. 제안된 `git add -N .` 은 실제로 동작하지만
인덱스를 오염시켜 `git commit -a` 가 추가한 적 없는 파일을 커밋하게 만든다.
동등하면서 부작용 없는 형태로 교체해 채택한다.
C-2 가 지목한 A-2↔O-2/B-8 충돌은 `reconcile.sh` 참조 0건으로 **존재하지 않는다**.
그러나 파일 매트릭스를 만들어 보니 **내 트랙 분해가 4곳에서 틀렸고**,
`lib.sh` 에는 5개 항목이 몰려 있었다. 트랙이라는 추상화를 버리고 파일 소유권 슬롯으로 바꾼다.
우선순위 순서 자체는 Rev.1 그대로다. 바뀐 것은 **B-7 의 처방**과 **병렬화 방식** 두 가지다.
**[AGREEMENT: REACHED]**
@@ -0,0 +1,92 @@
# Cross-Code Review — Job `f4f441fb`
- **Job ID**: f4f441fb · **Reviewer**: cline · **Base**: `29f0be5` (working-tree, uncommitted)
- **Task**: `IMPROVEMENTS.md` 12건 미해결 과제(A-2, B-5..B-10, O-2, A-4, C-3..C-6)에 대한 우선순위 실행 로드맵 신설 및 누적 변경분(git diff) 교차 코드 리뷰 (lint / 동작성 / 유실)
- **Diff scope**: `IMPROVEMENTS.md` 단일 파일 — `git diff --stat` = **1 file changed, 120 insertions(+), 13 deletions(-)**
---
## 1. 변경분 요약 및 검증 대상
변경분은 **문서(백로그)**에 대한 두 가지 갱신이다. (1) 4개 기존 항목(A-2·B-5·B-7·C-3·C-4)의 서술을 현재 코드 실측 기반으로 정정, (2) **§6 「🧭 우선순위 실행 로드맵」** 신설(6.1 정렬원칙 / 6.2 실행순서표 / 6.3 파일-소유권 병렬 슬롯 / 6.4 B-7 처방 / 6.5 정정사항 / 6.6 결론). 코드·배포 자산·테스트는 건드리지 않았다(`git status --porcelain`: ` M IMPROVEMENTS.md` 단일).
브리프에 첨부된 diff 헤더(`index da41a28..157344b`)와 working-tree diff가 정확히 일치한다. 로드맵은 브리프가 요구한 4 평가축(보안 위험·런타임 안정성·개발 생산성·아키텍처 영향)을 모두 반영하며, 12건 과제를 전부 단일 순서표에 배치했다(P0~P5 + 종결 권고). A-4는 M0~M1(P2-1)·M2~M7(P4-1)로 분할, C-3은 C-3a(P3-2 즉시)·C-3b(P4-3 보류)로 분리되어 있어 누락 0건이다.
| 검증 항목 | 방법 | 결과 |
|---|---|---|
| Diff 일치 (브리프 vs working tree) | `git --no-pager diff IMPROVEMENTS.md` | ✅ 정확 일치 |
| 코드/자산 부재 (순수 문서) | `git status --porcelain` | ✅ IMPROVEMENTS.md 단일 |
| 12건 전수 배치 | §6.2 순서표 + 분할 항목 대조 | ✅ 누락 0건 |
| §3 카운트 정정 근거 | `git show HEAD:IMPROVEMENTS.md` §3 | ✅ HEAD §3="2건"이나 본문은 O-2 단일(스테일) → 1건 정정 타당 |
---
## 2. Lint (정적 품질)
`IMPROVEMENTS.md`는 Markdown 문서로 셸/파이썬 린트 대상이 아니다. Markdown 구조 정합성만 점검했다.
- 헤더 계층(`#`~`######`) 일관. §6의 `###`~`####` 하위 구조 정상.
- §6.2 실행순서표: 5열(순위/항목/근거/비용/선행) 정합, 13행. §6.3 파일표(2열)·슬롯표(2열) 정합.
- §6.4 코드블록(` ```bash `` ``` `) 정상 펜스, 내부 `git ls-files -o --exclude-standard -z` 등 유효 bash.
- 인라인 백틱 쌍 정합, 한국어/영문 혼용 깨짐 없음.
- **내부 집계 일관성**: 헤더 `12건(아키텍처 2·엣지 6·오케스트 1·레거시 3)` ↔ §1=2·§2=6·§3=1·§4=3 정합(이 diff가 §3을 2→1로 정정해 일관성 확보). `완료된 과제 10건` 줄·§5 미변경.
---
## 3. 동작성 (설계 주장의 코드베이스 정합성)
코드 변경이 없으므로, 변경된 서술 및 로드맵 근거가 현 코드베이스 사실과 일치하는지(거짓 주장·과장·스테일 여부)를 교차 검증했다.
| 변경/주장 | 코드베이스 실측 | 판정 |
|---|---|---|
| **A-2**: `verify_hmac``if not auth_token: return True` 상시 타점 | `mqtt_common.py:278-279` `if not auth_token: return True # PoC mode — no auth` | ✅ 정합 |
| **A-2**: 잡 `auth_token=None` (실측 **26/26**) | `.mam/jobs/*.json` 30건 전수 → `auth_token=None: 30/30` | ⚠️ 카운트 스테일(26→30); 정성(100% None)은 정확 |
| **A-2**: 발행자 전역 토픽 + `reconcile.sh:237` 전역 구독 | `reconcile.sh:236-238` legacy `python/mqtt/jobs/+/events` 구독(지문 토픽 병기) | ✅ 정합 |
| **A-2**: HMAC 구현 자체는 정상 | 토큰 있으면 `hmac.compare_digest` 검증 경로 존재 | ✅ 정합 |
| **B-5**: `df --output=target` 실패 + `df -P` 폴백 정상 | `lib.sh:927` `df --output=target` / `lib.sh:929` `df -P` 폴백 | ✅ 정합(종결 권고 타당) |
| **B-5 잔여**: `mount\|grep -E "$mountpoint"` 비이스케이프 보간 | `lib.sh:931` `mount \| grep -i -q -E "$mountpoint.*(nfs\|cifs\|smb\|sshfs)"` | ✅ 정합(B-11 분리 근거 유효) |
| **B-7**: `REPO_ROOT` BASH_SOURCE(9-10행), `cd` 없음, `git diff` 537·539행 | `run_loop.sh:8-9` / `cd` 없음 / `git diff` L537·L539 `‖ echo "No git diff available"` / 프롬프트 L547 | ✅ 정합(행 번호 정확) |
| **B-7 처방**: `git add -N .` 인덱스 오염 → 기각, `git ls-files -o` 대안 | `git add -N` 동작 git 공식문서상 맞음; 대안은 인덱스 비변경 | ✅ 논리 정합(처방은 미구현 설계) |
| **C-3a**: 4종 빈 스텁, 프로덕션 호출자 0건, 테스트 고정 | `lib.sh:1614/1619/1626/1630` / 호출자 0건 / `test_tier1_unit.py`+`test_tier2_component.py` | ✅ 정합 |
| **C-3b**: `isolation.root` 소비자(되살린 코드) | `verify_session_uuid` iso_root 분기 등 존재 | ✅ 보류 분리 타당 |
| **C-4**: `_HERDR_SHIM_DIR_PATTERN` 사용 중(L57 정의·L79 사용) | `lib.sh:57` 정의 / `lib.sh:79` 사용 | ✅ 정합(목록 제외 정당) |
| **C-4**: `local_herdr` 참조 0건(이미 제거) | `grep -rn local_herdr` → 0건 | ✅ 정합 |
| **C-4**: `_REAL_HERDR_PATH`(대입·export만) | `lib.sh:100-101`, 타 참조 0건 | ✅ 정합 |
| **C-4**: `TERMINAL_STATUSES`(`registry.py:38` 정의만) | `registry.py:38`, 타 참조 0건 | ✅ 정합 |
| **C-4**: `ISOLATE`(`create_session.sh:57` 대입만) | `create_session.sh:57 ISOLATE=1`, 타 참조 0건 | ✅ 정합 |
| **O-2**: `run_loop.sh:83-89` 마커 무조건 덮어쓰기 + 트랩 소유권 대조 없이 삭제 | L83 마커 / L87 `>` 덮어쓰기 / L88 `rm -f`(대조 无) | ✅ 정합(행 번호·위험 서술 정확) |
| **§6.3**: `reconcile.sh``MAM_LOOP_MARKER`·`send_keys_safe` 참조 0건 | `grep -cn` → 0 | ✅ 정합(슬롯 비경합 근거 유효) |
**동작성 결과: PASS** — 17개 항목 중 16개 완전 정합, 1개(A-2 카운트 26→30) 스테일이나 정성 주장은 부정확하지 않음. 거짓·과장 주장 없음.
---
## 4. 유실 (Loss / Orphan)
`git diff`**삭제 13줄**. 전부 교체성 갱신 또는 정정이며 원 정보 손실 아님:
- **헤더 갱신일**(1줄): `A-4 ... 등재``7747d745 Rev.2 — B-7 처방 ...` — 정당.
- **A-2 현상**(1줄→다행): 단문을 상세 실측으로 확장. 원 의미 보존 + 정정.
- **B-5/B-7**(각 1~2줄): 원 서술을 `원 서술:` 라벨로 보존한 채 실측 부가 — **삭제가 아니라 주석화**. 정보 손실 0.
- **§3 제목**(1줄): `2건``1건`. `git show HEAD:IMPROVEMENTS.md` 확인 결과 HEAD §3 본문은 O-2 단일이었고 "2건"은 스테일 카운트. 항목 삭제가 아니라 라벨 정정.
- 기존 §4(C-3·C-4·C-6)·§5(완료 10건)는 미변경(존재 보존). 신규 자산/임포트 추가 없으므로 orphan 0건.
**유실 결과: PASS** — 부당 삭제/잔재 없음.
---
## 5. 비차단 발견 (Non-blocking Findings)
**N-1 (A-2 카운트 스테일, 비본질).** A-2 현상 및 §6.2 P0-1 근거에 "실측 26/26 잡이 `auth_token=None`"로 기재됐으나, 현재 `.mam/jobs/*.json` 30건 전수 측정 시 `auth_token=None: 30/30`이다. 본 리뷰 잡(f4f441fb)·선행 잡(0d9712c6) 등 4건이 측정 후 추가된 것이다. 정성 주장("발급 0건 → 검증 공허")은 30/30=100%로 정확히 유지되므로 결론에 영향 없음. 구현 시점 재측정 권고. 비차단.
**N-2 (§6.4 처방 코드 미검증, 설계 범위).** B-7 처방의 `git diff --no-index --binary /dev/null "$f"` 루프와 크기 상한 로직은 저장소에 반영되지 않은 설계안이므로 본 리뷰에서 실행 검증 불가. 논리(`git add -N` 인덱스 오염 회피, `--exclude-standard` 존중)는 정합. M0 구현 시 샌드박스 측정이 필요하다는 문서 자체 권고와 일치. 비차단.
**N-3 (A-4/O-4 명명 혼선, 선행 커밋).** 선행 커밋 `29f0be5` 메시지는 "record **O-4** ..."이나 문서 본문은 **A-4**를 사용. 본 diff가 도입한 것이 아니며, 오히려 §3 카운트를 정정해 오케스트레이션 항목을 1건(O-2)으로 명확히 했다. 문서 소유자 후속 명명 통일 권고. 비차단.
---
## 6. 종합 판정
변경분은 `IMPROVEMENTS.md` 단일 문서에 대한 (1) 4개 스테일 항목의 실측 정정 + (2) 12건 전수를 아우르는 우선순위 실행 로드맵 신설이다. 코드·배포·테스트 변경이 전무해 런타임·린트·회귀 영향은 0이다. 로드맵은 브리프가 요구한 4 평가축을 반영하고, 정렬 원칙(외부 트리거 위험 → 거짓 검증 신호 → 구조 작업 → 국소 결함 → 정리, 조용한 실패 가중)에 12건을 빈틈없이 배치했으며, 파일-소유권 기반 병렬 슬롯과 Rev.1 정정 4건까지 명시해 실행 가능성이 높다. 변경된 서술 17개 항목을 코드베이스와 교차 검증한 결과 16개 완전 정합·1개 카운트 스테일(정성은 정확)이며 거짓/과장은 없었다. 부당 삭제나 잔재도 없다. 설계 재작업 수준의 재계획이 필요한 근거(escalation)는 발견되지 않는다 — 이 변경은 "우선순위 로드맵 등재"라는 명시적 산출물 목표를 충족한다.
[VERDICT: PASS]
+120 -13
View File
@@ -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건)을 위 우선순위에 따라 일원화된 보완 로드맵으로 관리합니다.