# Supervised dispatch

> check → dispatch → register 흐름, 계약 해시·ledger, model probe, Codex/Cursor pretrust, 완료 채널 orchestration.

- Repository: local/mogui-ADE-orchestrator

- Human docs: https://grok-wiki.com/public/docs/local-mogui-ade-orchestrator-97afe791d5ac
- Complete Markdown: https://grok-wiki.com/public/docs/local-mogui-ade-orchestrator-97afe791d5ac/llms-full.txt

## Source Files

- `docs/public/delegation-and-review.md`
- `scripts/dispatch-gate`
- `src/master_runtime/core/dispatch_gate.py`
- `master-ops/docs/charter/05-dispatch-gate.md`
- `master-ops/scripts/dispatch`
- `scripts/codex-worker-pretrust`
- `scripts/cursor-worker-pretrust`
- `tests/test_dispatch_gate.py`

---

---
title: "Supervised dispatch"
description: "check → dispatch → register 흐름, 계약 해시·ledger, model probe, Codex/Cursor pretrust, 완료 채널 orchestration."
---

Supervised dispatch는 `scripts/dispatch-gate`와 `master-ops/scripts/dispatch`가 강제하는 **기록된 허가 경계**다. 워커 계약이 게이트를 통과하고(`check`), Orca orchestration으로 작업이 기동되며(`dispatch`), job id·모델·완료 채널이 ledger에 독립 검증된 뒤에야(`register`) 디스패치가 성립한다. 자체 보고(self-report)만으로는 성립하지 않는다.

## 표면 요약

| 표면 | 역할 |
|------|------|
| `scripts/dispatch-gate` | 게이트 CLI: `check` · `register` · `watch` · `report` |
| `src/master_runtime/core/dispatch_gate.py` | 판정·티켓·ledger·티어 정책 코어 |
| `master-ops/scripts/dispatch` | 원샷 파이프라인: gate → task-create → inject → register → delivery |
| `scripts/model-identity-probe` | transcript JSONL에서 assistant 모델 id 실측 |
| `scripts/codex-worker-pretrust` | Codex 계정 `config.toml` project trust 선기입 |
| `scripts/cursor-worker-pretrust` | Cursor `.workspace-trusted` 마커 선기입 |
| `master-ops/model-tier-policy.json` (또는 `config/model-tier-policy.json`) | v2 티어 × fan-out 정책 |

<Note>
`dispatch` 단계는 게이트가 워커를 직접 기동하지 않는다. 마스터(또는 `master-ops/scripts/dispatch`)가 계약이 지정한 런타임/터미널에 워커를 붙인다. 예전에 존재하던 typed adapter 래핑 경로는 제거되었다.
</Note>

## 파이프라인: check → dispatch → register

```text
check  →  (pretrust)  →  Orca task-create / worker inject  →  register  →  delivery 확인
         ticket 발급                                              job 검증
         ledger ALLOW                                            model 검증
```

| 단계 | 누가 | 무엇을 증명하는가 |
|------|------|------------------|
| `check` | `dispatch-gate check` | 계약 가독성, 완료 채널, 모델·티어 정책, 문자 예산, 고비용 런타임 규칙 |
| `dispatch` | Orca orchestration (또는 래퍼) | Task 생성, terminal attach, `dispatch --inject` |
| `register` | `dispatch-gate register` | job id가 아티팩트에 존재, (해당 시) orchestration task 존재, 선언 모델 vs 실측 모델 |
| delivery | `master-ops/scripts/dispatch` | inject 전후 pane 분류 — register 성공 ≠ 스펙 전달 |

### 원샷 래퍼 (`master-ops/scripts/dispatch`)

측정된 운영 경로:

1. top 티어면 `--top-approved "<reason>"` 없으면 즉시 거부 (ledger 행 없음)
2. `check --no-record`로 사전 평가 → `--check-only`면 여기서 종료
3. Codex면 `codex-worker-pretrust` 실행 (`Summary:`에 `skipped` 있으면 fail-closed)
4. 기록형 `check` (ticket 발급 + ledger 행)
5. `orca orchestration task-create --spec …`
6. terminal 재사용 또는 `orca terminal create --worktree …`
7. `orca orchestration dispatch --task … --to … --inject`
8. `register` (`dispatch-show`로 job id 프로브, 가능하면 model probe)
9. pane 분류로 delivery class 판정 (`agent-started` / `hook-trust` / `limit` / `unknown`)

