[Bug] pytest 실행 시 create_session.sh 온보딩 job 등록이 실제 .mam/jobs 레지스트리·delegate_job_logs 로 누수됨 (cwd 기준 기본 registry dir, 593건 누적) #15

Closed
opened 2026-09-12 14:53:30 +00:00 by Godopu · 1 comment
Owner

문제 개요 (Summary)

pytest tests/ 를 저장소 루트에서 실행하면, 테스트 샌드박스(tmp_path)가 아니라 실제 워크스페이스의 .mam/jobs 레지스트리와 .mam/delegate_job_logs 감사 로그에 job 레코드가 남습니다. create_session.sh 의 기본 온보딩(ONBOARD=1)이 등록하는 job 이 cwd 기준 기본 경로(.mam/jobs)로 떨어지기 때문입니다. 등록만 되고 어떤 에이전트도 집어가지 않으므로 레코드는 영구히 running/pending 으로 남습니다.

현재 실측 (2026-09-12, main 4d444ce 기준 워크스페이스)

항목 값
.mam/jobs/*.json 총 레코드 849건 (25 MB)
그중 테스트 세션 이름(custom-* 300, pytest-* 192, reuse-* 100, test-* 1) 593건 (약 70%)
누수 레코드 상태 running 586 / pending 6 / cancelled 1 — 완료된 것 없음
누수 발생일 2026-08-31(46) · 09-01(6) · 09-05(58) · 09-06(190) · 09-07(54) · 09-08(85) · 09-09(32) · 09-12(13) — 온보딩 기능 도입 이후 매 스위트 실행마다 누적
.mam/delegate_job_logs/ 1,898개 디렉터리 (21 MB); 표본 400개 중 32개가 테스트 세션(herdr:pytest-*, custom-*, reuse-*)을 참조
누수 레코드의 brief 디렉터리 없음 (register 만 수행된 레코드)

예: c9b1e6c0 — agent_session: herdr:pytest-12-test-comp-create-sqlite-tables0-creator-claude, d4a93ed9 — herdr:reuse-creator-claude, a8388190 — herdr:custom-proj-default-claude (모두 tests/test_tier2_component.py 의 세션 이름, 13:55–13:57Z 전체 스위트 실행 중 생성).

참고: 현재 살아 있는 job_subscriber 프로세스는 실행 중인 루프의 1개뿐이며, 데몬 프로세스 누수는 확인되지 않았습니다. 이 이슈는 레코드·로그 파일 누수에 한정합니다.


세부 원인 분석 (Detailed Root Causes)

1. 레지스트리·감사 로그 기본 경로가 워크스페이스가 아니라 cwd 기준

  • .agents/skills/lib_py/delegation/mqtt_common.py:136 — DEFAULT_REGISTRY_DIR = ".mam/jobs" (상대 경로 → 호출 프로세스의 cwd)
  • .agents/skills/lib_py/delegation/mqtt_common.py:160 — 감사 로그 기본값 os.path.join(os.getcwd(), ".mam", "delegate_job_logs")
  • lib.sh:1946, lib.sh:2040 — MAM_JOBS_DIR 가 설정된 경우에만 --registry-dir 를 전달. WORKSPACE_ROOT 는 참조하지 않음
  • create_session.sh:353 — 토큰 조회도 os.environ.get('MAM_JOBS_DIR', '.mam/jobs')
  • 반면 agent-sessions.yaml(AGENT_SESSIONS_YAML)·HOME_DIR·WORKSPACE_ROOT 는 환경변수로 격리되므로, job 레지스트리만 격리 계약에서 빠져 있음

2. create_session.sh 기본 온보딩이 job 을 무조건 등록

  • create_session.sh:62 ONBOARD=1 기본값 → :318 온보딩 프롬프트 생성 → :345 delegate_submit_job → lib.sh:2005 _delegation_py submit → lib_py.delegation.cli submit → registry.main(["register", ...]) (--registry-dir 미전달)
  • 테스트가 --workspace <tmp> 를 넘겨도 등록 경로는 cwd 를 따름

3. 테스트 스위트가 cwd/온보딩을 통제하지 않음

  • tests/*.py 의 create_session.sh 호출 48건 중 --no-onboard 8건, cwd= 지정 8건뿐 (예: tests/test_tier2_component.py:196-205 — subprocess.run([...]) 에 cwd 없음)
  • tests/conftest.py mam_sandbox 는 HOME/HOME_DIR/WORKSPACE_ROOT/AGENT_SESSIONS_YAML/LOCAL_BIN/MAM_ENV_FILE 은 격리하지만 MAM_JOBS_DIR·DELEGATE_JOB_LOGS_DIR 는 설정하지 않음
  • 래퍼(multi-agent-mux-delegate-job submit --registry-dir <tmp>)를 쓰는 테스트도 감사 로그는 cwd 기본값(원인 1)으로 실제 트리에 남김

영향 (Impact)

  • 레지스트리 오염: 실제 job 의 2.3배에 달하는 가짜 running 레코드가 섞여 list/status 출력과 운영 판단을 흐림
  • 핫패스 비용: registry.py:132/155/188 _iter_records 가 매 호출마다 849개 파일을 순회 — pick_pending(publish_event.py:210, registry.py:499), job_subscriber.py:238, notifier.py:41 모두 영향
  • 디스크: .mam/jobs 25 MB + .mam/delegate_job_logs 21 MB 가 계속 증가
  • 보안 표면: 누수 레코드에도 auth_token·broker 블록이 그대로 기록됨 (#12 와 결합)
  • 테스트 격리 원칙 위반: 스위트 실행이 저장소 상태를 바꾸므로 재현성이 떨어지고, 개발자 워크스페이스에서 돌릴 때마다 오염됨

제안 해결책 (Proposed Fix)

  1. 기본 경로를 워크스페이스에 고정: mqtt_common 의 레지스트리/로그 기본값을 MAM_JOBS_DIR → WORKSPACE_ROOT/.mam/jobs → cwd 순으로 해석 (로그도 동일). create_session.sh 는 --workspace 를 알고 있으므로 delegate_submit_job 에 --registry-dir "$WORKSPACE/.mam/jobs" 를 명시 전달
  2. 테스트 격리 계약 보강: mam_sandbox 가 MAM_JOBS_DIR=<tmp>/.mam/jobs, DELEGATE_JOB_LOGS_DIR=<tmp>/.mam/delegate_job_logs 를 export 하고, 스크립트 호출은 cwd=mam_sandbox 로 통일. 세션 스코프 가드 fixture 로 실제 .mam/jobs·.mam/delegate_job_logs 스냅샷을 비교해 새 파일이 생기면 스위트를 실패시킴
  3. 온보딩 옵트아웃 기본값(테스트): 세션 생성만 검증하는 테스트는 --no-onboard 를 기본으로 사용
  4. 일회성 정리 + 정리 도구: agent_session 이 테스트 접두사(pytest-*, custom-*, reuse-*, test-*)이고 상태가 pending/running 이며 brief 디렉터리가 없는 레코드 593건과 고아 delegate_job_logs 디렉터리를 제거. 재발 방지용으로 registry.py prune --stale-test-artifacts 같은 서브커맨드(dry-run 기본) 제공 검토

환경 정보 (Environment)

  • OS: macOS (Darwin 25.6.0)
  • MAM Version: 4d444ce (main) / fix/issue-9-14 브랜치에서도 동일 (해당 브랜치는 이 경로를 건드리지 않음)
  • 재현: 저장소 루트에서 .venv/bin/python -m pytest tests/test_tier2_component.py -q 실행 후 ls .mam/jobs | wc -l 증가 및 grep -l '"agent_session": "herdr:custom-' .mam/jobs/*.json 확인
## 문제 개요 (Summary) `pytest tests/` 를 저장소 루트에서 실행하면, 테스트 샌드박스(`tmp_path`)가 아니라 **실제 워크스페이스의 `.mam/jobs` 레지스트리와 `.mam/delegate_job_logs` 감사 로그**에 job 레코드가 남습니다. `create_session.sh` 의 기본 온보딩(`ONBOARD=1`)이 등록하는 job 이 cwd 기준 기본 경로(`.mam/jobs`)로 떨어지기 때문입니다. 등록만 되고 어떤 에이전트도 집어가지 않으므로 레코드는 영구히 `running`/`pending` 으로 남습니다. **현재 실측 (2026-09-12, main 4d444ce 기준 워크스페이스)** | 항목 | 값 | |---|---| | `.mam/jobs/*.json` 총 레코드 | 849건 (25 MB) | | 그중 테스트 세션 이름(`custom-*` 300, `pytest-*` 192, `reuse-*` 100, `test-*` 1) | **593건 (약 70%)** | | 누수 레코드 상태 | `running` 586 / `pending` 6 / `cancelled` 1 — 완료된 것 없음 | | 누수 발생일 | 2026-08-31(46) · 09-01(6) · 09-05(58) · **09-06(190)** · 09-07(54) · 09-08(85) · 09-09(32) · 09-12(13) — 온보딩 기능 도입 이후 매 스위트 실행마다 누적 | | `.mam/delegate_job_logs/` | 1,898개 디렉터리 (21 MB); 표본 400개 중 32개가 테스트 세션(`herdr:pytest-*`, `custom-*`, `reuse-*`)을 참조 | | 누수 레코드의 brief 디렉터리 | 없음 (`register` 만 수행된 레코드) | 예: `c9b1e6c0` — `agent_session: herdr:pytest-12-test-comp-create-sqlite-tables0-creator-claude`, `d4a93ed9` — `herdr:reuse-creator-claude`, `a8388190` — `herdr:custom-proj-default-claude` (모두 `tests/test_tier2_component.py` 의 세션 이름, 13:55–13:57Z 전체 스위트 실행 중 생성). > 참고: 현재 살아 있는 `job_subscriber` 프로세스는 실행 중인 루프의 1개뿐이며, 데몬 프로세스 누수는 확인되지 않았습니다. 이 이슈는 **레코드·로그 파일 누수**에 한정합니다. --- ## 세부 원인 분석 (Detailed Root Causes) ### 1. 레지스트리·감사 로그 기본 경로가 워크스페이스가 아니라 cwd 기준 - `.agents/skills/lib_py/delegation/mqtt_common.py:136` — `DEFAULT_REGISTRY_DIR = ".mam/jobs"` (상대 경로 → 호출 프로세스의 cwd) - `.agents/skills/lib_py/delegation/mqtt_common.py:160` — 감사 로그 기본값 `os.path.join(os.getcwd(), ".mam", "delegate_job_logs")` - `lib.sh:1946`, `lib.sh:2040` — `MAM_JOBS_DIR` 가 설정된 경우에만 `--registry-dir` 를 전달. `WORKSPACE_ROOT` 는 참조하지 않음 - `create_session.sh:353` — 토큰 조회도 `os.environ.get('MAM_JOBS_DIR', '.mam/jobs')` - 반면 `agent-sessions.yaml`(`AGENT_SESSIONS_YAML`)·`HOME_DIR`·`WORKSPACE_ROOT` 는 환경변수로 격리되므로, **job 레지스트리만 격리 계약에서 빠져 있음** ### 2. `create_session.sh` 기본 온보딩이 job 을 무조건 등록 - `create_session.sh:62` `ONBOARD=1` 기본값 → `:318` 온보딩 프롬프트 생성 → `:345` `delegate_submit_job` → `lib.sh:2005 _delegation_py submit` → `lib_py.delegation.cli submit` → `registry.main(["register", ...])` (`--registry-dir` 미전달) - 테스트가 `--workspace <tmp>` 를 넘겨도 등록 경로는 cwd 를 따름 ### 3. 테스트 스위트가 cwd/온보딩을 통제하지 않음 - `tests/*.py` 의 `create_session.sh` 호출 48건 중 `--no-onboard` 8건, `cwd=` 지정 8건뿐 (예: `tests/test_tier2_component.py:196-205` — `subprocess.run([...])` 에 `cwd` 없음) - `tests/conftest.py mam_sandbox` 는 `HOME`/`HOME_DIR`/`WORKSPACE_ROOT`/`AGENT_SESSIONS_YAML`/`LOCAL_BIN`/`MAM_ENV_FILE` 은 격리하지만 **`MAM_JOBS_DIR`·`DELEGATE_JOB_LOGS_DIR` 는 설정하지 않음** - 래퍼(`multi-agent-mux-delegate-job submit --registry-dir <tmp>`)를 쓰는 테스트도 감사 로그는 cwd 기본값(원인 1)으로 실제 트리에 남김 --- ## 영향 (Impact) - **레지스트리 오염**: 실제 job 의 2.3배에 달하는 가짜 `running` 레코드가 섞여 `list`/`status` 출력과 운영 판단을 흐림 - **핫패스 비용**: `registry.py:132/155/188` `_iter_records` 가 매 호출마다 849개 파일을 순회 — `pick_pending`(`publish_event.py:210`, `registry.py:499`), `job_subscriber.py:238`, `notifier.py:41` 모두 영향 - **디스크**: `.mam/jobs` 25 MB + `.mam/delegate_job_logs` 21 MB 가 계속 증가 - **보안 표면**: 누수 레코드에도 `auth_token`·`broker` 블록이 그대로 기록됨 (#12 와 결합) - **테스트 격리 원칙 위반**: 스위트 실행이 저장소 상태를 바꾸므로 재현성이 떨어지고, 개발자 워크스페이스에서 돌릴 때마다 오염됨 --- ## 제안 해결책 (Proposed Fix) 1. **기본 경로를 워크스페이스에 고정**: `mqtt_common` 의 레지스트리/로그 기본값을 `MAM_JOBS_DIR` → `WORKSPACE_ROOT/.mam/jobs` → cwd 순으로 해석 (로그도 동일). `create_session.sh` 는 `--workspace` 를 알고 있으므로 `delegate_submit_job` 에 `--registry-dir "$WORKSPACE/.mam/jobs"` 를 명시 전달 2. **테스트 격리 계약 보강**: `mam_sandbox` 가 `MAM_JOBS_DIR=<tmp>/.mam/jobs`, `DELEGATE_JOB_LOGS_DIR=<tmp>/.mam/delegate_job_logs` 를 export 하고, 스크립트 호출은 `cwd=mam_sandbox` 로 통일. 세션 스코프 가드 fixture 로 실제 `.mam/jobs`·`.mam/delegate_job_logs` 스냅샷을 비교해 새 파일이 생기면 스위트를 실패시킴 3. **온보딩 옵트아웃 기본값(테스트)**: 세션 생성만 검증하는 테스트는 `--no-onboard` 를 기본으로 사용 4. **일회성 정리 + 정리 도구**: `agent_session` 이 테스트 접두사(`pytest-*`, `custom-*`, `reuse-*`, `test-*`)이고 상태가 `pending`/`running` 이며 brief 디렉터리가 없는 레코드 593건과 고아 `delegate_job_logs` 디렉터리를 제거. 재발 방지용으로 `registry.py prune --stale-test-artifacts` 같은 서브커맨드(dry-run 기본) 제공 검토 --- ## 환경 정보 (Environment) - OS: macOS (Darwin 25.6.0) - MAM Version: 4d444ce (main) / fix/issue-9-14 브랜치에서도 동일 (해당 브랜치는 이 경로를 건드리지 않음) - 재현: 저장소 루트에서 `.venv/bin/python -m pytest tests/test_tier2_component.py -q` 실행 후 `ls .mam/jobs | wc -l` 증가 및 `grep -l '"agent_session": "herdr:custom-' .mam/jobs/*.json` 확인
Author
Owner

fix/issue-10-11-13-15 에서 해결, main 8a09e02 로 병합·push 완료 (v4.4.3).

수정 내용

  • mqtt_common.default_registry_dir() / get_logs_dir(): 기본 경로를 MAM_JOBS_DIR·DELEGATE_JOB_LOGS_DIR → $WORKSPACE_ROOT/.mam/jobs·$WORKSPACE_ROOT/.mam/delegate_job_logs(lib.sh 가 export) → cwd 기준 .mam/… 순으로 해석. registry.py·publish_event.py·job_subscriber.py·service.py 의 CLI 기본값과 create_session.sh·stop_session.sh 의 조회가 같은 순서를 사용 (c82ea75, 7610258)
  • tests/conftest.py mam_sandbox 가 MAM_JOBS_DIR·DELEGATE_JOB_LOGS_DIR 를 샌드박스로 고정
  • 기존 테스트 조정: R1 helper 테스트·B-9 logs-dir 테스트·publish_event 스냅샷을 워크스페이스 고정 계약으로 갱신

검증: tests/test_issue15_registry_isolation.py(저장소 루트 cwd 에서 create_session.sh 를 돌려도 샌드박스에만 기록, WORKSPACE_ROOT 만으로도 격리), 전체 스위트 실행 전후 실제 .mam/jobs 레코드 수 불변(881→881, 901→901 두 차례 확인), 리뷰 루프 만장일치 PASS.

남은 것: 이미 누적된 테스트 레코드 593건과 고아 delegate_job_logs 의 일회성 정리 및 registry.py prune 도구는 #17 항목 5 로 이관.

`fix/issue-10-11-13-15` 에서 해결, main `8a09e02` 로 병합·push 완료 (v4.4.3). **수정 내용** - `mqtt_common.default_registry_dir()` / `get_logs_dir()`: 기본 경로를 `MAM_JOBS_DIR`·`DELEGATE_JOB_LOGS_DIR` → `$WORKSPACE_ROOT/.mam/jobs`·`$WORKSPACE_ROOT/.mam/delegate_job_logs`(lib.sh 가 export) → cwd 기준 `.mam/…` 순으로 해석. `registry.py`·`publish_event.py`·`job_subscriber.py`·`service.py` 의 CLI 기본값과 `create_session.sh`·`stop_session.sh` 의 조회가 같은 순서를 사용 (`c82ea75`, `7610258`) - `tests/conftest.py mam_sandbox` 가 `MAM_JOBS_DIR`·`DELEGATE_JOB_LOGS_DIR` 를 샌드박스로 고정 - 기존 테스트 조정: R1 helper 테스트·B-9 logs-dir 테스트·publish_event 스냅샷을 워크스페이스 고정 계약으로 갱신 **검증**: `tests/test_issue15_registry_isolation.py`(저장소 루트 cwd 에서 `create_session.sh` 를 돌려도 샌드박스에만 기록, `WORKSPACE_ROOT` 만으로도 격리), 전체 스위트 실행 전후 실제 `.mam/jobs` 레코드 수 불변(881→881, 901→901 두 차례 확인), 리뷰 루프 만장일치 PASS. **남은 것**: 이미 누적된 테스트 레코드 593건과 고아 `delegate_job_logs` 의 일회성 정리 및 `registry.py prune` 도구는 #17 항목 5 로 이관.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: tmpl/multi-agent-mux#15