# 작업자 정리

> settled dispatch 확인, terminal close, worktree clean과 merge 포함 여부 검사, dry-run, reap ledger 기록을 설명합니다.

- Repository: local/master-ops-with-local-mogui-ADE-orchestrator

- Human docs: https://grok-wiki.com/public/docs/local-master-ops-with-local-mogui-ade-orches-0ac7093355f3
- Complete Markdown: https://grok-wiki.com/public/docs/local-master-ops-with-local-mogui-ade-orches-0ac7093355f3/llms-full.txt

## Source Files

- `local-mogui-ade-orchestrator:src/master_runtime/core/worker_reap.py`
- `local-mogui-ade-orchestrator:scripts/worker-reap`
- `local-mogui-ade-orchestrator:docs/runbooks/worker-reap.md`
- `local-mogui-ade-orchestrator:tests/test_worker_reap.py`
- `local-master-ops:scripts/worker-pane-sweep`

---

---
title: "작업자 정리"
description: "settled dispatch 확인, terminal close, worktree clean과 merge 포함 여부 검사, dry-run, reap ledger 기록을 설명합니다."
---

`local-mogui-ade-orchestrator:scripts/worker-reap`는 Orca dispatch 상태를 조회한 뒤, settled 상태인 작업자 terminal을 닫고 안전하다고 판정된 worktree만 제거하는 명시 실행 CLI입니다. `local-master-ops:scripts/worker-pane-sweep`는 같은 수명주기에서 live Orca pane을 분류하는 보조 검사기이며, terminal close나 worktree 제거를 직접 수행하지 않습니다.

## 실행 표면

| 표면 | 역할 |
| --- | --- |
| `local-mogui-ade-orchestrator:scripts/worker-reap` | settled dispatch 정리 실행기 |
| `master_runtime.core.worker_reap.WorkerReaper` | dispatch 조회, terminal close, worktree 안전성 검사, ledger append 구현 |
| `master_runtime.core.work_ledger.ReapObservability` | ledger에서 settled지만 reap 기록이 없는 dispatch 탐지 |
| `local-master-ops:scripts/worker-pane-sweep` | live Orca terminal 상태 분류기 |

```bash
local-mogui-ade-orchestrator/scripts/worker-reap \
  --task-id <task-id> \
  --ledger ~/.mogui/dispatch-ledger.jsonl
```

`--task-id`와 `--dispatch-id`는 상호 배타이며 둘 중 하나가 필수입니다. `--ledger`를 넘기면 실제 실행 시 reap 이벤트가 JSONL로 append됩니다.

## 정리 가능 상태

`worker-reap`는 `orca orchestration dispatch-show --json`으로 dispatch를 읽습니다. 상태 문자열은 대문자로 정규화되며, 다음 상태만 settled로 취급합니다.

| 상태 | reap 허용 |
| --- | --- |
| `COMPLETED` | 예 |
| `ACCEPTED` | 예 |
| `FAILED` | 예 |
| `ABANDONED` | 예 |
| `RUNNING` | 아니요 |
| `REGISTERED` | 아니요 |

열린 dispatch는 정리하지 않습니다. `RUNNING` 또는 `REGISTERED`처럼 settled가 아닌 상태는 exit code `3`으로 거부됩니다.

<Warning>
`FAILED`와 `ABANDONED`도 settled입니다. 이 구현은 성공 여부가 아니라 dispatch가 더 이상 열린 작업이 아닌지를 기준으로 terminal 회수를 허용합니다.
</Warning>

## 실행 순서

<Steps>
<Step title="Dispatch 상태 조회">
`--task-id`가 있으면 `orca orchestration dispatch-show --json --task <task-id>`를 호출하고, `--dispatch-id`가 있으면 `--dispatch <dispatch-id>`를 사용합니다. JSON 파싱 실패는 exit code `4`입니다.
</Step>

<Step title="Settled 여부 확인">
상태가 `COMPLETED`, `ACCEPTED`, `FAILED`, `ABANDONED` 중 하나가 아니면 실행을 중단합니다. 이 단계 전에는 terminal close나 worktree 제거를 하지 않습니다.
</Step>