```bash
# 템플릿 자리표시자는 인스턴스 치환 후 사용
G={{RUNTIME_ROOT}}/scripts/dispatch-gate
L=~/.mogui/dispatch-ledger.jsonl

"$G" --ledger "$L" check \
  --runtime codex --model gpt-5.3-codex \
  --contract ./contracts/job.md \
  --agents 1 --est-chars 3000 \
  --completion-channel orchestration

# … Orca task-create / terminal / dispatch --inject …

"$G" --ledger "$L" register \
  --job-id <dispatch-id> \
  --probe-cmd 'orca orchestration dispatch-show --task <task-id> --json | grep -o <dispatch-id> | head -1' \
  --orchestration-task <task-id> \
  --declared-model gpt-5.3-codex \
  --model-probe-cmd '<scoped probe that prints model id>' \
  --contract-sha <sha-from-check> \
  --runtime codex
```

<Warning>
stdout는 JSON 판정, stderr는 사람용 진단이다. `2>&1`로 합치면 JSON 파서가 깨진다. 기계 사용 시 `2>/dev/null`로 stderr를 분리한다.
</Warning>

## `check`

### 필수 입력

<ParamField body="--runtime" type="string" required>
소문자 런타임 id (`^[a-z0-9][a-z0-9_-]{0,31}$`).
</ParamField>

<ParamField body="--contract" type="path" required>
워커 계약 파일. 내용은 SHA-256 `contract_sha`로 해시된다.
</ParamField>

<ParamField body="--agents" type="int" required>
에이전트 수 (`>= 1`). cost proxy = `n_agents * est_input_chars`.
</ParamField>

<ParamField body="--model" type="string" required>
선언 모델 id. 공백-only/미지정은 `NO_MODEL`.
</ParamField>

<ParamField body="--completion-channel" type="orchestration | sentinel-log" required>
완료 채널. 없거나 미허용 값이면 `NO_COMPLETION_CHANNEL`.
</ParamField>

<ParamField body="--est-chars" type="int">
예상 입력 문자. 생략 시 completion channel이 있으면 계약 파일 길이, 없으면 `0`. 측정 불가(`None`)면 `CONTRACT_UNREADABLE`로 fail-closed.
</ParamField>

<ParamField body="--tier-policy" type="path">
정책 파일 명시. 없으면 아래 해석 순서.
</ParamField>

<ParamField body="--tier-override" type="string">
cap/deny 초과 시 한 요청을 통과시키는 사유 문자열.
</ParamField>

<ParamField body="--no-record" type="flag">
ledger append·ticket 발급 없이 평가만. dry-run/`--check-only`용. 기록하면 fan-out 예산을 소모한다.
</ParamField>

### 티어 정책 해석 순서

1. CLI `--tier-policy`
2. 환경 변수 `DISPATCH_TIER_POLICY`
3. 인스턴스 `config/model-tier-policy.json` (온보딩 후 존재 시)
4. 템플릿 `master-ops/model-tier-policy.json`

### v2 정책 동작 (현재 템플릿)

| 규칙 | 동작 |
|------|------|
| 모델 → 티어 | `tiers` 목록 casefold 매칭; 미등록은 `unknown` |
| fan-out | 티어별 `fanout_caps` 창(`window_seconds`, 기본 86400초) 누적 agent 수 |
| 키 없음 | 해당 티어 **무제한** (top 포함). 템플릿은 `unknown: 8`만 캡 |
| top 운영 | 게이트 cap이 아니라 `master-ops/scripts/dispatch`가 `--top-approved`를 요구 |
| 창 의미 | 동시성이 아니라 **누적**. 순차 1명×10회 = fan-out 10과 동일 소모 |
| override | `--tier-override`는 한 요청만 통과; 이미 센 창 예산은 환불하지 않음 |

