# Orca 객체 모델

> project·folder workspace·worktree·terminal·Run, 마스터 좌석 규칙, 검증된 selector 형식, 오해하기 쉬운 UI 라벨.

- 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/orca-concepts.md`
- `src/master_runtime/core/succession.py`
- `master-ops/docs/runbooks/succession-boot-card.md`
- `master-ops/onboarding/04-seat.md`
- `config/workspace-descriptor.example.json`
- `docs/public/master-lifecycle.md`

---

---
title: "Orca 객체 모델"
description: "project·folder workspace·worktree·terminal·Run, 마스터 좌석 규칙, 검증된 selector 형식, 오해하기 쉬운 UI 라벨."
---

이 런타임은 모든 에이전트를 Orca 안에 앉힌다. project·workspace(worktree/folder)·terminal·Run 계층과 마스터 좌석 규칙이 어긋나면 코드가 정상인데도 실측 misplacement가 난다. 공개 개념 문서는 `docs/public/orca-concepts.md`, 좌석 측정 절차는 `master-ops/onboarding/04-seat.md`, 배치 fail-closed 검증은 `scripts/master-succeed spawn`과 `src/master_runtime/core/succession.py`가 담당한다.

## 객체 계층

Orca가 추적하는 세 층과, 이 런타임이 그 위에 두는 오케스트레이션 문맥은 다음과 같다.

| 객체 | 의미 | 이 런타임에서의 역할 |
| --- | --- | --- |
| **Project** | Orca에 등록한 폴더(단일 Git repo, 여러 repo를 담은 plain folder, 빈 폴더 모두 project가 됨) | 사이드바 그룹은 표시용일 뿐 객체가 아님 |
| **Workspace** | project 안의 seat. terminal·에이전트가 사는 자리 | 종류가 첫 명령의 가능 범위를 결정함 |
| **Terminal** | workspace 안의 라이브 세션 | 마스터·워커 모두 terminal |
| **Run** | terminal에 묶인 내구성 오케스트레이션 문맥 | task·dispatch·mailbox를 세션 재시작 너머로 유지 |

```text
Project (Orca 등록 단위)
├── repository worktree  …  Git checkout 1개, 워커 seat
└── folder workspace     …  plain folder seat, 보통 마스터 seat
    └── Terminal         …  에이전트/셸 세션
        └── Run          …  디스패치·mailbox 바인딩