<Step title="Terminal close">
dispatch payload에 `terminal_id`가 있으면 실제 실행 모드에서 `orca terminal close <terminal-id>`를 호출합니다. close 실패는 reap 실패로 처리됩니다.
</Step>

<Step title="Worktree 검사와 제거">
`worktree_path`가 있으면 git 상태와 merge 포함 여부를 검사합니다. clean하고 `origin/main`에 포함된 worktree만 `git worktree remove <path>`로 제거합니다.
</Step>

<Step title="Ledger 기록">
실제 실행이고 `--ledger`가 제공된 경우에만 `event: "reap"` JSONL 행을 append합니다. `--dry-run`은 ledger를 쓰지 않습니다.
</Step>
</Steps>

## Worktree 제거 조건

worktree 제거는 보수적으로 동작합니다. 아래 조건을 모두 만족해야 제거됩니다.

| 검사 | 명령 또는 판정 |
| --- | --- |
| 경로 존재 | `worktree_path.exists()` |
| git 상태 clean | `git -C <worktree> status --porcelain` 출력이 비어 있어야 함 |
| 현재 branch 확인 | `git -C <worktree> branch --show-current` |
| 일반 merge 포함 | 현재 branch가 `git -C <worktree> branch -a --merged origin/main` 결과에 포함 |
| squash merge 포함 | `git merge-tree --write-tree origin/main HEAD` 결과 tree가 `origin/main^{tree}`와 동일 |

일반 ancestry merge가 아니어도, squash merge 후 branch 변경분이 이미 `origin/main` tree에 포함되어 있으면 제거 가능합니다. 반대로 dirty 상태, detached HEAD, git 오류, `origin/main` 해석 실패, virtual merge 충돌, tree 변경이 남는 경우는 제거하지 않습니다.

```text
dispatch settled
  -> terminal close
  -> worktree exists?
       no  -> worktree_left:<path>:Worktree path does not exist
       yes -> clean?
               no  -> worktree_left:<path>:Worktree has uncommitted changes
               yes -> included in origin/main?
                       yes -> worktree_removed:<path>
                       no  -> worktree_left:<path>:Current branch ... is not merged to origin/main (...)
```

## Dry-run 동작

`--dry-run`은 `execute=False`로 실행됩니다. dispatch 조회와 안전성 검사는 수행하지만, terminal close, worktree remove, ledger append는 수행하지 않습니다.

```bash
local-mogui-ade-orchestrator/scripts/worker-reap \
  --dispatch-id dispatch_xyz \
  --ledger ~/.mogui/dispatch-ledger.jsonl \
  --dry-run
```

출력의 `record.actions_taken`에는 실제 실행 시 수행될 action 문자열이 들어갑니다. 따라서 dry-run 출력의 `terminal_closed:<id>`나 `worktree_removed:<path>`는 실행 결과가 아니라 계획된 결과로 읽어야 합니다. JSON 최상위의 `dry_run: true`가 실행 여부를 구분합니다.

## 출력과 ledger 형식

기본 출력은 pretty JSON이며, `--json`을 주면 compact JSON입니다.

```json
{
  "record": {
    "task_id": "task_abc123",
    "dispatch_id": "dispatch_xyz",
    "terminal_id": "term_123",
    "worktree_path": "/path/to/worktree",
    "actions_taken": "terminal_closed:term_123;worktree_removed:/path/to/worktree",
    "timestamp": 1722787200.0
  },
  "dry_run": false
}
```

ledger append 행은 `event`, `ts`, 그리고 record 필드를 함께 담습니다.

```json
{"actions_taken":"terminal_closed:term_123;worktree_removed:/path/to/worktree","dispatch_id":"dispatch_xyz","event":"reap","task_id":"task_abc123","terminal_id":"term_123","timestamp":1722787200.0,"ts":1722787200.0,"worktree_path":"/path/to/worktree"}
```

`actions_taken`은 세미콜론으로 연결된 문자열입니다. 대표 action은 다음과 같습니다.