기본 문자 한도: 단일 디스패치 `500_000`, 배치(cost proxy) `1_000_000`. 고비용 런타임 집합 기본값은 `fable` (2+ agents면 `ROUTING_VIOLATION`).

### 성공 시 부수 효과

- JSON `GateDecision` (`allow`, `reason`, `warnings`, `contract_sha`, …)을 stdout
- `record=True`면 JSONL ledger에 ALLOW 행 + `~/.mogui/dispatch-tickets/{runtime}-{sha12}.json` 티켓 발급
- 티켓 TTL 기본 **600초**; 만료 후 grace(기본 24h) 지나면 GC

## `register`

선행 성공 `check` 없이 유효한 registration은 없다. 티켓·pending ledger 행을 매칭하고, 프로브가 job id를 증명한 뒤에만 등록한다.

### 필수/핵심 플래그

| 플래그 | 의미 |
|--------|------|
| `--job-id` | 등록할 dispatch/job id |
| `--probe-cmd` | shell 명령: **exit 0** 이고 **stdout에 job id 문자열** 포함 |
| `--contract-sha` | check 산출 sha (최소 12 hex; 접두 매칭). 다중 후보 시 `AMBIGUOUS_TICKET` |
| `--runtime` | 티켓/pending 필터 |
| `--orchestration-task` | 완료 채널이 `orchestration`이면 **필수** |
| `--declared-model` | check 때 선언한 모델 |
| `--model-probe-cmd` | 워커가 쓴 아티팩트에서 실측 모델 id를 stdout으로 출력 |
| `--tier-policy` | 실측 티어 escalation 비교용 (check와 동일 해석) |

### 프로브 계약

```text
probe 성공  ⇔  returncode == 0  AND  job_id ∈ stdout
```

<Warning>
파일명만 출력하는 프로브(내용 미독)는 검증 스탬프만 남긴다. `grep &lt;job-id&gt; logfile`, `cat evidence.txt`처럼 **내용**을 stdout에 내도록 한다. 타임아웃: orchestration 프로브·model 프로브 각 30초.
</Warning>

### orchestration 검증

완료 채널이 `sentinel-log`가 아니면:

1. `--orchestration-task` 누락 → `ORCHESTRATION_UNVERIFIED` (`task_omitted`)
2. `orca` 부재 / 타임아웃 / 파싱 실패 / task 미존재 → 동일 deny 계열, ledger에 실패 원인 기록

### 모델 검증 등급

| 상황 | 코드 | 결과 |
|------|------|------|
| 선언·실측 일치 (정책 관점 허용) | — | `model_verified=true` |
| 실측 티어가 선언보다 엄격(더 비싼 쪽으로 승격) | `MODEL_TIER_ESCALATION` | **DENY** |
| 실측 ≠ 선언이지만 escalation 아님 | `MODEL_MISMATCH` | 경고 후 등록 가능 |
| 선언 없음 / 실측 없음 | `MODEL_UNVERIFIED` | 경고 후 등록 |
| 프로브 실패·비0·타임아웃 | `MODEL_PROBE_FAILED` | 경고 후 등록 |

ledger 필드: `model_declared`, `model_measured`, `model_verified`. 미검증 등록과 검증 등록을 구분한다.

## 계약 해시 · ledger · 티켓

```text
contract bytes  --sha256-->  contract_sha (64 hex)
check ALLOW  -->  ledger JSONL row + ticket {runtime, contract_sha, issued_ts, count}
register     -->  ticket 소모(매칭 시 unlink) + registered 행 + attempt 카운트
```

| 저장소 | 기본 경로 | 비고 |
|--------|-----------|------|
| Ledger | `.dispatch-gate-ledger.jsonl` 또는 `DISPATCH_GATE_LEDGER` / `--ledger` | 운영 래퍼는 `~/.mogui/dispatch-ledger.jsonl` 사용 |
| Tickets | `~/.mogui/dispatch-tickets/` | 파일명 `{runtime}-{sha[:12]}.json` |
| Lock | 티켓 디렉터리 `.dispatch-gate.lock` | Unix `fcntl` |

`dispatch-gate report` (옵션 `--today`)는 모델별 디스패치 수·cost proxy, deny reason, 티어 누적, 정책 path+`sha256`, tier override를 집계한다. 스팬에 **정책 행이 둘 이상**이면 단일 정책으로 판단되지 않은 구간이다.