```

### Workspace 두 종류

프로젝트 형태가 어떤 workspace를 만들 수 있는지 결정한다.

| 종류 | 생성 경로 | 시작 cwd | 판정 필드 |
| --- | --- | --- | --- |
| **Repository worktree** | Create worktree 대화 / 저장소 project | checkout 안. git 즉시 가능 | `worktreeId` = `id:<repoId>::<path>` 계열 |
| **Folder workspace** | Create Folder Workspace / folder project | checkout 밖. git은 먼저 cd 필요 | `worktreeId` = `folder:<uuid>`, `worktreePath` 비어 있음(정상) |

워크스페이스 루트가 plain folder이고 멤버 저장소가 sibling으로 늘어선 형태가 이 런타임의 기본 모델이다. 서브모듈 부모는 지원하지 않는다. 선언형 인벤토리는 `config/workspace-descriptor.json`(예시는 `config/workspace-descriptor.example.json`)에 둔다.

## 마스터 좌석 규칙

마스터는 워크스페이스 전체 저장소를 조율하므로 **workspace-level seat**에 앉는다.

| 워크스페이스 형태 | 마스터 seat | selector 형태(권장 기록) |
| --- | --- | --- |
| multi-repo, root = plain folder project | 그 root의 **folder workspace** | `id:folder:<uuid>` |
| single-repo workspace | 그 저장소의 **primary worktree** | `id:<repoId>::<path>` |

<Warning>
multi-repo 워크스페이스에서 마스터를 개별 저장소 worktree에 앉히면 cwd·hooks·session 파일이 맞아 보여도 misplacement다. 사이드바에서는 그 저장소 아래에 걸리고, 워커용 seat를 점유한다. 2026-08-03 실측 사고가 이 형태였다.
</Warning>

온보딩 Step 3.5(`master-ops/onboarding/04-seat.md`) 절차 요약:

1. ops 저장소를 `orca repo add`로 등록(워커 worktree 소스).
2. `{{WORKSPACE_ROOT}}`를 project로 두고 folder workspace를 연다(단일 저장소여도 parent folder seat).
3. **임시 plain terminal**로 seat id만 측정한다. 마스터를 이 단계에서 만들지 않는다.
4. `orca terminal show --terminal <handle> --json`으로 `worktreeId`를 읽고, durable 기록에는 **`id:` 접두 형태**만 남긴다.
5. 임시 terminal을 닫아 좌석을 비운 뒤 founding spawn(`scripts/master-succeed spawn`)이 유일한 마스터 terminal이 되게 한다.

durable identity는 terminal handle이 아니다. handle은 앱 런타임 스코프이며 재시작과 함께 죽는다. 남는 것은 selector다.

descriptor의 `master_seat` 필드는 보통 `folder-workspace-of-workspace-root` 같은 서술 문자열이며, 실측 selector 문자열과 1:1이 아닐 수 있다. 실행 경로의 권위는 측정된 selector와 spawn 검증이다.

## 워커 좌석

마스터와 반대다.

| 역할 | seat | 금지 |
| --- | --- | --- |
| 마스터 | folder workspace(또는 single-repo primary worktree) | multi-repo에서 개별 product worktree에 안착 |
| 워커(git 필요) | 대상 저장소의 **isolated repository worktree**, 자체 브랜치 | folder workspace 공유, 마스터 checkout 공유 |

folder seat에 워커를 두는 것은 첫 명령이 checkout으로 `cd`할 때만 허용된다. 그렇지 않으면 첫 git 호출에서 실패한다. 생성만 하고 prompt/cwd를 확인하지 않으면 “만든 terminal”과 “동작 중인 worker”를 혼동한다.

워커 수명 끝에서는 `scripts/worker-reap`이 terminal close와 clean/merged worktree 정리를 담당한다. dirty·unmerged·접근 불가 worktree는 제거하지 않고 사유를 남긴다.

## 검증된 selector 형식

placement 명령(`orca terminal create --worktree`, `scripts/master-succeed spawn --workspace-selector`)은 selector 문자열을 받는다. 2026-08-03 실측과 `succession.py` 정규화 규칙이 합쳐진 동작은 다음과 같다.

| Selector | 동작 | 권장 |
| --- | --- | --- |
| `id:<repoId>::<path>` | repository worktree end-to-end | 기본. `orca worktree list --json`의 full `id` 복사 |
| `id:folder:<uuid>` | folder workspace: list precheck·create·spawn match 통과 | durable 기록 표준 |
| `folder:<uuid>` (bare) | `terminal create`는 수용, `terminal list --worktree`는 `selector_not_found`로 거부(하위명령 비대칭). spawn 코드는 list 시 `id:`를 붙인다 | 한 문자열이 모든 소비자에서 통해야 하면 `id:` 형태 |
| `path:/abs/dir` | Orca는 `<repoId>::<path>`로 해석. spawn 비교기가 거부하거나 경로 해석 매칭에만 부분 성공 | durable/요청 문자열로 쓰지 말 것 |

`succession.py`의 정규화:

- `_normalize_worktree_selector`: 선행 `id:`를 벗겨 비교한다. 응답의 `repoId::path`와 요청의 `id:repoId::path`를 동일 좌석으로 본다.
- `_terminal_list_worktree_selector`: bare `folder:`이면 list 전에 `id:`를 붙인다.
- `_path_worktree_matches`: 요청이 `path:`일 때만 actual `repoId::path`와 realpath 비교한다. folder seat에는 해당 없음.

두 규칙:

1. **Selector는 추론하지 말고 측정한다.** `orca terminal show` 또는 `orca worktree list --json`. `--worktree` 생략 시 cwd 추론이 misplacement 원인이 된다.
2. **placement match는 “요청한 것과 같은가”만 본다.** “요청 자체가 올바른 자리인가”는 lineage/descriptor 기대값과 별도로 비교해야 한다. 요청을 녹색이 될 때까지 고쳐 통과시킨 것이 2026-08-03 misplacement 경로였다.

## Spawn placement 검증

`scripts/master-succeed spawn`은 호스트 terminal을 만들고 응답 `worktreeId`를 요청 selector와 대조한다.

```bash
scripts/master-succeed spawn \
  --workspace-selector "id:folder:<uuid>" \
  --kickoff-text "Founding master boot" \
  --root . \
  --model example-model \
  --title "Founding master boot" \
  --expected-placement "id:folder:<uuid>" \
  --json \
  --dry-run
```

| 플래그/필드 | 의미 |
| --- | --- |
| `--workspace-selector` | create에 넘기는 요청 좌석(필수) |
| `--expected-placement` | 독립 기대 `worktreeId`. 불일치 시 fail-closed, exit **26** (`SPAWN_PLACEMENT_MISMATCH`) |
| 요청 vs 응답 worktree 불일치 | exit **22** (`SPAWN_WORKTREE_MISMATCH`), 가능하면 생성 terminal close |
| create 명령 | `orca terminal create --worktree <selector> --title … --command … --json` |
| liveness | create 전 snapshot → 후 list. handle이 live·new·요청 worktree 안이어야 함. 아니면 동일 title 후보 1개만 `MATCH_REISSUED`로 채택 |

```text
requested selector ──create──► worktreeId
        │                         │
        ├─ _worktrees_match? ─────┤
        │                         │
        └─ expected_placement? ───┘
                 fail-closed → close terminal when safe
