증상 (stickygap1 런, 2026-08-21, dev-loop 1.8.3 실측)
한 런에서 worktree_escape 에스컬레이션이 읽기 전용 명령으로 3회 발생했다 (메인 워크트리의 .env*를 ls/grep으로 조회 — dev 서버용 카카오 키 확인 목적). 1회차는 코디네이터가 승인을 전달해 정상 해소. 그런데 2·3회차(14:35)는 워커가 답을 기다리지 않고 다른 경로로 우회해 그대로 impl_done까지 진행했고, 레코드는 escalations/에 남았다. 그 결과:
- 다음
watch-status.sh ... done 1이 시작하자마자 exit 5 — 그러나 답을 전달할 대상이 없다 (워커는 이미 지나감).
- 코디네이터가 레코드
ts와 status updatedAt을 수동 대조해 "스테일"을 판별하고 rm 해야 했다. exit 5는 레코드가 있는 한 재발하도록 설계돼 있으므로(의도된 동작), 스테일 레코드는 사실상 watch를 영구히 깨우는 잔재가 된다.
원인
- 에스컬레이션 레코드에 생성만 있고 소멸 경로가 없다: 정상 플로우(코디네이터 approve/deny → rm)만 정의돼 있고, "워커가 거부를 받아들이고 우회해 진행한" 경우를 아무도 정리하지 않는다.
watch-status.sh의 exit 5 메시지(task:rule 나열)에는 레코드 시각·해당 태스크의 현재 phase가 없어, 코디네이터가 매번 파일 2개를 열어 대조해야 스테일 여부를 안다.
- 같은 명령 계열이 반복 에스컬레이션돼도 dedupe가 없어 왕복이 배가된다.
제안
- triage 정보를 exit 5 출력에 포함 (가장 저비용):
[watch] escalation pending — <task>:<rule> (recorded <ts>; task phase=<phase> @<updatedAt>). 레코드 ts보다 phase 전이가 나중이면 코디네이터가 즉시 "워커가 이미 지나감 → 답장 없이 rm"을 판단할 수 있다. 스킬 문서의 escalation playbook에도 이 분기(대기 중인 워커에게만 답장 전달, 지나간 워커는 레코드만 삭제)를 명시.
- 워커 측 정리 규약: 워커 프로토콜에 "거부된 명령을 우회하기로 했으면 자신의 escalation 레코드를 삭제(또는
resolved: worker-bypassed 마킹)하고 진행"을 추가. 레코드의 의미가 '답변 대기 중'으로 유지된다.
- worktree_escape의 읽기 전용 구분 또는 dedupe: 메인 워크트리 대상이라도 쓰기 동사/리다이렉션이 없는 명령(ls, grep, cat)은 escalate 대신 allow(혹은 로그만)하거나, 최소한 동일
cmd 해시의 재-에스컬레이션을 런 내에서 접기. 이번 런의 3건은 전부 동일한 read-only 패턴이었다.
1은 즉시 적용 가능하고 위험이 없다. 2가 근본 해결, 3은 발생 자체를 줄인다. (자동 스테일 판정 후 무시하는 방식은 비추 — 워커 턴 중간의 정당한 대기와 구분이 안 됨. 판단은 코디네이터에 남기되 판단 재료를 주는 방향.)
증상 (stickygap1 런, 2026-08-21, dev-loop 1.8.3 실측)
한 런에서
worktree_escape에스컬레이션이 읽기 전용 명령으로 3회 발생했다 (메인 워크트리의.env*를ls/grep으로 조회 — dev 서버용 카카오 키 확인 목적). 1회차는 코디네이터가 승인을 전달해 정상 해소. 그런데 2·3회차(14:35)는 워커가 답을 기다리지 않고 다른 경로로 우회해 그대로 impl_done까지 진행했고, 레코드는escalations/에 남았다. 그 결과:watch-status.sh ... done 1이 시작하자마자 exit 5 — 그러나 답을 전달할 대상이 없다 (워커는 이미 지나감).ts와 statusupdatedAt을 수동 대조해 "스테일"을 판별하고rm해야 했다. exit 5는 레코드가 있는 한 재발하도록 설계돼 있으므로(의도된 동작), 스테일 레코드는 사실상 watch를 영구히 깨우는 잔재가 된다.원인
watch-status.sh의 exit 5 메시지(task:rule나열)에는 레코드 시각·해당 태스크의 현재 phase가 없어, 코디네이터가 매번 파일 2개를 열어 대조해야 스테일 여부를 안다.제안
[watch] escalation pending — <task>:<rule> (recorded <ts>; task phase=<phase> @<updatedAt>). 레코드 ts보다 phase 전이가 나중이면 코디네이터가 즉시 "워커가 이미 지나감 → 답장 없이 rm"을 판단할 수 있다. 스킬 문서의 escalation playbook에도 이 분기(대기 중인 워커에게만 답장 전달, 지나간 워커는 레코드만 삭제)를 명시.resolved: worker-bypassed마킹)하고 진행"을 추가. 레코드의 의미가 '답변 대기 중'으로 유지된다.cmd해시의 재-에스컬레이션을 런 내에서 접기. 이번 런의 3건은 전부 동일한 read-only 패턴이었다.1은 즉시 적용 가능하고 위험이 없다. 2가 근본 해결, 3은 발생 자체를 줄인다. (자동 스테일 판정 후 무시하는 방식은 비추 — 워커 턴 중간의 정당한 대기와 구분이 안 됨. 판단은 코디네이터에 남기되 판단 재료를 주는 방향.)