## 완료 채널: orchestration

허용 값: `orchestration` | `sentinel-log`.

규정 준수 디스패치는 **벤더 중립 Orca orchestration**이다.

1. Run에 바인딩
2. `orca orchestration task-create`
3. `orca orchestration worker-start` 또는 `dispatch --inject`
4. 이벤트 대기: `check --wait --types worker_done,escalation,question`
5. 응답의 camelCase `deliveryId`를 다음 wait의 ack에 연결 — 미ack 백로그는 같은 배치를 반복 반환

<Info>
원시 terminal polling·벤더 직행 CLI는 task/Dispatch 출처와 `worker_done` 권한을 우회한다. 비규정 경로다. 2차 의견 리뷰 등 비디스패치 용도의 벤더 플러그인은 허용된다. 실수로 orchestration 밖에서 한 작업은 **non-orchestrated**로 기록하고 소급 재라벨하지 않는다.
</Info>

## Model probe

`scripts/model-identity-probe`가 참조 구현이다.

- 입력: 세션 transcript JSONL (`--transcript`) 또는 instance config / `MOGUI_TRANSCRIPT_GLOB`으로 최신 매칭
- 출력: 최근 assistant 모델 분포; `--expect`/`MODEL_IDENTITY_EXPECT` 있으면 OK/DRIFT
- TUI status line 스크래핑 금지 — 렌더러가 그린 문자열이 아니라 **에이전트가 쓴 아티팩트**만

`master-ops/scripts/dispatch`는 worktree-scoped glob이 가능한 런타임(현재 파생: `claude`)에서만 model probe를 켠다. 스코프 불가 런타임은 `model=unavailable`로 표기하고 **false pass를 만들지 않는다**. 호출자가 확인한 경로만 `--transcript-glob`으로 넘긴다.

## Pretrust: Codex / Cursor

| 런타임 | 스크립트 | 동작 | 성공 조건 |
|--------|----------|------|-----------|
| Codex | `scripts/codex-worker-pretrust <abs-worktree>` | Orca codex-accounts `*/home/config.toml`에 `[projects."<path>"]` trust | `Summary:`에 `skipped` 없음. 래퍼는 skipped를 fail-closed |
| Cursor | `scripts/cursor-worker-pretrust <abs-worktree>` | `~/.cursor/projects/<key>/.workspace-trusted` | exit 0, summary가 `added`/`updated`/`already trusted` (not `skipped`) |

절대 경로 필수. Codex 계정이 없으면 “nothing to pre-trust”로 0 종료할 수 있으나, tomllib 없는 Python이면 `Summary: skipped` — 디스패치 래퍼는 이를 거절한다. Cursor launch 플래그 `--force --trust`는 보조이며, worktree attach 전 pretrust를 대체하지 않는다.

## 워커 계약 필드 (게이트 밖 규율)

계약은 다른 세션이 추측 없이 실행할 수 있을 만큼 좁혀 쓴다.

- 대상 저장소·checkout
- 허용 작업면 / 금지 편집
- acceptance 기준·필수 증거
- commit / push / branch 규칙 (권한 없으면 미커밋이 보수 기본)
- 알려진 제외 항목

워커 “Done”은 클레임일 뿐이다. 수락은 마스터의 독립 검증이다 → [증거와 수락](/evidence-and-acceptance).

## Delivery vs register

`register ✓`는 ledger에 job이 잡혔다는 뜻이다. inject가 trust 메뉴·start screen에 떨어지면 스펙이 소비되지 않은 채 전 단계가 성공으로 보일 수 있다.

`master-ops/scripts/dispatch` exit 요약:

| 코드 | 의미 |
|------|------|
| 0 | 정상 (delivery 경고 포함 가능) |
| 1 | 인자/계약 파일 문제 |
| 2 | gate DENY, top 미승인, model/runtime 불일치, pretrust 실패 등 |
| 3 | task-create / terminal 실패 |
| 4 | register DENY (워커는 이미 돌 수 있음 — 수동 정리) |
| 5 | delivery FAILED (`hook-trust` / `limit`) |