```

힌트 문자열(오류 메시지 꼬리):  
`Accepted selector forms are full id:<repoId>::<path>, id:folder:<uuid> for folder workspaces; path: is matched by resolved directory.`

placement 증거 three-set(승계 부트 카드):

1. host pane / worktree selector가 의도 workspace와 일치
2. process cwd가 `{{WORKSPACE_ROOT}}` 아래
3. session artifact/log 경로가 기대 namespace

UI pane title·status line은 힌트이지 placement 증거가 아니다.

## 오해하기 쉬운 UI·CLI 라벨

| 표시 | 실제 의미 | 조치 |
| --- | --- | --- |
| **Unavailable worktree** (Agent Session History) | 세션 seat가 Git worktree가 아님 | folder-workspace 마스터에서 **정상**. 크래시 아님 |
| **빈 `worktreePath`** (`orca terminal list --json`) | folder workspace 형태 | `worktreeId`(`folder:<uuid>`)로 판정. path로 기각하지 말 것 |
| **Not a valid worktree folder** (workspace root) | root가 git repo/worktree가 아님 | plain folder 그룹 루트에서 **의도된 경고**. submodule 부모로 만들지 말 것 |
| pane status의 저장소 이름 | shell cwd 반영 | seat identity가 아님 |
| `process_id: null` (folder-workspace pane) | 호스트 list가 pid를 안 줌 | retire 시 pid/tty를 호출자가 실측해 전달 |

## Workspace descriptor와의 관계

| 키 | 값/제약 |
| --- | --- |
| `workspace_root_is_plain_folder` | 이 런타임에서 항상 true로 해석 |
| `workspace_root` | 절대 경로. absolute path lookup용 |
| `master_seat` | 마스터 seat 서술(보통 folder-workspace-of-workspace-root) |
| `repositories[].path` | workspace root 상대 경로 |
| `repositories[].role` | `product` \| `ops` |
| `capabilities` / `prohibited` | 워커 레인 허용·하드 스톱(open set) |

소비자는 `scripts/workspace-descriptor-check`와 워커 라우팅이다. 해석 순서: 환경 오버라이드 → 파일 → unconfigured. submodule shape는 없다.

## 원격·모바일 함의

Orca 세션은 시작한 책상에 묶이지 않는다(SSH remote worktree, headless `orca serve`, mobile companion). 이 런타임에 직접 닿는 결과:

- frozen 마스터는 폰에서도 재개 가능 → retirement 완료는 process·pane·tty **세 소멸 실측** 후에만.
- boot에 lineage session id revival 스캔이 있다(2026-08-03: 은퇴 마스터 4개가 동시 부활).
- 원격 머신 저장소에 대한 주장은 git remote·forge 상태로 따로 측정한다.

Orca 플래그를 추측하지 않는다. `orca --help`, `orca skills get`, `master-ops/docs/orca-docs-grounding.md` 스냅샷 순으로 측정한다.

## 검증 신호

<Check>
좌석이 맞으면 다음이 동시에 성립한다.
</Check>

- `orca terminal show`의 `worktreeId`가 workspace-level seat(`folder:<uuid>` 또는 단일 repo primary worktree)
- durable ops 기록의 selector가 `id:` 접두
- 마스터 founding/successor spawn 전 해당 seat에 임시 terminal이 없음
- `scripts/master-succeed spawn … --json`이 `verified: true`, 요청과 `worktreeId` 일치
- folder 마스터의 빈 `worktreePath` / Unavailable worktree chip을 오류로 취급하지 않음

## 트러블슈팅

| 증상 | 원인 | 대응 |
| --- | --- | --- |
| `terminal list`가 selector 거부 | bare `folder:<uuid>` | `id:folder:<uuid>`로 재기록 |
| spawn 비교 거부 / exit 22 | 요청·응답 worktree 불일치 | 기대 seat 재측정, path 치환 금지 |
| exit 26 `SPAWN_PLACEMENT_MISMATCH` | `--expected-placement`와 실제 `worktreeId` 불일치 | lineage 기대값과 요청을 각각 수정; “통과할 때까지 요청 변경” 금지 |
| `selector_not_found` on create | project 미등록·잘못된 id | `orca repo add`, `worktree list --json` |
| 마스터가 product repo 아래 표시 | repository worktree에 착석 | folder workspace로 재측정·재spawn |
| folder seat 워커 git 실패 | checkout 없는 cwd | repository worktree로 재배치 |

## Related pages

<CardGroup>
  <Card title="마스터 라이프사이클" href="/master-lifecycle">
    founding spawn부터 succession·lineage까지의 세대 루프.
  </Card>
  <Card title="Clean succession" href="/succession">
    handoff, placement 검증 spawn, retire, revival 측정.
  </Card>
  <Card title="Workspace descriptor" href="/workspace-descriptor">
    sibling 저장소 인벤토리, role·prohibited, master_seat.
  </Card>
  <Card title="master-succeed 레퍼런스" href="/succession-cli-reference">
    spawn 플래그, exit 코드, SPAWN_PLACEMENT_MISMATCH.
  </Card>
  <Card title="프로그레시브 온보딩" href="/onboarding">
    seat 측정(Step 3.5)과 founding spawn 경계.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    placement mismatch, seat 중복, revival 복구.
  </Card>
</CardGroup>
