release(v4.12.0): update skill with in-place install and an update admission gate; resume starts the monitor (Issue #72) - archive the review reports, bump the lockstep version
The update skill joins the version matrix and the lockstep test's skill list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
1 parent
ec7f5c4e57
commit
56e6713292
26 files changed
+542
-30
No files matched your search
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"loop_id": "loop-20261027T201245Z-63c71b",
|
||||
"base_sha": "1d63e882bc1c46e9af8484647d5091b296d8fa3f",
|
||||
"head_sha": "ec7f5c4e57286fb3c4238b8220f39094f4640391",
|
||||
"tree_sha": "fbadb24de60ccdae684b23e2e0a41cdf23ab81eb",
|
||||
"review_commit": "ec7f5c4e57286fb3c4238b8220f39094f4640391",
|
||||
"reviewer": "planner-reviewer-claude-01",
|
||||
"job_id": "1d2c21dc",
|
||||
"verdict": "PASS",
|
||||
"transport": "herdr",
|
||||
"evidence": "review-tree",
|
||||
"isolation": "worktree",
|
||||
"verified_at": "2026-10-27T21:06:27Z"
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
# PR #75 후속 라운드 리뷰 — 1d63e88..ec7f5c4 (review round 5)
|
||||
|
||||
리뷰어: planner-reviewer-claude-01 (claude) · job 1d2c21dc
|
||||
|
||||
## 0. 리뷰 경로 확인
|
||||
|
||||
- 검증 경로: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261027T201245Z-63c71b/1`
|
||||
- HEAD `ec7f5c4e57286fb3c4238b8220f39094f4640391`, tree `fbadb24de60ccdae684b23e2e0a41cdf23ab81eb` 로 [리뷰 identity] 와 같다.
|
||||
- `git status --porcelain --ignored` 는 비어 있다. `.mam` 은 없다.
|
||||
- 리뷰 전후로 확인했다. 본 체크아웃 main 은 `0e1e2e8` 그대로다.
|
||||
- 범위: 1d63e88..HEAD 의 커밋 `ec7f5c4` 하나다.
|
||||
- 바뀐 파일: `.agents/skills/lib.sh`(+7/−1), `tests/test_issue72_update.py`(+32/−3)
|
||||
- 브리프가 정한 범위(R2 와 테스트의 `pkill` 제거) 밖은 건드리지 않았다.
|
||||
|
||||
## 1. R2 — legacy `start_watchdog` 의 프로세스 그룹 분리
|
||||
|
||||
### 1.1 코드 (`lib.sh:2297-2310`)
|
||||
|
||||
- 모니터를 띄우는 `nohup bash … &` 직전에 `set -m` 을 켠다.
|
||||
- 켜기 전에 호출자의 `$-` 에 `m` 이 있었는지 `had_m` 에 기억한다.
|
||||
- `pid=$!` 를 읽은 뒤, 원래 꺼져 있었으면 `set +m` 으로 되돌린다.
|
||||
- job control 이 켜진 상태에서 띄운 백그라운드 잡은 자기 프로세스 그룹의 리더가 된다(PGID = PID). 그래서 다음 효과가 있다.
|
||||
- `$!` 는 그대로 그 PID 다. nohup 과 bash 가 exec 해도 PID 는 바뀌지 않는다.
|
||||
- 따라서 정확한 PID 보고(`echo "$pid"`, `:2314-2316`)와 `mam_monitor_started` 확인이 바뀌지 않는다.
|
||||
- 다음 기존 동작은 바뀌지 않았다.
|
||||
- 중복 방지(`_monitor_pids`, `:2291`)
|
||||
- `MAM_NO_SUBSCRIBER_DAEMON=1` 분기(`:2295-2296`)
|
||||
- stdin `/dev/null`, 로그 append(`>> "$log_file"`), 작업 공간 cwd, `--idle-timeout 0`
|
||||
- 바뀐 것은 분기 안의 세 줄뿐이다.
|
||||
- 호출하는 곳은 모두 `$(…)` 안이다. 그래서 `set -m` 은 그 서브셸 안에서만 잠깐 켜진다.
|
||||
- `update.sh:106`, `post_update.sh:41`, `install_phase.sh:64`
|
||||
- `create_session.sh:748`, `resume_session.sh:162`
|
||||
|
||||
### 1.2 이 Mac 에서 직접 확인 (`/bin/bash` 3.2, tty 없음, `set -euo pipefail`)
|
||||
|
||||
- 같은 모양의 함수를 스크래치 스크립트로 만들어 돌렸다.
|
||||
- 결과 1: `$(f)` 안에서 띄운 자식의 PGID 는 자기 PID 와 같다(53727 = 53727). 호출자의 PGID(53714)와 다르다.
|
||||
- 결과 2: 직접 호출한 경우도 마찬가지다.
|
||||
- 결과 3: 호출 뒤 `$-` 는 `ehuB` 로 그대로다. 곧 `m` 이 남지 않는다.
|
||||
- 결과 4: "no job control", "[1] PID", "Done" 같은 잡 메시지가 stdout 에도 stderr 에도 나오지 않았다. 그래서 `$(…)` 로 받는 PID 출력이 오염되지 않는다.
|
||||
- **고치기 전 코드에서 실패하는지도 확인했다.**
|
||||
- 방법: `git archive HEAD` 로 TMPDIR 에 사본을 풀었다. 그 사본의 `lib.sh` 만 1d63e88 판으로 바꿨다.
|
||||
- 그 사본에서 `-k test_every_restart` 를 실행했다.
|
||||
- 결과: **mode=0 의 3개(installed, killed, rolled-back)가 `left in the caller's group` 로 실패했다. mode=1 의 3개는 통과했다(3 failed, 3 passed).**
|
||||
- 즉 새 assertion(`tests/test_issue72_update.py:723-724`)이 R2 를 실제로 잡는다. 수정 뒤 6개가 모두 통과한다(§3).
|
||||
- 사본은 확인 뒤 지웠고, 남은 프로세스도 없다.
|
||||
- 세 경로와 두 모드: 정상 설치, 정지 시간 초과 뒤 복원, rollback 뒤 복원을 mode 0·1 로 돌리는 6 조합이 모두 같은 함수를 지나고, 모두 통과한다.
|
||||
- rollback 경로는 되돌린 트리의 `lib.sh` 를 쓴다. 테스트 상자에서는 그 트리가 이 버전이다.
|
||||
|
||||
### 1.3 python 경로와의 차이 (비차단, 참고)
|
||||
|
||||
- 두 경로가 분리하는 정도가 다르다.
|
||||
- python 경로(`daemon.py:95`): `start_new_session=True` 로 새 **세션**을 만든다. 그래서 제어 터미널에서도 떨어진다.
|
||||
- legacy 경로: 새 **프로세스 그룹**만 만든다. 세션과 제어 터미널은 호출자와 같다.
|
||||
- 결정 2 의 요구("부른 쪽 프로세스 그룹에서 분리")는 이것으로 충족된다.
|
||||
- 프로세스 그룹 신호(테스트 러너·timeout 래퍼의 killpg, 터미널의 SIGINT)는 이제 모니터에 닿지 않는다. 터미널 신호는 전경 그룹에만 가는데, 모니터는 배경 그룹이다.
|
||||
- 터미널이 닫힐 때의 SIGHUP 은 nohup 이 무시한다.
|
||||
- 배경 그룹이 tty 에 읽고 쓸 때 생기는 SIGTTIN/SIGTTOU 도 없다. stdin 은 `/dev/null` 이고 출력은 로그 파일로 간다.
|
||||
- `lib.sh:246-253`(shim 서버 기동)은 같은 문제에 `start_new_session=True` 를 쓰는 관례를 적어 두었다. legacy 경로만 `set -m` 을 쓴다.
|
||||
- 브리프가 "가장 작은 수정" 을 요구했고, legacy 경로는 opt-in 이므로 결함으로 보지 않는다.
|
||||
|
||||
## 2. 테스트의 `pkill` 제거 (`tests/test_issue72_update.py:184-194`, `:218-240`)
|
||||
|
||||
### 2.1 새 teardown 이 정리하는 것
|
||||
|
||||
- 패턴 kill 이 없어졌다. `tests/test_issue72_*.py` 전체에 `pkill`·`killall` 이 남아 있지 않다(grep 으로 확인).
|
||||
- 대신 다음 순서로 정리한다.
|
||||
1. 테스트가 `Box.helper`(`:132-135`, `start_new_session=True`)로 띄우고 `b.helpers` 에 기록한 프로세스의 그룹을 `killpg` 하고 `wait` 한다.
|
||||
2. 이 테스트의 작업 공간 `ws` 에 대해 `bash <ws>/…/reconcile.sh --subscribe` 형태로 정확히 맞는 모니터(`_exact_monitor_pids`)와 그 자손(`_descendants`, `pgrep -P` 재귀)만 SIGKILL 한다.
|
||||
- 남은 프로세스 확인: 명령줄에 `ws` 가 들어 있는 살아 있는 프로세스가 10초 안에 없어지지 않으면 이름을 적어 실패한다(`_processes_naming`, `:236-240`).
|
||||
- `ws` 는 basetemp 아래의 테스트별 경로다. 그래서 다른 작업 공간의 프로세스와 겹치지 않는다.
|
||||
|
||||
### 2.2 남은 프로세스 확인이 약해지지 않았는지
|
||||
|
||||
- 예전 `pkill -KILL -f <ws>` 는 `ws` 를 명령줄에 가진 것을 **조용히 죽였을** 뿐이다. 남은 프로세스를 확인하지는 않았다.
|
||||
- 새 방식은 정확히 고른 것만 죽인다. 나머지 가운데 `ws` 를 가진 프로세스가 남으면 **실패로 드러낸다**.
|
||||
- 그래서 확인은 더 강해졌다.
|
||||
- 대가가 하나 있다. 그런 프로세스가 생기면 정리되지 않고 남는다. 다만 이름이 실패 메시지에 나오므로 사람이 정리할 수 있다.
|
||||
- `ws` 를 명령줄에 갖지 않은 손자(예: stub 모니터의 `sleep 120`)는 두 방식 모두 패턴으로는 못 찾는다.
|
||||
- 새 방식은 모니터의 자손으로 찾아서 정리한다. 따라서 이 부분도 약해지지 않았다.
|
||||
- 이번 실행에서 teardown 실패는 없었다. 실행 뒤 `ps` 로 봐도 테스트가 남긴 프로세스가 없다(§3).
|
||||
|
||||
## 3. 실행한 테스트 (이 Mac: macOS, `/bin/bash` 3.2, `/usr/bin/python3` 3.9.6)
|
||||
|
||||
```
|
||||
cd <검증 경로>
|
||||
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID -u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME \
|
||||
-u HERDR_SESSION -u WORKSPACE_ROOT -u MAM_ENV_FILE -u MAM_JOBS_DIR -u DELEGATE_JOB_LOGS_DIR \
|
||||
PYTHONDONTWRITEBYTECODE=1 /Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python \
|
||||
-m pytest -p no:cacheprovider --basetemp="$TMPDIR/claude-j1d2c-bt" -q -rfs \
|
||||
tests/test_issue72_update.py tests/test_issue19_subscriber_daemon_lifecycle.py \
|
||||
tests/test_issue5_phase1_delegation.py
|
||||
```
|
||||
|
||||
- 결과: **132 passed, 0 failed, 0 skipped** (191 s)
|
||||
- `test_every_restart_starts_a_real_monitor_in_both_delegation_modes` 의 6 조합이 이 안에 들어 있다.
|
||||
- `test_issue19`·`test_issue5_phase1` 의 watchdog 시험(중복 방지, `MAM_NO_SUBSCRIBER_DAEMON`, PID 보고, legacy·python 동등성)이 모두 통과한다.
|
||||
- 고치기 전 대조 실행: TMPDIR 사본, `-k test_every_restart` → 3 failed(mode=0), 3 passed(mode=1). 자세한 것은 §1.2.
|
||||
- 테스트 뒤 남은 프로세스: 테스트가 띄운 `reconcile.sh`, stub monitor, mock herdr, 구독자는 없다. 남은 것은 원래 있던 셋이다.
|
||||
- 본 체크아웃 모니터 3714
|
||||
- 이번 루프 7552
|
||||
- 이번 잡을 디스패치할 때 띄운 job_subscriber 53086
|
||||
|
||||
## 4. 발견 사항
|
||||
|
||||
### 차단
|
||||
|
||||
- 없음.
|
||||
|
||||
### 비차단
|
||||
|
||||
- **N8 (이월, R2 에도 해당).** rollback 뒤 재기동은 결정 2 에 따라 **되돌린 옛 트리의** `start_watchdog` 을 쓴다.
|
||||
- 그래서 실제로 이 PR 이전 버전으로 되돌리면, `MAM_DELEGATION_PY=0` 에서는 옛 `nohup … &` 그대로라 호출자 그룹에 남는다.
|
||||
- 이 PR 이후 버전 사이의 rollback 에서는 해결된다.
|
||||
- 결정 2 가 정한 방식("되돌린 트리의 함수")에서 생기는 한계라 결함으로 보지 않는다.
|
||||
- **1.3 의 세션 차이.** legacy 경로는 프로세스 그룹만 분리하고, python 경로는 세션까지 분리한다. 결정 요구는 충족한다.
|
||||
- N5·N6·N1·N3·N4 는 이번 범위 밖이라 그대로다.
|
||||
|
||||
## 5. 사용자 확인 필요
|
||||
|
||||
- N8: rollback 대상이 이 PR 이전 버전이고 `MAM_DELEGATION_PY=0` 인 경우를 받아들일지.
|
||||
- 받아들이지 않는다면 결정 2 의 "되돌린 트리의 start_watchdog" 대신 `install_phase.sh` 복사본 쪽에서 분리해 띄우도록 결정을 바꿔야 한다.
|
||||
- 이전 라운드에서 넘어온 N2, 그리고 결정 8 문구 보강 건은 그대로다.
|
||||
|
||||
## 6. 결론
|
||||
|
||||
- R2 는 정상 설치, 시간 초과 복원, rollback 복원의 세 경로와 두 모드 모두에서 해결됐다.
|
||||
- 고치기 전 코드에서 mode=0 이 실패하고, 고친 뒤 6개가 모두 통과하는 것을 이 Mac 에서 확인했다.
|
||||
- 분리 방식(`set -m`)은 중복 방지, opt-out, PID 보고, 로그를 바꾸지 않는다. bash 3.2 에서 잡 메시지 없이 동작한다.
|
||||
- 테스트의 패턴 kill 은 기록한 PID 와 정확히 맞는 모니터·자손 정리로 바뀌었다. 남은 프로세스 확인은 오히려 강해졌다.
|
||||
|
||||
[VERDICT: PASS]
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"loop_id": "loop-20261027T201245Z-63c71b",
|
||||
"base_sha": "1d63e882bc1c46e9af8484647d5091b296d8fa3f",
|
||||
"head_sha": "ec7f5c4e57286fb3c4238b8220f39094f4640391",
|
||||
"tree_sha": "fbadb24de60ccdae684b23e2e0a41cdf23ab81eb",
|
||||
"review_commit": "ec7f5c4e57286fb3c4238b8220f39094f4640391",
|
||||
"reviewer": "planner-reviewer-codex-01",
|
||||
"job_id": "028e98cb",
|
||||
"verdict": "PASS",
|
||||
"transport": "herdr",
|
||||
"evidence": "review-tree",
|
||||
"isolation": "worktree",
|
||||
"verified_at": "2026-10-27T21:06:27Z"
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
# PR #75 후속 리뷰 — job 028e98cb
|
||||
|
||||
## 판정과 검증 대상
|
||||
|
||||
이번 범위의 차단 사항을 발견하지 않았다. R2의 PGID 분리와 테스트 teardown 수정이 요구 사항을 충족한다.
|
||||
|
||||
- base: 1d63e882bc1c46e9af8484647d5091b296d8fa3f
|
||||
- head: ec7f5c4e57286fb3c4238b8220f39094f4640391
|
||||
- tree: fbadb24de60ccdae684b23e2e0a41cdf23ab81eb
|
||||
- 검증 경로: /var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261027T201245Z-63c71b/1
|
||||
- HEAD/tree 일치, clean status, `git diff --check 1d63e88..HEAD` 통과. 실제 diff는 lib.sh와 test_issue72_update.py 두 파일이다.
|
||||
- 새 브리프의 좁혀진 범위인 1d63e88..HEAD를 검토했다. 이전 비차단 권고에 해당하는 파일/기능을 추가 변경하지 않았음을 확인했다.
|
||||
- `tea issues 72 --comments`, `tea pulls 75`를 다시 읽었다. 기준 이슈 내용은 앞선 검토와 같고, 이번 수정은 결정 2 및 기존 중복 방지/opt-out/PID/로그 계약과 정합적이다.
|
||||
|
||||
## 확인한 것
|
||||
|
||||
| 항목 | 파일:줄 근거 | 확인 결과 |
|
||||
|---|---|---|
|
||||
| R2: 호출자 PGID에서 분리 | `.agents/skills/lib.sh:2303–2309` | 기존 monitor 옵션을 기록하고 spawn 때만 `set -m` 사용. 비동기 monitor가 별도 PGID에서 뜨며, 기존 옵션은 복원된다. macOS에 없는 setsid(1) 없이 동작. |
|
||||
| 기존 기동 계약 | `lib.sh:2289–2315` | 정확한 PID 검색과 중복 방지, opt-out 분기는 유지. cwd를 작업 공간으로 두고 원래 cwd로 복원, stdin /dev/null, 로그 append, --idle-timeout 0, nohup의 SIGHUP 처리와 PID stdout 계약 유지. |
|
||||
| 0/1 × 세 복원 경로 회귀 | `tests/test_issue72_update.py:699–725`, 특히 `:724` | 정상 설치·정지 timeout·rollback의 두 모드 모두 실제 새 monitor와 PGID 분리를 검증한다. decoy 미신호 및 기동 횟수 검증도 유지. 여섯 조합 모두 통과. |
|
||||
| pkill 제거·소유 프로세스 정리 | `test_issue72_update.py:184–193,220–240` | 기록된 helper 그룹을 정리하고 wait한다. monitor는 이 테스트의 정확한 절대 스크립트 명령행으로 고른 뒤, 미리 수집한 자손 PID와 함께 정리한다. 전역 패턴 kill은 없다. |
|
||||
| 잔여 프로세스 검출 유지 | `test_issue72_update.py:237–240` | ws를 명령행에 남긴 프로세스가 있으면 최대 10초 기다린 뒤 실패한다. 이 문자열 검색은 보고/검증용이며 kill 대상으로 사용되지 않는다. 원본 테스트를 외부 정리 플러그인 없이 실행해 통과. |
|
||||
|
||||
## R2의 전후 재현 결과
|
||||
|
||||
base 1d63e88의 부정 대조는 직전 d14ae099 리뷰에서 실제로 실행한 동일 외부 탐침 로그를 사용했다. 당시 mode=0의 정상·timeout·rollback 세 경우는 PGID가 호출자와 같아 실패했고, mode=1의 세 대조군은 통과했다. 이번에도 같은 탐침 코드를 변경 없이 지정된 새 snapshot에서 실행했다.
|
||||
|
||||
| 경로 | mode=0의 새 monitor PGID / caller PGID | mode=1의 새 monitor PGID / caller PGID |
|
||||
|---|---|---|
|
||||
| 정상 설치 | 93359 / 88049 — 분리 | 96481 / 88049 — 분리 |
|
||||
| 정지 timeout 복원 | 91992 / 88631 — 분리 | 94916 / 88631 — 분리 |
|
||||
| rollback 복원 | 93376 / 88631 — 분리 | 96166 / 88631 — 분리 |
|
||||
|
||||
- 기존 `probe_monitor_group.py`: **2 passed / 11.95s** (base에서는 1 failed, 1 passed).
|
||||
- 기존 `probe_monitor_restore_group.py`: **4 passed / 10.40s** (base에서는 2 failed, 2 passed).
|
||||
- 별도 직접 호출 탐침으로 monitor 옵션 초기 off→off 및 on→on, cwd 복원을 확인: **2 passed / 3.24s**. 새 monitor의 PGID 분리도 확인했다.
|
||||
- PGID 검증은 조회로 했으며 호출자의 프로세스 그룹에 신호를 보내지 않았다.
|
||||
|
||||
base 로그와 동일 탐침 코드, 이번 새 결과를 evidence/에 보존했다. base를 이번 허용 경로 밖에서 다시 실행한 것은 아니다.
|
||||
|
||||
## Mac에서 실행한 테스트
|
||||
|
||||
/bin/bash 3.2.57, Python 3.9.6에서 실행했다. 스냅샷에 .venv가 없어 브리프 앞부분에 명시된 제어 루트 .venv/bin/python을 사용했다.
|
||||
|
||||
작업 디렉터리는 위 snapshot이며, 주요 실행 명령은 다음과 같다.
|
||||
|
||||
```bash
|
||||
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID \
|
||||
-u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME -u HERDR_SESSION \
|
||||
-u WORKSPACE_ROOT -u MAM_ENV_FILE -u MAM_JOBS_DIR \
|
||||
-u DELEGATE_JOB_LOGS_DIR -u AGENT_SESSIONS_YAML \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python \
|
||||
-m pytest -p no:cacheprovider \
|
||||
--basetemp=/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review-028e98cb-pytest -ra \
|
||||
tests/test_issue72_update.py \
|
||||
tests/test_issue5_phase1_delegation.py::test_c07_watchdog_spawns_daemon_with_workdir_and_log \
|
||||
tests/test_issue5_phase1_delegation.py::test_c08_watchdog_second_call_reuses_running_daemon \
|
||||
tests/test_issue5_phase1_delegation.py::test_c09_start_watchdog_and_ensure_subscriber_daemon_agree \
|
||||
tests/test_issue5_phase1_delegation.py::test_daemon_missing_monitor_raises_with_the_legacy_path \
|
||||
tests/test_issue5_phase1_delegation.py::test_daemon_spawn_dedup_and_survives_parent_exit \
|
||||
tests/test_issue19_subscriber_daemon_lifecycle.py::test_opt_out_still_reports_a_daemon_that_already_runs
|
||||
```
|
||||
|
||||
**59 passed / 133.12s / exit 0**. update 파일 50건, phase1 watchdog 8건, 기존 daemon의 opt-out 보고 1건이다.
|
||||
|
||||
같은 환경 제거·Python·no-cache 설정으로 실행한 추가 검증:
|
||||
|
||||
| 선택 | 결과 |
|
||||
|---|---|
|
||||
| `test_issue19_subscriber_daemon_lifecycle.py::test_sandbox_default_never_spawns_a_daemon` (0/1) | 2 passed / 0.53s |
|
||||
| `-p probe_monitor_group ... tests/test_issue72_update.py` | 2 passed / 11.95s |
|
||||
| `-p probe_monitor_restore_group ... tests/test_issue72_update.py` | 4 passed / 10.40s |
|
||||
| `-p probe_monitor_options ... tests/test_issue72_update.py` | 2 passed / 3.24s |
|
||||
|
||||
외부 탐침은 기존 Module의 Box fixture를 사용하고 항목만 외부 plugin으로 선택했다. source는 변경하지 않았다. 각 basetemp는 TMPDIR 아래 서로 다른 mam-review-028e98cb-{pytest,group,restore-group,options,optout}이었다. 이번에는 safe_cleanup 등의 외부 teardown 대체 없이 수정된 원본 cleanup을 실행했다.
|
||||
|
||||
- `/bin/bash -n .agents/skills/lib.sh`: 통과.
|
||||
- `ast.parse(test_issue72_update.py, feature_version=(3,9))`: 통과.
|
||||
- diff --check: 통과.
|
||||
- ShellCheck는 PATH에 없어 실행하지 못했다. bash -n을 ShellCheck 통과로 표기하지 않는다.
|
||||
- 이번 새 브리프가 정한 수정 파일·watchdog 범위로 실행했고 전체 스위트는 실행하지 않았다.
|
||||
|
||||
## 발견 사항 및 사용자 확인
|
||||
|
||||
차단/비차단 신규 지적 없음. R2와 pkill 제거 요구 모두 해결됐다. 새 정책 결정이나 재계획이 필요하지 않다.
|
||||
|
||||
## 자원 안전
|
||||
|
||||
- 검증은 지정된 snapshot에서만 했고 creator 작업 트리에서 실행·수정하지 않았다. installer/update는 TMPDIR 가짜 설치 및 로컬 source/file:// installer만 사용했다.
|
||||
- 실제 herdr 서버·설정·에이전트 홈 DB를 조작하지 않았고, 실제 .mam.env 값을 테스트에 출력하거나 export하지 않았다. 이슈/PR 댓글·상태 변경, push/merge 없음.
|
||||
- 다섯 basetemp의 종료 후 프로세스 점검 결과 `remaining_test_processes=[]`.
|
||||
- 원래 제어 루트 monitor PID 3714는 실행 전후 같은 명령으로 살아 있었으며 신호를 보내지 않았다.
|
||||
- 종료 시 HEAD/tree와 clean status가 그대로이며 diff --check도 다시 통과했다.
|
||||
- 승인된 잡 이벤트·리포트 외에 실제 control-plane 상태를 수정하지 않았다. 원본 로그와 외부 탐침 코드는 이 리포트 옆 evidence/에 보존했다.
|
||||
|
||||
[VERDICT: PASS]
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"loop_id": "loop-20261027T201245Z-63c71b",
|
||||
"base_sha": "1d63e882bc1c46e9af8484647d5091b296d8fa3f",
|
||||
"head_sha": "ec7f5c4e57286fb3c4238b8220f39094f4640391",
|
||||
"tree_sha": "fbadb24de60ccdae684b23e2e0a41cdf23ab81eb",
|
||||
"review_commit": "ec7f5c4e57286fb3c4238b8220f39094f4640391",
|
||||
"reviewer": "reviewer-agy-01",
|
||||
"job_id": "a967e100",
|
||||
"verdict": "PASS",
|
||||
"transport": "herdr",
|
||||
"evidence": "review-tree",
|
||||
"isolation": "worktree",
|
||||
"verified_at": "2026-10-27T21:06:27Z"
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
# Code Review Report — PR #75 Follow-up Round (`1d63e88..ec7f5c4`, Issue #72)
|
||||
|
||||
- **Job ID**: `a967e100`
|
||||
- **Reviewer**: `agy` (`herdr:reviewer-agy-01`)
|
||||
- **Loop ID**: `loop-20261027T201245Z-63c71b` (Round 1)
|
||||
- **Review Snapshot Path**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261027T201245Z-63c71b/1`
|
||||
- **Branch**: `fix/issue-72`
|
||||
- **Base Commit**: `1d63e882bc1c46e9af8484647d5091b296d8fa3f` (cumulative base: `0e1e2e87dea7fcaab69d6ac388121c35b02b7dab`)
|
||||
- **Head Commit**: `ec7f5c4e57286fb3c4238b8220f39094f4640391`
|
||||
- **Tree Hash**: `fbadb24de60ccdae684b23e2e0a41cdf23ab81eb`
|
||||
|
||||
---
|
||||
|
||||
## 1. 확인한 것 (Files & Line Ranges Inspected in Review Snapshot)
|
||||
|
||||
- **`1d63e88..ec7f5c4` 변경분 집중 검증**:
|
||||
- `.agents/skills/lib.sh:2278-2317` (`_start_watchdog_legacy`):
|
||||
- `MAM_DELEGATION_PY=0` 경로에서 `case $- in *m*) had_m=1 ;; esac`, `set -m`으로 `nohup bash "$monitor_script" --subscribe --idle-timeout 0 </dev/null >> "$log_file" 2>&1 &`를 실행한 뒤 `[ "$had_m" = 1 ] || set +m`으로 호출자의 job-control 옵션을 복원(`lib.sh:2303-2309`).
|
||||
- macOS(`/bin/bash` 3.2, `setsid(1)` 없음)에서도 `set -m` 아래 백그라운드 작업이 자체 프로세스 그룹(`pgid == pid`)으로 기동되어 호출자의 프로세스 그룹에서 분리됨을 확인.
|
||||
- 기존 동작(`_monitor_pids` 중복 방지, `MAM_NO_SUBSCRIBER_DAEMON=1` opt-out, `echo "$pid"` 보고, `</dev/null`, `>> "$log_file" 2>&1`)이 그대로 보존됨을 확인.
|
||||
- `tests/test_issue72_update.py:184-195, 221-241, 697-726`:
|
||||
- `_descendants(pid)`(`184-186`) 및 읽기 전용 `_processes_naming(path)`(`189-193`) 추가.
|
||||
- `box` fixture teardown(`221-241`)에서 패턴 기반 `pkill -KILL -f <ws>`를 완전히 제거하고, 테스트가 직접 띄운 `b.helpers` 프로세스 그룹(`os.killpg`)과 `_exact_monitor_pids(ws / MONITOR_REL)` + 그 자식(`_descendants(pid)`)만 `SIGKILL`로 정리한 뒤 `_until(lambda: not _processes_naming(ws), timeout=10)`으로 잔존 프로세스가 없음을 검증.
|
||||
- `test_every_restart_starts_a_real_monitor_in_both_delegation_modes`(`697-726`): 6개 조합(`mode` `0`/`1` × `installed`/`killed`/`rolled-back`) 모두에서 `assert all(os.getpgid(int(p)) != os.getpgrp() for p in box.monitor_pids())`로 모니터의 PGID가 호출자의 PGID와 다름을 검증.
|
||||
- **누적 변경분(`0e1e2e8..ec7f5c4`) 정합성 확인**:
|
||||
- `.agents/skills/lib.sh:24-35, 2238-2317, 3299-3379`
|
||||
- `.agents/skills/lib_py/delegation/daemon.py:40-79`
|
||||
- `.agents/skills/lib_py/pane_lock.py:1-130`
|
||||
- `.agents/skills/lib_py/update.py:1-428`
|
||||
- `.agents/skills/multi-agent-mux-update/SKILL.md:1-30`
|
||||
- `.agents/skills/multi-agent-mux-update/scripts/{update.sh,install_phase.sh,post_update.sh}`
|
||||
- `.agents/skills/multi-agent-mux-{create,resume,stop,loop,orc-onboard,delegate-job}` 및 `deploy/{install.sh,install_mam.sh,remove.sh}`
|
||||
|
||||
---
|
||||
|
||||
## 2. 결정 1–10, U1–U4, Attach 댓글 및 완료 조건 대조표
|
||||
|
||||
| 항목 | 요구사항 요약 | 구현 위치 | 테스트 커버리지 | 상태 |
|
||||
|---|---|---|---|---|
|
||||
| 결정 1 | 활성 세션(레지스트리 `running` + 모든 실행 중 herdr 서버의 워크스페이스 내 라이브 에이전트)·루프·열린 잡(`pending`/`dispatched`/`running`, 타 제어 평면은 본 레지스트리 대상 잡만) 있으면 거부 및 해제 명령 안내 | `lib_py/update.py:150-267`, `update.sh:124-162` | `tests/test_issue72_update.py` (`test_every_refusal_condition_blocks_and_leaves_the_workspace_untouched` 외 9개) | 충족 |
|
||||
| 결정 2 | 모니터 데몬(`reconcile.sh --subscribe`) 자동 정지(`SIGTERM`→`SIGKILL`)·설치/타임아웃/롤백 후 호출자 프로세스 그룹에서 분리하여 재기동(`MAM_DELEGATION_PY=0/1` 모두 정확 매칭 및 별도 PGID); `resume` 시 모니터 보장 | `update.sh:100-116,165-212`, `post_update.sh:37-46`, `install_phase.sh:57-69`, `resume_session.sh:215-225,250,299`, `daemon.py:40-79`, `lib.sh:2238-2317` | `tests/test_issue72_update.py` (`test_every_restart_starts_a_real_monitor_in_both_delegation_modes` 외), `tests/test_issue72_resume_monitor.py` | 충족 |
|
||||
| 결정 3 | 설치 실패 시 `.agents`, `.mam_deploy`, 루트 문서, `.venv`, 설치기 관리 `.mam` 항목, 레지스트리 전체 되돌리기 | `update.sh:240-262`, `install_phase.sh:27-44,104-115` | `tests/test_issue72_update.py` (`test_a_failing_install_rolls_back_the_entire_workspace_and_restarts_the_monitor` 외) | 충족 |
|
||||
| 결정 4 | 업데이트 완료 후 새 코드로 레지스트리 변환(`lib_py.registry_format`), 레지스트리 없으면 생략, 실패 시 설치 유지 + 0 아닌 종료 | `post_update.sh:27-35` | `tests/test_issue72_update.py` (`test_a_conversion_failure_keeps_the_new_install_and_exits_nonzero` 외) | 충족 |
|
||||
| 결정 5 | 2단계 분리: 워크스페이스 밖 임시 복사본(`install_phase.sh`)을 `exec`(같은 PID 유지)한 뒤 새 트리의 `post_update.sh`를 별도 프로세스로 실행 | `update.sh:214-215,264-267`, `install_phase.sh:118-129` | `tests/test_issue72_update.py` (`test_the_clean_update_runs_both_phases_converts_the_registry_and_restarts_the_monitor`) | 충족 |
|
||||
| 결정 6 | `deploy/update.sh` 제거, `multi-agent-mux-update` 스킬로 일원화, `deploy/install.sh` 제자리 재실행 정리(없어진 파일 삭제·수정 파일 보존, `install_state` 제자리 갱신) | `deploy/install.sh:191-196,403-448,632-653`, `deploy/update.sh`(삭제) | `tests/test_issue72_installer.py`, `tests/test_deploy_layout.py`, `tests/test_issue8_update_state.py` | 충족 |
|
||||
| 결정 7 | 호출 에이전트 자신(`(caller_server, HERDR_PANE_ID)`)과 그 `running` 행·실행 중인 잡 1개는 차단 대상에서 제외 | `lib_py/update.py:192-219,229-230,244-250`, `lib_py/pane_lock.py:25-39` | `tests/test_issue72_update.py` (`test_the_calling_agent_its_row_and_its_running_job_are_excluded` 외 3개) | 충족 |
|
||||
| 결정 8 | 업데이트 입장 잠금(`.mam/update-admission.lock` 공유/배타 + `.mam/update-in-progress` 표식): `create`·`resume`·`run_loop`·`delegate submit`·`stop`·`orc-onboard` 차단, 자식 프로세스 fd 누수 방지 | `lib.sh:3312-3379`, `lib_py/pane_lock.py:42-115`, `lib_py/update.py:277-322` | `tests/test_issue72_admission.py` (21개 케이스) | 충족 |
|
||||
| 결정 9 | `update.sh [-y|--yes]`: TTY면 프롬프트, 비-TTY에서 `-y` 없으면 거부(`exit 1`) | `update.sh:30-60` | `tests/test_issue72_update.py` (`test_confirmation_prompt_and_non_tty_refusal`) | 충족 |
|
||||
| 결정 10 | 되돌리기 범위에서 작업 기록(`jobs`, `delegate_job_logs`, `state`, `worktrees`, `locks`) 보존 및 레지스트리 백업(`sqlite3.backup` + YAML/bak) 복원 | `update.sh:241-256`, `lib_py/update.py:342-366`, `install_phase.sh:37-44` | `tests/test_issue72_update.py` (`test_rollback_restores_every_item_the_installer_can_touch_and_leaves_work_records`) | 충족 |
|
||||
| U1 | attach 안내 헬퍼는 추가하지 않고 기존 행의 `attach_command`(`ATTACH_CMD`)를 그대로 사용 | `create_session.sh:654`, `multi-agent-mux-delegate-job:680-687` | `tests/test_issue72_attach_hints.py` | 충족 |
|
||||
| U2 | `.mam` 없는 트리에서 입장 잠금 헬퍼가 `.mam`이나 잠금 파일을 만들지 않고 통과 | `lib.sh:3315` | `tests/test_issue72_admission.py` (`test_a_tree_without_mam_stays_clean`) | 충족 |
|
||||
| U3 | `MAM_UPDATE_MONITOR_STOP_S`를 `mam_int_knob`으로 읽고 `test_issue26_ints.py` 표에 등록 | `update.sh:189`, `tests/test_issue26_ints.py:67` | `tests/test_issue26_ints.py` | 충족 |
|
||||
| U4 | 이전 업데이트가 남긴 `.mam/update-backup/` 상태별 처리(`backing-up`/`installed`/빈 상태 삭제, `installing`은 `--skip-registry`로 파일만 복원, 알 수 없는 상태 거부) | `update.sh:218-237`, `install_phase.sh:36` | `tests/test_issue72_update.py` (`test_a_leftover_backup_from_a_killed_update_is_handled_by_state`) | 충족 |
|
||||
| 댓글 #926, #930 | `multi-agent-mux-delegate-job` 및 `create_session.sh`의 attach 안내가 `--session <server>`를 포함한 `attach_command`를 출력 | `create_session.sh:654`, `multi-agent-mux-delegate-job:680-687` | `tests/test_issue72_attach_hints.py` (8개 케이스) | 충족 |
|
||||
| 첫 전환 (완료 조건 5) | 옛 `update.sh`가 있는 설치본에서 첫 전환 시 새 `install.sh`를 거쳐 `multi-agent-mux-update` 스킬과 레지스트리 변환까지 도달 | `deploy/install.sh:191-196,403-405`, `tests/test_issue72_update.py:909-966` | `tests/test_issue72_update.py` (`test_the_first_transition_from_the_old_updater_reaches_the_skill_and_conversion`) | 충족 |
|
||||
|
||||
빠진 완료 조건: **없음**.
|
||||
|
||||
---
|
||||
|
||||
## 3. 실행한 테스트와 결과 (macOS 실측)
|
||||
|
||||
검증 경로(`/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261027T201245Z-63c71b/1`)에서 브리프의 격리 실행 명령으로 새·바뀐 테스트 파일과 watchdog 관련 테스트(`test_issue5_phase1_delegation.py`, `test_issue19_subscriber_daemon_lifecycle.py`)를 모두 실행했습니다.
|
||||
|
||||
### 명령 1 (`tests/test_issue72_update.py`, `tests/test_issue72_resume_monitor.py`, `tests/test_issue42_skill_blocks.py`)
|
||||
```bash
|
||||
BT="$(mktemp -d "${TMPDIR:-/tmp}/mam-rev-a967e100-1.XXXXXX")"
|
||||
trap 'rm -rf "$BT"' EXIT
|
||||
cd /var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261027T201245Z-63c71b/1 && \
|
||||
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID -u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME -u HERDR_SESSION -u WORKSPACE_ROOT -u MAM_ENV_FILE -u MAM_JOBS_DIR -u DELEGATE_JOB_LOGS_DIR \
|
||||
PYTHONDONTWRITEBYTECODE=1 /Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python -m pytest -p no:cacheprovider --basetemp="$BT/pytest" \
|
||||
tests/test_issue72_update.py \
|
||||
tests/test_issue72_resume_monitor.py \
|
||||
tests/test_issue42_skill_blocks.py
|
||||
```
|
||||
- **결과**: `95 passed, 1 skipped in 379.90s (0:06:19)` (exit code `0`)
|
||||
|
||||
### 명령 2 (watchdog 관련 스위트 2종 + 나머지 변경·신규 테스트 7종)
|
||||
```bash
|
||||
BT="$(mktemp -d "${TMPDIR:-/tmp}/mam-rev-a967e100-2.XXXXXX")"
|
||||
trap 'rm -rf "$BT"' EXIT
|
||||
cd /var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261027T201245Z-63c71b/1 && \
|
||||
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID -u HERDR_WORKSPACE_ID -u HERDR_SESSION_NAME -u HERDR_SESSION -u WORKSPACE_ROOT -u MAM_ENV_FILE -u MAM_JOBS_DIR -u DELEGATE_JOB_LOGS_DIR \
|
||||
PYTHONDONTWRITEBYTECODE=1 /Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python -m pytest -p no:cacheprovider --basetemp="$BT/pytest" \
|
||||
tests/test_issue5_phase1_delegation.py \
|
||||
tests/test_issue19_subscriber_daemon_lifecycle.py \
|
||||
tests/test_deploy_layout.py \
|
||||
tests/test_issue26_ints.py \
|
||||
tests/test_issue8_update_state.py \
|
||||
tests/test_version_consistency.py \
|
||||
tests/test_issue72_attach_hints.py \
|
||||
tests/test_issue72_installer.py \
|
||||
tests/test_issue72_admission.py
|
||||
```
|
||||
- **결과**: `219 passed in 509.96s (0:08:29)` (exit code `0`)
|
||||
|
||||
### 명령 3 (`/bin/bash -n` 구문 검사 및 프로세스·워크트리 무결성 확인)
|
||||
- 변경된 모든 셸 스크립트(13개) `/bin/bash -n` 통과 (`exit 0`).
|
||||
- `git status --short`: 출력 없음 (검증 스냅샷 깨끗함).
|
||||
- `ps -ef`: 본 체크아웃의 기존 `reconcile.sh --subscribe` 데몬(PID `3714`)만 정상 유지 중이며, 테스트가 남긴 자식·더미 프로세스 없음.
|
||||
|
||||
---
|
||||
|
||||
## 4. 발견 사항 (차단 / 비차단)
|
||||
|
||||
- **차단 (Blocking)**: 없음.
|
||||
- **비차단 (Non-Blocking)**: 없음.
|
||||
|
||||
---
|
||||
|
||||
## 5. 사용자 확인 필요
|
||||
|
||||
- 없음.
|
||||
|
||||
[VERDICT: PASS]
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"loop_id": "loop-20261027T201245Z-63c71b",
|
||||
"base_sha": "1d63e882bc1c46e9af8484647d5091b296d8fa3f",
|
||||
"head_sha": "ec7f5c4e57286fb3c4238b8220f39094f4640391",
|
||||
"tree_sha": "fbadb24de60ccdae684b23e2e0a41cdf23ab81eb",
|
||||
"review_commit": "ec7f5c4e57286fb3c4238b8220f39094f4640391",
|
||||
"reviewer": "reviewer-grok-01",
|
||||
"job_id": "a43bca93",
|
||||
"verdict": "PASS",
|
||||
"transport": "herdr",
|
||||
"evidence": "review-tree",
|
||||
"isolation": "worktree",
|
||||
"verified_at": "2026-10-27T21:06:27Z"
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
# PR #75 (Issue #72) 리뷰 — 라운드 5
|
||||
|
||||
검증 경로 `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261027T201245Z-63c71b/1` 만 봤다. HEAD `ec7f5c4e57286fb3c4238b8220f39094f4640391`, tree `fbadb24de60ccdae684b23e2e0a41cdf23ab81eb`, base `1d63e882bc1c46e9af8484647d5091b296d8fa3f` (HEAD 의 부모이자 조상), porcelain 0. 스냅샷에는 `.venv` 가 없다. 테스트 뒤에도 HEAD·tree·porcelain 은 같았다. 제어 평면의 입장 잠금과 업데이트 표식은 없었고, 체크아웃 모니터 pid 3714 (`reconcile.sh --subscribe --idle-timeout 0`) 는 그대로였다.
|
||||
|
||||
이번 커밋은 `ec7f5c4` 하나다. `1d63e88..ec7f5c4` 는 `lib.sh` 와 `tests/test_issue72_update.py` 이고 `git diff --check` 는 깨끗했다. diff 에 `mapfile`, `declare -A`, `local -n`, `[[ -v`, `sed -i`, `stat -c`, `readlink -f`, `date -d` 는 없다. `setsid(1)` 도 호출하지 않는다.
|
||||
|
||||
## 확인한 것
|
||||
|
||||
R2. `MAM_DELEGATION_PY=0` 의 기동도 호출자 프로세스 그룹 밖에 둔다.
|
||||
|
||||
- `lib.sh:2297-2310`. 이미 떠 있는 모니터가 없을 때만, 호출자가 이미 `-m` 이었는지 기억하고 `set -m` 으로 잡은 뒤 `nohup bash <reconcile.sh> --subscribe --idle-timeout 0` 을 백그라운드로 띄운다. stdin 은 `/dev/null`, 로그는 append, 그 다음 호출자의 `-m` 을 되돌린다. 중복 확인(`lib.sh:2291` `_monitor_pids`)과 `MAM_NO_SUBSCRIBER_DAEMON=1` (`lib.sh:2295-2296`) 은 그 앞에 그대로다. PID 출력은 `lib.sh:2314-2315` 이다.
|
||||
- 이 함수를 쓰는 재시작은 세 곳이다. 설치 성공은 `post_update.sh:41`, 정지 시간 초과는 `update.sh:106`, 롤백과 상태 기록 실패는 `install_phase.sh:64` 의 `bash -c` 가 복구된 트리의 `start_watchdog` 를 부른다. `lib.sh:2567-2573` 에서 `MAM_DELEGATION_PY=0` 이면 레거시, 아니면 Python `start_new_session` 이다.
|
||||
- tty 없이 `set -euo pipefail` 인 bash 3.2 에서 `set -m` 으로 띄운 `sleep` 의 PGID 는 그 PID 와 같고 부모 PGID 와 달랐다. 부모가 끝난 뒤에도 그 프로세스는 남아 있었고, 확인 뒤에 그 PID 만 종료했다.
|
||||
- `test_issue72_update.py:697-725`. `MAM_DELEGATION_PY` 0 과 1, 설치 성공·TERM 무시 후 KILL·롤백 여섯 조합에서 새 모니터의 PGID 가 이 테스트 프로세스 그룹과 다른지 본다. `box.update` 는 프로세스 그룹을 바꾸지 않으므로 그 그룹이 호출자 그룹이다.
|
||||
|
||||
정리. 테스트는 패턴으로 죽이지 않는다.
|
||||
|
||||
- `tests/test_issue72_update.py` 에 `pkill` 과 `killall` 은 없다.
|
||||
- `test_issue72_update.py:221-240`. 이 테스트가 `helper` 로 띄운 프로세스 그룹만 `os.killpg` 하고, 이 임시 작업공간의 `reconcile.sh --subscribe` 명령줄과 그 `pgrep -P` 자식만 `os.kill` 한다. 그 다음 10초 동안 그 작업공간 경로를 명령줄에 가진 프로세스가 남아 있으면 실패한다 (`_processes_naming`, `184-193`). 읽는 용도이고, 다른 작업공간의 모니터는 경로가 다르므로 대상이 아니다.
|
||||
|
||||
이전 라운드에서 맞던 중복 방지, opt-out, PID 보고, 로그 append 는 이 diff 가 그 순서를 바꾸지 않았다. Python 쪽 세션 분리는 `tests/test_issue5_phase1_delegation.py:697-699` 가 그대로 본다.
|
||||
|
||||
## 실행한 테스트
|
||||
|
||||
작업 디렉터리는 스냅샷이다. 인터프리터는 제어 평면 `/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python` (Python 3.9.6). `--basetemp=/tmp/mam-i72-a43bca93`.
|
||||
|
||||
```
|
||||
env -u HERDR_SOCKET_PATH -u HERDR_PANE_ID -u HERDR_TAB_ID -u HERDR_WORKSPACE_ID \
|
||||
-u HERDR_SESSION_NAME -u HERDR_SESSION -u WORKSPACE_ROOT -u MAM_ENV_FILE \
|
||||
-u MAM_JOBS_DIR -u DELEGATE_JOB_LOGS_DIR \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
/Users/godopu16/PuKi/laa/canary_projects/multi-agent-mux/.venv/bin/python -m pytest \
|
||||
-p no:cacheprovider --basetemp=/tmp/mam-i72-a43bca93 \
|
||||
tests/test_issue72_admission.py tests/test_issue72_attach_hints.py \
|
||||
tests/test_issue72_installer.py tests/test_issue72_resume_monitor.py \
|
||||
tests/test_issue72_update.py tests/test_issue8_update_state.py \
|
||||
tests/test_deploy_layout.py tests/test_issue42_skill_blocks.py \
|
||||
tests/test_issue26_ints.py tests/test_version_consistency.py \
|
||||
tests/test_issue5_phase1_delegation.py \
|
||||
tests/test_issue19_subscriber_daemon_lifecycle.py \
|
||||
-q --tb=line
|
||||
```
|
||||
|
||||
결과: **314 passed, 1 skipped**, 888.47s, 종료 코드 0. PGID 여섯 조합과 watchdog 수명 주기가 이 안에 들어 있다.
|
||||
|
||||
건너뛴 한 건은 `tests/test_issue42_skill_blocks.py:266` (`.claude/skills` 가 이 체크아웃에 없음). 같은 파일만 `--basetemp=/tmp/mam-i72-a43bca93-skip -rs` 로 다시 돌리면 39 passed, 1 skipped, 0.07s 이다.
|
||||
|
||||
basetemp 경로를 가진 프로세스는 종료 뒤에 남아 있지 않았다.
|
||||
|
||||
## 발견 사항
|
||||
|
||||
차단: 없음. 설계를 다시 잡아야 하는 결함도 없다.
|
||||
|
||||
비차단:
|
||||
|
||||
- 레거시 경로는 새 프로세스 그룹이다 (`set -m`). Python 경로는 `start_new_session` 으로 새 세션이다. 이번 라운드가 요구한 것은 호출자 프로세스 그룹에서 벗어나는 것이고, 둘 다 그렇게 한다. `nohup` 이 SIGHUP 을 무시하는 것은 그대로다.
|
||||
- `lib.sh:2310`. 모니터를 띄운 뒤 원래 디렉터리로 돌아가지 못하면 함수는 1 을 반환한다. 그 시점에는 이미 `set +m` 이 실행됐고 데몬은 떠 있다. 호출자는 PID 를 받지 못한다. 디렉터리가 사라진 경우에만 해당한다.
|
||||
- 앞 라운드의 비차단 항목(롤백 재시작이 `mam_monitor_started` 를 호출하지 않음, SIGKILL 자식 PID 재확인, 이미 떠 있는 resume 의 잠금 범위, 호출자의 실행 중 잡이 둘일 때)은 이 커밋이 건드리지 않았고 이번 수정 범위 밖이다.
|
||||
|
||||
전용 테스트가 없는 조건:
|
||||
|
||||
| 조건 | 코드 | 테스트 |
|
||||
| --- | --- | --- |
|
||||
| 레거시 모니터가 호출자와 다른 세션인지 | `lib.sh:2306-2308` 은 프로세스 그룹만 분리 | 이번 테스트는 PGID 만 비교 (`test_issue72_update.py:724`) |
|
||||
| 앞 라운드 표의 세 조건 | 변경 없음 | 이번 범위 밖 |
|
||||
|
||||
## 사용자 확인 필요
|
||||
|
||||
없음.
|
||||
|
||||
[VERDICT: PASS]
|
||||
Reference in new issue
Block a user