## 주요 reason code

| 코드 | 단계 | 의미 |
|------|------|------|
| `OK` | check/register | 허용 |
| `NO_COMPLETION_CHANNEL` | check | 완료 채널 누락/불법 |
| `NO_MODEL` | check | 모델 미지정 |
| `CONTRACT_UNREADABLE` | check | 계약 읽기/크기 측정 실패 |
| `BUDGET_EXCEEDED` | check | 문자/배치 한도 |
| `TIER_POLICY` / `TIER_POLICY_UNAVAILABLE` | check | v1 거부 또는 정책 파일 불능 |
| `TIER_FANOUT_CAP` | check | v2 창 누적 cap 초과 |
| `TIER_UNKNOWN_MODEL` | check | 경고: 미등록 모델 → `unknown` |
| `UNVERIFIED_JOB` | register | probe 실패 |
| `NO_MATCHING_TICKET` / `AMBIGUOUS_TICKET` | register | 티켓 0개/다수 |
| `ORCHESTRATION_UNVERIFIED` | register | task 미검증 |
| `MODEL_TIER_ESCALATION` | register | 실측 티어 승격 **거부** |
| `MODEL_MISMATCH` / `MODEL_UNVERIFIED` / `MODEL_PROBE_FAILED` | register | 경고 기록 |

CLI: check/register 거부 시 exit **2**. `watch` stalled는 **3**, missing은 **2**.

## 검증 신호

<Check>
- `check` stdout `allow: true` + 비어 있지 않은 `contract_sha`
- 기록 모드에서 ticket 파일 존재, ledger에 ALLOW 행 (policy path + `tier_policy_sha256`)
- Codex/Cursor: pretrust `Summary:`가 skipped가 아님
- `register` allow + (가능하면) `model_verified` 또는 명시적 unverified 경고
- orchestration 경로: task id와 dispatch id가 `dispatch-show` 등으로 교차 확인
- 래퍼 사용 시 `delivery … class=agent-started` 또는 수동 pane 확인
</Check>

## 자주 나는 실패

| 증상 | 원인 | 조치 |
|------|------|------|
| dry-run 후 cap 초과 | `--no-record` 없이 check | `--check-only` / `--no-record` |
| `MODEL_PROBE_FAILED` | transcript 미생성·비범위 glob | worktree-scoped 경로; 없으면 미검증으로 기록 후 수동 확인 |
| inject 성공·일 안 함 | trust/start 메뉴에 idle | pretrust, pane 분류, 메뉴에 재주입 금지 |
| 잘못된 master host 가드 | `master_host_runtime` fallback | `MOGUI_MASTER_HOST_RUNTIME` 또는 instance-runtime 설정 |
| top 거부 | `--top-approved` 없음 | 오너 사유를 플래그로 전달 (절차 증거, 인증 경계 아님) |

## 관련 표면 경계

- **수락 루프·리뷰 렌즈**: 이 페이지의 register 이후. 게이트는 “출발 허가 + 등록”만 담당.
- **Worker reap**: lease `issued→reaped`, terminal/worktree 정리 — [Worker reap](/worker-reap).
- **플래그·스키마 전체 표**: [dispatch-gate 레퍼런스](/dispatch-gate-reference).

## Next

<CardGroup>
  <Card title="dispatch-gate 레퍼런스" href="/dispatch-gate-reference">
    check·register·watch·report 플래그, ledger 스키마, reason code, TTL, 문자 한도.
  </Card>
  <Card title="증거와 수락" href="/evidence-and-acceptance">
    self-report와 독립 검증, 리뷰 렌즈, acceptance 판정.
  </Card>
  <Card title="방어 인벤토리" href="/defense-inventory">
    디스패치 게이트·model probe·pretrust를 포함한 가드 표.
  </Card>
  <Card title="인스턴스 설정" href="/configure-instance">
    instance-runtime, model-tier-policy, transcript glob, host runtime.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    MODEL_PROBE_FAILED, placement, preflight BLOCKED 복구.
  </Card>
  <Card title="Worker reap" href="/worker-reap">
    등록 이후 lease 회수와 worktree 정리.
  </Card>
</CardGroup>
