Issue #36: delegated prompts travel by file, a delegation that fails ends the loop with rc 1. VERSIONS.md carries the entry; the merge-side reports (round 1 @59be1c8 and round 2 @708262a with identity sidecars, base59be1c8-> head708262a, evidence review-tree) are archived under .agents/reports/<session>/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
58 lines
5.6 KiB
Markdown
58 lines
5.6 KiB
Markdown
# PR #37 델타 리뷰 2회차
|
||
|
||
- Job: `d493b472`; reviewer: `planner-reviewer-codex-01`
|
||
- Loop: `loop-20260924T085626Z-b8987e`
|
||
- Base: `59be1c89209a232059aec0c5aeecc2329929cb49`
|
||
- Head: `708262a598c4301c0ccc70efba5401093b4b1e30`
|
||
- Tree: `d601c2d01bb4c09931e5e1989e140b01d51f5b96`
|
||
- 검증 경로: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20260924T085626Z-b8987e/1`
|
||
|
||
직전 리뷰의 R1/R2가 해결됐고, 추가된 빈 파일 거부도 기존 wrapper 계약과 일치한다. 이번 델타에서 병합 차단 결함을 발견하지 않았다. 브리프에 명시된 4.7.3 락스텝 버전 변경은 오케스트레이터 후속 작업이다.
|
||
|
||
## R1/H1 — 파일 쓰기 실패 처리 및 정리: 해소
|
||
|
||
근거: `.agents/skills/lib_py/loop/runner.py:472`–`:491`, `:504`–`:516`.
|
||
|
||
경로를 빈 문자열로 초기화하고, 디렉터리 생성·임시 파일 생성·쓰기·context manager 종료를 새 try 범위에 포함했다. 파일 이름을 쓰기 전에 저장하므로 쓰기 또는 닫기 중 오류에서도 부분 파일을 지울 수 있다. 오류 경로는 원인이 포함된 rc 126의 `CompletedProcess`를 반환하며, 뒤의 wrapper 실행 try/finally에 들어가지 않는다. 정상 경로에서는 기존 finally가 파일을 지운다. 따라서 두 정리 경로가 같은 파일에 중복 적용되지 않는다.
|
||
|
||
실제 `RLIMIT_FSIZE=1024`와 `SIGXFSZ` 무시를 독립 subprocess에 적용해 재검증했다. 제품 코드에서 추출한 동일 `_run_cmd`에 실행/삭제 횟수 관찰만 추가한 결과:
|
||
|
||
| 조건 | 반환 코드 | wrapper 실행 시도 | 파일 삭제 호출 | 잔여 파일 |
|
||
|---|---:|---:|---:|---|
|
||
| 20,000바이트 쓰기 중 실제 EFBIG | 126 | 0 | 1 | 없음 |
|
||
| 2,000바이트 버퍼의 close/flush 시 실제 EFBIG | 126 | 0 | 1 | 없음 |
|
||
| 정상 실행 | 0 | 1 | 1 | 없음 |
|
||
| exec 실패(PATH에서 bash 제거) | 126 | 1 | 1 | 없음 |
|
||
| `.mam`이 디렉터리가 아닌 파일 | 126 | 0 | 0 | 없음 |
|
||
|
||
추출 함수뿐 아니라 실제 `LoopRunner.delegate_job()`도 별도 subprocess에서 같은 20,000바이트 쓰기 실패로 실행했다. 결과는 `None`, `delegate_job submit failed (exit 126)` 및 파일 쓰기 원인 로그, 잔여 파일 없음이었다.
|
||
|
||
busy 재시도 경로는 첫 wrapper 호출만 rc 5로 모사하고 그때 실제 파일 크기 제한을 설정했다. 두 번째 시도의 파일 쓰기가 EFBIG로 실패하자 `retry failed (exit 126)`이 기록됐고, wrapper는 한 번만 호출됐으며 결과는 `None`, 잔여 파일은 없었다. 미등록 상태에서 가짜 job ID나 `failed_submit_jobs` 항목을 만들지 않고 기존 실패 제출 흐름으로 돌아간다.
|
||
|
||
역검증: S4c에만 base의 `delegate_job` 메서드를 임시 namespace로 적용했다. 새 회귀는 처리되지 않은 ENOSPC로 실패했고 파일 한 개가 남았다. 수정된 HEAD의 S4c는 통과했다. 기존 R1 지적을 해소한다.
|
||
|
||
## R2/N1 — macOS S9 오류 문구: 해소
|
||
|
||
근거: `tests/test_issue36_prompt_transport.py:637` 이후.
|
||
|
||
libc/bash의 `File too large` 문구는 Linux에서만 요구한다. 비정상 반환 코드, 잔여 파일 없음, 프로젝트 고유의 `delegate_job_safe: cannot write the prompt file` 진단은 모든 플랫폼에서 여전히 검사한다. 현재 macOS에서 S9가 통과했다. 쓰기 실패와 정리의 검증 의도를 유지한 이식성 수정이다.
|
||
|
||
## H3 — 빈 프롬프트 파일 거부: 적절
|
||
|
||
근거: `.agents/skills/multi-agent-mux-delegate-job/multi-agent-mux-delegate-job:193`.
|
||
|
||
읽을 수 있는 일반 파일 확인 다음에 `-s` 검사를 추가하므로, 0바이트 입력은 registry 등록 전에 거부된다. 기존 wrapper의 `--prompt ''`도 허용하지 않았으므로 유효한 기존 wrapper 사용처를 차단하는 변경은 아니다. registry 자체의 register/update 구현은 이번 델타에서 바뀌지 않았다. loop 형의 내부 `prompt.md`는 registry update에 직접 전달되므로 이 입구 검사와 혼동되지 않는다. 공백/개행으로만 된 비어 있지 않은 파일을 거부하는 의미로 확대된 변경도 아니다.
|
||
|
||
S1e가 통과했다. 샌드박스 skills 사본의 wrapper만 base로 교체하고 같은 S1e를 호출하면 assertion이 실패하며 빈 프롬프트 잡 한 개가 등록됐다. 새 검사가 기존 결함을 검출한다는 역검증이다.
|
||
|
||
## 검증 및 범위
|
||
|
||
- `git diff 59be1c8...HEAD`의 변경 파일 3개를 검토했다. HEAD/tree가 브리프와 일치했고 검증 후 작업 트리도 깨끗했다.
|
||
- `tests/test_issue36_prompt_transport.py` 전체: **23 passed, 1 skipped in 42.24s**. skip은 Linux 전용 MAX_ARG_STRLEN 음성 대조군이다. 기존 파일 전달, exec 오류/재시도, 셸 루프, create 온보딩 테스트도 이 실행에 포함된다.
|
||
- pytest에는 브리프의 절대 Python 경로를 실행 명령과 `AGENT_PYTHON_BIN`에 지정하고 `PYTHONDONTWRITEBYTECODE=1`, `-p no:cacheprovider`, 검증 경로 밖의 고유 `/tmp/mam-review-d493b472.*` basetemp를 사용했다.
|
||
- `git diff --check`, 변경 wrapper의 `bash -n`, 변경 Python 파일 2개의 AST 구문 검사 통과.
|
||
- 위 실패 주입, 역검증, 실행/삭제 횟수 검사는 별도 임시 경로와 독립 subprocess에서 수행했다. 제품 코드, creator 워크트리, 실제 herdr 서버/에이전트 세션은 수정하지 않았다.
|
||
- 직전 리뷰의 넓은 계약 테스트 전체를 이번 트리에서 재실행했다고 주장하지 않는다. 이번 검증은 정정된 세 항목과 프롬프트 전달 회귀에 집중했다. 이전 판정을 유지할 추가 차단 사유를 발견하지 못했으며 재설계 에스컬레이션은 필요하지 않다.
|
||
|
||
[VERDICT: PASS]
|