Загружаем каталог…
Загружаем каталог…
먼저 결론부터 봅시다. 감독자 없는 워커는 권한 프롬프트에 도달할 수 있으면 안 됩니다. 이번에 이 원칙을 어겨서, 병렬 AI 워커 3개가 아무도 보지 않는 1. Yes / 2. No 다이얼로그 앞에서 97분간 멈춰 있는 장애를 겪었습니다. 그리고 이 문제를 30년 된 메일 서버 패턴(maildir)으로 풀었습니다. 워커는 멈췄는데, 밖에서는 "작업 중"으로 보였다 저는 Claude Code 세션 여러 개를 tmux로 병렬 실행하는 오케스트레이션 플러그인을 운영하고 있습니다. 어느 날 런 하나를 확인하러 터미널을 열었더니, 워커 3개가 전부 같은 지점에서 정지해 있었습니다. 장애 리포트에 남긴 원문 그대로입니다: All three workers finished their implementation, then stalled at the same final step — the impl_done status write — sitting on a 1. Yes / 2. No dialog. They sat there ~1h37m before I looked at a terminal. 워커들을 붙잡은 건 제가 직접 만든 보안 훅이었습니다: Hook PreToolUse:Bash requires confirmation for this command: Writing into the main worktree (/.../repo) from a linked worktree — a worker can corrupt the shared checkout. [plugin:guardrails] 워커가 자기 워크트리 밖, 코디네이터 체크아웃의 상태 디렉토리에 완료 신호를 쓰는 프로토콜이었는데, 그 쓰기가 "교차 워크트리 쓰기"로 판정돼 확인 프롬프트에 걸린 겁니다. 헤드리스 세션이라 그 프롬프트에 답할 사람은 아무도 없었습니다. 더 고약했던 건 세 가지였습니다. 첫째, 상태 파일이 유일한 완료 신호 라서, 그 쓰기가 막히니 폴러는 계속 "still working"만 보고했습니다. 멈춘 워커가 밖에서는 정상 작업 중으로 보인 거죠. 둘째, 훅은 경로 기준이라 상태 디렉토리를 단순히 cat 으로 읽으려던 워커도 걸렸습니다. 셋째가 진짜 데드락인데 — 수정된 프로토콜을 메시지 큐로 보내줘도, 키보드 입력을 기다리며 멈춘 워커는 그 메시지를 읽을 수 없습니다. 결국 터미널에 직접 2 (거부)를 넣어서야 풀렸습니다. 우리만의 문제가 아니었다 리서치를 해보니 이건 알려진 장애 클래스였습니다. Claude Code 쪽에는 "permission prompts invisible, causing agent deadlock"(anthropics/claude-code#25254), opencode 쪽에는 권한이 "ask"면 헤드리스에서 무한 행이 걸린다는 이슈(anomalyco/opencode#16367, #14473)가 있었습니다. Anthropic 공식 가이드의 처방도 같은 방향이었습니다 — 헤드리스 파이프라인은 프롬프트가 아예 발생하지 않도록 권한을 사전 스코핑하라. 그런데 저희 경우는 권한 스코핑만으로는 부족했습니다. "코디네이터 체크아웃에 쓰기"라는 행위 자체가 신뢰 경계를 넘는 설계였으니까요. 그래서 프로토콜을 갈아엎기로 했습니다. 30년 된 메일 서버에서 답을 찾다 qmail의 maildir 패턴이 정확히 이 모양의 문제를 풉니다. 각 생산자는 자기 tmp/ 영역에만 쓰고, 원자적 rename으로 넘기며, 파일 하나에 작성자는 하나 — 그래서 잠금 없이도 경합이 없습니다. 이걸 그대로 이식했습니다. 워커는 자기 워크트리 안의 상태 파일에만 쓰고, 코디네이터 쪽 수집기가 주기적으로 긁어서 정본 디렉토리로 원자 복사 합니다. 워커는 이제 자기 영역 밖을 절대 건드리지 않으니 프롬프트에 도달할 경로 자체가 사라집니다. 수집기( collect-status.sh )의 계약은 주석에 이렇게 못 박았습니다: # Each in-graph record is copied into <canonical-status-dir>/<task>.json via # tmp+mv when: # - no canonical record exists yet, or # - the canonical .phase is not done/failed (tombstone — never overwritten), AND # - the worker record's .updatedAt is strictly greater than the canonical's tmp에 쓰고 mv 로 원자 교체, done/failed는 묘비(tombstone)로 취급해 뒤늦게 도착한 "running"이 덮어쓰지 못하게 — maildir의 규율 그대로입니다. 재설계를 그 오케스트레이션으로 구현했더니 재미있는 건 이 수정 자체를 문제의 그 오케스트레이션 시스템으로 구현했다는 점입니다. 그리고 리뷰 단계에서 제 구현의 결함이 하나 잡혔습니다. 태스크 필터 함수였는데요: # before — 리뷰에서 blocking 판정 is_task() { echo "$ids" | grep -qx "$1"; } # after is_task() { echo "$ids" | grep -Fqx -- "$1"; } grep -x 는 패턴을 정규식으로 해석합니다. 태스크 id에 . 같은 메타문자가 있으면, 병행 중인 다른 런의 근사-일치 파일 ( t1-status vs t1.status )이 필터를 뚫고 정본 디렉토리에 섞여 들어올 수 있었습니다. -F (리터럴 비교) 한 글자 차이입니다. 회귀 가드도 같이 넣었습니다: @test "r1 F1: a regex-metacharacter id does not fuzzy-match a near-miss basename" { graph '{"tasks":[{"id":"t1-status","deps":[]}]}' worker_status other-run t1.status planning 2026-01-01T00:00:00Z run sh "$CS" "$G" "$CDIR" "$WROOT" [ "$output" = "collected=1 skipped=0 foreign=1" ] [ ! -e "$CDIR/t1.status.json" ] } 통합 단계에서 실패 1건이 더 나왔는데(888개 중 887 통과), 원인은 버그가 아니라 제 계획의 검증 목록 누락이었습니다. 문서의 절차 순서를 문자열로 핀하는 기존 테스트가 있었는데, 절차를 고치면서 그 테스트를 검증 목록에 안 넣은 거죠. 테스트를 현대화하고 재실행해서 최종 888/888 그린, 독립 리뷰어 승인 후 머지했습니다. 배운 것 워커의 유일한 완료 신호가, 프롬프트를 유발할 수 있는 도구 호출에 의존하면 안 됩니다. 신호 경로가 막히는 순간 장애가 "정상 작업 중"으로 위장되니까요. 그리고 신뢰 경계를 넘는 쓰기는 "ask"가 아니라 결정적으로 deny 되어야 합니다. deny는 워커가 반응할 수 있는 명시적 에러를 남기지만, ask는 아무도 없는 방에서 손을 든 채 영원히 기다리게 만듭니다. 파일 기반 IPC의 고전 패턴이 AI 오케스트레이션에 이렇게 그대로 이식된다는 것도 수확이었습니다. 에이전트 인프라를 만들고 계시다면, 새 프로토콜을 발명하기 전에 maildir 문서(cr.yp.to/proto/maildir.html)를 한 번 읽어보시길 권합니다. 다음 목표는 이런 "프롬프트 도달 가능 경로"를 런 시작 전에 정적으로 검출하는 프리플라이트 체크입니다.
То, что RADAR обнаружил и классифицировал для этой возможности. Это опубликованный источником текст, а не подтверждение, что предложение ещё действует.
아무도 안 보는 다이얼로그 앞에서 AI 워커 3개가 97분을 멈춰 있었다 — maildir 패턴으로 푼 오케스트레이션 데드락. 먼저 결론부터 봅시다. 감독자 없는 워커는 권한 프롬프트에 도달할 수 있으면 안 됩니다. 이번에 이 원칙을 어겨서, 병렬 AI 워커 3개가 아무도 보지 않는 1. Yes / 2. No 다이얼로그 앞에서 97분간 멈춰 있는 장애를 겪었습니다. 그리고 이 문제를 30년 된 메일 서버 패턴(maildir)으로 풀었습니다. 워커는 멈췄는데, 밖에서는 "작업 중"으로 보였다 저는 Claude Code 세션 여러 개를 tmux로 병렬 실행하는 오케스트레이션 플러그인을 운영하고 있습니다. 어느 날 런 하나를 확인하러 터미널을 열었더니, 워커 3개가 전부 같은 지점에서 정지해 있었습니다. 장애…
Открыть источник