| action | 의미 |
| --- | --- |
| `terminal_closed:<terminal-id>` | dispatch terminal close가 계획 또는 실행됨 |
| `worktree_removed:<path>` | clean하고 포함된 worktree가 제거됨 |
| `worktree_left:<path>:<reason>` | worktree를 남겼고 reason을 기록함 |

## Unreaped dispatch 탐지

`ReapObservability`는 dispatch ledger를 읽어 settled 상태지만 `reap` 이벤트가 없는 dispatch를 반환합니다.

```python
from master_runtime.core.work_ledger import ReapObservability

obs = ReapObservability("~/.mogui/dispatch-ledger.jsonl")
unreaped = obs.unreaped_settled_leases()
```

이 탐지는 `dispatch_submitted`, `dispatch_completed`, `reap` 이벤트를 재생합니다. 유효하지 않은 JSON 행이나 dispatch id가 없는 행은 건너뜁니다.

## Pane sweep과의 관계

`local-master-ops:scripts/worker-pane-sweep`는 정리 전후에 live terminal 상태를 읽는 분류 도구입니다. `orca terminal list`로 terminal handle을 찾고, 각 handle의 최근 frame을 `orca terminal read --terminal <handle>`로 읽어 verdict를 출력합니다.

| verdict | 의미 | exit 영향 |
| --- | --- | --- |
| `working` | TUI가 작업 중 | `ok` |
| `idle` | ready prompt 상태 | `ok` |
| `approval` | 승인 또는 확인 prompt 대기 | exit `1` |
| `start-screen` | launch/resume 화면 | exit `1` |
| `update` | runtime restart 필요 | exit `1` |
| `limit` | quota 또는 rate limit | exit `1` |
| `shell` | agent가 종료되고 shell만 남음 | `note` |
| `unknown` | 분류 불가 | exit `1` |

<Info>
`scripts/worker-pane-sweep`는 action을 수행하지 않습니다. 출력이 `ACTION` 또는 `UNREAD`이면 pane을 직접 읽고 coordinator 결정을 내려야 합니다.
</Info>

## 실패와 보류 신호

| 신호 | 원인 | 조치 |
| --- | --- | --- |
| exit `2` | `--task-id`와 `--dispatch-id`가 모두 없음 | 둘 중 하나만 지정 |
| exit `3` | dispatch가 settled 상태가 아님 | completion, acceptance, failure, abandon 상태를 먼저 확인 |
| exit `4` | dispatch JSON 파싱 실패 | Orca 출력과 CLI 버전 확인 |
| `Worktree has uncommitted changes` | worktree dirty | 변경분을 검토, commit 또는 수동 정리 |
| `detached HEAD` | 현재 branch를 확인할 수 없음 | branch 상태를 수동 확인 |
| `not merged to origin/main` | ancestry 또는 squash 포함을 증명하지 못함 | merge 여부를 확인하고 필요 시 남겨 둠 |
| `Check failed: ...` | git 검사 또는 remove 중 예외 | worktree를 남긴 상태로 reason 확인 |

## 운영 원칙

정리는 자동 sweep이 아니라 명시 호출입니다. completion report 처리는 검증, merge 판단, reap ledger 기록까지 끝나야 닫힌 것으로 취급합니다. 애매한 worktree는 제거하지 않고 reason을 남깁니다. terminal close는 worker 세션 자원을 회수하는 단계이고, worktree remove는 git 상태와 `origin/main` 포함 여부가 별도로 증명될 때만 수행하는 단계입니다.

## Related pages

<CardGroup>
<Card title="작업자 위임" href="/dispatch-workers">
dispatch 생성, register, completion channel, acceptance 전 재검증 흐름.
</Card>
<Card title="Acceptance loop 실행" href="/run-acceptance-loop">
작업 결과를 수락하기 전 반복 검증과 scorecard 처리.
</Card>
<Card title="CLI 참조" href="/cli-reference">
`scripts/worker-reap` 옵션, exit code, 공개 command surface.
</Card>
<Card title="문제 해결" href="/troubleshooting">
열린 dispatch, unavailable worktree, model probe, redaction 실패 신호별 대응.
</Card>
</CardGroup>
